SEO Ultimate - Version 7.6.5.2

Version Description

Download this release

Release Info

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

Code changes from version 7.6.5.1 to 7.6.5.2

Files changed (117) hide show
  1. includes/encoder.js +235 -235
  2. includes/index.php +3 -3
  3. includes/jlfunctions/arr.php +222 -222
  4. includes/jlfunctions/html.php +31 -31
  5. includes/jlfunctions/index.php +3 -3
  6. includes/jlfunctions/io.php +142 -142
  7. includes/jlfunctions/jlfunctions.php +10 -10
  8. includes/jlfunctions/num.php +32 -32
  9. includes/jlfunctions/str.php +289 -289
  10. includes/jlfunctions/url.php +68 -68
  11. includes/jlfunctions/web.php +30 -30
  12. includes/jlsuggest/jlsuggest.css +120 -120
  13. includes/jlsuggest/jlsuggest.js +361 -361
  14. includes/jlwp/functions.php +164 -164
  15. includes/jlwp/index.php +3 -3
  16. includes/jlwp/jlwp.php +4 -4
  17. includes/tabs.js +53 -53
  18. index.php +3 -3
  19. modules/404s/fofs-log.php +266 -266
  20. modules/404s/fofs-settings.php +50 -50
  21. modules/404s/fofs.css +36 -36
  22. modules/404s/fofs.php +109 -109
  23. modules/404s/index.php +3 -3
  24. modules/author-links/index.php +3 -3
  25. modules/autolinks/autolinks.css +51 -51
  26. modules/autolinks/autolinks.php +174 -174
  27. modules/autolinks/content-autolinks-settings.php +94 -94
  28. modules/autolinks/content-autolinks.php +3 -2
  29. modules/autolinks/footer-autolinks-settings.php +39 -39
  30. modules/autolinks/footer-autolinks.php +226 -226
  31. modules/autolinks/index.php +3 -3
  32. modules/canonical/canonical.php +236 -236
  33. modules/canonical/index.php +3 -3
  34. modules/class.su-importmodule.php +199 -199
  35. modules/class.su-module.php +3072 -3065
  36. modules/files/files.php +191 -191
  37. modules/files/index.php +3 -3
  38. modules/import-aiosp/import-aiosp.php +41 -41
  39. modules/import-aiosp/index.php +3 -3
  40. modules/index.php +3 -3
  41. modules/internal-link-aliases/index.php +3 -3
  42. modules/internal-link-aliases/internal-link-aliases.css +34 -34
  43. modules/internal-link-aliases/internal-link-aliases.php +373 -373
  44. modules/link-nofollow/index.php +3 -3
  45. modules/link-nofollow/link-nofollow.php +141 -141
  46. modules/linkbox/index.php +3 -3
  47. modules/linkbox/linkbox.css +3 -3
  48. modules/linkbox/linkbox.php +146 -146
  49. modules/meta/index.php +3 -3
  50. modules/meta/meta-descriptions.css +13 -13
  51. modules/meta/meta-descriptions.php +239 -239
  52. modules/meta/meta-keywords.php +226 -226
  53. modules/meta/meta-robots.css +7 -7
  54. modules/meta/meta-robots.php +116 -116
  55. modules/meta/webmaster-verify.css +20 -20
  56. modules/meta/webmaster-verify.php +109 -109
  57. modules/misc/index.php +3 -3
  58. modules/misc/misc.php +41 -41
  59. modules/modules.css +166 -166
  60. modules/modules.js +48 -48
  61. modules/modules/index.php +3 -3
  62. modules/modules/modules.css +10 -10
  63. modules/modules/modules.js +8 -8
  64. modules/modules/modules.php +235 -235
  65. modules/more-links/index.php +3 -3
  66. modules/more-links/more-links.php +122 -122
  67. modules/noindex/index.php +3 -3
  68. modules/noindex/noindex.php +180 -180
  69. modules/opengraph/index.php +3 -3
  70. modules/opengraph/opengraph.css +12 -12
  71. modules/opengraph/opengraph.php +557 -557
  72. modules/permalinks/index.php +3 -3
  73. modules/permalinks/permalinks.css +18 -18
  74. modules/permalinks/permalinks.php +208 -208
  75. modules/rich-snippets/index.php +3 -3
  76. modules/rich-snippets/rich-snippets.php +429 -429
  77. modules/sdf-ads/banners/01.png +0 -0
  78. modules/sdf-ads/banners/02.png +0 -0
  79. modules/sdf-ads/banners/06.png +0 -0
  80. modules/sdf-ads/banners/07.png +0 -0
  81. modules/sdf-ads/banners/InternalLinkBanner.jpg +0 -0
  82. modules/sdf-ads/banners/MetaWritingBanner.jpg +0 -0
  83. modules/sdf-ads/banners/SEO-VideoTraining-Banner-v3.jpg +0 -0
  84. modules/sdf-ads/sdf-ads.css +71 -71
  85. modules/sdf-ads/sdf-ads.js +79 -87
  86. modules/sds-blog/index.php +3 -3
  87. modules/sds-blog/sds-blog.css +37 -37
  88. modules/sds-blog/sds-blog.php +217 -217
  89. modules/settings/global-settings.php +68 -68
  90. modules/settings/index.php +3 -3
  91. modules/settings/install.css +28 -28
  92. modules/settings/install.php +243 -243
  93. modules/settings/settings-data.css +19 -19
  94. modules/settings/settings-data.php +291 -291
  95. modules/settings/settings.php +93 -93
  96. modules/settings/uninstall.php +108 -108
  97. modules/sharing-buttons/index.php +3 -3
  98. modules/sharing-buttons/sharing-buttons.css +13 -13
  99. modules/sharing-buttons/sharing-buttons.php +96 -96
  100. modules/slugs/index.php +3 -3
  101. modules/slugs/slugs.php +140 -140
  102. modules/titles/index.php +3 -3
  103. modules/titles/titles.php +488 -488
  104. modules/user-code/index.php +3 -3
  105. modules/user-code/user-code.php +125 -125
  106. modules/widgets/index.php +3 -3
  107. modules/widgets/widgets.php +242 -242
  108. modules/wp-settings/index.php +3 -3
  109. modules/wp-settings/wp-settings.php +111 -111
  110. plugin/class.seo-ultimate.php +11 -11
  111. plugin/class.su-installer.php +85 -85
  112. plugin/global.css +275 -275
  113. plugin/global.js +9 -9
  114. plugin/img/index.php +3 -3
  115. plugin/index.php +3 -3
  116. plugin/sdf/bootstrap/css/bootstrap-theme.admin.css +385 -385
  117. plugin/sdf/bootstrap/css/bootstrap.admin.css +0 -380
includes/encoder.js CHANGED
@@ -1,236 +1,236 @@
1
- /**
2
- * A Javascript object to encode and/or decode html characters using HTML or Numeric entities that handles double or partial encoding
3
- * Author: R Reid
4
- * source: http://www.strictly-software.com/htmlencode
5
- * Licences: GPL, The MIT License (MIT)
6
- * Copyright: (c) 2011 Robert Reid - Strictly-Software.com
7
- *
8
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9
- * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11
- *
12
- * Revision:
13
- * 2011-07-14, Jacques-Yves Bleau:
14
- * - fixed conversion error with capitalized accentuated characters
15
- * + converted arr1 and arr2 to object property to remove redundancy
16
- *
17
- * Revision:
18
- * 2011-11-10, Ce-Yi Hio:
19
- * - fixed conversion error with a number of capitalized entity characters
20
- *
21
- * Revision:
22
- * 2011-11-10, Rob Reid:
23
- * - changed array format
24
- */
25
-
26
- Encoder = {
27
-
28
- // When encoding do we convert characters into html or numerical entities
29
- EncodeType : "entity", // entity OR numerical
30
-
31
- isEmpty : function(val){
32
- if(val){
33
- return ((val===null) || val.length==0 || /^\s+$/.test(val));
34
- }else{
35
- return true;
36
- }
37
- },
38
-
39
- // arrays for conversion from HTML Entities to Numerical values
40
- arr1: [' ','¡','¢','£','¤','¥','¦','§','¨','©','ª','«','¬','­','®','¯','°','±','²','³','´','µ','¶','·','¸','¹','º','»','¼','½','¾','¿','À','Á','Â','Ã','Ä','Å','Æ','Ç','È','É','Ê','Ë','Ì','Í','Î','Ï','Ð','Ñ','Ò','Ó','Ô','Õ','Ö','×','Ø','Ù','Ú','Û','Ü','Ý','Þ','ß','à','á','â','ã','ä','å','æ','ç','è','é','ê','ë','ì','í','î','ï','ð','ñ','ò','ó','ô','õ','ö','÷','ø','ù','ú','û','ü','ý','þ','ÿ','"','&','<','>','Œ','œ','Š','š','Ÿ','ˆ','˜',' ',' ',' ','‌','‍','‎','‏','–','—','‘','’','‚','“','”','„','†','‡','‰','‹','›','€','ƒ','Α','Β','Γ','Δ','Ε','Ζ','Η','Θ','Ι','Κ','Λ','Μ','Ν','Ξ','Ο','Π','Ρ','Σ','Τ','Υ','Φ','Χ','Ψ','Ω','α','β','γ','δ','ε','ζ','η','θ','ι','κ','λ','μ','ν','ξ','ο','π','ρ','ς','σ','τ','υ','φ','χ','ψ','ω','ϑ','ϒ','ϖ','•','…','′','″','‾','⁄','℘','ℑ','ℜ','™','ℵ','←','↑','→','↓','↔','↵','⇐','⇑','⇒','⇓','⇔','∀','∂','∃','∅','∇','∈','∉','∋','∏','∑','−','∗','√','∝','∞','∠','∧','∨','∩','∪','∫','∴','∼','≅','≈','≠','≡','≤','≥','⊂','⊃','⊄','⊆','⊇','⊕','⊗','⊥','⋅','⌈','⌉','⌊','⌋','⟨','⟩','◊','♠','♣','♥','♦'],
41
- arr2: [' ','¡','¢','£','¤','¥','¦','§','¨','©','ª','«','¬','­','®','¯','°','±','²','³','´','µ','¶','·','¸','¹','º','»','¼','½','¾','¿','À','Á','Â','Ã','Ä','Å','Æ','Ç','È','É','Ê','Ë','Ì','Í','Î','Ï','Ð','Ñ','Ò','Ó','Ô','Õ','Ö','×','Ø','Ù','Ú','Û','Ü','Ý','Þ','ß','à','á','â','ã','ä','å','æ','ç','è','é','ê','ë','ì','í','î','ï','ð','ñ','ò','ó','ô','õ','ö','÷','ø','ù','ú','û','ü','ý','þ','ÿ','"','&','<','>','Œ','œ','Š','š','Ÿ','ˆ','˜',' ',' ',' ','‌','‍','‎','‏','–','—','‘','’','‚','“','”','„','†','‡','‰','‹','›','€','ƒ','Α','Β','Γ','Δ','Ε','Ζ','Η','Θ','Ι','Κ','Λ','Μ','Ν','Ξ','Ο','Π','Ρ','Σ','Τ','Υ','Φ','Χ','Ψ','Ω','α','β','γ','δ','ε','ζ','η','θ','ι','κ','λ','μ','ν','ξ','ο','π','ρ','ς','σ','τ','υ','φ','χ','ψ','ω','ϑ','ϒ','ϖ','•','…','′','″','‾','⁄','℘','ℑ','ℜ','™','ℵ','←','↑','→','↓','↔','↵','⇐','⇑','⇒','⇓','⇔','∀','∂','∃','∅','∇','∈','∉','∋','∏','∑','−','∗','√','∝','∞','∠','∧','∨','∩','∪','∫','∴','∼','≅','≈','≠','≡','≤','≥','⊂','⊃','⊄','⊆','⊇','⊕','⊗','⊥','⋅','⌈','⌉','⌊','⌋','〈','〉','◊','♠','♣','♥','♦'],
42
-
43
- // Convert HTML entities into numerical entities
44
- HTML2Numerical : function(s){
45
- return this.swapArrayVals(s,this.arr1,this.arr2);
46
- },
47
-
48
- // Convert Numerical entities into HTML entities
49
- NumericalToHTML : function(s){
50
- return this.swapArrayVals(s,this.arr2,this.arr1);
51
- },
52
-
53
-
54
- // Numerically encodes all unicode characters
55
- numEncode : function(s){
56
-
57
- if(this.isEmpty(s)) return "";
58
-
59
- var e = "";
60
- for (var i = 0; i < s.length; i++)
61
- {
62
- var c = s.charAt(i);
63
- if (c < " " || c > "~")
64
- {
65
- c = "&#" + c.charCodeAt() + ";";
66
- }
67
- e += c;
68
- }
69
- return e;
70
- },
71
-
72
- // HTML Decode numerical and HTML entities back to original values
73
- htmlDecode : function(s){
74
-
75
- var c,m,d = s;
76
-
77
- if(this.isEmpty(d)) return "";
78
-
79
- // convert HTML entites back to numerical entites first
80
- d = this.HTML2Numerical(d);
81
-
82
- // look for numerical entities &#34;
83
- arr=d.match(/&#[0-9]{1,5};/g);
84
-
85
- // if no matches found in string then skip
86
- if(arr!=null){
87
- for(var x=0;x<arr.length;x++){
88
- m = arr[x];
89
- c = m.substring(2,m.length-1); //get numeric part which is refernce to unicode character
90
- // if its a valid number we can decode
91
- if(c >= -32768 && c <= 65535){
92
- // decode every single match within string
93
- d = d.replace(m, String.fromCharCode(c));
94
- }else{
95
- d = d.replace(m, ""); //invalid so replace with nada
96
- }
97
- }
98
- }
99
-
100
- return d;
101
- },
102
-
103
- // encode an input string into either numerical or HTML entities
104
- htmlEncode : function(s,dbl){
105
-
106
- if(this.isEmpty(s)) return "";
107
-
108
- // do we allow double encoding? E.g will &amp; be turned into &amp;amp;
109
- dbl = dbl || false; //default to prevent double encoding
110
-
111
- // if allowing double encoding we do ampersands first
112
- if(dbl){
113
- if(this.EncodeType=="numerical"){
114
- s = s.replace(/&/g, "&#38;");
115
- }else{
116
- s = s.replace(/&/g, "&amp;");
117
- }
118
- }
119
-
120
- // convert the xss chars to numerical entities ' " < >
121
- s = this.XSSEncode(s,false);
122
-
123
- if(this.EncodeType=="numerical" || !dbl){
124
- // Now call function that will convert any HTML entities to numerical codes
125
- s = this.HTML2Numerical(s);
126
- }
127
-
128
- // Now encode all chars above 127 e.g unicode
129
- s = this.numEncode(s);
130
-
131
- // now we know anything that needs to be encoded has been converted to numerical entities we
132
- // can encode any ampersands & that are not part of encoded entities
133
- // to handle the fact that I need to do a negative check and handle multiple ampersands &&&
134
- // I am going to use a placeholder
135
-
136
- // if we don't want double encoded entities we ignore the & in existing entities
137
- if(!dbl){
138
- s = s.replace(/&#/g,"##AMPHASH##");
139
-
140
- if(this.EncodeType=="numerical"){
141
- s = s.replace(/&/g, "&#38;");
142
- }else{
143
- s = s.replace(/&/g, "&amp;");
144
- }
145
-
146
- s = s.replace(/##AMPHASH##/g,"&#");
147
- }
148
-
149
- // replace any malformed entities
150
- s = s.replace(/&#\d*([^\d;]|$)/g, "$1");
151
-
152
- if(!dbl){
153
- // safety check to correct any double encoded &amp;
154
- s = this.correctEncoding(s);
155
- }
156
-
157
- // now do we need to convert our numerical encoded string into entities
158
- if(this.EncodeType=="entity"){
159
- s = this.NumericalToHTML(s);
160
- }
161
-
162
- return s;
163
- },
164
-
165
- // Encodes the basic 4 characters used to malform HTML in XSS hacks
166
- XSSEncode : function(s,en){
167
- if(!this.isEmpty(s)){
168
- en = en || true;
169
- // do we convert to numerical or html entity?
170
- if(en){
171
- s = s.replace(/\'/g,"&#39;"); //no HTML equivalent as &apos is not cross browser supported
172
- s = s.replace(/\"/g,"&quot;");
173
- s = s.replace(/</g,"&lt;");
174
- s = s.replace(/>/g,"&gt;");
175
- }else{
176
- s = s.replace(/\'/g,"&#39;"); //no HTML equivalent as &apos is not cross browser supported
177
- s = s.replace(/\"/g,"&#34;");
178
- s = s.replace(/</g,"&#60;");
179
- s = s.replace(/>/g,"&#62;");
180
- }
181
- return s;
182
- }else{
183
- return "";
184
- }
185
- },
186
-
187
- // returns true if a string contains html or numerical encoded entities
188
- hasEncoded : function(s){
189
- if(/&#[0-9]{1,5};/g.test(s)){
190
- return true;
191
- }else if(/&[A-Z]{2,6};/gi.test(s)){
192
- return true;
193
- }else{
194
- return false;
195
- }
196
- },
197
-
198
- // will remove any unicode characters
199
- stripUnicode : function(s){
200
- return s.replace(/[^\x20-\x7E]/g,"");
201
-
202
- },
203
-
204
- // corrects any double encoded &amp; entities e.g &amp;amp;
205
- correctEncoding : function(s){
206
- return s.replace(/(&amp;)(amp;)+/,"$1");
207
- },
208
-
209
-
210
- // Function to loop through an array swaping each item with the value from another array e.g swap HTML entities with Numericals
211
- swapArrayVals : function(s,arr1,arr2){
212
- if(this.isEmpty(s)) return "";
213
- var re;
214
- if(arr1 && arr2){
215
- //ShowDebug("in swapArrayVals arr1.length = " + arr1.length + " arr2.length = " + arr2.length)
216
- // array lengths must match
217
- if(arr1.length == arr2.length){
218
- for(var x=0,i=arr1.length;x<i;x++){
219
- re = new RegExp(arr1[x], 'g');
220
- s = s.replace(re,arr2[x]); //swap arr1 item with matching item from arr2
221
- }
222
- }
223
- }
224
- return s;
225
- },
226
-
227
- inArray : function( item, arr ) {
228
- for ( var i = 0, x = arr.length; i < x; i++ ){
229
- if ( arr[i] === item ){
230
- return i;
231
- }
232
- }
233
- return -1;
234
- }
235
-
236
  }
1
+ /**
2
+ * A Javascript object to encode and/or decode html characters using HTML or Numeric entities that handles double or partial encoding
3
+ * Author: R Reid
4
+ * source: http://www.strictly-software.com/htmlencode
5
+ * Licences: GPL, The MIT License (MIT)
6
+ * Copyright: (c) 2011 Robert Reid - Strictly-Software.com
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11
+ *
12
+ * Revision:
13
+ * 2011-07-14, Jacques-Yves Bleau:
14
+ * - fixed conversion error with capitalized accentuated characters
15
+ * + converted arr1 and arr2 to object property to remove redundancy
16
+ *
17
+ * Revision:
18
+ * 2011-11-10, Ce-Yi Hio:
19
+ * - fixed conversion error with a number of capitalized entity characters
20
+ *
21
+ * Revision:
22
+ * 2011-11-10, Rob Reid:
23
+ * - changed array format
24
+ */
25
+
26
+ Encoder = {
27
+
28
+ // When encoding do we convert characters into html or numerical entities
29
+ EncodeType : "entity", // entity OR numerical
30
+
31
+ isEmpty : function(val){
32
+ if(val){
33
+ return ((val===null) || val.length==0 || /^\s+$/.test(val));
34
+ }else{
35
+ return true;
36
+ }
37
+ },
38
+
39
+ // arrays for conversion from HTML Entities to Numerical values
40
+ arr1: ['&nbsp;','&iexcl;','&cent;','&pound;','&curren;','&yen;','&brvbar;','&sect;','&uml;','&copy;','&ordf;','&laquo;','&not;','&shy;','&reg;','&macr;','&deg;','&plusmn;','&sup2;','&sup3;','&acute;','&micro;','&para;','&middot;','&cedil;','&sup1;','&ordm;','&raquo;','&frac14;','&frac12;','&frac34;','&iquest;','&Agrave;','&Aacute;','&Acirc;','&Atilde;','&Auml;','&Aring;','&AElig;','&Ccedil;','&Egrave;','&Eacute;','&Ecirc;','&Euml;','&Igrave;','&Iacute;','&Icirc;','&Iuml;','&ETH;','&Ntilde;','&Ograve;','&Oacute;','&Ocirc;','&Otilde;','&Ouml;','&times;','&Oslash;','&Ugrave;','&Uacute;','&Ucirc;','&Uuml;','&Yacute;','&THORN;','&szlig;','&agrave;','&aacute;','&acirc;','&atilde;','&auml;','&aring;','&aelig;','&ccedil;','&egrave;','&eacute;','&ecirc;','&euml;','&igrave;','&iacute;','&icirc;','&iuml;','&eth;','&ntilde;','&ograve;','&oacute;','&ocirc;','&otilde;','&ouml;','&divide;','&oslash;','&ugrave;','&uacute;','&ucirc;','&uuml;','&yacute;','&thorn;','&yuml;','&quot;','&amp;','&lt;','&gt;','&OElig;','&oelig;','&Scaron;','&scaron;','&Yuml;','&circ;','&tilde;','&ensp;','&emsp;','&thinsp;','&zwnj;','&zwj;','&lrm;','&rlm;','&ndash;','&mdash;','&lsquo;','&rsquo;','&sbquo;','&ldquo;','&rdquo;','&bdquo;','&dagger;','&Dagger;','&permil;','&lsaquo;','&rsaquo;','&euro;','&fnof;','&Alpha;','&Beta;','&Gamma;','&Delta;','&Epsilon;','&Zeta;','&Eta;','&Theta;','&Iota;','&Kappa;','&Lambda;','&Mu;','&Nu;','&Xi;','&Omicron;','&Pi;','&Rho;','&Sigma;','&Tau;','&Upsilon;','&Phi;','&Chi;','&Psi;','&Omega;','&alpha;','&beta;','&gamma;','&delta;','&epsilon;','&zeta;','&eta;','&theta;','&iota;','&kappa;','&lambda;','&mu;','&nu;','&xi;','&omicron;','&pi;','&rho;','&sigmaf;','&sigma;','&tau;','&upsilon;','&phi;','&chi;','&psi;','&omega;','&thetasym;','&upsih;','&piv;','&bull;','&hellip;','&prime;','&Prime;','&oline;','&frasl;','&weierp;','&image;','&real;','&trade;','&alefsym;','&larr;','&uarr;','&rarr;','&darr;','&harr;','&crarr;','&lArr;','&uArr;','&rArr;','&dArr;','&hArr;','&forall;','&part;','&exist;','&empty;','&nabla;','&isin;','&notin;','&ni;','&prod;','&sum;','&minus;','&lowast;','&radic;','&prop;','&infin;','&ang;','&and;','&or;','&cap;','&cup;','&int;','&there4;','&sim;','&cong;','&asymp;','&ne;','&equiv;','&le;','&ge;','&sub;','&sup;','&nsub;','&sube;','&supe;','&oplus;','&otimes;','&perp;','&sdot;','&lceil;','&rceil;','&lfloor;','&rfloor;','&lang;','&rang;','&loz;','&spades;','&clubs;','&hearts;','&diams;'],
41
+ arr2: ['&#160;','&#161;','&#162;','&#163;','&#164;','&#165;','&#166;','&#167;','&#168;','&#169;','&#170;','&#171;','&#172;','&#173;','&#174;','&#175;','&#176;','&#177;','&#178;','&#179;','&#180;','&#181;','&#182;','&#183;','&#184;','&#185;','&#186;','&#187;','&#188;','&#189;','&#190;','&#191;','&#192;','&#193;','&#194;','&#195;','&#196;','&#197;','&#198;','&#199;','&#200;','&#201;','&#202;','&#203;','&#204;','&#205;','&#206;','&#207;','&#208;','&#209;','&#210;','&#211;','&#212;','&#213;','&#214;','&#215;','&#216;','&#217;','&#218;','&#219;','&#220;','&#221;','&#222;','&#223;','&#224;','&#225;','&#226;','&#227;','&#228;','&#229;','&#230;','&#231;','&#232;','&#233;','&#234;','&#235;','&#236;','&#237;','&#238;','&#239;','&#240;','&#241;','&#242;','&#243;','&#244;','&#245;','&#246;','&#247;','&#248;','&#249;','&#250;','&#251;','&#252;','&#253;','&#254;','&#255;','&#34;','&#38;','&#60;','&#62;','&#338;','&#339;','&#352;','&#353;','&#376;','&#710;','&#732;','&#8194;','&#8195;','&#8201;','&#8204;','&#8205;','&#8206;','&#8207;','&#8211;','&#8212;','&#8216;','&#8217;','&#8218;','&#8220;','&#8221;','&#8222;','&#8224;','&#8225;','&#8240;','&#8249;','&#8250;','&#8364;','&#402;','&#913;','&#914;','&#915;','&#916;','&#917;','&#918;','&#919;','&#920;','&#921;','&#922;','&#923;','&#924;','&#925;','&#926;','&#927;','&#928;','&#929;','&#931;','&#932;','&#933;','&#934;','&#935;','&#936;','&#937;','&#945;','&#946;','&#947;','&#948;','&#949;','&#950;','&#951;','&#952;','&#953;','&#954;','&#955;','&#956;','&#957;','&#958;','&#959;','&#960;','&#961;','&#962;','&#963;','&#964;','&#965;','&#966;','&#967;','&#968;','&#969;','&#977;','&#978;','&#982;','&#8226;','&#8230;','&#8242;','&#8243;','&#8254;','&#8260;','&#8472;','&#8465;','&#8476;','&#8482;','&#8501;','&#8592;','&#8593;','&#8594;','&#8595;','&#8596;','&#8629;','&#8656;','&#8657;','&#8658;','&#8659;','&#8660;','&#8704;','&#8706;','&#8707;','&#8709;','&#8711;','&#8712;','&#8713;','&#8715;','&#8719;','&#8721;','&#8722;','&#8727;','&#8730;','&#8733;','&#8734;','&#8736;','&#8743;','&#8744;','&#8745;','&#8746;','&#8747;','&#8756;','&#8764;','&#8773;','&#8776;','&#8800;','&#8801;','&#8804;','&#8805;','&#8834;','&#8835;','&#8836;','&#8838;','&#8839;','&#8853;','&#8855;','&#8869;','&#8901;','&#8968;','&#8969;','&#8970;','&#8971;','&#9001;','&#9002;','&#9674;','&#9824;','&#9827;','&#9829;','&#9830;'],
42
+
43
+ // Convert HTML entities into numerical entities
44
+ HTML2Numerical : function(s){
45
+ return this.swapArrayVals(s,this.arr1,this.arr2);
46
+ },
47
+
48
+ // Convert Numerical entities into HTML entities
49
+ NumericalToHTML : function(s){
50
+ return this.swapArrayVals(s,this.arr2,this.arr1);
51
+ },
52
+
53
+
54
+ // Numerically encodes all unicode characters
55
+ numEncode : function(s){
56
+
57
+ if(this.isEmpty(s)) return "";
58
+
59
+ var e = "";
60
+ for (var i = 0; i < s.length; i++)
61
+ {
62
+ var c = s.charAt(i);
63
+ if (c < " " || c > "~")
64
+ {
65
+ c = "&#" + c.charCodeAt() + ";";
66
+ }
67
+ e += c;
68
+ }
69
+ return e;
70
+ },
71
+
72
+ // HTML Decode numerical and HTML entities back to original values
73
+ htmlDecode : function(s){
74
+
75
+ var c,m,d = s;
76
+
77
+ if(this.isEmpty(d)) return "";
78
+
79
+ // convert HTML entites back to numerical entites first
80
+ d = this.HTML2Numerical(d);
81
+
82
+ // look for numerical entities &#34;
83
+ arr=d.match(/&#[0-9]{1,5};/g);
84
+
85
+ // if no matches found in string then skip
86
+ if(arr!=null){
87
+ for(var x=0;x<arr.length;x++){
88
+ m = arr[x];
89
+ c = m.substring(2,m.length-1); //get numeric part which is refernce to unicode character
90
+ // if its a valid number we can decode
91
+ if(c >= -32768 && c <= 65535){
92
+ // decode every single match within string
93
+ d = d.replace(m, String.fromCharCode(c));
94
+ }else{
95
+ d = d.replace(m, ""); //invalid so replace with nada
96
+ }
97
+ }
98
+ }
99
+
100
+ return d;
101
+ },
102
+
103
+ // encode an input string into either numerical or HTML entities
104
+ htmlEncode : function(s,dbl){
105
+
106
+ if(this.isEmpty(s)) return "";
107
+
108
+ // do we allow double encoding? E.g will &amp; be turned into &amp;amp;
109
+ dbl = dbl || false; //default to prevent double encoding
110
+
111
+ // if allowing double encoding we do ampersands first
112
+ if(dbl){
113
+ if(this.EncodeType=="numerical"){
114
+ s = s.replace(/&/g, "&#38;");
115
+ }else{
116
+ s = s.replace(/&/g, "&amp;");
117
+ }
118
+ }
119
+
120
+ // convert the xss chars to numerical entities ' " < >
121
+ s = this.XSSEncode(s,false);
122
+
123
+ if(this.EncodeType=="numerical" || !dbl){
124
+ // Now call function that will convert any HTML entities to numerical codes
125
+ s = this.HTML2Numerical(s);
126
+ }
127
+
128
+ // Now encode all chars above 127 e.g unicode
129
+ s = this.numEncode(s);
130
+
131
+ // now we know anything that needs to be encoded has been converted to numerical entities we
132
+ // can encode any ampersands & that are not part of encoded entities
133
+ // to handle the fact that I need to do a negative check and handle multiple ampersands &&&
134
+ // I am going to use a placeholder
135
+
136
+ // if we don't want double encoded entities we ignore the & in existing entities
137
+ if(!dbl){
138
+ s = s.replace(/&#/g,"##AMPHASH##");
139
+
140
+ if(this.EncodeType=="numerical"){
141
+ s = s.replace(/&/g, "&#38;");
142
+ }else{
143
+ s = s.replace(/&/g, "&amp;");
144
+ }
145
+
146
+ s = s.replace(/##AMPHASH##/g,"&#");
147
+ }
148
+
149
+ // replace any malformed entities
150
+ s = s.replace(/&#\d*([^\d;]|$)/g, "$1");
151
+
152
+ if(!dbl){
153
+ // safety check to correct any double encoded &amp;
154
+ s = this.correctEncoding(s);
155
+ }
156
+
157
+ // now do we need to convert our numerical encoded string into entities
158
+ if(this.EncodeType=="entity"){
159
+ s = this.NumericalToHTML(s);
160
+ }
161
+
162
+ return s;
163
+ },
164
+
165
+ // Encodes the basic 4 characters used to malform HTML in XSS hacks
166
+ XSSEncode : function(s,en){
167
+ if(!this.isEmpty(s)){
168
+ en = en || true;
169
+ // do we convert to numerical or html entity?
170
+ if(en){
171
+ s = s.replace(/\'/g,"&#39;"); //no HTML equivalent as &apos is not cross browser supported
172
+ s = s.replace(/\"/g,"&quot;");
173
+ s = s.replace(/</g,"&lt;");
174
+ s = s.replace(/>/g,"&gt;");
175
+ }else{
176
+ s = s.replace(/\'/g,"&#39;"); //no HTML equivalent as &apos is not cross browser supported
177
+ s = s.replace(/\"/g,"&#34;");
178
+ s = s.replace(/</g,"&#60;");
179
+ s = s.replace(/>/g,"&#62;");
180
+ }
181
+ return s;
182
+ }else{
183
+ return "";
184
+ }
185
+ },
186
+
187
+ // returns true if a string contains html or numerical encoded entities
188
+ hasEncoded : function(s){
189
+ if(/&#[0-9]{1,5};/g.test(s)){
190
+ return true;
191
+ }else if(/&[A-Z]{2,6};/gi.test(s)){
192
+ return true;
193
+ }else{
194
+ return false;
195
+ }
196
+ },
197
+
198
+ // will remove any unicode characters
199
+ stripUnicode : function(s){
200
+ return s.replace(/[^\x20-\x7E]/g,"");
201
+
202
+ },
203
+
204
+ // corrects any double encoded &amp; entities e.g &amp;amp;
205
+ correctEncoding : function(s){
206
+ return s.replace(/(&amp;)(amp;)+/,"$1");
207
+ },
208
+
209
+
210
+ // Function to loop through an array swaping each item with the value from another array e.g swap HTML entities with Numericals
211
+ swapArrayVals : function(s,arr1,arr2){
212
+ if(this.isEmpty(s)) return "";
213
+ var re;
214
+ if(arr1 && arr2){
215
+ //ShowDebug("in swapArrayVals arr1.length = " + arr1.length + " arr2.length = " + arr2.length)
216
+ // array lengths must match
217
+ if(arr1.length == arr2.length){
218
+ for(var x=0,i=arr1.length;x<i;x++){
219
+ re = new RegExp(arr1[x], 'g');
220
+ s = s.replace(re,arr2[x]); //swap arr1 item with matching item from arr2
221
+ }
222
+ }
223
+ }
224
+ return s;
225
+ },
226
+
227
+ inArray : function( item, arr ) {
228
+ for ( var i = 0, x = arr.length; i < x; i++ ){
229
+ if ( arr[i] === item ){
230
+ return i;
231
+ }
232
+ }
233
+ return -1;
234
+ }
235
+
236
  }
includes/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
includes/jlfunctions/arr.php CHANGED
@@ -1,223 +1,223 @@
1
- <?php
2
- /*
3
- JLFunctions Array Class
4
- Copyright (c)2009-2012 John Lamansky
5
- */
6
-
7
- class suarr {
8
-
9
- /**
10
- * Plugs an array's keys and/or values into sprintf-style format string(s).
11
- *
12
- * @param string|false $keyformat The sprintf-style format for the key, e.g. "prefix_%s" or "%s_suffix"
13
- * @param string|false $valueformat The sprintf-style format for the value.
14
- * @param array $array The array whose keys/values should be formatted.
15
- * @return array The array with the key/value formats applied.
16
- */
17
- static function aprintf($keyformat, $valueformat, $array) {
18
- $newarray = array();
19
- foreach ($array as $key => $value) {
20
- if ($keyformat) {
21
- if (is_int($key)) $key = $value;
22
- $key = str_replace('%s', $key, $keyformat);
23
- }
24
- if ($valueformat) $value = str_replace('%s', $value, $valueformat);
25
- $newarray[$key] = $value;
26
- }
27
- return $newarray;
28
- }
29
-
30
- /**
31
- * Removes a value from the array if found.
32
- *
33
- * @param array $array Passed by reference.
34
- * @param mixed $value The value to remove.
35
- */
36
- static function remove_value(&$array, $value) {
37
- $index = array_search($value, $array);
38
- if ($index !== false)
39
- unset($array[$index]);
40
- }
41
-
42
- /**
43
- * Turns a string into an array, with one line per array element.
44
- *
45
- * @param string $lines
46
- *
47
- * @return array
48
- */
49
- static function explode_lines($lines) {
50
- $lines = explode("\n", $lines);
51
- $lines = array_map('trim', $lines); //Remove any \r's
52
- return $lines;
53
- }
54
-
55
- /**
56
- * Sorts an array of arrays by using a given array key to locate string values in the second-level arrays and sorting the first-level array accordingly.
57
- * Alphabetical sorting is used.
58
- *
59
- * @param array $arr Passed by reference
60
- * @param string $valuekey The array key used to access the string values by which the arrays in $arr are to be sorted
61
- */
62
- static function vksort(&$arr, $valuekey) {
63
- $valuekey = sustr::preg_filter('A-Za-z0-9 ', $valuekey);
64
- uasort($arr, create_function('$a,$b', 'return strcasecmp($a["'.$valuekey.'"], $b["'.$valuekey.'"]);'));
65
- }
66
-
67
- /**
68
- * Sorts an array of arrays by using a given array key to locate string values in the second-level arrays and sorting the first-level array accordingly.
69
- * Reverse length sorting is used. (Longest strings are first, shortest strings last.)
70
- *
71
- * @param array $arr Passed by reference
72
- * @param string $valuekey The array key used to access the string values by which the arrays in $arr are to be sorted
73
- */
74
- static function vklrsort(&$arr, $valuekey) {
75
- $valuekey = sustr::preg_filter('A-Za-z0-9 ', $valuekey);
76
- uasort($arr, create_function('$a,$b', 'return strlen($b["'.$valuekey.'"]) - strlen($a["'.$valuekey.'"]);'));
77
- }
78
-
79
- /**
80
- * Flattens a multidimensional array (or an array of objects) into a single-dimensional array by discarding all but one element of the higher-level array(s).
81
- * Works like WordPress's wp_list_pluck(), except this function is recursive and supports inserting a default value if a subarray doesn't have the specified key.
82
- *
83
- * Usage example:
84
- * ---
85
- * $post_types = get_post_types(array('public' => true), 'objects');
86
- * $singular_names = suarr::flatten_values($post_types, array('labels', 'singular_name'));
87
- * ---
88
- *
89
- * @param array $arr The multidimensional array (or array of objects) to flatten
90
- * @param array|string|int $value_keys Each array/object in $arr will be replaced with its element/property named $value_keys. If $value_keys is an array, this will be done recursively.
91
- * @param bool $use_default_if_empty If a given array/object in $arr does not have an element/property named $value_keys, should a default value be inserted?
92
- * @param mixed $default
93
- *
94
- * @return array The flattened array
95
- */
96
- static function flatten_values($arr, $value_keys, $use_default_if_empty=false, $default='') {
97
- foreach ((array)$value_keys as $key)
98
- $arr = suarr::_flatten_values($arr, $key, $use_default_if_empty, $default);
99
- return $arr;
100
- }
101
-
102
- static function _flatten_values($arr, $value_key = 0, $use_default_if_empty=false, $default='') {
103
- if (!is_array($arr) || !count($arr)) return array();
104
- $newarr = array();
105
- foreach ($arr as $key => $array_value) {
106
- $success = false;
107
-
108
- if (is_array($array_value)) {
109
- if (isset($array_value[$value_key])) {
110
- $newarr[$key] = $array_value[$value_key];
111
- $success = true;
112
- }
113
- } elseif (is_object($array_value)) {
114
- if (isset($array_value->$value_key)) {
115
- $newarr[$key] = $array_value->$value_key;
116
- $success = true;
117
- }
118
- }
119
-
120
- if (!$success && $use_default_if_empty)
121
- $newarr[$key] = $default;
122
- }
123
- return $newarr;
124
- }
125
-
126
- /**
127
- * Renames keys in an array. Supports recursion.
128
- *
129
- * @param array $array The array whose keys should be renamed
130
- * @param array $key_changes An array of (old_key => new_key)
131
- * @param bool $recursive Whether or not to do the same for subarrays of $array
132
- * @param bool $return_replaced_only If true, then elements whose keys were *not* renamed will be discarded
133
- *
134
- * @return array
135
- */
136
- static function key_replace($array, $key_changes, $recursive = true, $return_replaced_only = false) {
137
- $newarray = array();
138
- foreach ($array as $key => $value) {
139
- $changed = false;
140
- if ($recursive && is_array($value)) {
141
- $oldvalue = $value;
142
- $value = suarr::key_replace($value, $key_changes, true, $return_replaced_only);
143
- if ($oldvalue != $value) $changed = true;
144
- }
145
-
146
- if (isset($key_changes[$key])) {
147
- $key = $key_changes[$key];
148
- $changed = true;
149
- }
150
-
151
- if ($changed || !$return_replaced_only)
152
- $newarray[$key] = $value;
153
- }
154
- return $newarray;
155
- }
156
-
157
- /**
158
- * Runs a find/replace operation on values in an array.
159
- *
160
- * @param array $array The array whose values should be replaced
161
- * @param array $value_changes An array of (old_value => new_value)
162
- * @param bool $recursive Whether or not to do the same for subarrays of $array
163
- * @param bool $return_replaced_only If true, then elements *not* replaced will be discarded
164
- *
165
- * @return array
166
- */
167
- static function value_replace($array, $value_changes, $recursive = true, $return_replaced_only = false) {
168
- $newarray = array();
169
-
170
- foreach ((array)$array as $key => $value) {
171
-
172
- $oldvalue = $value;
173
-
174
- if ($recursive && is_array($value))
175
- $value = suarr::value_replace($value, $value_changes, true);
176
- elseif (isset($value_changes[$value]))
177
- $value = $value_changes[$value];
178
-
179
- if ($value != $oldvalue || !$return_replaced_only)
180
- $newarray[$key] = $value;
181
- }
182
-
183
- return $newarray;
184
- }
185
-
186
- /**
187
- * Goes through an array of arrays/objects, plucks two elements/properties from each array/object, and constructs a new array, with one element/property as the key, and the other as the value.
188
- *
189
- * @param array $arr The array to run this process on.
190
- * @param array|string|int $keyloc The location (either a string/integer key, or an array of nested keys) of the elements' values to be used as keys in the new array
191
- * @param array|string|int $valloc The location (either a string/integer key, or an array of nested keys) of the elements' values to be used as values in the new array
192
- * @param bool $use_default_if_empty Whether or not to use a default value in the event that nothing is located at $keyloc or $valloc for a given array/object in $arr
193
- * @param mixed $default
194
- *
195
- * @return array
196
- */
197
- static function simplify($arr, $keyloc, $valloc, $use_default_if_empty=false, $default='') {
198
- $keys = suarr::flatten_values($arr, $keyloc, $use_default_if_empty, $default);
199
- $values = suarr::flatten_values($arr, $valloc, $use_default_if_empty, $default);
200
- return array_combine($keys, $values);
201
- }
202
-
203
- //Function based on http://php.net/manual/en/function.array-unique.php#82508
204
- static function in_array_i($str, $a) {
205
- foreach($a as $v){
206
- if (strcasecmp($str, $v)==0)
207
- return true;
208
- }
209
- return false;
210
- }
211
-
212
- //Function based on http://php.net/manual/en/function.array-unique.php#82508
213
- static function array_unique_i($a) {
214
- $n = array();
215
- foreach($a as $k=>$v) {
216
- if (!suarr::in_array_i($v, $n))
217
- $n[$k] = $v;
218
- }
219
- return $n;
220
- }
221
- }
222
-
223
  ?>
1
+ <?php
2
+ /*
3
+ JLFunctions Array Class
4
+ Copyright (c)2009-2012 John Lamansky
5
+ */
6
+
7
+ class suarr {
8
+
9
+ /**
10
+ * Plugs an array's keys and/or values into sprintf-style format string(s).
11
+ *
12
+ * @param string|false $keyformat The sprintf-style format for the key, e.g. "prefix_%s" or "%s_suffix"
13
+ * @param string|false $valueformat The sprintf-style format for the value.
14
+ * @param array $array The array whose keys/values should be formatted.
15
+ * @return array The array with the key/value formats applied.
16
+ */
17
+ static function aprintf($keyformat, $valueformat, $array) {
18
+ $newarray = array();
19
+ foreach ($array as $key => $value) {
20
+ if ($keyformat) {
21
+ if (is_int($key)) $key = $value;
22
+ $key = str_replace('%s', $key, $keyformat);
23
+ }
24
+ if ($valueformat) $value = str_replace('%s', $value, $valueformat);
25
+ $newarray[$key] = $value;
26
+ }
27
+ return $newarray;
28
+ }
29
+
30
+ /**
31
+ * Removes a value from the array if found.
32
+ *
33
+ * @param array $array Passed by reference.
34
+ * @param mixed $value The value to remove.
35
+ */
36
+ static function remove_value(&$array, $value) {
37
+ $index = array_search($value, $array);
38
+ if ($index !== false)
39
+ unset($array[$index]);
40
+ }
41
+
42
+ /**
43
+ * Turns a string into an array, with one line per array element.
44
+ *
45
+ * @param string $lines
46
+ *
47
+ * @return array
48
+ */
49
+ static function explode_lines($lines) {
50
+ $lines = explode("\n", $lines);
51
+ $lines = array_map('trim', $lines); //Remove any \r's
52
+ return $lines;
53
+ }
54
+
55
+ /**
56
+ * Sorts an array of arrays by using a given array key to locate string values in the second-level arrays and sorting the first-level array accordingly.
57
+ * Alphabetical sorting is used.
58
+ *
59
+ * @param array $arr Passed by reference
60
+ * @param string $valuekey The array key used to access the string values by which the arrays in $arr are to be sorted
61
+ */
62
+ static function vksort(&$arr, $valuekey) {
63
+ $valuekey = sustr::preg_filter('A-Za-z0-9 ', $valuekey);
64
+ uasort($arr, create_function('$a,$b', 'return strcasecmp($a["'.$valuekey.'"], $b["'.$valuekey.'"]);'));
65
+ }
66
+
67
+ /**
68
+ * Sorts an array of arrays by using a given array key to locate string values in the second-level arrays and sorting the first-level array accordingly.
69
+ * Reverse length sorting is used. (Longest strings are first, shortest strings last.)
70
+ *
71
+ * @param array $arr Passed by reference
72
+ * @param string $valuekey The array key used to access the string values by which the arrays in $arr are to be sorted
73
+ */
74
+ static function vklrsort(&$arr, $valuekey) {
75
+ $valuekey = sustr::preg_filter('A-Za-z0-9 ', $valuekey);
76
+ uasort($arr, create_function('$a,$b', 'return strlen($b["'.$valuekey.'"]) - strlen($a["'.$valuekey.'"]);'));
77
+ }
78
+
79
+ /**
80
+ * Flattens a multidimensional array (or an array of objects) into a single-dimensional array by discarding all but one element of the higher-level array(s).
81
+ * Works like WordPress's wp_list_pluck(), except this function is recursive and supports inserting a default value if a subarray doesn't have the specified key.
82
+ *
83
+ * Usage example:
84
+ * ---
85
+ * $post_types = get_post_types(array('public' => true), 'objects');
86
+ * $singular_names = suarr::flatten_values($post_types, array('labels', 'singular_name'));
87
+ * ---
88
+ *
89
+ * @param array $arr The multidimensional array (or array of objects) to flatten
90
+ * @param array|string|int $value_keys Each array/object in $arr will be replaced with its element/property named $value_keys. If $value_keys is an array, this will be done recursively.
91
+ * @param bool $use_default_if_empty If a given array/object in $arr does not have an element/property named $value_keys, should a default value be inserted?
92
+ * @param mixed $default
93
+ *
94
+ * @return array The flattened array
95
+ */
96
+ static function flatten_values($arr, $value_keys, $use_default_if_empty=false, $default='') {
97
+ foreach ((array)$value_keys as $key)
98
+ $arr = suarr::_flatten_values($arr, $key, $use_default_if_empty, $default);
99
+ return $arr;
100
+ }
101
+
102
+ static function _flatten_values($arr, $value_key = 0, $use_default_if_empty=false, $default='') {
103
+ if (!is_array($arr) || !count($arr)) return array();
104
+ $newarr = array();
105
+ foreach ($arr as $key => $array_value) {
106
+ $success = false;
107
+
108
+ if (is_array($array_value)) {
109
+ if (isset($array_value[$value_key])) {
110
+ $newarr[$key] = $array_value[$value_key];
111
+ $success = true;
112
+ }
113
+ } elseif (is_object($array_value)) {
114
+ if (isset($array_value->$value_key)) {
115
+ $newarr[$key] = $array_value->$value_key;
116
+ $success = true;
117
+ }
118
+ }
119
+
120
+ if (!$success && $use_default_if_empty)
121
+ $newarr[$key] = $default;
122
+ }
123
+ return $newarr;
124
+ }
125
+
126
+ /**
127
+ * Renames keys in an array. Supports recursion.
128
+ *
129
+ * @param array $array The array whose keys should be renamed
130
+ * @param array $key_changes An array of (old_key => new_key)
131
+ * @param bool $recursive Whether or not to do the same for subarrays of $array
132
+ * @param bool $return_replaced_only If true, then elements whose keys were *not* renamed will be discarded
133
+ *
134
+ * @return array
135
+ */
136
+ static function key_replace($array, $key_changes, $recursive = true, $return_replaced_only = false) {
137
+ $newarray = array();
138
+ foreach ($array as $key => $value) {
139
+ $changed = false;
140
+ if ($recursive && is_array($value)) {
141
+ $oldvalue = $value;
142
+ $value = suarr::key_replace($value, $key_changes, true, $return_replaced_only);
143
+ if ($oldvalue != $value) $changed = true;
144
+ }
145
+
146
+ if (isset($key_changes[$key])) {
147
+ $key = $key_changes[$key];
148
+ $changed = true;
149
+ }
150
+
151
+ if ($changed || !$return_replaced_only)
152
+ $newarray[$key] = $value;
153
+ }
154
+ return $newarray;
155
+ }
156
+
157
+ /**
158
+ * Runs a find/replace operation on values in an array.
159
+ *
160
+ * @param array $array The array whose values should be replaced
161
+ * @param array $value_changes An array of (old_value => new_value)
162
+ * @param bool $recursive Whether or not to do the same for subarrays of $array
163
+ * @param bool $return_replaced_only If true, then elements *not* replaced will be discarded
164
+ *
165
+ * @return array
166
+ */
167
+ static function value_replace($array, $value_changes, $recursive = true, $return_replaced_only = false) {
168
+ $newarray = array();
169
+
170
+ foreach ((array)$array as $key => $value) {
171
+
172
+ $oldvalue = $value;
173
+
174
+ if ($recursive && is_array($value))
175
+ $value = suarr::value_replace($value, $value_changes, true);
176
+ elseif (isset($value_changes[$value]))
177
+ $value = $value_changes[$value];
178
+
179
+ if ($value != $oldvalue || !$return_replaced_only)
180
+ $newarray[$key] = $value;
181
+ }
182
+
183
+ return $newarray;
184
+ }
185
+
186
+ /**
187
+ * Goes through an array of arrays/objects, plucks two elements/properties from each array/object, and constructs a new array, with one element/property as the key, and the other as the value.
188
+ *
189
+ * @param array $arr The array to run this process on.
190
+ * @param array|string|int $keyloc The location (either a string/integer key, or an array of nested keys) of the elements' values to be used as keys in the new array
191
+ * @param array|string|int $valloc The location (either a string/integer key, or an array of nested keys) of the elements' values to be used as values in the new array
192
+ * @param bool $use_default_if_empty Whether or not to use a default value in the event that nothing is located at $keyloc or $valloc for a given array/object in $arr
193
+ * @param mixed $default
194
+ *
195
+ * @return array
196
+ */
197
+ static function simplify($arr, $keyloc, $valloc, $use_default_if_empty=false, $default='') {
198
+ $keys = suarr::flatten_values($arr, $keyloc, $use_default_if_empty, $default);
199
+ $values = suarr::flatten_values($arr, $valloc, $use_default_if_empty, $default);
200
+ return array_combine($keys, $values);
201
+ }
202
+
203
+ //Function based on http://php.net/manual/en/function.array-unique.php#82508
204
+ static function in_array_i($str, $a) {
205
+ foreach($a as $v){
206
+ if (strcasecmp($str, $v)==0)
207
+ return true;
208
+ }
209
+ return false;
210
+ }
211
+
212
+ //Function based on http://php.net/manual/en/function.array-unique.php#82508
213
+ static function array_unique_i($a) {
214
+ $n = array();
215
+ foreach($a as $k=>$v) {
216
+ if (!suarr::in_array_i($v, $n))
217
+ $n[$k] = $v;
218
+ }
219
+ return $n;
220
+ }
221
+ }
222
+
223
  ?>
includes/jlfunctions/html.php CHANGED
@@ -1,32 +1,32 @@
1
- <?php
2
- /*
3
- JLFunctions HTML Class
4
- Copyright (c)2010-2012 John Lamansky
5
- */
6
-
7
- class suhtml {
8
-
9
- /**
10
- * Returns <option> tags.
11
- *
12
- * @param array $options An array of (value => label)
13
- * @param string $current The value of the option that should be initially selected on the dropdown
14
- *
15
- * @return string
16
- */
17
- static function option_tags($options, $current) {
18
- $html = '';
19
- foreach ($options as $value => $label) {
20
- if (is_array($label)) {
21
- $html .= "<optgroup label='$value'>\n".suhtml::option_tags($label, $current)."</optgroup>\n";
22
- } else {
23
- $html .= "\t<option value='$value'";
24
- if ((string)$value == (string)$current) $html .= " selected='selected'";
25
- $html .= ">$label</option>\n";
26
- }
27
- }
28
- return $html;
29
- }
30
- }
31
-
32
  ?>
1
+ <?php
2
+ /*
3
+ JLFunctions HTML Class
4
+ Copyright (c)2010-2012 John Lamansky
5
+ */
6
+
7
+ class suhtml {
8
+
9
+ /**
10
+ * Returns <option> tags.
11
+ *
12
+ * @param array $options An array of (value => label)
13
+ * @param string $current The value of the option that should be initially selected on the dropdown
14
+ *
15
+ * @return string
16
+ */
17
+ static function option_tags($options, $current) {
18
+ $html = '';
19
+ foreach ($options as $value => $label) {
20
+ if (is_array($label)) {
21
+ $html .= "<optgroup label='$value'>\n".suhtml::option_tags($label, $current)."</optgroup>\n";
22
+ } else {
23
+ $html .= "\t<option value='$value'";
24
+ if ((string)$value == (string)$current) $html .= " selected='selected'";
25
+ $html .= ">$label</option>\n";
26
+ }
27
+ }
28
+ return $html;
29
+ }
30
+ }
31
+
32
  ?>
includes/jlfunctions/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
includes/jlfunctions/io.php CHANGED
@@ -1,143 +1,143 @@
1
- <?php
2
- /*
3
- JLFunctions IO Class
4
- Copyright (c)2009-2012 John Lamansky
5
- */
6
-
7
- class suio {
8
-
9
- /**
10
- * Checks whether a given $filename in $path is actually a file, and optionally whether $filename ends in extension .$ext
11
- *
12
- * @param string $filename The name of the purported file (e.g. "index.php")
13
- * @param string $path The path in which this file is purportedly located
14
- * @param string $ext The extension that the file should have (e.g. "php") (optional)
15
- *
16
- * @return bool
17
- */
18
- static function is_file($filename, $path, $ext=false) {
19
- $is_ext = strlen($ext) ? sustr::endswith($filename, '.'.ltrim($ext, '*.')) : true;
20
- return is_file(suio::tslash($path).$filename) && $is_ext;
21
- }
22
-
23
- /**
24
- * Checks whether a given path name points to a real directory.
25
- * Ensures that the path name is not "." or ".."
26
- *
27
- * @param string $name The name of the purported directory
28
- * @param string $path The path in which this directory is purportedly located
29
- *
30
- * @return bool
31
- */
32
- static function is_dir($name, $path) {
33
- return $name != '.' && $name != '..' && is_dir(suio::tslash($path).$name);
34
- }
35
-
36
- /**
37
- * Makes sure a directory path or URL ends in a trailing slash.
38
- *
39
- * @param string $path
40
- *
41
- * @return string
42
- */
43
- static function tslash($path) {
44
- return suio::untslash($path).'/';
45
- }
46
-
47
- /**
48
- * Removes any trailing slash at the end of a directory path or URL.
49
- *
50
- * @param string $path
51
- *
52
- * @return string
53
- */
54
- static function untslash($path) {
55
- return rtrim($path, '/');
56
- }
57
-
58
- /**
59
- * Converts the contents of a CSV file into an array.
60
- * The first row of the CSV file must contain the column headers.
61
- *
62
- * @param $path The location of the CSV file on the server.
63
- *
64
- * @return array An array of arrays which represent rows of the file.
65
- */
66
- static function import_csv($path) {
67
- if (!is_readable($path)) return false;
68
-
69
- $result = array();
70
-
71
- //Open the CSV file
72
- $handle = @fopen($path, 'r');
73
- if ($handle === false) return false;
74
-
75
- //Get the columns
76
- $headers = fgetcsv($handle, 99999, ',');
77
- if ($headers === false) {
78
- fclose($handle);
79
- return false;
80
- }
81
-
82
- //Get the rows
83
- while (($row = fgetcsv($handle, 99999, ',')) !== false) {
84
-
85
- if (count($row) > count($headers))
86
- //Too long
87
- $row = array_slice($row, 0, count($headers));
88
- elseif (count($row) < count($headers))
89
- //Too short
90
- $row = array_pad($row, count($headers), '');
91
-
92
- $new = array_combine($headers, $row);
93
- if ($new !== false) $result[] = $new;
94
- }
95
-
96
- //Close the CSV file
97
- fclose($handle);
98
-
99
- //Return
100
- return $result;
101
- }
102
-
103
- /**
104
- * Converts an array into a CSV file, outputs it with the appropriate HTTP header, and terminates program execution.
105
- *
106
- * @param array $csv The array to convert and output
107
- *
108
- * @return false Returns a value only if conversion failed
109
- */
110
- static function export_csv($csv) {
111
- header("Content-Type: text/csv");
112
- $result = suio::print_csv($csv);
113
- if ($result) die(); else return false;
114
- }
115
-
116
- /**
117
- * Converts an array into a CSV file and outputs it.
118
- *
119
- * @param array $csv The array to convert and output
120
- *
121
- * @return bool Whether or not the conversion was successful
122
- */
123
- static function print_csv($csv) {
124
- if (!is_array($csv) || !count($csv) || !is_array($csv[0])) return false;
125
-
126
- $headers = array_keys($csv[0]);
127
- array_unshift($csv, array_combine($headers, $headers));
128
-
129
- foreach ($csv as $row) {
130
- $csv_row = array();
131
- foreach ($headers as $header) {
132
- $csv_row[$header] = $row[$header];
133
- if (sustr::has($csv_row[$header], ',')) $csv_row[$header] = '"'.$csv_row[$header].'"';
134
- }
135
-
136
- echo implode(',', $csv_row)."\r\n";
137
- }
138
-
139
- return true;
140
- }
141
- }
142
-
143
  ?>
1
+ <?php
2
+ /*
3
+ JLFunctions IO Class
4
+ Copyright (c)2009-2012 John Lamansky
5
+ */
6
+
7
+ class suio {
8
+
9
+ /**
10
+ * Checks whether a given $filename in $path is actually a file, and optionally whether $filename ends in extension .$ext
11
+ *
12
+ * @param string $filename The name of the purported file (e.g. "index.php")
13
+ * @param string $path The path in which this file is purportedly located
14
+ * @param string $ext The extension that the file should have (e.g. "php") (optional)
15
+ *
16
+ * @return bool
17
+ */
18
+ static function is_file($filename, $path, $ext=false) {
19
+ $is_ext = strlen($ext) ? sustr::endswith($filename, '.'.ltrim($ext, '*.')) : true;
20
+ return is_file(suio::tslash($path).$filename) && $is_ext;
21
+ }
22
+
23
+ /**
24
+ * Checks whether a given path name points to a real directory.
25
+ * Ensures that the path name is not "." or ".."
26
+ *
27
+ * @param string $name The name of the purported directory
28
+ * @param string $path The path in which this directory is purportedly located
29
+ *
30
+ * @return bool
31
+ */
32
+ static function is_dir($name, $path) {
33
+ return $name != '.' && $name != '..' && is_dir(suio::tslash($path).$name);
34
+ }
35
+
36
+ /**
37
+ * Makes sure a directory path or URL ends in a trailing slash.
38
+ *
39
+ * @param string $path
40
+ *
41
+ * @return string
42
+ */
43
+ static function tslash($path) {
44
+ return suio::untslash($path).'/';
45
+ }
46
+
47
+ /**
48
+ * Removes any trailing slash at the end of a directory path or URL.
49
+ *
50
+ * @param string $path
51
+ *
52
+ * @return string
53
+ */
54
+ static function untslash($path) {
55
+ return rtrim($path, '/');
56
+ }
57
+
58
+ /**
59
+ * Converts the contents of a CSV file into an array.
60
+ * The first row of the CSV file must contain the column headers.
61
+ *
62
+ * @param $path The location of the CSV file on the server.
63
+ *
64
+ * @return array An array of arrays which represent rows of the file.
65
+ */
66
+ static function import_csv($path) {
67
+ if (!is_readable($path)) return false;
68
+
69
+ $result = array();
70
+
71
+ //Open the CSV file
72
+ $handle = @fopen($path, 'r');
73
+ if ($handle === false) return false;
74
+
75
+ //Get the columns
76
+ $headers = fgetcsv($handle, 99999, ',');
77
+ if ($headers === false) {
78
+ fclose($handle);
79
+ return false;
80
+ }
81
+
82
+ //Get the rows
83
+ while (($row = fgetcsv($handle, 99999, ',')) !== false) {
84
+
85
+ if (count($row) > count($headers))
86
+ //Too long
87
+ $row = array_slice($row, 0, count($headers));
88
+ elseif (count($row) < count($headers))
89
+ //Too short
90
+ $row = array_pad($row, count($headers), '');
91
+
92
+ $new = array_combine($headers, $row);
93
+ if ($new !== false) $result[] = $new;
94
+ }
95
+
96
+ //Close the CSV file
97
+ fclose($handle);
98
+
99
+ //Return
100
+ return $result;
101
+ }
102
+
103
+ /**
104
+ * Converts an array into a CSV file, outputs it with the appropriate HTTP header, and terminates program execution.
105
+ *
106
+ * @param array $csv The array to convert and output
107
+ *
108
+ * @return false Returns a value only if conversion failed
109
+ */
110
+ static function export_csv($csv) {
111
+ header("Content-Type: text/csv");
112
+ $result = suio::print_csv($csv);
113
+ if ($result) die(); else return false;
114
+ }
115
+
116
+ /**
117
+ * Converts an array into a CSV file and outputs it.
118
+ *
119
+ * @param array $csv The array to convert and output
120
+ *
121
+ * @return bool Whether or not the conversion was successful
122
+ */
123
+ static function print_csv($csv) {
124
+ if (!is_array($csv) || !count($csv) || !is_array($csv[0])) return false;
125
+
126
+ $headers = array_keys($csv[0]);
127
+ array_unshift($csv, array_combine($headers, $headers));
128
+
129
+ foreach ($csv as $row) {
130
+ $csv_row = array();
131
+ foreach ($headers as $header) {
132
+ $csv_row[$header] = $row[$header];
133
+ if (sustr::has($csv_row[$header], ',')) $csv_row[$header] = '"'.$csv_row[$header].'"';
134
+ }
135
+
136
+ echo implode(',', $csv_row)."\r\n";
137
+ }
138
+
139
+ return true;
140
+ }
141
+ }
142
+
143
  ?>
includes/jlfunctions/jlfunctions.php CHANGED
@@ -1,11 +1,11 @@
1
- <?php
2
- /*
3
- JLFunctions Library
4
- Copyright (c)2009-2012 John Lamansky
5
- */
6
-
7
- foreach (array('arr', 'html', 'io', 'num', 'str', 'url', 'web') as $jlfuncfile) {
8
- include dirname(__FILE__)."/$jlfuncfile.php";
9
- }
10
-
11
  ?>
1
+ <?php
2
+ /*
3
+ JLFunctions Library
4
+ Copyright (c)2009-2012 John Lamansky
5
+ */
6
+
7
+ foreach (array('arr', 'html', 'io', 'num', 'str', 'url', 'web') as $jlfuncfile) {
8
+ include dirname(__FILE__)."/$jlfuncfile.php";
9
+ }
10
+
11
  ?>
includes/jlfunctions/num.php CHANGED
@@ -1,33 +1,33 @@
1
- <?php
2
- /*
3
- JLFunctions Number Class
4
- Copyright (c)2011-2012 John Lamansky
5
- */
6
-
7
- class sunum {
8
-
9
- /**
10
- * Returns the lowest of a set of numbers.
11
- *
12
- * @param array|int $number,... The numbers may be passed as function arguments or as an array.
13
- *
14
- * @return int The lowest of the numbers.
15
- */
16
- static function lowest() {
17
- $numbers = func_get_args();
18
- $numbers = array_values($numbers);
19
-
20
- if (count($numbers)) {
21
-
22
- if (is_array($numbers[0]))
23
- $numbers = $numbers[0];
24
-
25
- if (array_walk($numbers, 'intval')) {
26
- sort($numbers, SORT_NUMERIC);
27
- return reset($numbers);
28
- }
29
- }
30
- return false;
31
- }
32
- }
33
  ?>
1
+ <?php
2
+ /*
3
+ JLFunctions Number Class
4
+ Copyright (c)2011-2012 John Lamansky
5
+ */
6
+
7
+ class sunum {
8
+
9
+ /**
10
+ * Returns the lowest of a set of numbers.
11
+ *
12
+ * @param array|int $number,... The numbers may be passed as function arguments or as an array.
13
+ *
14
+ * @return int The lowest of the numbers.
15
+ */
16
+ static function lowest() {
17
+ $numbers = func_get_args();
18
+ $numbers = array_values($numbers);
19
+
20
+ if (count($numbers)) {
21
+
22
+ if (is_array($numbers[0]))
23
+ $numbers = $numbers[0];
24
+
25
+ if (array_walk($numbers, 'intval')) {
26
+ sort($numbers, SORT_NUMERIC);
27
+ return reset($numbers);
28
+ }
29
+ }
30
+ return false;
31
+ }
32
+ }
33
  ?>
includes/jlfunctions/str.php CHANGED
@@ -1,290 +1,290 @@
1
- <?php
2
- /*
3
- JLFunctions String Class
4
- Copyright (c)2009-2012 John Lamansky
5
- */
6
-
7
- class sustr {
8
-
9
- /**
10
- * Returns whether or not a given string starts with a given substring.
11
- *
12
- * @param string $str The "haystack" string.
13
- * @param string $sub The "needle" string.
14
- * @return bool Whether or not $str starts with $sub.
15
- */
16
- static function startswith( $str, $sub ) {
17
- return ( substr( $str, 0, strlen( $sub ) ) === $sub );
18
- }
19
-
20
- /**
21
- * Returns whether or not a given string ends with a given substring.
22
- *
23
- * @param string $str The "haystack" string.
24
- * @param string $sub The "needle" string.
25
- * @return bool Whether or not $str ends with $sub.
26
- */
27
- static function endswith( $str, $sub ) {
28
- return ( substr( $str, strlen( $str ) - strlen( $sub ) ) === $sub );
29
- }
30
-
31
- /**
32
- * Makes a string start with a given string if it doesn't already.
33
- *
34
- * @param string $str The string that should start with $start
35
- * @param string $start
36
- *
37
- * @return string The string with $start at the beginning
38
- */
39
- static function startwith( $str, $start ) {
40
- if (!sustr::startswith($str, $start))
41
- return $start.$str;
42
- else
43
- return $str;
44
- }
45
-
46
- /**
47
- * Makes a string end with a given string if it doesn't already.
48
- *
49
- * @param string $str The string that should end with $end
50
- * @param string $end
51
- *
52
- * @return string The string with $end at the end
53
- */
54
- static function endwith( $str, $end ) {
55
- if (!sustr::endswith($str, $end))
56
- return $str.$end;
57
- else
58
- return $str;
59
- }
60
-
61
- /**
62
- * Checks whether or not $str has $sub in it somewhere.
63
- *
64
- * @param string $str
65
- * @param string $sub
66
- * @return bool
67
- */
68
- static function has($str, $sub) {
69
- return (strpos($str, $sub) !== false);
70
- }
71
-
72
- /**
73
- * Case-insensitively checks whether or not $str has $sub in it somewhere.
74
- *
75
- * @param string $str
76
- * @param string $sub
77
- * @return bool
78
- */
79
- static function ihas($str, $sub) {
80
- $str = strtolower($str);
81
- $sub = strtolower($sub);
82
- return (strpos($str, $sub) !== false);
83
- }
84
-
85
- /**
86
- * Truncates a string if it is longer than a given length.
87
- *
88
- * @param string $str The string to possibly truncate.
89
- * @param int $maxlen The desired maximum length of the string.
90
- * @param string $truncate The string that should be added to the end of a truncated string.
91
- * @return string
92
- */
93
- static function truncate( $str, $maxlen, $truncate = '...', $maintain_words=false ) {
94
-
95
- if ( strlen($str) > $maxlen ) {
96
- $str = substr( $str, 0, $maxlen - strlen($truncate) );
97
- if ($maintain_words) $str = preg_replace('/ ([^ ]+)$/', '', $str);
98
- $str .= $truncate;
99
- }
100
-
101
- return $str;
102
- }
103
-
104
- /**
105
- * Returns the contents of $str up to, but not including, the first instance of $sub.
106
- *
107
- * @param string $str
108
- * @param string $sub
109
- * @return string
110
- */
111
- static function upto($str, $sub) {
112
- $end = strpos($str, $sub);
113
- if ($end === false)
114
- return $str;
115
- else
116
- return substr($str, 0, $end);
117
- }
118
-
119
- /**
120
- * Joins strings into a natural-language list (e.g. "A and B" or "A, B, and C")
121
- * Can be internationalized with gettext or the su_lang_implode filter.
122
- *
123
- * @param array $items The strings (or objects with $var child strings) to join.
124
- * @param string|false $var The name of the items' object variables whose values should be imploded into a list.
125
- If false, the items themselves will be used.
126
- * @param bool $ucwords Whether or not to capitalize the first letter of every word in the list.
127
- * @return string|array The items in a natural-language list.
128
- */
129
- static function nl_implode($items, $var=false, $ucwords=false) {
130
-
131
- if (is_array($items) ) {
132
-
133
- if (strlen($var)) {
134
- $_items = array();
135
- foreach ($items as $item) $_items[] = $item->$var;
136
- $items = $_items;
137
- }
138
-
139
- if ($ucwords) $items = array_map('ucwords', $items);
140
-
141
- switch (count($items)) {
142
- case 0: $list = ''; break;
143
- case 1: $list = $items[0]; break;
144
- case 2: $list = sprintf(__('%s and %s', 'seo-ultimate'), $items[0], $items[1]); break;
145
- default:
146
- $last = array_pop($items);
147
- $list = implode(__(', ', 'seo-ultimate'), $items);
148
- $list = sprintf(__('%s, and %s', 'seo-ultimate'), $list, $last);
149
- break;
150
- }
151
-
152
- return apply_filters('su_lang_implode', $list, $items);
153
- }
154
-
155
- return $items;
156
- }
157
-
158
- /**
159
- * If the given string ends with the given suffix, the suffix is removed.
160
- *
161
- * @param string $str The string from which the provided suffix should be trimmed if located.
162
- * @param string $totrim The suffix that should be trimmed if found.
163
- * @return string The possibly-trimmed string.
164
- */
165
- static function rtrim_str($str, $totrim) {
166
- if (strlen($str) > strlen($totrim) && sustr::endswith($str, $totrim))
167
- return substr($str, 0, -strlen($totrim));
168
-
169
- return $str;
170
- }
171
-
172
- /**
173
- * If the given string ends with the given suffix or any portion thereof, the suffix or suffix portion is removed.
174
- *
175
- * @param string $str The string from which the provided suffix should be trimmed if located.
176
- * @param string $totrim The suffix that should be trimmed if it or a portion of it is found.
177
- * @return string The possibly-trimmed string.
178
- */
179
- static function rtrim_substr($str, $totrim) {
180
- for ($i = strlen($totrim); $i > 0; $i--) {
181
- $totrimsub = substr($totrim, 0, $i);
182
- if (sustr::endswith($str, $totrimsub))
183
- return sustr::rtrim_str($str, $totrimsub);
184
- }
185
-
186
- return $str;
187
- }
188
-
189
- /**
190
- * If the given string begins with the given prefix, the prefix is removed.
191
- *
192
- * @param string $str The string of which the provided prefix should be trimmed if located.
193
- * @param string $totrim The prefix that should be trimmed if found.
194
- * @return string The possibly-trimmed string.
195
- */
196
- static function ltrim_str($str, $totrim) {
197
- if (strlen($str) > strlen($totrim) && sustr::startswith($str, $totrim))
198
- return substr($str, strlen($totrim));
199
-
200
- return $str;
201
- }
202
-
203
- static function batch_replace($search, $replace, $subjects) {
204
- $subjects = array_unique((array)$subjects);
205
- $results = array();
206
- foreach ($subjects as $subject) {
207
- $results[$subject] = str_replace($search, $replace, $subject);
208
- }
209
- return $results;
210
- }
211
-
212
- static function to_int($str) {
213
- return intval(sustr::preg_filter('0-9', strval($str)));
214
- }
215
-
216
- static function preg_filter($filter, $str) {
217
- $filter = str_replace('/', '\\/', $filter);
218
- return preg_replace("/[^{$filter}]/", '', $str);
219
- }
220
-
221
- static function preg_escape($str, $delim='%') {
222
- $chars = "\ ^ . $ | ( ) [ ] * + ? { } , ".$delim;
223
- $chars = explode(' ', $chars);
224
- foreach ($chars as $char)
225
- $str = str_replace($char, '\\'.$char, $str);
226
- return $str;
227
- }
228
-
229
- static function htmlsafe_str_replace($search, $replace, $subject, $limit, &$count, $exclude_tags = false) {
230
- $search = sustr::preg_escape($search, '');
231
- return sustr::htmlsafe_preg_replace($search, $replace, $subject, $limit, $count, $exclude_tags);
232
- }
233
-
234
- static function htmlsafe_preg_replace($search, $replace, $subject, $limit, &$count, $exclude_tags = false) {
235
-
236
- if (!$exclude_tags || !is_array($exclude_tags)) $exclude_tags = array('a', 'pre', 'code', 'kbd');
237
- if (count($exclude_tags) > 1)
238
- $exclude_tags = sustr::preg_filter('a-z0-9|', implode('|', $exclude_tags));
239
- else
240
- $exclude_tags = array_shift($exclude_tags);
241
-
242
- $search = str_replace('/', '\/', $search);
243
-
244
- //Based off of regex from
245
- //http://stackoverflow.com/questions/3013164/regex-to-replace-a-string-in-html-but-not-within-a-link-or-heading
246
- $search_regex = "/\b($search)\b(?!(?:(?!<\/?(?:$exclude_tags).*?>).)*<\/(?:$exclude_tags).*?>)(?![^<>]*>)/imsU";
247
-
248
- return preg_replace($search_regex, $replace, $subject, $limit, $count);
249
- }
250
-
251
- static function tclcwords($str) {
252
- $words = explode(' ', $str);
253
- $new_words = array();
254
- foreach ($words as $word) {
255
- if (strtolower($word) == $word)
256
- $new_words[] = ucwords($word);
257
- else
258
- $new_words[] = $word;
259
- }
260
- return implode(' ', $new_words);
261
- }
262
-
263
- static function camel_case($string) {
264
- $string = strtolower($string);
265
- $string = preg_replace('@[^a-z0-9]@', ' ', $string);
266
- $words = array_filter(explode(' ', $string));
267
- $first = array_shift($words);
268
- $words = array_map('ucwords', $words);
269
- $words = implode('', $words);
270
- $string = $first . $words;
271
- return $string;
272
- }
273
-
274
- static function wildcards_to_regex($wcstr) {
275
- $wcstr = sustr::preg_escape($wcstr, '@');
276
- $wcstr = str_replace('\\*', '.*', $wcstr);
277
- $regex = "@^$wcstr$@i";
278
- $regex = str_replace(array('@^.*', '.*$@i'), array('@', '@i'), $regex);
279
- return $regex;
280
- }
281
-
282
- static function tolower($str) {
283
- if (function_exists('mb_strtolower'))
284
- return mb_strtolower($str);
285
-
286
- return strtolower($str);
287
- }
288
- }
289
-
290
  ?>
1
+ <?php
2
+ /*
3
+ JLFunctions String Class
4
+ Copyright (c)2009-2012 John Lamansky
5
+ */
6
+
7
+ class sustr {
8
+
9
+ /**
10
+ * Returns whether or not a given string starts with a given substring.
11
+ *
12
+ * @param string $str The "haystack" string.
13
+ * @param string $sub The "needle" string.
14
+ * @return bool Whether or not $str starts with $sub.
15
+ */
16
+ static function startswith( $str, $sub ) {
17
+ return ( substr( $str, 0, strlen( $sub ) ) === $sub );
18
+ }
19
+
20
+ /**
21
+ * Returns whether or not a given string ends with a given substring.
22
+ *
23
+ * @param string $str The "haystack" string.
24
+ * @param string $sub The "needle" string.
25
+ * @return bool Whether or not $str ends with $sub.
26
+ */
27
+ static function endswith( $str, $sub ) {
28
+ return ( substr( $str, strlen( $str ) - strlen( $sub ) ) === $sub );
29
+ }
30
+
31
+ /**
32
+ * Makes a string start with a given string if it doesn't already.
33
+ *
34
+ * @param string $str The string that should start with $start
35
+ * @param string $start
36
+ *
37
+ * @return string The string with $start at the beginning
38
+ */
39
+ static function startwith( $str, $start ) {
40
+ if (!sustr::startswith($str, $start))
41
+ return $start.$str;
42
+ else
43
+ return $str;
44
+ }
45
+
46
+ /**
47
+ * Makes a string end with a given string if it doesn't already.
48
+ *
49
+ * @param string $str The string that should end with $end
50
+ * @param string $end
51
+ *
52
+ * @return string The string with $end at the end
53
+ */
54
+ static function endwith( $str, $end ) {
55
+ if (!sustr::endswith($str, $end))
56
+ return $str.$end;
57
+ else
58
+ return $str;
59
+ }
60
+
61
+ /**
62
+ * Checks whether or not $str has $sub in it somewhere.
63
+ *
64
+ * @param string $str
65
+ * @param string $sub
66
+ * @return bool
67
+ */
68
+ static function has($str, $sub) {
69
+ return (strpos($str, $sub) !== false);
70
+ }
71
+
72
+ /**
73
+ * Case-insensitively checks whether or not $str has $sub in it somewhere.
74
+ *
75
+ * @param string $str
76
+ * @param string $sub
77
+ * @return bool
78
+ */
79
+ static function ihas($str, $sub) {
80
+ $str = strtolower($str);
81
+ $sub = strtolower($sub);
82
+ return (strpos($str, $sub) !== false);
83
+ }
84
+
85
+ /**
86
+ * Truncates a string if it is longer than a given length.
87
+ *
88
+ * @param string $str The string to possibly truncate.
89
+ * @param int $maxlen The desired maximum length of the string.
90
+ * @param string $truncate The string that should be added to the end of a truncated string.
91
+ * @return string
92
+ */
93
+ static function truncate( $str, $maxlen, $truncate = '...', $maintain_words=false ) {
94
+
95
+ if ( strlen($str) > $maxlen ) {
96
+ $str = substr( $str, 0, $maxlen - strlen($truncate) );
97
+ if ($maintain_words) $str = preg_replace('/ ([^ ]+)$/', '', $str);
98
+ $str .= $truncate;
99
+ }
100
+
101
+ return $str;
102
+ }
103
+
104
+ /**
105
+ * Returns the contents of $str up to, but not including, the first instance of $sub.
106
+ *
107
+ * @param string $str
108
+ * @param string $sub
109
+ * @return string
110
+ */
111
+ static function upto($str, $sub) {
112
+ $end = strpos($str, $sub);
113
+ if ($end === false)
114
+ return $str;
115
+ else
116
+ return substr($str, 0, $end);
117
+ }
118
+
119
+ /**
120
+ * Joins strings into a natural-language list (e.g. "A and B" or "A, B, and C")
121
+ * Can be internationalized with gettext or the su_lang_implode filter.
122
+ *
123
+ * @param array $items The strings (or objects with $var child strings) to join.
124
+ * @param string|false $var The name of the items' object variables whose values should be imploded into a list.
125
+ If false, the items themselves will be used.
126
+ * @param bool $ucwords Whether or not to capitalize the first letter of every word in the list.
127
+ * @return string|array The items in a natural-language list.
128
+ */
129
+ static function nl_implode($items, $var=false, $ucwords=false) {
130
+
131
+ if (is_array($items) ) {
132
+
133
+ if (strlen($var)) {
134
+ $_items = array();
135
+ foreach ($items as $item) $_items[] = $item->$var;
136
+ $items = $_items;
137
+ }
138
+
139
+ if ($ucwords) $items = array_map('ucwords', $items);
140
+
141
+ switch (count($items)) {
142
+ case 0: $list = ''; break;
143
+ case 1: $list = $items[0]; break;
144
+ case 2: $list = sprintf(__('%s and %s', 'seo-ultimate'), $items[0], $items[1]); break;
145
+ default:
146
+ $last = array_pop($items);
147
+ $list = implode(__(', ', 'seo-ultimate'), $items);
148
+ $list = sprintf(__('%s, and %s', 'seo-ultimate'), $list, $last);
149
+ break;
150
+ }
151
+
152
+ return apply_filters('su_lang_implode', $list, $items);
153
+ }
154
+
155
+ return $items;
156
+ }
157
+
158
+ /**
159
+ * If the given string ends with the given suffix, the suffix is removed.
160
+ *
161
+ * @param string $str The string from which the provided suffix should be trimmed if located.
162
+ * @param string $totrim The suffix that should be trimmed if found.
163
+ * @return string The possibly-trimmed string.
164
+ */
165
+ static function rtrim_str($str, $totrim) {
166
+ if (strlen($str) > strlen($totrim) && sustr::endswith($str, $totrim))
167
+ return substr($str, 0, -strlen($totrim));
168
+
169
+ return $str;
170
+ }
171
+
172
+ /**
173
+ * If the given string ends with the given suffix or any portion thereof, the suffix or suffix portion is removed.
174
+ *
175
+ * @param string $str The string from which the provided suffix should be trimmed if located.
176
+ * @param string $totrim The suffix that should be trimmed if it or a portion of it is found.
177
+ * @return string The possibly-trimmed string.
178
+ */
179
+ static function rtrim_substr($str, $totrim) {
180
+ for ($i = strlen($totrim); $i > 0; $i--) {
181
+ $totrimsub = substr($totrim, 0, $i);
182
+ if (sustr::endswith($str, $totrimsub))
183
+ return sustr::rtrim_str($str, $totrimsub);
184
+ }
185
+
186
+ return $str;
187
+ }
188
+
189
+ /**
190
+ * If the given string begins with the given prefix, the prefix is removed.
191
+ *
192
+ * @param string $str The string of which the provided prefix should be trimmed if located.
193
+ * @param string $totrim The prefix that should be trimmed if found.
194
+ * @return string The possibly-trimmed string.
195
+ */
196
+ static function ltrim_str($str, $totrim) {
197
+ if (strlen($str) > strlen($totrim) && sustr::startswith($str, $totrim))
198
+ return substr($str, strlen($totrim));
199
+
200
+ return $str;
201
+ }
202
+
203
+ static function batch_replace($search, $replace, $subjects) {
204
+ $subjects = array_unique((array)$subjects);
205
+ $results = array();
206
+ foreach ($subjects as $subject) {
207
+ $results[$subject] = str_replace($search, $replace, $subject);
208
+ }
209
+ return $results;
210
+ }
211
+
212
+ static function to_int($str) {
213
+ return intval(sustr::preg_filter('0-9', strval($str)));
214
+ }
215
+
216
+ static function preg_filter($filter, $str) {
217
+ $filter = str_replace('/', '\\/', $filter);
218
+ return preg_replace("/[^{$filter}]/", '', $str);
219
+ }
220
+
221
+ static function preg_escape($str, $delim='%') {
222
+ $chars = "\ ^ . $ | ( ) [ ] * + ? { } , ".$delim;
223
+ $chars = explode(' ', $chars);
224
+ foreach ($chars as $char)
225
+ $str = str_replace($char, '\\'.$char, $str);
226
+ return $str;
227
+ }
228
+
229
+ static function htmlsafe_str_replace($search, $replace, $subject, $limit, &$count, $exclude_tags = false) {
230
+ $search = sustr::preg_escape($search, '');
231
+ return sustr::htmlsafe_preg_replace($search, $replace, $subject, $limit, $count, $exclude_tags);
232
+ }
233
+
234
+ static function htmlsafe_preg_replace($search, $replace, $subject, $limit, &$count, $exclude_tags = false) {
235
+
236
+ if (!$exclude_tags || !is_array($exclude_tags)) $exclude_tags = array('a', 'pre', 'code', 'kbd');
237
+ if (count($exclude_tags) > 1)
238
+ $exclude_tags = sustr::preg_filter('a-z0-9|', implode('|', $exclude_tags));
239
+ else
240
+ $exclude_tags = array_shift($exclude_tags);
241
+
242
+ $search = str_replace('/', '\/', $search);
243
+
244
+ //Based off of regex from
245
+ //http://stackoverflow.com/questions/3013164/regex-to-replace-a-string-in-html-but-not-within-a-link-or-heading
246
+ $search_regex = "/\b($search)\b(?!(?:(?!<\/?(?:$exclude_tags).*?>).)*<\/(?:$exclude_tags).*?>)(?![^<>]*>)/imsU";
247
+
248
+ return preg_replace($search_regex, $replace, $subject, $limit, $count);
249
+ }
250
+
251
+ static function tclcwords($str) {
252
+ $words = explode(' ', $str);
253
+ $new_words = array();
254
+ foreach ($words as $word) {
255
+ if (strtolower($word) == $word)
256
+ $new_words[] = ucwords($word);
257
+ else
258
+ $new_words[] = $word;
259
+ }
260
+ return implode(' ', $new_words);
261
+ }
262
+
263
+ static function camel_case($string) {
264
+ $string = strtolower($string);
265
+ $string = preg_replace('@[^a-z0-9]@', ' ', $string);
266
+ $words = array_filter(explode(' ', $string));
267
+ $first = array_shift($words);
268
+ $words = array_map('ucwords', $words);
269
+ $words = implode('', $words);
270
+ $string = $first . $words;
271
+ return $string;
272
+ }
273
+
274
+ static function wildcards_to_regex($wcstr) {
275
+ $wcstr = sustr::preg_escape($wcstr, '@');
276
+ $wcstr = str_replace('\\*', '.*', $wcstr);
277
+ $regex = "@^$wcstr$@i";
278
+ $regex = str_replace(array('@^.*', '.*$@i'), array('@', '@i'), $regex);
279
+ return $regex;
280
+ }
281
+
282
+ static function tolower($str) {
283
+ if (function_exists('mb_strtolower'))
284
+ return mb_strtolower($str);
285
+
286
+ return strtolower($str);
287
+ }
288
+ }
289
+
290
  ?>
includes/jlfunctions/url.php CHANGED
@@ -1,69 +1,69 @@
1
- <?php
2
- /*
3
- JLFunctions URL Class
4
- Copyright (c)2009-2012 John Lamansky
5
- */
6
-
7
- class suurl {
8
-
9
- /**
10
- * Approximately determines the URL in the visitor's address bar. (Includes query strings, but not #anchors.)
11
- *
12
- * @return string The current URL.
13
- */
14
- static function current() {
15
- $url = 'http';
16
- if (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on") $url .= "s";
17
- $url .= "://";
18
-
19
- if ($_SERVER["SERVER_PORT"] != "80")
20
- return $url.$_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"];
21
- else
22
- return $url.$_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
23
- }
24
-
25
- /**
26
- * Checks whether or not two URLs are equivalent.
27
- *
28
- * @param string $url1
29
- * @param string $url2
30
- * @return bool
31
- */
32
- static function equal($url1, $url2) {
33
-
34
- if (($url1parts = parse_url($url1)) && isset($url1parts['host'])) {
35
- $url1parts['host'] = strtolower($url1parts['host']);
36
- $url1 = self::build($url1parts);
37
- }
38
-
39
- if (($url2parts = parse_url($url2)) && isset($url2parts['host'])) {
40
- $url2parts['host'] = strtolower($url2parts['host']);
41
- $url2 = self::build($url2parts);
42
- }
43
-
44
- return $url1 == $url2;
45
- }
46
-
47
- /**
48
- * Turns an array of URL parts (host, scheme, path, query, fragment) into a URL.
49
- *
50
- * @param array $parts
51
- * @return string
52
- */
53
- static function build($parts) {
54
-
55
- $url = '';
56
-
57
- if (!empty($parts['host'])) {
58
- $url = empty($parts['scheme']) ? 'http://' : $parts['scheme'] . '://';
59
- $url .= $parts['host'];
60
- }
61
-
62
- if (!empty($parts['path'])) $url .= $parts['path'];
63
- if (!empty($parts['query'])) $url .= '?' . $parts['query'];
64
- if (!empty($parts['fragment'])) $url .= '#' . $parts['fragment'];
65
- return $url;
66
- }
67
- }
68
-
69
  ?>
1
+ <?php
2
+ /*
3
+ JLFunctions URL Class
4
+ Copyright (c)2009-2012 John Lamansky
5
+ */
6
+
7
+ class suurl {
8
+
9
+ /**
10
+ * Approximately determines the URL in the visitor's address bar. (Includes query strings, but not #anchors.)
11
+ *
12
+ * @return string The current URL.
13
+ */
14
+ static function current() {
15
+ $url = 'http';
16
+ if (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on") $url .= "s";
17
+ $url .= "://";
18
+
19
+ if ($_SERVER["SERVER_PORT"] != "80")
20
+ return $url.$_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"];
21
+ else
22
+ return $url.$_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
23
+ }
24
+
25
+ /**
26
+ * Checks whether or not two URLs are equivalent.
27
+ *
28
+ * @param string $url1
29
+ * @param string $url2
30
+ * @return bool
31
+ */
32
+ static function equal($url1, $url2) {
33
+
34
+ if (($url1parts = parse_url($url1)) && isset($url1parts['host'])) {
35
+ $url1parts['host'] = strtolower($url1parts['host']);
36
+ $url1 = self::build($url1parts);
37
+ }
38
+
39
+ if (($url2parts = parse_url($url2)) && isset($url2parts['host'])) {
40
+ $url2parts['host'] = strtolower($url2parts['host']);
41
+ $url2 = self::build($url2parts);
42
+ }
43
+
44
+ return $url1 == $url2;
45
+ }
46
+
47
+ /**
48
+ * Turns an array of URL parts (host, scheme, path, query, fragment) into a URL.
49
+ *
50
+ * @param array $parts
51
+ * @return string
52
+ */
53
+ static function build($parts) {
54
+
55
+ $url = '';
56
+
57
+ if (!empty($parts['host'])) {
58
+ $url = empty($parts['scheme']) ? 'http://' : $parts['scheme'] . '://';
59
+ $url .= $parts['host'];
60
+ }
61
+
62
+ if (!empty($parts['path'])) $url .= $parts['path'];
63
+ if (!empty($parts['query'])) $url .= '?' . $parts['query'];
64
+ if (!empty($parts['fragment'])) $url .= '#' . $parts['fragment'];
65
+ return $url;
66
+ }
67
+ }
68
+
69
  ?>
includes/jlfunctions/web.php CHANGED
@@ -1,31 +1,31 @@
1
- <?php
2
- /*
3
- JLFunctions Web Class
4
- Copyright (c)2010 John Lamansky
5
- */
6
-
7
- class suweb {
8
-
9
- static function is_search_engine_ua($user_agent) {
10
- $ua_keywords = array(
11
- 'Googlebot' //Google
12
- , 'Yahoo', 'Y!' //Yahoo
13
- , 'Baiduspider' //Baidu (Chinese)
14
- , 'msnbot' //Bing
15
- , 'Yandex' //Yandex (Russian)
16
- , 'Sosospider' //Soso (Chinese)
17
- , 'Teoma' //Ask.com
18
- , 'sogou spider' //Sogou (Chinese)
19
- , 'Scooter', 'AltaVista' //AltaVista
20
- );
21
-
22
- foreach ($ua_keywords as $keyword) {
23
- if (sustr::ihas($user_agent, $keyword)) return true;
24
- }
25
-
26
- return false;
27
- }
28
-
29
- }
30
-
31
  ?>
1
+ <?php
2
+ /*
3
+ JLFunctions Web Class
4
+ Copyright (c)2010 John Lamansky
5
+ */
6
+
7
+ class suweb {
8
+
9
+ static function is_search_engine_ua($user_agent) {
10
+ $ua_keywords = array(
11
+ 'Googlebot' //Google
12
+ , 'Yahoo', 'Y!' //Yahoo
13
+ , 'Baiduspider' //Baidu (Chinese)
14
+ , 'msnbot' //Bing
15
+ , 'Yandex' //Yandex (Russian)
16
+ , 'Sosospider' //Soso (Chinese)
17
+ , 'Teoma' //Ask.com
18
+ , 'sogou spider' //Sogou (Chinese)
19
+ , 'Scooter', 'AltaVista' //AltaVista
20
+ );
21
+
22
+ foreach ($ua_keywords as $keyword) {
23
+ if (sustr::ihas($user_agent, $keyword)) return true;
24
+ }
25
+
26
+ return false;
27
+ }
28
+
29
+ }
30
+
31
  ?>
includes/jlsuggest/jlsuggest.css CHANGED
@@ -1,120 +1,120 @@
1
-
2
- input.jlsuggest,
3
- .jls_text_dest {
4
- width: 100%;
5
- }
6
-
7
- input.jls_loading {
8
- background-image: url(loading.gif) !important;
9
- background-repeat: no-repeat;
10
- background-position: 98% center;
11
- }
12
-
13
- .jls_text_dest {
14
- border: 1px solid #C0CDFF;
15
- border-radius: 3px;
16
- background-color: #E0E7FF;
17
- position: relative;
18
- margin: 1px -1px;
19
- padding: 3px 0 1px;
20
- }
21
-
22
- .jlsuggest-disabled {
23
- background-color: #FFE0E0;
24
- border-color: #FFC1C1;
25
- }
26
-
27
- .jls_text_dest_text {
28
- cursor: default;
29
- padding: 0 0 0 5px;
30
- }
31
-
32
- .jls_text_dest_text .type {
33
- color: #666;
34
- font-variant: small-caps;
35
- font-size: smaller;
36
- }
37
-
38
- .jls_text_dest_close {
39
- position: absolute;
40
- top: 0;
41
- right: 0;
42
- cursor: pointer;
43
- padding: 3px 10px 1px;
44
- color: black;
45
- text-decoration: none;
46
- }
47
-
48
- .jls_text_dest_close:hover,
49
- .jls_text_dest_close:focus {
50
- color: red;
51
- }
52
-
53
- .jls_results {
54
- padding: 0;
55
- margin: 0;
56
- list-style: none;
57
- position: absolute;
58
- z-index: 10000;
59
- display: none;
60
- border: 1px solid #DFDFDF;
61
- background-color: white;
62
- border-radius: 4px;
63
- }
64
-
65
- .jls_results li {
66
- margin: 0;
67
- padding: 2px 5px;
68
- min-width: 100px;
69
- white-space: nowrap;
70
- text-align: left;
71
- }
72
-
73
- .jls_results li.jls_header {
74
- margin-top: 10px;
75
- background-color: #C0CDFF;
76
- text-align: center;
77
- font-weight: bold;
78
- cursor: default;
79
- }
80
-
81
- .jls_results li.jls_header:first-child {
82
- margin-top: 0;
83
- }
84
-
85
- .jls_over {
86
- cursor: pointer;
87
- }
88
-
89
- .jls_match {
90
- background-color: yellow;
91
- color: black;
92
- }
93
-
94
- .jls_over {
95
- background-color: #E0E7FF;
96
- }
97
-
98
- .jls_results li {
99
- color:#101010;
100
- }
101
-
102
-
103
- input.jlsuggest:-moz-placeholder {
104
- background-color: #E0E7FF;
105
- border-color: #C0CDFF;
106
- color: black;
107
- }
108
-
109
- /* Requires IE10+ */
110
- input.jlsuggest:-ms-input-placeholder {
111
- background-color: #E0E7FF;
112
- border-color: #C0CDFF;
113
- color: black;
114
- }
115
-
116
- /*
117
- A ::-webkit-input-placeholder block is not included because
118
- the background-color rule doesn't apply correctly on Chrome
119
- and it looks rather horrendous...
120
- */
1
+
2
+ input.jlsuggest,
3
+ .jls_text_dest {
4
+ width: 100%;
5
+ }
6
+
7
+ input.jls_loading {
8
+ background-image: url(loading.gif) !important;
9
+ background-repeat: no-repeat;
10
+ background-position: 98% center;
11
+ }
12
+
13
+ .jls_text_dest {
14
+ border: 1px solid #C0CDFF;
15
+ border-radius: 3px;
16
+ background-color: #E0E7FF;
17
+ position: relative;
18
+ margin: 1px -1px;
19
+ padding: 3px 0 1px;
20
+ }
21
+
22
+ .jlsuggest-disabled {
23
+ background-color: #FFE0E0;
24
+ border-color: #FFC1C1;
25
+ }
26
+
27
+ .jls_text_dest_text {
28
+ cursor: default;
29
+ padding: 0 0 0 5px;
30
+ }
31
+
32
+ .jls_text_dest_text .type {
33
+ color: #666;
34
+ font-variant: small-caps;
35
+ font-size: smaller;
36
+ }
37
+
38
+ .jls_text_dest_close {
39
+ position: absolute;
40
+ top: 0;
41
+ right: 0;
42
+ cursor: pointer;
43
+ padding: 3px 10px 1px;
44
+ color: black;
45
+ text-decoration: none;
46
+ }
47
+
48
+ .jls_text_dest_close:hover,
49
+ .jls_text_dest_close:focus {
50
+ color: red;
51
+ }
52
+
53
+ .jls_results {
54
+ padding: 0;
55
+ margin: 0;
56
+ list-style: none;
57
+ position: absolute;
58
+ z-index: 10000;
59
+ display: none;
60
+ border: 1px solid #DFDFDF;
61
+ background-color: white;
62
+ border-radius: 4px;
63
+ }
64
+
65
+ .jls_results li {
66
+ margin: 0;
67
+ padding: 2px 5px;
68
+ min-width: 100px;
69
+ white-space: nowrap;
70
+ text-align: left;
71
+ }
72
+
73
+ .jls_results li.jls_header {
74
+ margin-top: 10px;
75
+ background-color: #C0CDFF;
76
+ text-align: center;
77
+ font-weight: bold;
78
+ cursor: default;
79
+ }
80
+
81
+ .jls_results li.jls_header:first-child {
82
+ margin-top: 0;
83
+ }
84
+
85
+ .jls_over {
86
+ cursor: pointer;
87
+ }
88
+
89
+ .jls_match {
90
+ background-color: yellow;
91
+ color: black;
92
+ }
93
+
94
+ .jls_over {
95
+ background-color: #E0E7FF;
96
+ }
97
+
98
+ .jls_results li {
99
+ color:#101010;
100
+ }
101
+
102
+
103
+ input.jlsuggest:-moz-placeholder {
104
+ background-color: #E0E7FF;
105
+ border-color: #C0CDFF;
106
+ color: black;
107
+ }
108
+
109
+ /* Requires IE10+ */
110
+ input.jlsuggest:-ms-input-placeholder {
111
+ background-color: #E0E7FF;
112
+ border-color: #C0CDFF;
113
+ color: black;
114
+ }
115
+
116
+ /*
117
+ A ::-webkit-input-placeholder block is not included because
118
+ the background-color rule doesn't apply correctly on Chrome
119
+ and it looks rather horrendous...
120
+ */
includes/jlsuggest/jlsuggest.js CHANGED
@@ -1,361 +1,361 @@
1
- jQuery(document).ready( function($) {
2
- $('input.jlsuggest', '.sdf-admin,#su-postmeta-box').each(function() {
3
- var params = $(this).attr('su:params') ? '&' + $(this).attr('su:params') : '';
4
- $(this).jlsuggest(ajaxurl + '?action=su-jlsuggest-autocomplete' + params,
5
- { delay: 500, minchars: 2, multiple: false, textDest: true, noUrls: true } );
6
- });
7
- } );
8
-
9
-
10
- /*
11
- * jquery.jlsuggest
12
- * Based on WordPress's jquery.suggest 1.1b (2007-08-06)
13
- * Modified by John Lamansky (2011-05-16)
14
- */
15
-
16
- (function($) {
17
-
18
- $.jlsuggest = function(input, options) {
19
- var $input, $results, timeout, prevLength, cache, cacheSize;
20
-
21
- $input = $(input).attr("autocomplete", "off");
22
- $results = $(document.createElement("ul"));
23
-
24
- timeout = false; // hold timeout ID for suggestion results to appear
25
- prevLength = 0; // last recorded length of $input.val()
26
- cache = []; // cache MRU list
27
- cacheSize = 0; // size of cache in chars (bytes?)
28
-
29
- $results.addClass(options.resultsClass).appendTo('body');
30
-
31
-
32
- resetPosition();
33
- $(window)
34
- .load(resetPosition) // just in case user is changing size of page while loading
35
- .resize(resetPosition);
36
-
37
- $input.blur(function() {
38
- setTimeout(function() { $results.hide() }, 200);
39
- });
40
-
41
-
42
- // help IE users if possible
43
- if ( $.browser.msie ) {
44
- try {
45
- $results.bgiframe();
46
- } catch(e) { }
47
- }
48
-
49
- // I really hate browser detection, but I don't see any other way
50
- if ($.browser.mozilla)
51
- $input.keypress(processKey); // onkeypress repeats arrow keys in Mozilla/Opera
52
- else
53
- $input.keydown(processKey); // onkeydown repeats arrow keys in IE/Safari
54
-
55
- $('.' + options.textDestCloseClass).click(function() {
56
- $(this).parent().siblings('.' + options.textDestTextClass + ':first').text('').parent().hide().removeClass(options.textDestDisabledClass).siblings('input:first').val('').show().focus()
57
- });
58
-
59
-
60
- function resetPosition() {
61
- // requires jquery.dimension plugin
62
- var offset = $input.offset();
63
- $results.css({
64
- top: (offset.top + input.offsetHeight) + 'px',
65
- left: offset.left + 'px'
66
- });
67
- }
68
-
69
-
70
- function processKey(e) {
71
-
72
- // handling up/down/escape requires results to be visible
73
- // handling enter/tab requires that AND a result to be selected
74
- if ((/27$|38$|40$/.test(e.keyCode) && $results.is(':visible')) ||
75
- (/^13$|^9$/.test(e.keyCode) && getCurrentResult())) {
76
-
77
- if (e.preventDefault)
78
- e.preventDefault();
79
- if (e.stopPropagation)
80
- e.stopPropagation();
81
-
82
- e.cancelBubble = true;
83
- e.returnValue = false;
84
-
85
- switch(e.keyCode) {
86
-
87
- case 38: // up
88
- prevResult();
89
- break;
90
-
91
- case 40: // down
92
- nextResult();
93
- break;
94
-
95
- case 9: // tab
96
- case 13: // return
97
- selectCurrentResult();
98
- break;
99
-
100
- case 27: // escape
101
- $results.hide();
102
- break;
103
-
104
- }
105
-
106
- } else if ($input.val().length != prevLength) {
107
-
108
- if (timeout)
109
- clearTimeout(timeout);
110
-
111
- //Only trigger suggestions if the minimum length is met and if this isn't a URL (assuming the noUrls option is set)
112
- if ($input.val().length >= options.minchars && (!options.noUrls || ($input.val().substring(0, 7) != 'http://' && $input.val().substring(0, 8) != 'https://' && $input.val().indexOf('/') == '-1'))) {
113
- $input.addClass(options.timeoutClass);
114
-
115
- //Wait a bit before giving autocomplete suggestions
116
- timeout = setTimeout(suggest, options.delay);
117
- } else {
118
- $results.hide();
119
- $input.removeClass(options.timeoutClass);
120
- }
121
-
122
- prevLength = $input.val().length;
123
-
124
- }
125
-
126
-
127
- }
128
-
129
-
130
- function suggest() {
131
-
132
- var q = $.trim($input.val()), items;
133
-
134
- if (q.length >= options.minchars) {
135
-
136
- cached = checkCache(q);
137
-
138
- if (cached) {
139
-
140
- displayItems(cached['items']);
141
-
142
- } else {
143
-
144
- $.get(options.source, {q: q}, function(txt) {
145
-
146
- $results.hide();
147
-
148
- items = parseTxt(txt, q);
149
-
150
- displayItems(items);
151
- addToCache(q, items, txt.length);
152
-
153
- });
154
-
155
- }
156
-
157
- } else {
158
-
159
- $results.hide();
160
- $input.removeClass(options.timeoutClass);
161
- }
162
-
163
- }
164
-
165
-
166
- function checkCache(q) {
167
- var i;
168
- for (i = 0; i < cache.length; i++)
169
- if (cache[i]['q'] == q) {
170
- cache.unshift(cache.splice(i, 1)[0]);
171
- return cache[0];
172
- }
173
-
174
- return false;
175
-
176
- }
177
-
178
- function addToCache(q, items, size) {
179
- var cached;
180
- while (cache.length && (cacheSize + size > options.maxCacheSize)) {
181
- cached = cache.pop();
182
- cacheSize -= cached['size'];
183
- }
184
-
185
- cache.push({
186
- q: q,
187
- size: size,
188
- items: items
189
- });
190
-
191
- cacheSize += size;
192
-
193
- }
194
-
195
- function displayItems(items) {
196
- var i;
197
- if (!items)
198
- return;
199
-
200
- if (!items.length) {
201
- $results.hide();
202
- $input.removeClass(options.timeoutClass);
203
- return;
204
- }
205
-
206
- resetPosition(); // when the form moves after the page has loaded
207
-
208
- $results.html(items.join('')).show();
209
-
210
- $results
211
- .children('li.' + options.itemClass)
212
- .mouseover(function() {
213
- $results.children('li.' + options.itemClass).removeClass(options.selectClass);
214
- $(this).addClass(options.selectClass);
215
- })
216
- .click(function(e) {
217
- e.preventDefault();
218
- e.stopPropagation();
219
- selectCurrentResult();
220
- });
221
-
222
- $input.removeClass(options.timeoutClass);
223
- }
224
-
225
- function parseTxt(txt, q) {
226
-
227
- var lis = [], items = $.parseJSON(txt), i, item;
228
-
229
- // parse returned data for non-empty items
230
- for (i = 0; i < items.length; i++) {
231
-
232
- item = items[i];
233
- if (item) {
234
-
235
- if (item.isheader)
236
- html = '<li class="' + options.headerClass + '">' + item.text + '</li>';
237
- else {
238
- html = item.text.replace(
239
- new RegExp(q, 'ig'),
240
- function(q) { return '<span class="' + options.matchClass + '">' + q + '</span>' }
241
- );
242
- html = '<li'
243
- + ' class="' + Encoder.htmlEncode(options.itemClass, true) + '"'
244
- + ' su:value="' + Encoder.htmlEncode(item.value || '', true) + '"'
245
- + ' su:selectedtext="' + Encoder.htmlEncode(item.selectedtext || '', true) + '"'
246
- + '>' + html + '</li>';
247
- }
248
- lis[lis.length] = html;
249
- }
250
-
251
- }
252
-
253
- return lis;
254
- }
255
-
256
- function getCurrentResult() {
257
- var $currentResult;
258
- if (!$results.is(':visible'))
259
- return false;
260
-
261
- $currentResult = $results.children('li.' + options.selectClass);
262
-
263
- if (!$currentResult.length)
264
- $currentResult = false;
265
-
266
- return $currentResult;
267
-
268
- }
269
-
270
- function selectCurrentResult() {
271
-
272
- $currentResult = getCurrentResult();
273
-
274
- if ($currentResult) {
275
- if (options.textDest) {
276
- $input
277
- .hide() //Hide the input box
278
- .siblings('.' + options.textDestClass + ':first')
279
- .show() //Show the selection box
280
- .children('.' + options.textDestTextClass)
281
- .html($currentResult.attr('su:selectedtext') || $currentResult.text()) //Put the selected item into the selection box
282
- .parentsUntil('tr') //If we're in a table...
283
- .next('td')
284
- .children('input')
285
- .focus(); //...then focus the next textbox in the table
286
-
287
- $input.val($currentResult.attr('su:value'));
288
- } else {
289
- $input.val($currentResult.text());
290
- }
291
- $results.hide();
292
-
293
- if (options.onSelect)
294
- options.onSelect.apply($input[0]);
295
-
296
- }
297
-
298
- }
299
-
300
- function nextResult() {
301
-
302
- $currentResult = getCurrentResult();
303
-
304
- if ($currentResult)
305
- $currentResult
306
- .removeClass(options.selectClass)
307
- .nextAll('.' + options.itemClass + ':first')
308
- .addClass(options.selectClass);
309
- else
310
- $results.children('li.' + options.itemClass + ':first').addClass(options.selectClass);
311
-
312
- }
313
-
314
- function prevResult() {
315
- var $currentResult = getCurrentResult();
316
-
317
- if ($currentResult)
318
- $currentResult
319
- .removeClass(options.selectClass)
320
- .prevAll('.' + options.itemClass + ':first')
321
- .addClass(options.selectClass);
322
- else
323
- $results.children('li.' + options.itemClass + ':last').addClass(options.selectClass);
324
-
325
- }
326
- }
327
-
328
- $.fn.jlsuggest = function(source, options) {
329
-
330
- if (!source)
331
- return;
332
-
333
- options = options || {};
334
- options.source = source;
335
- options.delay = options.delay || 100;
336
- options.resultsClass = options.resultsClass || 'jls_results';
337
- options.selectClass = options.selectClass || 'jls_over';
338
- options.matchClass = options.matchClass || 'jls_match';
339
- options.headerClass = options.headerClass || 'jls_header';
340
- options.itemClass = options.itemClass || 'jls_item';
341
- options.minchars = options.minchars || 2;
342
- options.delimiter = options.delimiter || '\n';
343
- options.onSelect = options.onSelect || false;
344
- options.maxCacheSize = options.maxCacheSize || 65536;
345
- options.noUrls = options.noUrls || false;
346
- options.textDest = options.textDest || false;
347
- options.textDestClass = options.textDestClass || 'jls_text_dest';
348
- options.textDestDisabledClass = options.textDestDisabledClass || 'jlsuggest-disabled';
349
- options.textDestTextClass = options.textDestTextClass || 'jls_text_dest_text';
350
- options.textDestCloseClass = options.textDestCloseClass || 'jls_text_dest_close';
351
- options.timeoutClass = options.timeoutClass || 'jls_loading';
352
-
353
- this.each(function() {
354
- new $.jlsuggest(this, options);
355
- });
356
-
357
- return this;
358
-
359
- };
360
-
361
- })(jQuery);
1
+ jQuery(document).ready( function($) {
2
+ $('input.jlsuggest', '.sdf-admin,#su-postmeta-box').each(function() {
3
+ var params = $(this).attr('su:params') ? '&' + $(this).attr('su:params') : '';
4
+ $(this).jlsuggest(ajaxurl + '?action=su-jlsuggest-autocomplete' + params,
5
+ { delay: 500, minchars: 2, multiple: false, textDest: true, noUrls: true } );
6
+ });
7
+ } );
8
+
9
+
10
+ /*
11
+ * jquery.jlsuggest
12
+ * Based on WordPress's jquery.suggest 1.1b (2007-08-06)
13
+ * Modified by John Lamansky (2011-05-16)
14
+ */
15
+
16
+ (function($) {
17
+
18
+ $.jlsuggest = function(input, options) {
19
+ var $input, $results, timeout, prevLength, cache, cacheSize;
20
+
21
+ $input = $(input).attr("autocomplete", "off");
22
+ $results = $(document.createElement("ul"));
23
+
24
+ timeout = false; // hold timeout ID for suggestion results to appear
25
+ prevLength = 0; // last recorded length of $input.val()
26
+ cache = []; // cache MRU list
27
+ cacheSize = 0; // size of cache in chars (bytes?)
28
+
29
+ $results.addClass(options.resultsClass).appendTo('body');
30
+
31
+
32
+ resetPosition();
33
+ $(window)
34
+ .load(resetPosition) // just in case user is changing size of page while loading
35
+ .resize(resetPosition);
36
+
37
+ $input.blur(function() {
38
+ setTimeout(function() { $results.hide() }, 200);
39
+ });
40
+
41
+
42
+ // help IE users if possible
43
+ if ( $.browser.msie ) {
44
+ try {
45
+ $results.bgiframe();
46
+ } catch(e) { }
47
+ }
48
+
49
+ // I really hate browser detection, but I don't see any other way
50
+ if ($.browser.mozilla)
51
+ $input.keypress(processKey); // onkeypress repeats arrow keys in Mozilla/Opera
52
+ else
53
+ $input.keydown(processKey); // onkeydown repeats arrow keys in IE/Safari
54
+
55
+ $('.' + options.textDestCloseClass).click(function() {
56
+ $(this).parent().siblings('.' + options.textDestTextClass + ':first').text('').parent().hide().removeClass(options.textDestDisabledClass).siblings('input:first').val('').show().focus()
57
+ });
58
+
59
+
60
+ function resetPosition() {
61
+ // requires jquery.dimension plugin
62
+ var offset = $input.offset();
63
+ $results.css({
64
+ top: (offset.top + input.offsetHeight) + 'px',
65
+ left: offset.left + 'px'
66
+ });
67
+ }
68
+
69
+
70
+ function processKey(e) {
71
+
72
+ // handling up/down/escape requires results to be visible
73
+ // handling enter/tab requires that AND a result to be selected
74
+ if ((/27$|38$|40$/.test(e.keyCode) && $results.is(':visible')) ||
75
+ (/^13$|^9$/.test(e.keyCode) && getCurrentResult())) {
76
+
77
+ if (e.preventDefault)
78
+ e.preventDefault();
79
+ if (e.stopPropagation)
80
+ e.stopPropagation();
81
+
82
+ e.cancelBubble = true;
83
+ e.returnValue = false;
84
+
85
+ switch(e.keyCode) {
86
+
87
+ case 38: // up
88
+ prevResult();
89
+ break;
90
+
91
+ case 40: // down
92
+ nextResult();
93
+ break;
94
+
95
+ case 9: // tab
96
+ case 13: // return
97
+ selectCurrentResult();
98
+ break;
99
+
100
+ case 27: // escape
101
+ $results.hide();
102
+ break;
103
+
104
+ }
105
+
106
+ } else if ($input.val().length != prevLength) {
107
+
108
+ if (timeout)
109
+ clearTimeout(timeout);
110
+
111
+ //Only trigger suggestions if the minimum length is met and if this isn't a URL (assuming the noUrls option is set)
112
+ if ($input.val().length >= options.minchars && (!options.noUrls || ($input.val().substring(0, 7) != 'http://' && $input.val().substring(0, 8) != 'https://' && $input.val().indexOf('/') == '-1'))) {
113
+ $input.addClass(options.timeoutClass);
114
+
115
+ //Wait a bit before giving autocomplete suggestions
116
+ timeout = setTimeout(suggest, options.delay);
117
+ } else {
118
+ $results.hide();
119
+ $input.removeClass(options.timeoutClass);
120
+ }
121
+
122
+ prevLength = $input.val().length;
123
+
124
+ }
125
+
126
+
127
+ }
128
+
129
+
130
+ function suggest() {
131
+
132
+ var q = $.trim($input.val()), items;
133
+
134
+ if (q.length >= options.minchars) {
135
+
136
+ cached = checkCache(q);
137
+
138
+ if (cached) {
139
+
140
+ displayItems(cached['items']);
141
+
142
+ } else {
143
+
144
+ $.get(options.source, {q: q}, function(txt) {
145
+
146
+ $results.hide();
147
+
148
+ items = parseTxt(txt, q);
149
+
150
+ displayItems(items);
151
+ addToCache(q, items, txt.length);
152
+
153
+ });
154
+
155
+ }
156
+
157
+ } else {
158
+
159
+ $results.hide();
160
+ $input.removeClass(options.timeoutClass);
161
+ }
162
+
163
+ }
164
+
165
+
166
+ function checkCache(q) {
167
+ var i;
168
+ for (i = 0; i < cache.length; i++)
169
+ if (cache[i]['q'] == q) {
170
+ cache.unshift(cache.splice(i, 1)[0]);
171
+ return cache[0];
172
+ }
173
+
174
+ return false;
175
+
176
+ }
177
+
178
+ function addToCache(q, items, size) {
179
+ var cached;
180
+ while (cache.length && (cacheSize + size > options.maxCacheSize)) {
181
+ cached = cache.pop();
182
+ cacheSize -= cached['size'];
183
+ }
184
+
185
+ cache.push({
186
+ q: q,
187
+ size: size,
188
+ items: items
189
+ });
190
+
191
+ cacheSize += size;
192
+
193
+ }
194
+
195
+ function displayItems(items) {
196
+ var i;
197
+ if (!items)
198
+ return;
199
+
200
+ if (!items.length) {
201
+ $results.hide();
202
+ $input.removeClass(options.timeoutClass);
203
+ return;
204
+ }
205
+
206
+ resetPosition(); // when the form moves after the page has loaded
207
+
208
+ $results.html(items.join('')).show();
209
+
210
+ $results
211
+ .children('li.' + options.itemClass)
212
+ .mouseover(function() {
213
+ $results.children('li.' + options.itemClass).removeClass(options.selectClass);
214
+ $(this).addClass(options.selectClass);
215
+ })
216
+ .click(function(e) {
217
+ e.preventDefault();
218
+ e.stopPropagation();
219
+ selectCurrentResult();
220
+ });
221
+
222
+ $input.removeClass(options.timeoutClass);
223
+ }
224
+
225
+ function parseTxt(txt, q) {
226
+
227
+ var lis = [], items = $.parseJSON(txt), i, item;
228
+
229
+ // parse returned data for non-empty items
230
+ for (i = 0; i < items.length; i++) {
231
+
232
+ item = items[i];
233
+ if (item) {
234
+
235
+ if (item.isheader)
236
+ html = '<li class="' + options.headerClass + '">' + item.text + '</li>';
237
+ else {
238
+ html = item.text.replace(
239
+ new RegExp(q, 'ig'),
240
+ function(q) { return '<span class="' + options.matchClass + '">' + q + '</span>' }
241
+ );
242
+ html = '<li'
243
+ + ' class="' + Encoder.htmlEncode(options.itemClass, true) + '"'
244
+ + ' su:value="' + Encoder.htmlEncode(item.value || '', true) + '"'
245
+ + ' su:selectedtext="' + Encoder.htmlEncode(item.selectedtext || '', true) + '"'
246
+ + '>' + html + '</li>';
247
+ }
248
+ lis[lis.length] = html;
249
+ }
250
+
251
+ }
252
+
253
+ return lis;
254
+ }
255
+
256
+ function getCurrentResult() {
257
+ var $currentResult;
258
+ if (!$results.is(':visible'))
259
+ return false;
260
+
261
+ $currentResult = $results.children('li.' + options.selectClass);
262
+
263
+ if (!$currentResult.length)
264
+ $currentResult = false;
265
+
266
+ return $currentResult;
267
+
268
+ }
269
+
270
+ function selectCurrentResult() {
271
+
272
+ $currentResult = getCurrentResult();
273
+
274
+ if ($currentResult) {
275
+ if (options.textDest) {
276
+ $input
277
+ .hide() //Hide the input box
278
+ .siblings('.' + options.textDestClass + ':first')
279
+ .show() //Show the selection box
280
+ .children('.' + options.textDestTextClass)
281
+ .html($currentResult.attr('su:selectedtext') || $currentResult.text()) //Put the selected item into the selection box
282
+ .parentsUntil('tr') //If we're in a table...
283
+ .next('td')
284
+ .children('input')
285
+ .focus(); //...then focus the next textbox in the table
286
+
287
+ $input.val($currentResult.attr('su:value'));
288
+ } else {
289
+ $input.val($currentResult.text());
290
+ }
291
+ $results.hide();
292
+
293
+ if (options.onSelect)
294
+ options.onSelect.apply($input[0]);
295
+
296
+ }
297
+
298
+ }
299
+
300
+ function nextResult() {
301
+
302
+ $currentResult = getCurrentResult();
303
+
304
+ if ($currentResult)
305
+ $currentResult
306
+ .removeClass(options.selectClass)
307
+ .nextAll('.' + options.itemClass + ':first')
308
+ .addClass(options.selectClass);
309
+ else
310
+ $results.children('li.' + options.itemClass + ':first').addClass(options.selectClass);
311
+
312
+ }
313
+
314
+ function prevResult() {
315
+ var $currentResult = getCurrentResult();
316
+
317
+ if ($currentResult)
318
+ $currentResult
319
+ .removeClass(options.selectClass)
320
+ .prevAll('.' + options.itemClass + ':first')
321
+ .addClass(options.selectClass);
322
+ else
323
+ $results.children('li.' + options.itemClass + ':last').addClass(options.selectClass);
324
+
325
+ }
326
+ }
327
+
328
+ $.fn.jlsuggest = function(source, options) {
329
+
330
+ if (!source)
331
+ return;
332
+
333
+ options = options || {};
334
+ options.source = source;
335
+ options.delay = options.delay || 100;
336
+ options.resultsClass = options.resultsClass || 'jls_results';
337
+ options.selectClass = options.selectClass || 'jls_over';
338
+ options.matchClass = options.matchClass || 'jls_match';
339
+ options.headerClass = options.headerClass || 'jls_header';
340
+ options.itemClass = options.itemClass || 'jls_item';
341
+ options.minchars = options.minchars || 2;
342
+ options.delimiter = options.delimiter || '\n';
343
+ options.onSelect = options.onSelect || false;
344
+ options.maxCacheSize = options.maxCacheSize || 65536;
345
+ options.noUrls = options.noUrls || false;
346
+ options.textDest = options.textDest || false;
347
+ options.textDestClass = options.textDestClass || 'jls_text_dest';
348
+ options.textDestDisabledClass = options.textDestDisabledClass || 'jlsuggest-disabled';
349
+ options.textDestTextClass = options.textDestTextClass || 'jls_text_dest_text';
350
+ options.textDestCloseClass = options.textDestCloseClass || 'jls_text_dest_close';
351
+ options.timeoutClass = options.timeoutClass || 'jls_loading';
352
+
353
+ this.each(function() {
354
+ new $.jlsuggest(this, options);
355
+ });
356
+
357
+ return this;
358
+
359
+ };
360
+
361
+ })(jQuery);
includes/jlwp/functions.php CHANGED
@@ -1,165 +1,165 @@
1
- <?php
2
-
3
- define('SUWP_QUERY_PERMALINKS', 0);
4
- define('SUWP_INDEX_PERMALINKS', 1);
5
- define('SUWP_PRETTY_PERMALINKS', 2);
6
-
7
- class suwp {
8
-
9
- /**
10
- * Determines the ID of the current post.
11
- * Works in the admin as well as the front-end.
12
- *
13
- * @return int|false The ID of the current post, or false on failure.
14
- */
15
- static function get_post_id() {
16
- if (is_admin()) {
17
- if (!empty($_REQUEST['post']))
18
- return intval($_REQUEST['post']);
19
- elseif (!empty($_REQUEST['post_ID']))
20
- return intval($_REQUEST['post_ID']);
21
- else
22
- return false;
23
- } elseif (in_the_loop()) {
24
- return intval(get_the_ID());
25
- } elseif (is_singular()) {
26
- global $wp_query;
27
- return $wp_query->get_queried_object_id();
28
- }
29
-
30
- return false;
31
- }
32
-
33
- static function is_tax($taxonomy='', $term='') {
34
- if ($taxonomy) {
35
- switch ($taxonomy) {
36
- case 'category': return is_category($term); break;
37
- case 'post_tag': return is_tag($term); break;
38
- default: return is_tax($taxonomy, $term); break;
39
- }
40
- } else {
41
- return is_category() || is_tag() || is_tax();
42
- }
43
- }
44
-
45
- static function get_taxonomies() {
46
- $taxonomies = get_taxonomies(array('public' => true), 'objects');
47
- if (isset($taxonomies['post_format']) && $taxonomies['post_format']->labels->name == _x( 'Format', 'post format' ))
48
- $taxonomies['post_format']->labels->name = __('Post Format Archives', 'seo-ultimate');
49
- return $taxonomies;
50
- }
51
-
52
- static function get_taxonomy_names() {
53
- return get_taxonomies(array('public' => true), 'names');
54
- }
55
-
56
- static function get_object_taxonomies($post_type) {
57
- $taxonomies = get_object_taxonomies($post_type, 'objects');
58
- $taxonomies = wp_filter_object_list($taxonomies, array('public' => true, 'show_ui' => true));
59
- return $taxonomies;
60
- }
61
-
62
- function get_object_taxonomy_names($post_type) {
63
- $taxonomies = get_object_taxonomies($post_type, 'objects');
64
- $taxonomies = wp_filter_object_list($taxonomies, array('public' => true, 'show_ui' => true), 'and', 'name');
65
- return $taxonomies;
66
- }
67
-
68
- /**
69
- * Loads an RSS feed and returns it as an object.
70
- *
71
- * @param string $url The URL of the RSS feed to load.
72
- * @param callback $ua The user agent to use.
73
- * @return object $rss The RSS object.
74
- */
75
- static function load_rss($url, $ua) {
76
- $ua = addslashes($ua);
77
- $uafunc = create_function('', "return '$ua';");
78
- add_filter('http_headers_useragent', $uafunc);
79
- require_once (ABSPATH . WPINC . '/class-simplepie.php');
80
- $rss = fetch_feed($url);
81
- remove_filter('http_headers_useragent', $uafunc);
82
- return $rss;
83
- }
84
-
85
- /**
86
- * @return string
87
- */
88
- static function add_backup_url($text) {
89
- $anchor = __('backup your database', 'seo-ultimate');
90
- return str_replace($anchor, '<a href="'.suwp::get_backup_url().'" target="_blank">'.$anchor.'</a>', $text);
91
- }
92
-
93
- /**
94
- * @return string
95
- */
96
- static function get_backup_url() {
97
- if (is_plugin_active('wp-db-backup/wp-db-backup.php'))
98
- return admin_url('tools.php?page=wp-db-backup');
99
- else
100
- return 'http://codex.wordpress.org/Backing_Up_Your_Database';
101
- }
102
-
103
- static function get_edit_term_link($id, $taxonomy) {
104
- $tax_obj = get_taxonomy($taxonomy);
105
- if ($tax_obj->show_ui)
106
- return get_edit_term_link($id, $taxonomy);
107
- else
108
- return false;
109
- }
110
-
111
- static function get_term_slug($term_obj) {
112
- $tax_name = $term_obj->taxonomy;
113
- $tax_obj = get_taxonomy($tax_name);
114
- if ($tax_obj->rewrite['hierarchical']) {
115
- $hierarchical_slugs = array();
116
- $ancestors = get_ancestors($term_obj->term_id, $tax_name);
117
- foreach ( (array)$ancestors as $ancestor ) {
118
- $ancestor_term = get_term($ancestor, $tax_name);
119
- $hierarchical_slugs[] = $ancestor_term->slug;
120
- }
121
- $hierarchical_slugs = array_reverse($hierarchical_slugs);
122
- $hierarchical_slugs[] = $term_obj->slug;
123
- $term_slug = implode('/', $hierarchical_slugs);
124
- } else {
125
- $term_slug = $term_obj->slug;
126
- }
127
-
128
- if ('post_format' == $tax_name)
129
- $term_slug = str_replace('post-format-', '', $term_slug);
130
-
131
- return $term_slug;
132
- }
133
-
134
- static function permalink_mode() {
135
- if (strlen($struct = get_option('permalink_structure'))) {
136
- if (sustr::startswith($struct, '/index.php/'))
137
- return SUWP_INDEX_PERMALINKS;
138
- else
139
- return SUWP_PRETTY_PERMALINKS;
140
- } else
141
- return SUWP_QUERY_PERMALINKS;
142
- }
143
-
144
- static function get_blog_home_url() {
145
- if ('page' == get_option('show_on_front') && $page_id = (int)get_option('page_for_posts'))
146
- return get_permalink($page_id);
147
-
148
- return home_url('/');
149
- }
150
-
151
- static function get_admin_scope() {
152
- if (is_blog_admin())
153
- return 'blog';
154
-
155
- if (is_network_admin())
156
- return 'network';
157
-
158
- if (is_user_admin())
159
- return 'user';
160
-
161
- return false;
162
- }
163
- }
164
-
165
  ?>
1
+ <?php
2
+
3
+ define('SUWP_QUERY_PERMALINKS', 0);
4
+ define('SUWP_INDEX_PERMALINKS', 1);
5
+ define('SUWP_PRETTY_PERMALINKS', 2);
6
+
7
+ class suwp {
8
+
9
+ /**
10
+ * Determines the ID of the current post.
11
+ * Works in the admin as well as the front-end.
12
+ *
13
+ * @return int|false The ID of the current post, or false on failure.
14
+ */
15
+ static function get_post_id() {
16
+ if (is_admin()) {
17
+ if (!empty($_REQUEST['post']))
18
+ return intval($_REQUEST['post']);
19
+ elseif (!empty($_REQUEST['post_ID']))
20
+ return intval($_REQUEST['post_ID']);
21
+ else
22
+ return false;
23
+ } elseif (in_the_loop()) {
24
+ return intval(get_the_ID());
25
+ } elseif (is_singular()) {
26
+ global $wp_query;
27
+ return $wp_query->get_queried_object_id();
28
+ }
29
+
30
+ return false;
31
+ }
32
+
33
+ static function is_tax($taxonomy='', $term='') {
34
+ if ($taxonomy) {
35
+ switch ($taxonomy) {
36
+ case 'category': return is_category($term); break;
37
+ case 'post_tag': return is_tag($term); break;
38
+ default: return is_tax($taxonomy, $term); break;
39
+ }
40
+ } else {
41
+ return is_category() || is_tag() || is_tax();
42
+ }
43
+ }
44
+
45
+ static function get_taxonomies() {
46
+ $taxonomies = get_taxonomies(array('public' => true), 'objects');
47
+ if (isset($taxonomies['post_format']) && $taxonomies['post_format']->labels->name == _x( 'Format', 'post format' ))
48
+ $taxonomies['post_format']->labels->name = __('Post Format Archives', 'seo-ultimate');
49
+ return $taxonomies;
50
+ }
51
+
52
+ static function get_taxonomy_names() {
53
+ return get_taxonomies(array('public' => true), 'names');
54
+ }
55
+
56
+ static function get_object_taxonomies($post_type) {
57
+ $taxonomies = get_object_taxonomies($post_type, 'objects');
58
+ $taxonomies = wp_filter_object_list($taxonomies, array('public' => true, 'show_ui' => true));
59
+ return $taxonomies;
60
+ }
61
+
62
+ function get_object_taxonomy_names($post_type) {
63
+ $taxonomies = get_object_taxonomies($post_type, 'objects');
64
+ $taxonomies = wp_filter_object_list($taxonomies, array('public' => true, 'show_ui' => true), 'and', 'name');
65
+ return $taxonomies;
66
+ }
67
+
68
+ /**
69
+ * Loads an RSS feed and returns it as an object.
70
+ *
71
+ * @param string $url The URL of the RSS feed to load.
72
+ * @param callback $ua The user agent to use.
73
+ * @return object $rss The RSS object.
74
+ */
75
+ static function load_rss($url, $ua) {
76
+ $ua = addslashes($ua);
77
+ $uafunc = create_function('', "return '$ua';");
78
+ add_filter('http_headers_useragent', $uafunc);
79
+ require_once (ABSPATH . WPINC . '/class-simplepie.php');
80
+ $rss = fetch_feed($url);
81
+ remove_filter('http_headers_useragent', $uafunc);
82
+ return $rss;
83
+ }
84
+
85
+ /**
86
+ * @return string
87
+ */
88
+ static function add_backup_url($text) {
89
+ $anchor = __('backup your database', 'seo-ultimate');
90
+ return str_replace($anchor, '<a href="'.suwp::get_backup_url().'" target="_blank">'.$anchor.'</a>', $text);
91
+ }
92
+
93
+ /**
94
+ * @return string
95
+ */
96
+ static function get_backup_url() {
97
+ if (is_plugin_active('wp-db-backup/wp-db-backup.php'))
98
+ return admin_url('tools.php?page=wp-db-backup');
99
+ else
100
+ return 'http://codex.wordpress.org/Backing_Up_Your_Database';
101
+ }
102
+
103
+ static function get_edit_term_link($id, $taxonomy) {
104
+ $tax_obj = get_taxonomy($taxonomy);
105
+ if ($tax_obj->show_ui)
106
+ return get_edit_term_link($id, $taxonomy);
107
+ else
108
+ return false;
109
+ }
110
+
111
+ static function get_term_slug($term_obj) {
112
+ $tax_name = $term_obj->taxonomy;
113
+ $tax_obj = get_taxonomy($tax_name);
114
+ if ($tax_obj->rewrite['hierarchical']) {
115
+ $hierarchical_slugs = array();
116
+ $ancestors = get_ancestors($term_obj->term_id, $tax_name);
117
+ foreach ( (array)$ancestors as $ancestor ) {
118
+ $ancestor_term = get_term($ancestor, $tax_name);
119
+ $hierarchical_slugs[] = $ancestor_term->slug;
120
+ }
121
+ $hierarchical_slugs = array_reverse($hierarchical_slugs);
122
+ $hierarchical_slugs[] = $term_obj->slug;
123
+ $term_slug = implode('/', $hierarchical_slugs);
124
+ } else {
125
+ $term_slug = $term_obj->slug;
126
+ }
127
+
128
+ if ('post_format' == $tax_name)
129
+ $term_slug = str_replace('post-format-', '', $term_slug);
130
+
131
+ return $term_slug;
132
+ }
133
+
134
+ static function permalink_mode() {
135
+ if (strlen($struct = get_option('permalink_structure'))) {
136
+ if (sustr::startswith($struct, '/index.php/'))
137
+ return SUWP_INDEX_PERMALINKS;
138
+ else
139
+ return SUWP_PRETTY_PERMALINKS;
140
+ } else
141
+ return SUWP_QUERY_PERMALINKS;
142
+ }
143
+
144
+ static function get_blog_home_url() {
145
+ if ('page' == get_option('show_on_front') && $page_id = (int)get_option('page_for_posts'))
146
+ return get_permalink($page_id);
147
+
148
+ return home_url('/');
149
+ }
150
+
151
+ static function get_admin_scope() {
152
+ if (is_blog_admin())
153
+ return 'blog';
154
+
155
+ if (is_network_admin())
156
+ return 'network';
157
+
158
+ if (is_user_admin())
159
+ return 'user';
160
+
161
+ return false;
162
+ }
163
+ }
164
+
165
  ?>
includes/jlwp/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
includes/jlwp/jlwp.php CHANGED
@@ -1,5 +1,5 @@
1
- <?php
2
-
3
- include dirname(__FILE__).'/functions.php';
4
-
5
  ?>
1
+ <?php
2
+
3
+ include dirname(__FILE__).'/functions.php';
4
+
5
  ?>
includes/tabs.js CHANGED
@@ -1,54 +1,54 @@
1
- function su_init_tabs()
2
- {
3
- /* if this is not an SEO Ultimate admin page, quit */
4
- if (!jQuery("#su-tabset").length) return;
5
-
6
- /* init markup for tabs */
7
- jQuery('#su-tabset').prepend("<ul><\/ul>");
8
- jQuery('#su-tabset > fieldset').each(function(i)
9
- {
10
- id = jQuery(this).attr('id');
11
- caption = jQuery(this).find('h3').text();
12
- jQuery('#su-tabset > ul').append('<li><a href="#'+id+'"><span>'+caption+"<\/span><\/a><\/li>");
13
- jQuery(this).find('h3').hide();
14
- });
15
-
16
- /* init the tabs plugin */
17
- var jquiver = undefined == jQuery.ui ? [0,0,0] : undefined == jQuery.ui.version ? [0,1,0] : jQuery.ui.version.split('.');
18
- switch(true) {
19
- // tabs plugin has been fixed to work on the parent element again.
20
- case jquiver[0] >= 1 && jquiver[1] >= 7:
21
- jQuery("#su-tabset").tabs();
22
- break;
23
- // tabs plugin has bug and needs to work on ul directly.
24
- default:
25
- jQuery("#su-tabset > ul").tabs();
26
- }
27
-
28
- if (location.hash.length) {
29
- jQuery(document).ready(function() {
30
- su_hash_form(location.hash);
31
- });
32
- window.scrollTo(0,0);
33
- }
34
-
35
- /* handler for opening the last tab after submit (compability version) */
36
- jQuery('#su-tabset ul a').click(function(i){
37
- su_hash_form(jQuery(this).attr('href'));
38
- });
39
- }
40
-
41
- jQuery(document).ready(function() {
42
- su_init_tabs();
43
- });
44
-
45
- function su_hash_form(hash) {
46
- var form = jQuery('#su-admin-form');
47
- if (form) {
48
- var action = form.attr("action").split('#', 1) + hash;
49
- // an older bug pops up with some jQuery version(s), which makes it
50
- // necessary to set the form's action attribute by standard javascript
51
- // node access:
52
- form.get(0).setAttribute("action", action);
53
- }
54
  }
1
+ function su_init_tabs()
2
+ {
3
+ /* if this is not an SEO Ultimate admin page, quit */
4
+ if (!jQuery("#su-tabset").length) return;
5
+
6
+ /* init markup for tabs */
7
+ jQuery('#su-tabset').prepend("<ul><\/ul>");
8
+ jQuery('#su-tabset > fieldset').each(function(i)
9
+ {
10
+ id = jQuery(this).attr('id');
11
+ caption = jQuery(this).find('h3').text();
12
+ jQuery('#su-tabset > ul').append('<li><a href="#'+id+'"><span>'+caption+"<\/span><\/a><\/li>");
13
+ jQuery(this).find('h3').hide();
14
+ });
15
+
16
+ /* init the tabs plugin */
17
+ var jquiver = undefined == jQuery.ui ? [0,0,0] : undefined == jQuery.ui.version ? [0,1,0] : jQuery.ui.version.split('.');
18
+ switch(true) {
19
+ // tabs plugin has been fixed to work on the parent element again.
20
+ case jquiver[0] >= 1 && jquiver[1] >= 7:
21
+ jQuery("#su-tabset").tabs();
22
+ break;
23
+ // tabs plugin has bug and needs to work on ul directly.
24
+ default:
25
+ jQuery("#su-tabset > ul").tabs();
26
+ }
27
+
28
+ if (location.hash.length) {
29
+ jQuery(document).ready(function() {
30
+ su_hash_form(location.hash);
31
+ });
32
+ window.scrollTo(0,0);
33
+ }
34
+
35
+ /* handler for opening the last tab after submit (compability version) */
36
+ jQuery('#su-tabset ul a').click(function(i){
37
+ su_hash_form(jQuery(this).attr('href'));
38
+ });
39
+ }
40
+
41
+ jQuery(document).ready(function() {
42
+ su_init_tabs();
43
+ });
44
+
45
+ function su_hash_form(hash) {
46
+ var form = jQuery('#su-admin-form');
47
+ if (form) {
48
+ var action = form.attr("action").split('#', 1) + hash;
49
+ // an older bug pops up with some jQuery version(s), which makes it
50
+ // necessary to set the form's action attribute by standard javascript
51
+ // node access:
52
+ form.get(0).setAttribute("action", action);
53
+ }
54
  }
index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/404s/fofs-log.php CHANGED
@@ -1,267 +1,267 @@
1
- <?php
2
- /**
3
- * 404 Monitor Log Module
4
- *
5
- * @since 2.1
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- function su_fofs_log_export_filter($all_settings) {
11
- unset($all_settings['404s']['log']);
12
- return $all_settings;
13
- }
14
- add_filter('su_settings_export_array', 'su_fofs_log_export_filter');
15
-
16
- class SU_FofsLog extends SU_Module {
17
-
18
- static function get_parent_module() { return 'fofs'; }
19
- static function get_child_order() { return 10; }
20
- static function is_independent_module() { return false; }
21
-
22
- static function get_module_title() { return __('404 Monitor Log', 'seo-ultimate'); }
23
- function get_module_subtitle() { return __('Log', 'seo-ultimate'); }
24
-
25
- static function has_menu_count() { return true; }
26
- function get_settings_key() { return '404s'; }
27
-
28
- function get_menu_count() {
29
- $new = 0;
30
- $the404s = $this->get_setting('log');
31
- if (count($the404s)) {
32
- foreach ($the404s as $a404) {
33
- if ($a404['is_new']) $new++;
34
- }
35
- }
36
- return $new;
37
- }
38
-
39
- function init() {
40
- add_action('admin_enqueue_scripts', array(&$this, 'queue_admin_scripts'));
41
- add_action('su_save_hit', array(&$this, 'log_hit'));
42
- }
43
-
44
- //Upgrade to new wp_options-only system if needed
45
- function upgrade() {
46
- global $wpdb;
47
-
48
- $suppress = $wpdb->suppress_errors(true);
49
-
50
- //Get old storage system if it exists
51
- if ($result = @$wpdb->get_results("SELECT * FROM {$wpdb->prefix}sds_hits WHERE status_code=404 AND redirect_url='' AND url NOT LIKE '%/favicon.ico' ORDER BY id DESC", ARRAY_A)) {
52
-
53
- //Get new storage system
54
- $l = $this->get_setting('log', array());
55
-
56
- //Move old to new
57
- foreach ($result as $row) $this->log_hit($row);
58
-
59
- //Out with the old
60
- mysql_query("DROP TABLE IF EXISTS {$wpdb->prefix}sds_hits");
61
- }
62
-
63
- $wpdb->suppress_errors($suppress);
64
- }
65
-
66
- function queue_admin_scripts() {
67
- //if ($this->is_module_admin_page()) wp_enqueue_script('scriptaculous-effects');
68
- }
69
-
70
- function log_hit($hit) {
71
-
72
- if ($hit['status_code'] == 404) {
73
-
74
- if ($this->get_setting('restrict_logging', true)) {
75
- if (!($this->get_setting('log_spiders', true) && suweb::is_search_engine_ua($hit['user_agent'])) &&
76
- !($this->get_setting('log_errors_with_referers', true) && strlen($hit['referer'])))
77
- return $hit;
78
- }
79
-
80
- $exceptions = suarr::explode_lines($this->get_setting('exceptions', ''));
81
- foreach ($exceptions as $exception) {
82
- if (preg_match(sustr::wildcards_to_regex($exception), $hit['url']))
83
- return $hit;
84
- }
85
-
86
- $l = $this->get_setting('log', array());
87
- $max_log_size = absint(sustr::preg_filter('0-9', strval($this->get_setting('max_log_size', 100))));
88
- while (count($l) > $max_log_size) array_pop($l);
89
-
90
- $u = $hit['url'];
91
- if (!isset($l[$u])) {
92
- $l[$u] = array();
93
- $l[$u]['hit_count'] = 0;
94
- $l[$u]['is_new'] = isset($hit['is_new']) ? $hit['is_new'] : true;
95
- $l[$u]['referers'] = array();
96
- $l[$u]['user_agents'] = array();
97
- $l[$u]['last_hit_time'] = 0;
98
- }
99
-
100
- $l[$u]['hit_count']++;
101
- if (!$l[$u]['is_new'] && $hit['is_new'])
102
- $l[$u]['is_new'] = true;
103
- if ($hit['time'] > $l[$u]['last_hit_time'])
104
- $l[$u]['last_hit_time'] = $hit['time'];
105
- if (strlen($hit['referer']) && !in_array($hit['referer'], $l[$u]['referers']))
106
- $l[$u]['referers'][] = $hit['referer'];
107
- if (strlen($hit['user_agent']) && !in_array($hit['user_agent'], $l[$u]['user_agents']))
108
- $l[$u]['user_agents'][] = $hit['user_agent'];
109
-
110
- $this->update_setting('log', $l);
111
- }
112
-
113
- return $hit;
114
- }
115
-
116
- function get_admin_table_columns() {
117
- return array(
118
- 'actions' => __('Actions', 'seo-ultimate')
119
- , 'hit-count' => __('Hits', 'seo-ultimate')
120
- , 'url' => __('URL with 404 Error', 'seo-ultimate')
121
- , 'last-hit-time' => __('Date of Most Recent Hit', 'seo-ultimate')
122
- , 'referers' => __('Referers', 'seo-ultimate')
123
- , 'user-agents' => __('User Agents', 'seo-ultimate')
124
- );
125
- }
126
-
127
- function sort_log_callback($a, $b) {
128
- if ($a['is_new'] == $b['is_new'])
129
- return $b['last_hit_time'] - $a['last_hit_time'];
130
-
131
- return $a['is_new'] ? -1 : 1;
132
- }
133
-
134
- function admin_page_contents() {
135
-
136
- $the404s = $this->get_setting('log');
137
-
138
- if (!$this->get_setting('log_enabled', true))
139
- $this->queue_message('warning', __('New 404 errors will not be recorded because 404 logging is disabled on the Settings tab.', 'seo-ultimate'));
140
-
141
- //Are we deleting a 404 entry?
142
- if ($this->is_action('delete')) {
143
-
144
- if (isset($the404s[$_GET['object']])) {
145
- unset($the404s[$_GET['object']]);
146
- $this->queue_message('success', __('The log entry was successfully deleted.', 'seo-ultimate'));
147
- } else
148
- $this->queue_message('error', __('This log entry has already been deleted.', 'seo-ultimate'));
149
-
150
- $this->update_setting('log', $the404s);
151
-
152
- //Are we clearing the whole 404 log?
153
- } elseif ($this->is_action('clear')) {
154
-
155
- $the404s = array();
156
- $this->update_setting('log', array());
157
- $this->queue_message('success', __('The log was successfully cleared.', 'seo-ultimate'));
158
- }
159
-
160
- if (!count($the404s))
161
- $this->queue_message('success', __('No 404 errors in the log.', 'seo-ultimate'));
162
-
163
- $this->print_messages();
164
-
165
- if (count($the404s)) {
166
-
167
- $this->clear_log_button();
168
-
169
- echo "<div id='su-404s-log-table'>\n";
170
- $headers = $this->get_admin_table_columns();
171
- $this->admin_wftable_start();
172
-
173
- uasort($the404s, array(&$this, 'sort_log_callback'));
174
-
175
- foreach ($the404s as $url => $data) {
176
- $new = $data['is_new'] ? ' su-404s-new-hit' : '';
177
-
178
- $a_url = su_esc_attr($url);
179
- $ae_url = su_esc_attr(urlencode($url));
180
- $md5url = md5($url);
181
-
182
- echo "\t<tr id='su-404s-hit-$md5url-data' class='su-404s-hit-data$new'>\n";
183
-
184
- $this->table_cells(array(
185
- 'actions' =>
186
- "<span class='su-404s-hit-open'><a href='$a_url' target='_blank'><img src='{$this->module_dir_url}hit-open.png' title='".__('Open URL in new window (will not be logged)', 'seo-ultimate')."' /></a></span>"
187
- . "<span class='su-404s-hit-cache'><a href='http://www.google.com/search?q=cache%3A{$ae_url}' target='_blank'><img src='{$this->module_dir_url}hit-cache.png' title='".__('Query Google for cached version of URL (opens in new window)', 'seo-ultimate')."' /></a></span>"
188
- . "<span class='su-404s-hit-delete'><a href='".$this->get_nonce_url('delete', $url)."'><img src='{$this->module_dir_url}hit-delete.png' title='".__('Remove this URL from the log', 'seo-ultimate')."' /></a></span>"
189
- , 'hit-count' => $data['hit_count']
190
- , 'url' => "<attr title='$a_url'>" . esc_html(sustr::truncate($url, 100)) . '</attr>'
191
- , 'last-hit-time' => sprintf(__('%s at %s', 'seo-ultimate')
192
- , date_i18n(get_option('date_format'), $data['last_hit_time'])
193
- , date_i18n(get_option('time_format'), $data['last_hit_time'])
194
- )
195
- , 'referers' => number_format_i18n(count($data['referers'])) . (count($data['referers']) ? " <a href='#' class='su_toggle_hide' data-toggle='su-404s-hit-$md5url-referers'><img src='{$this->module_dir_url}hit-details.png' title='".__('View list of referring URLs', 'seo-ultimate')."' /></a>" : '')
196
- , 'user-agents' => number_format_i18n(count($data['user_agents'])) . (count($data['user_agents']) ? " <a href='#' class='su_toggle_hide' data-toggle='su-404s-hit-$md5url-user-agents'><img src='{$this->module_dir_url}hit-details.png' title='".__('View list of user agents', 'seo-ultimate')."' /></a>" : '')
197
- ));
198
-
199
- echo "\t</tr>\n";
200
-
201
- echo "\t<tr class='su-404s-hit-referers$new'>\n\t\t<td colspan='".count($headers)."'>";
202
-
203
- if (count($data['referers'])) {
204
-
205
- echo "<div id='su-404s-hit-$md5url-referers' class='su-404s-hit-referers-list' style='display:none;'>\n";
206
- echo "\t\t\t<div><strong>".__('Referring URLs', 'seo-ultimate')."</strong> &mdash; ";
207
- echo "<a href='#' class='su_toggle_up' data-toggle='su-404s-hit-$md5url-referers'>".__('Hide list', 'seo-ultimate')."</a>";
208
- echo "</div>\n";
209
- echo "\t\t\t<ul>\n";
210
-
211
- foreach ($data['referers'] as $referer) {
212
- $referer = su_esc_attr($referer); //Don't let attacks pass through the referer URLs!
213
- echo "\t\t\t\t<li><a href='$referer' target='_blank'>$referer</a></li>\n";
214
- }
215
-
216
- echo "\t\t\t</ul>\n";
217
-
218
- echo "\t\t</div>";
219
- }
220
-
221
- echo "</td>\n\t</tr>\n";
222
-
223
- echo "\t<tr class='su-404s-hit-user-agents$new'>\n\t\t<td colspan='".count($headers)."'>";
224
-
225
- if (count($data['user_agents'])) {
226
- echo "<div id='su-404s-hit-$md5url-user-agents' class='su-404s-hit-user-agents-list' style='display:none;'>\n";
227
- echo "\t\t\t<div><strong>".__('User Agents', 'seo-ultimate')."</strong> &mdash; ";
228
- echo "<a href='#' class='su_toggle_up' data-toggle='su-404s-hit-$md5url-user-agents'>".__('Hide list', 'seo-ultimate')."</a>";
229
- echo "</div>\n";
230
- echo "\t\t\t<ul>\n";
231
-
232
- foreach ($data['user_agents'] as $useragent) {
233
- $useragent = su_esc_html($useragent); //Don't let attacks pass through the user agent strings!
234
- echo "\t\t\t\t<li>$useragent</li>\n";
235
- }
236
-
237
- echo "\t\t\t</ul>\n";
238
-
239
- echo "</td>\n\t</tr>\n";
240
- }
241
-
242
- echo "\t\t</div>";
243
-
244
- $the404s[$url]['is_new'] = false;
245
- }
246
-
247
- $this->update_setting('log', $the404s);
248
-
249
- $this->admin_wftable_end();
250
- echo "</div>\n";
251
-
252
- $this->clear_log_button();
253
- }
254
- }
255
-
256
- function clear_log_button() {
257
- //Create the "Clear Log" button
258
- $clearurl = $this->get_nonce_url('clear');
259
- $confirm = __('Are you sure you want to delete all 404 log entries?', 'seo-ultimate');
260
- echo "<div class='su-404s-clear-log'><a href=\"$clearurl\" class=\"button-secondary\" onclick=\"javascript:return confirm('$confirm')\">";
261
- _e('Clear Log', 'seo-ultimate');
262
- echo "</a></div>";
263
- }
264
- }
265
-
266
- }
267
  ?>
1
+ <?php
2
+ /**
3
+ * 404 Monitor Log Module
4
+ *
5
+ * @since 2.1
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ function su_fofs_log_export_filter($all_settings) {
11
+ unset($all_settings['404s']['log']);
12
+ return $all_settings;
13
+ }
14
+ add_filter('su_settings_export_array', 'su_fofs_log_export_filter');
15
+
16
+ class SU_FofsLog extends SU_Module {
17
+
18
+ static function get_parent_module() { return 'fofs'; }
19
+ static function get_child_order() { return 10; }
20
+ static function is_independent_module() { return false; }
21
+
22
+ static function get_module_title() { return __('404 Monitor Log', 'seo-ultimate'); }
23
+ function get_module_subtitle() { return __('Log', 'seo-ultimate'); }
24
+ function get_default_status() { return SU_MODULE_DISABLED; }
25
+ static function has_menu_count() { return true; }
26
+ function get_settings_key() { return '404s'; }
27
+
28
+ function get_menu_count() {
29
+ $new = 0;
30
+ $the404s = $this->get_setting('log');
31
+ if (count($the404s)) {
32
+ foreach ($the404s as $a404) {
33
+ if ($a404['is_new']) $new++;
34
+ }
35
+ }
36
+ return $new;
37
+ }
38
+
39
+ function init() {
40
+ add_action('admin_enqueue_scripts', array(&$this, 'queue_admin_scripts'));
41
+ add_action('su_save_hit', array(&$this, 'log_hit'));
42
+ }
43
+
44
+ //Upgrade to new wp_options-only system if needed
45
+ function upgrade() {
46
+ global $wpdb;
47
+
48
+ $suppress = $wpdb->suppress_errors(true);
49
+
50
+ //Get old storage system if it exists
51
+ if ($result = @$wpdb->get_results("SELECT * FROM {$wpdb->prefix}sds_hits WHERE status_code=404 AND redirect_url='' AND url NOT LIKE '%/favicon.ico' ORDER BY id DESC", ARRAY_A)) {
52
+
53
+ //Get new storage system
54
+ $l = $this->get_setting('log', array());
55
+
56
+ //Move old to new
57
+ foreach ($result as $row) $this->log_hit($row);
58
+
59
+ //Out with the old
60
+ mysql_query("DROP TABLE IF EXISTS {$wpdb->prefix}sds_hits");
61
+ }
62
+
63
+ $wpdb->suppress_errors($suppress);
64
+ }
65
+
66
+ function queue_admin_scripts() {
67
+ //if ($this->is_module_admin_page()) wp_enqueue_script('scriptaculous-effects');
68
+ }
69
+
70
+ function log_hit($hit) {
71
+
72
+ if ($hit['status_code'] == 404) {
73
+
74
+ if ($this->get_setting('restrict_logging', true)) {
75
+ if (!($this->get_setting('log_spiders', true) && suweb::is_search_engine_ua($hit['user_agent'])) &&
76
+ !($this->get_setting('log_errors_with_referers', true) && strlen($hit['referer'])))
77
+ return $hit;
78
+ }
79
+
80
+ $exceptions = suarr::explode_lines($this->get_setting('exceptions', ''));
81
+ foreach ($exceptions as $exception) {
82
+ if (preg_match(sustr::wildcards_to_regex($exception), $hit['url']))
83
+ return $hit;
84
+ }
85
+
86
+ $l = $this->get_setting('log', array());
87
+ $max_log_size = absint(sustr::preg_filter('0-9', strval($this->get_setting('max_log_size', 100))));
88
+ while (count($l) > $max_log_size) array_pop($l);
89
+
90
+ $u = $hit['url'];
91
+ if (!isset($l[$u])) {
92
+ $l[$u] = array();
93
+ $l[$u]['hit_count'] = 0;
94
+ $l[$u]['is_new'] = isset($hit['is_new']) ? $hit['is_new'] : true;
95
+ $l[$u]['referers'] = array();
96
+ $l[$u]['user_agents'] = array();
97
+ $l[$u]['last_hit_time'] = 0;
98
+ }
99
+
100
+ $l[$u]['hit_count']++;
101
+ if (!$l[$u]['is_new'] && $hit['is_new'])
102
+ $l[$u]['is_new'] = true;
103
+ if ($hit['time'] > $l[$u]['last_hit_time'])
104
+ $l[$u]['last_hit_time'] = $hit['time'];
105
+ if (strlen($hit['referer']) && !in_array($hit['referer'], $l[$u]['referers']))
106
+ $l[$u]['referers'][] = $hit['referer'];
107
+ if (strlen($hit['user_agent']) && !in_array($hit['user_agent'], $l[$u]['user_agents']))
108
+ $l[$u]['user_agents'][] = $hit['user_agent'];
109
+
110
+ $this->update_setting('log', $l);
111
+ }
112
+
113
+ return $hit;
114
+ }
115
+
116
+ function get_admin_table_columns() {
117
+ return array(
118
+ 'actions' => __('Actions', 'seo-ultimate')
119
+ , 'hit-count' => __('Hits', 'seo-ultimate')
120
+ , 'url' => __('URL with 404 Error', 'seo-ultimate')
121
+ , 'last-hit-time' => __('Date of Most Recent Hit', 'seo-ultimate')
122
+ , 'referers' => __('Referers', 'seo-ultimate')
123
+ , 'user-agents' => __('User Agents', 'seo-ultimate')
124
+ );
125
+ }
126
+
127
+ function sort_log_callback($a, $b) {
128
+ if ($a['is_new'] == $b['is_new'])
129
+ return $b['last_hit_time'] - $a['last_hit_time'];
130
+
131
+ return $a['is_new'] ? -1 : 1;
132
+ }
133
+
134
+ function admin_page_contents() {
135
+
136
+ $the404s = $this->get_setting('log');
137
+
138
+ if (!$this->get_setting('log_enabled', true))
139
+ $this->queue_message('warning', __('New 404 errors will not be recorded because 404 logging is disabled on the Settings tab.', 'seo-ultimate'));
140
+
141
+ //Are we deleting a 404 entry?
142
+ if ($this->is_action('delete')) {
143
+
144
+ if (isset($the404s[$_GET['object']])) {
145
+ unset($the404s[$_GET['object']]);
146
+ $this->queue_message('success', __('The log entry was successfully deleted.', 'seo-ultimate'));
147
+ } else
148
+ $this->queue_message('error', __('This log entry has already been deleted.', 'seo-ultimate'));
149
+
150
+ $this->update_setting('log', $the404s);
151
+
152
+ //Are we clearing the whole 404 log?
153
+ } elseif ($this->is_action('clear')) {
154
+
155
+ $the404s = array();
156
+ $this->update_setting('log', array());
157
+ $this->queue_message('success', __('The log was successfully cleared.', 'seo-ultimate'));
158
+ }
159
+
160
+ if (!count($the404s))
161
+ $this->queue_message('success', __('No 404 errors in the log.', 'seo-ultimate'));
162
+
163
+ $this->print_messages();
164
+
165
+ if (count($the404s)) {
166
+
167
+ $this->clear_log_button();
168
+
169
+ echo "<div id='su-404s-log-table'>\n";
170
+ $headers = $this->get_admin_table_columns();
171
+ $this->admin_wftable_start();
172
+
173
+ uasort($the404s, array(&$this, 'sort_log_callback'));
174
+
175
+ foreach ($the404s as $url => $data) {
176
+ $new = $data['is_new'] ? ' su-404s-new-hit' : '';
177
+
178
+ $a_url = su_esc_attr($url);
179
+ $ae_url = su_esc_attr(urlencode($url));
180
+ $md5url = md5($url);
181
+
182
+ echo "\t<tr id='su-404s-hit-$md5url-data' class='su-404s-hit-data$new'>\n";
183
+
184
+ $this->table_cells(array(
185
+ 'actions' =>
186
+ "<span class='su-404s-hit-open'><a href='$a_url' target='_blank'><img src='{$this->module_dir_url}hit-open.png' title='".__('Open URL in new window (will not be logged)', 'seo-ultimate')."' /></a></span>"
187
+ . "<span class='su-404s-hit-cache'><a href='http://www.google.com/search?q=cache%3A{$ae_url}' target='_blank'><img src='{$this->module_dir_url}hit-cache.png' title='".__('Query Google for cached version of URL (opens in new window)', 'seo-ultimate')."' /></a></span>"
188
+ . "<span class='su-404s-hit-delete'><a href='".$this->get_nonce_url('delete', $url)."'><img src='{$this->module_dir_url}hit-delete.png' title='".__('Remove this URL from the log', 'seo-ultimate')."' /></a></span>"
189
+ , 'hit-count' => $data['hit_count']
190
+ , 'url' => "<attr title='$a_url'>" . esc_html(sustr::truncate($url, 100)) . '</attr>'
191
+ , 'last-hit-time' => sprintf(__('%s at %s', 'seo-ultimate')
192
+ , date_i18n(get_option('date_format'), $data['last_hit_time'])
193
+ , date_i18n(get_option('time_format'), $data['last_hit_time'])
194
+ )
195
+ , 'referers' => number_format_i18n(count($data['referers'])) . (count($data['referers']) ? " <a href='#' class='su_toggle_hide' data-toggle='su-404s-hit-$md5url-referers'><img src='{$this->module_dir_url}hit-details.png' title='".__('View list of referring URLs', 'seo-ultimate')."' /></a>" : '')
196
+ , 'user-agents' => number_format_i18n(count($data['user_agents'])) . (count($data['user_agents']) ? " <a href='#' class='su_toggle_hide' data-toggle='su-404s-hit-$md5url-user-agents'><img src='{$this->module_dir_url}hit-details.png' title='".__('View list of user agents', 'seo-ultimate')."' /></a>" : '')
197
+ ));
198
+
199
+ echo "\t</tr>\n";
200
+
201
+ echo "\t<tr class='su-404s-hit-referers$new'>\n\t\t<td colspan='".count($headers)."'>";
202
+
203
+ if (count($data['referers'])) {
204
+
205
+ echo "<div id='su-404s-hit-$md5url-referers' class='su-404s-hit-referers-list' style='display:none;'>\n";
206
+ echo "\t\t\t<div><strong>".__('Referring URLs', 'seo-ultimate')."</strong> &mdash; ";
207
+ echo "<a href='#' class='su_toggle_up' data-toggle='su-404s-hit-$md5url-referers'>".__('Hide list', 'seo-ultimate')."</a>";
208
+ echo "</div>\n";
209
+ echo "\t\t\t<ul>\n";
210
+
211
+ foreach ($data['referers'] as $referer) {
212
+ $referer = su_esc_attr($referer); //Don't let attacks pass through the referer URLs!
213
+ echo "\t\t\t\t<li><a href='$referer' target='_blank'>$referer</a></li>\n";
214
+ }
215
+
216
+ echo "\t\t\t</ul>\n";
217
+
218
+ echo "\t\t</div>";
219
+ }
220
+
221
+ echo "</td>\n\t</tr>\n";
222
+
223
+ echo "\t<tr class='su-404s-hit-user-agents$new'>\n\t\t<td colspan='".count($headers)."'>";
224
+
225
+ if (count($data['user_agents'])) {
226
+ echo "<div id='su-404s-hit-$md5url-user-agents' class='su-404s-hit-user-agents-list' style='display:none;'>\n";
227
+ echo "\t\t\t<div><strong>".__('User Agents', 'seo-ultimate')."</strong> &mdash; ";
228
+ echo "<a href='#' class='su_toggle_up' data-toggle='su-404s-hit-$md5url-user-agents'>".__('Hide list', 'seo-ultimate')."</a>";
229
+ echo "</div>\n";
230
+ echo "\t\t\t<ul>\n";
231
+
232
+ foreach ($data['user_agents'] as $useragent) {
233
+ $useragent = su_esc_html($useragent); //Don't let attacks pass through the user agent strings!
234
+ echo "\t\t\t\t<li>$useragent</li>\n";
235
+ }
236
+
237
+ echo "\t\t\t</ul>\n";
238
+
239
+ echo "</td>\n\t</tr>\n";
240
+ }
241
+
242
+ echo "\t\t</div>";
243
+
244
+ $the404s[$url]['is_new'] = false;
245
+ }
246
+
247
+ $this->update_setting('log', $the404s);
248
+
249
+ $this->admin_wftable_end();
250
+ echo "</div>\n";
251
+
252
+ $this->clear_log_button();
253
+ }
254
+ }
255
+
256
+ function clear_log_button() {
257
+ //Create the "Clear Log" button
258
+ $clearurl = $this->get_nonce_url('clear');
259
+ $confirm = __('Are you sure you want to delete all 404 log entries?', 'seo-ultimate');
260
+ echo "<div class='su-404s-clear-log'><a href=\"$clearurl\" class=\"button-secondary\" onclick=\"javascript:return confirm('$confirm')\">";
261
+ _e('Clear Log', 'seo-ultimate');
262
+ echo "</a></div>";
263
+ }
264
+ }
265
+
266
+ }
267
  ?>
modules/404s/fofs-settings.php CHANGED
@@ -1,51 +1,51 @@
1
- <?php
2
- /**
3
- * 404 Monitor Settings Module
4
- *
5
- * @since 2.1
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_FofsSettings extends SU_Module {
11
-
12
- static function get_parent_module() { return 'fofs'; }
13
- static function get_child_order() { return 20; }
14
- static function is_independent_module() { return false; }
15
-
16
- static function get_module_title() { return __('404 Monitor Settings', 'seo-ultimate'); }
17
- function get_module_subtitle() { return __('Settings', 'seo-ultimate'); }
18
- function get_settings_key() { return '404s'; }
19
-
20
- function get_default_settings() {
21
- return array(
22
- 'exceptions' => "*/favicon.ico\n*/apple-touch-icon.png\n*/pingserver.php\n*/xmlrpc.php"
23
- , 'max_log_size' => 100
24
- , 'log_enabled' => $this->flush_setting('log_hits', true, 'settings')
25
- , 'restrict_logging' => true
26
- , 'log_spiders' => true
27
- , 'log_errors_with_referers' => true
28
- );
29
- }
30
-
31
- function init() {
32
- add_filter('su_get_setting-404s-max_log_size', array('sustr', 'to_int'));
33
- }
34
-
35
- function admin_page_contents() {
36
-
37
- $this->admin_form_start();
38
- $this->checkbox('log_enabled', __('Continue monitoring for new 404 errors', 'seo-ultimate'), __('Monitoring Settings', 'seo-ultimate'));
39
- $this->checkboxes(array(
40
- 'restrict_logging' => __('Only log these types of 404 errors:', 'seo-ultimate')
41
- , 'log_spiders' => array('description' => __('404s generated by search engine spiders', 'seo-ultimate'), 'indent' => true)
42
- , 'log_errors_with_referers' => array('description' => __('404s with referring URLs', 'seo-ultimate'), 'indent' => true)
43
- ), __('Log Restrictions', 'seo-ultimate'));
44
- $this->textbox('max_log_size', __('Maximum Log Entries', 'seo-ultimate'), $this->get_default_setting('max_log_size'));
45
- $this->textarea('exceptions', __('URLs to Ignore', 'seo-ultimate') . '<br /><small><em>' . __('(Use * as wildcard)', 'seo-ultimate') . '</em></small>', 15);
46
- $this->admin_form_end();
47
- }
48
- }
49
-
50
- }
51
  ?>
1
+ <?php
2
+ /**
3
+ * 404 Monitor Settings Module
4
+ *
5
+ * @since 2.1
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_FofsSettings extends SU_Module {
11
+
12
+ static function get_parent_module() { return 'fofs'; }
13
+ static function get_child_order() { return 20; }
14
+ static function is_independent_module() { return false; }
15
+
16
+ static function get_module_title() { return __('404 Monitor Settings', 'seo-ultimate'); }
17
+ function get_module_subtitle() { return __('Settings', 'seo-ultimate'); }
18
+ function get_settings_key() { return '404s'; }
19
+
20
+ function get_default_settings() {
21
+ return array(
22
+ 'exceptions' => "*/favicon.ico\n*/apple-touch-icon.png\n*/pingserver.php\n*/xmlrpc.php"
23
+ , 'max_log_size' => 100
24
+ , 'log_enabled' => $this->flush_setting('log_hits', true, 'settings')
25
+ , 'restrict_logging' => true
26
+ , 'log_spiders' => true
27
+ , 'log_errors_with_referers' => true
28
+ );
29
+ }
30
+
31
+ function init() {
32
+ add_filter('su_get_setting-404s-max_log_size', array('sustr', 'to_int'));
33
+ }
34
+
35
+ function admin_page_contents() {
36
+
37
+ $this->admin_form_start();
38
+ $this->checkbox('log_enabled', __('Continue monitoring for new 404 errors', 'seo-ultimate'), __('Monitoring Settings', 'seo-ultimate'));
39
+ $this->checkboxes(array(
40
+ 'restrict_logging' => __('Only log these types of 404 errors:', 'seo-ultimate')
41
+ , 'log_spiders' => array('description' => __('404s generated by search engine spiders', 'seo-ultimate'), 'indent' => true)
42
+ , 'log_errors_with_referers' => array('description' => __('404s with referring URLs', 'seo-ultimate'), 'indent' => true)
43
+ ), __('Log Restrictions', 'seo-ultimate'));
44
+ $this->textbox('max_log_size', __('Maximum Log Entries', 'seo-ultimate'), $this->get_default_setting('max_log_size'));
45
+ $this->textarea('exceptions', __('URLs to Ignore', 'seo-ultimate') . '<br /><small><em>' . __('(Use * as wildcard)', 'seo-ultimate') . '</em></small>', 15);
46
+ $this->admin_form_end();
47
+ }
48
+ }
49
+
50
+ }
51
  ?>
modules/404s/fofs.css CHANGED
@@ -1,37 +1,37 @@
1
- #su-fofs table.widefat {
2
- width: 100%;
3
- margin: 1em 0;
4
- }
5
-
6
- #su-fofs table tr.su-404s-hit-data td,
7
- #su-fofs table tr.su-404s-hit-referers td {
8
- border-bottom: 0 none;
9
- }
10
-
11
- #su-fofs table tr.su-404s-hit-referers td,
12
- #su-fofs table tr.su-404s-hit-user-agents td {
13
- padding: 0 1em;
14
- border-top: 0 none;
15
- }
16
-
17
- #su-fofs table .su-404s-hit-referers-list,
18
- #su-fofs table .su-404s-hit-user-agents-list {
19
- padding-top: 0.5em;
20
- }
21
-
22
- #su-fofs table tr.su-404s-new-hit td {
23
- background-color: #DFFFE3;
24
- }
25
-
26
- #su-fofs table .actions span {
27
- padding-right: 0.5em;
28
- }
29
-
30
- #su-fofs .su-404s-clear-log {
31
- text-align: right;
32
- padding: 0.5em 0;
33
- }
34
-
35
- #su-fofs .form-table input#max_log_size {
36
- width: 5em;
37
  }
1
+ #su-fofs table.widefat {
2
+ width: 100%;
3
+ margin: 1em 0;
4
+ }
5
+
6
+ #su-fofs table tr.su-404s-hit-data td,
7
+ #su-fofs table tr.su-404s-hit-referers td {
8
+ border-bottom: 0 none;
9
+ }
10
+
11
+ #su-fofs table tr.su-404s-hit-referers td,
12
+ #su-fofs table tr.su-404s-hit-user-agents td {
13
+ padding: 0 1em;
14
+ border-top: 0 none;
15
+ }
16
+
17
+ #su-fofs table .su-404s-hit-referers-list,
18
+ #su-fofs table .su-404s-hit-user-agents-list {
19
+ padding-top: 0.5em;
20
+ }
21
+
22
+ #su-fofs table tr.su-404s-new-hit td {
23
+ background-color: #DFFFE3;
24
+ }
25
+
26
+ #su-fofs table .actions span {
27
+ padding-right: 0.5em;
28
+ }
29
+
30
+ #su-fofs .su-404s-clear-log {
31
+ text-align: right;
32
+ padding: 0.5em 0;
33
+ }
34
+
35
+ #su-fofs .form-table input#max_log_size {
36
+ width: 5em;
37
  }
modules/404s/fofs.php CHANGED
@@ -1,110 +1,110 @@
1
- <?php
2
- /**
3
- * 404 Monitor Module
4
- *
5
- * @since 0.4
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_Fofs extends SU_Module {
11
- static function get_module_title() { return __('404 Monitor', 'seo-ultimate'); }
12
- static function get_menu_title() { return __('404 Monitor', 'seo-ultimate'); }
13
- static function has_menu_count() { return true; }
14
- function admin_page_contents() {
15
-
16
- if ($this->should_show_sdf_theme_promo()) {
17
- echo "\n\n<div class='row'>\n";
18
- echo "\n\n<div class='col-sm-8 col-md-9'>\n";
19
- }
20
-
21
- $this->children_admin_page_tabs();
22
-
23
- if ($this->should_show_sdf_theme_promo()) {
24
- echo "\n\n</div>\n";
25
- echo "\n\n<div class='col-sm-4 col-md-3'>\n";
26
- $this->promo_sdf_banners();
27
- echo "\n\n</div>\n";
28
- echo "\n\n</div>\n";
29
- }
30
-
31
- }
32
-
33
- function add_help_tabs($screen) {
34
-
35
- $screen->add_help_tab(array(
36
- 'id' => 'su-fofs-overview'
37
- , 'title' => __('Overview', 'seo-ultimate')
38
- , 'content' => __("
39
- <ul>
40
- <li><strong>What it does:</strong> The 404 Monitor keeps track of non-existent URLs that generated 404 errors. 404 errors are when a search engine or visitor comes to a URL on your site but nothing exists at that URL.</li>
41
- <li><strong>Why it helps:</strong> The 404 Monitor helps you spot 404 errors; then you can take steps to correct them to reduce link-juice loss from broken links.</li>
42
- <li><strong>How to use it:</strong> Check the 404 Monitor occasionally for errors. (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't seen yet. These new URLs will also be highlighted green in the table.) If a 404 error's referring URL is located on your site, try locating and fixing the broken URL. If moved content was previously located at the requested URL, try using a redirection plugin to point the old URL to the new one.</li>
43
- </ul>
44
-
45
- <p>If there are no 404 errors in the log, this is good and means there's no action required on your part.</p>
46
- ", 'seo-ultimate')));
47
-
48
- $screen->add_help_tab(array(
49
- 'id' => 'su-fofs-log'
50
- , 'title' => __('Log Help', 'seo-ultimate')
51
- , 'content' => __("
52
- <p>You can perform the following actions on each entry in the log:</p>
53
-
54
- <ul>
55
- <li>Clicking the first icon will open the URL in a new window. This is useful for testing whether or not a redirect is working.</li>
56
- <li>Clicking the second icon will open Google'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>
57
- <li>Once you've taken care of a 404 error, you can click the third icon to remove it from the list. The URL will reappear on the list if it triggers a 404 error in the future.</li>
58
- <li>To view the list of the URLs by which visitors and/or search engines reached this non-existent URL, click the scroll icon in the &#8220;Referers&#8221; column.</li>
59
- <li>To view the list of visitor browsers and search engine bots which tried to access this non-existent URL, click the scroll icon in the &#8220;User Agents&#8221; column.</li>
60
- </ul>
61
-
62
- <p>The &#8220;Clear Log&#8221; button will erase all of entries in the log. The log will remain empty until more 404 errors are logged.</p>
63
- ", 'seo-ultimate')));
64
-
65
- $screen->add_help_tab(array(
66
- 'id' => 'su-fofs-settings'
67
- , 'title' => __('Settings Help', 'seo-ultimate')
68
- , 'content' => __("
69
- <p>The following options are available on the Settings tab:</p>
70
-
71
- <ul>
72
- <li>
73
- <strong>Monitoring Settings</strong>
74
- <ul>
75
- <li><strong>Continue monitoring for new 404 errors</strong> &mdash; If disabled, 404 Monitor will keep existing 404 errors in the log but won't add any new ones.</li>
76
- </ul>
77
- </li>
78
- <li>
79
- <strong>Log Restrictions</strong>
80
- <ul>
81
- <li><strong>Only log these types of 404 errors</strong> &mdash; Check this option to log a 404 error <em>only</em> if it meets at least one of the criteria you specify. If you don't enable any criteria, no 404 errors will be logged.
82
- <ul>
83
- <li><strong>404s generated by search engine spiders</strong> &mdash; When logging restriction is enabled, this option will make an exception for 404 errors generated by one of the top search engines (Google, Yahoo, Baidu, Bing, Yandex, Soso, Ask.com, Sogou, or AltaVista).</li>
84
- <li><strong>404s with referring URLs</strong> &mdash; When logging restriction is enabled, this option will make an exception for 404 errors generated by users who click a link on your site or another site first before ending up at a 404 page on your site.</li>
85
- </ul>
86
- </li>
87
- </ul>
88
- </li>
89
- <li><strong>Maximum Log Entries</strong> &mdash; Here you can set the maximum number of log entries that 404 Monitor will keep at a time. Setting this to a reasonable number will help keep database usage under control. If you change this setting, it will take effect the next time a 404 is logged.</li>
90
- <li><strong>URLs to Ignore</strong> &mdash; URLs entered here will be ignored whenever they generate 404 errors in the future. You can use asterisks (*) as wildcards.</li>
91
- </ul>
92
- ", 'seo-ultimate')));
93
-
94
- $screen->add_help_tab(array(
95
- 'id' => 'su-fofs-troubleshooting'
96
- , 'title' => __('Troubleshooting', 'seo-ultimate')
97
- , 'content' => __("
98
- <p>404 Monitor doesn't appear to work? Take these notes into consideration:</p>
99
-
100
- <ul>
101
- <li>The 404 Monitor doesn't record 404 errors generated by logged-in users.</li>
102
- <li>In order for the 404 Monitor to track 404 errors, you must have non-default permalinks enabled under <a href='options-permalink.php' target='_blank'>Settings &rArr; Permalinks</a>.</li>
103
- <li>Some parts of your website may not be under WordPress's control; the 404 Monitor can't track 404 errors on non-WordPress website areas.</li>
104
- </ul>
105
- ", 'seo-ultimate')));
106
- }
107
- }
108
-
109
- }
110
  ?>
1
+ <?php
2
+ /**
3
+ * 404 Monitor Module
4
+ *
5
+ * @since 0.4
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_Fofs extends SU_Module {
11
+ static function get_module_title() { return __('404 Monitor', 'seo-ultimate'); }
12
+ static function get_menu_title() { return __('404 Monitor', 'seo-ultimate'); }
13
+ static function has_menu_count() { return true; }
14
+ function admin_page_contents() {
15
+
16
+ if ($this->should_show_sdf_theme_promo()) {
17
+ echo "\n\n<div class='row'>\n";
18
+ echo "\n\n<div class='col-sm-8 col-md-9'>\n";
19
+ }
20
+
21
+ $this->children_admin_page_tabs();
22
+
23
+ if ($this->should_show_sdf_theme_promo()) {
24
+ echo "\n\n</div>\n";
25
+ echo "\n\n<div class='col-sm-4 col-md-3'>\n";
26
+ $this->promo_sdf_banners();
27
+ echo "\n\n</div>\n";
28
+ echo "\n\n</div>\n";
29
+ }
30
+
31
+ }
32
+
33
+ function add_help_tabs($screen) {
34
+
35
+ $screen->add_help_tab(array(
36
+ 'id' => 'su-fofs-overview'
37
+ , 'title' => __('Overview', 'seo-ultimate')
38
+ , 'content' => __("
39
+ <ul>
40
+ <li><strong>What it does:</strong> The 404 Monitor keeps track of non-existent URLs that generated 404 errors. 404 errors are when a search engine or visitor comes to a URL on your site but nothing exists at that URL.</li>
41
+ <li><strong>Why it helps:</strong> The 404 Monitor helps you spot 404 errors; then you can take steps to correct them to reduce link-juice loss from broken links.</li>
42
+ <li><strong>How to use it:</strong> Check the 404 Monitor occasionally for errors. (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't seen yet. These new URLs will also be highlighted green in the table.) If a 404 error's referring URL is located on your site, try locating and fixing the broken URL. If moved content was previously located at the requested URL, try using a redirection plugin to point the old URL to the new one.</li>
43
+ </ul>
44
+
45
+ <p>If there are no 404 errors in the log, this is good and means there's no action required on your part.</p>
46
+ ", 'seo-ultimate')));
47
+
48
+ $screen->add_help_tab(array(
49
+ 'id' => 'su-fofs-log'
50
+ , 'title' => __('Log Help', 'seo-ultimate')
51
+ , 'content' => __("
52
+ <p>You can perform the following actions on each entry in the log:</p>
53
+
54
+ <ul>
55
+ <li>Clicking the first icon will open the URL in a new window. This is useful for testing whether or not a redirect is working.</li>
56
+ <li>Clicking the second icon will open Google'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>
57
+ <li>Once you've taken care of a 404 error, you can click the third icon to remove it from the list. The URL will reappear on the list if it triggers a 404 error in the future.</li>
58
+ <li>To view the list of the URLs by which visitors and/or search engines reached this non-existent URL, click the scroll icon in the &#8220;Referers&#8221; column.</li>
59
+ <li>To view the list of visitor browsers and search engine bots which tried to access this non-existent URL, click the scroll icon in the &#8220;User Agents&#8221; column.</li>
60
+ </ul>
61
+
62
+ <p>The &#8220;Clear Log&#8221; button will erase all of entries in the log. The log will remain empty until more 404 errors are logged.</p>
63
+ ", 'seo-ultimate')));
64
+
65
+ $screen->add_help_tab(array(
66
+ 'id' => 'su-fofs-settings'
67
+ , 'title' => __('Settings Help', 'seo-ultimate')
68
+ , 'content' => __("
69
+ <p>The following options are available on the Settings tab:</p>
70
+
71
+ <ul>
72
+ <li>
73
+ <strong>Monitoring Settings</strong>
74
+ <ul>
75
+ <li><strong>Continue monitoring for new 404 errors</strong> &mdash; If disabled, 404 Monitor will keep existing 404 errors in the log but won't add any new ones.</li>
76
+ </ul>
77
+ </li>
78
+ <li>
79
+ <strong>Log Restrictions</strong>
80
+ <ul>
81
+ <li><strong>Only log these types of 404 errors</strong> &mdash; Check this option to log a 404 error <em>only</em> if it meets at least one of the criteria you specify. If you don't enable any criteria, no 404 errors will be logged.
82
+ <ul>
83
+ <li><strong>404s generated by search engine spiders</strong> &mdash; When logging restriction is enabled, this option will make an exception for 404 errors generated by one of the top search engines (Google, Yahoo, Baidu, Bing, Yandex, Soso, Ask.com, Sogou, or AltaVista).</li>
84
+ <li><strong>404s with referring URLs</strong> &mdash; When logging restriction is enabled, this option will make an exception for 404 errors generated by users who click a link on your site or another site first before ending up at a 404 page on your site.</li>
85
+ </ul>
86
+ </li>
87
+ </ul>
88
+ </li>
89
+ <li><strong>Maximum Log Entries</strong> &mdash; Here you can set the maximum number of log entries that 404 Monitor will keep at a time. Setting this to a reasonable number will help keep database usage under control. If you change this setting, it will take effect the next time a 404 is logged.</li>
90
+ <li><strong>URLs to Ignore</strong> &mdash; URLs entered here will be ignored whenever they generate 404 errors in the future. You can use asterisks (*) as wildcards.</li>
91
+ </ul>
92
+ ", 'seo-ultimate')));
93
+
94
+ $screen->add_help_tab(array(
95
+ 'id' => 'su-fofs-troubleshooting'
96
+ , 'title' => __('Troubleshooting', 'seo-ultimate')
97
+ , 'content' => __("
98
+ <p>404 Monitor doesn't appear to work? Take these notes into consideration:</p>
99
+
100
+ <ul>
101
+ <li>The 404 Monitor doesn't record 404 errors generated by logged-in users.</li>
102
+ <li>In order for the 404 Monitor to track 404 errors, you must have non-default permalinks enabled under <a href='options-permalink.php' target='_blank'>Settings &rArr; Permalinks</a>.</li>
103
+ <li>Some parts of your website may not be under WordPress's control; the 404 Monitor can't track 404 errors on non-WordPress website areas.</li>
104
+ </ul>
105
+ ", 'seo-ultimate')));
106
+ }
107
+ }
108
+
109
+ }
110
  ?>
modules/404s/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/author-links/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/autolinks/autolinks.css CHANGED
@@ -1,52 +1,52 @@
1
- #su-autolinks table.widefat,
2
- #su-autolinks table.widefat input.textbox {
3
- width: 100%;
4
- }
5
-
6
- #su-autolinks table.widefat td {
7
- vertical-align: middle;
8
- }
9
-
10
- #su-autolinks table.widefat td.su-link-from-match label,
11
- #su-autolinks table.widefat td.su-link-options label {
12
- margin-right: 1em;
13
- }
14
-
15
- #su-autolinks table.widefat td.su-link-from-match {
16
- width: 11em;
17
- }
18
-
19
- #su-content-autolinks table.widefat td.su-link-to {
20
- width: 20em;
21
- }
22
-
23
- #su-footer-autolinks table.widefat td.su-link-from,
24
- #su-footer-autolinks table.widefat td.su-link-to {
25
- width: 15em;
26
- }
27
-
28
- #su-autolinks table.widefat td.su-link-dampen-sitewide-lpa {
29
- width: 5em;
30
- }
31
-
32
- #su-autolinks table.widefat td.su-link-dampen-sitewide-lpa input.textbox {
33
- width: 4em;
34
- }
35
-
36
- #su-autolinks table.widefat td.su-link-sitewide-lpa {
37
- width: 5em;
38
- }
39
-
40
- #su-autolinks table.widefat td.su-link-options {
41
- width: 9em;
42
- }
43
-
44
- #su-autolinks table.widefat td.su-link-delete,
45
- #su-autolinks table.widefat th.su-link-delete {
46
- width: 3em;
47
- text-align: center;
48
- }
49
-
50
- #su-autolinks table.widefat td {
51
- padding-right: 0.5em;
52
  }
1
+ #su-autolinks table.widefat,
2
+ #su-autolinks table.widefat input.textbox {
3
+ width: 100%;
4
+ }
5
+
6
+ #su-autolinks table.widefat td {
7
+ vertical-align: middle;
8
+ }
9
+
10
+ #su-autolinks table.widefat td.su-link-from-match label,
11
+ #su-autolinks table.widefat td.su-link-options label {
12
+ margin-right: 1em;
13
+ }
14
+
15
+ #su-autolinks table.widefat td.su-link-from-match {
16
+ width: 11em;
17
+ }
18
+
19
+ #su-content-autolinks table.widefat td.su-link-to {
20
+ width: 20em;
21
+ }
22
+
23
+ #su-footer-autolinks table.widefat td.su-link-from,
24
+ #su-footer-autolinks table.widefat td.su-link-to {
25
+ width: 15em;
26
+ }
27
+
28
+ #su-autolinks table.widefat td.su-link-dampen-sitewide-lpa {
29
+ width: 5em;
30
+ }
31
+
32
+ #su-autolinks table.widefat td.su-link-dampen-sitewide-lpa input.textbox {
33
+ width: 4em;
34
+ }
35
+
36
+ #su-autolinks table.widefat td.su-link-sitewide-lpa {
37
+ width: 5em;
38
+ }
39
+
40
+ #su-autolinks table.widefat td.su-link-options {
41
+ width: 9em;
42
+ }
43
+
44
+ #su-autolinks table.widefat td.su-link-delete,
45
+ #su-autolinks table.widefat th.su-link-delete {
46
+ width: 3em;
47
+ text-align: center;
48
+ }
49
+
50
+ #su-autolinks table.widefat td {
51
+ padding-right: 0.5em;
52
  }
modules/autolinks/autolinks.php CHANGED
@@ -1,175 +1,175 @@
1
- <?php
2
- /**
3
- * Deeplink Juggernaut Module
4
- *
5
- * @since 1.8
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_Autolinks extends SU_Module {
11
- static function get_module_title() { return __('Deeplink Juggernaut', 'seo-ultimate'); }
12
- static function get_menu_title() { return __('Deeplink Juggernaut', 'seo-ultimate'); }
13
-
14
- function add_help_tabs($screen) {
15
-
16
- $screen->add_help_tab(array(
17
- 'id' => 'su-autolinks-overview'
18
- , 'title' => __('Overview', 'seo-ultimate')
19
- , 'content' => __("
20
- <ul>
21
- <li><strong>What it does:</strong> Deeplink Juggernaut lets you automatically generate hyperlinks in your site&#8217;s content and footer.</li>
22
- <li><strong>Why it helps:</strong> Search engines use the anchor text of hyperlinks to determine the topicality of the webpage to which the link points. Deeplink Juggernaut lets you automatically generate hyperlinks to various pages on your site, which can help increase the linked page&#8217;s ranking for the term used in the anchor text.</li>
23
- <li><strong>How to use it:</strong> The Content Links section lets you automatically link words or phrases in your site&#8217;s content to a target page of your choosing. The Footer Links section lets you add links in the footer of your entire site or just a particular set of webpages.</li>
24
- </ul>
25
- ", 'seo-ultimate')));
26
-
27
- $screen->add_help_tab(array(
28
- 'id' => 'su-autolinks-content-links'
29
- , 'title' => __('Content Links Tab', 'seo-ultimate')
30
- , 'content' => __("
31
- <p>To add an autolink, fill in the fields and then click &#8220;Save Changes.&#8221; Once you do so, you can edit your new autolink or add another one.</p>
32
-
33
- <ul>
34
- <li><strong>Anchor Text</strong> &mdash; Deeplink Juggernaut will scan your site&#8217;s content for the word or phrase you put in this box, and then hyperlink instances of that word or phrase to the webpage or item you specify in the Destination box. The Anchor Text should be a keyword that you want the Destination page to rank for.</li>
35
- <li><p><strong>Destination</strong> &mdash; This is the box where you specify the webpage where you want the auto-generated hyperlinks to point.</p>
36
- <ul>
37
- <li>To link to a post, page, attachment, category, tag, term, or author on your site, just type in its name and then select it from the dropdown.</li>
38
- <li>To link to your blog homepage, just type in &#8220;home&#8221; and select &#8220;Blog Homepage&#8221; from the dropdown.</li>
39
- <li>To link to one of the aliased URLs you created with the Link Mask Generator, just type in part of the original URL or alias URL and then select the link mask from the dropdown.</li>
40
- <li>To link to some other webpage, just type or paste in its URL in the box.</li>
41
- </ul>
42
- </li>
43
- <li><strong>Title Attribute</strong> &mdash; The link&#8217;s title attribute is the text that will appear when the visitor&#8217;s mouse pointer hovers over the link. Totally optional.</li>
44
- <li><p><strong>Dampener:</strong> If the anchor text you specify occurs many times throughout your site&#8217;s content, you may wish to reduce the overall frequency with which the anchor text is hyperlinked. You can reduce the autolinking frequency by a percentage with the Dampener field. For example:</p>
45
- <ul>
46
- <li>0% dampening will have no effect.</li>
47
- <li>50% dampening means the anchor text will be autolinked approximately half as often as it otherwise would be.</li>
48
- <li>90% dampening means the anchor text will be autolinked only 10% as often as it otherwise would be.</li>
49
- <li>100% dampening means the anchor text won&#8217;t be linked at all.</li>
50
- </ul>
51
- <p>The &#8220;Dampener&#8221; column will only appear if you&#8217;ve enabled it under the &#8220;Content Link Settings&#8221; tab.</p>
52
- </li>
53
- <li><strong>Nofollow</strong> &mdash; Checking this will add the <code>rel=&quot;nofollow&quot;</code> attribute to all autolinks generated for that anchor text. You should enable this only if you&#8217;re creating an automatic affiliate link.</li>
54
- <li><strong>New window</strong> &mdash; Checking this will make the link destination open up in a new window when the autolink is clicked.</li>
55
- <li><strong>Delete</strong> &mdash; To delete an autolink, tick its &#8220;Delete&#8221; checkbox and then click &#8220;Save Changes.&#8221;</li>
56
- </ul>
57
- ", 'seo-ultimate')));
58
-
59
- $screen->add_help_tab(array(
60
- 'id' => 'su-autolinks-content-link-settings'
61
- , 'title' => __('Content Link Settings Tab', 'seo-ultimate')
62
- , 'content' => __("
63
- <p>The following options are available on the Content Link Settings tab:</p>
64
-
65
- <ul>
66
- <li><strong>Add Autolinks to...</strong> &mdash; You can stop Deeplink Juggernaut from adding hyperlinks to the content of items of a given post type by unchecking the post type&#8217;s checkbox.</li>
67
- <li>
68
- <p><strong>Self-Linking</strong></p>
69
- <ul>
70
- <li><strong>Allow posts to link to themselves</strong> &mdash; This permits Deeplink Juggernaut to add a link to the content of a given post/page even if the link is pointing to the URL of that post/page.</li>
71
- <li><strong>Allow posts to link to the URL by which the visitor is accessing the post</strong> &mdash; There are lots of URLs by which you can access any given post/page on your site. You can access posts/pages via the homepage URL, your site&#8217;s many archive URLs, or the URLs of the posts/pages themselves. If you have an autolink that points to the homepage, and if Deeplink Juggernaut were to add that link to the content of posts when those posts are accessed from the homepage, then the homepage would be linking to itself. By default, Deeplink Juggernaut won&#8217;t let this happen. But if you&#8217;re okay with that sort of behavior, you can enable it by checking this box.</li>
72
- </ul>
73
- </li>
74
- <li>
75
- <p><strong>Quantity Restrictions</strong></p>
76
- <ul>
77
- <li><strong>Don&#8217;t add any more than ___ autolinks per post/page/etc.</strong> &mdash; Use this option to cap the total number of autolinks (for all anchor texts combined) that can be added to the content of any one item.</li>
78
- <li><strong>Don&#8217;t link the same anchor text any more than ___ times per post/page/etc.</strong> &mdash; Use this option to cap the number of times that each anchor text can be autolinked in the content of any one item.</li>
79
- <li><strong>Don&#8217;t link to the same destination any more than ___ times per post/page/etc.</strong> &mdash; Use this option to cap the number of autolinks that any one URL can get within the content of any one item. (This is different from the previous option because you can have multiple anchor texts pointing to the same place.)</li>
80
- </ul>
81
- </li>
82
- <li>
83
- <p><strong>Additional Dampening Effect</strong></p>
84
- <ul>
85
- <li><strong>Globally decrease autolinking frequency by ___%</strong> &mdash; If you have massive amounts of content on your site (e.g. thousands of posts), the &#8220;Quantity Restrictions&#8221; settings may not be sufficient to reign in the number of autolinks being generated. If that is the case, you can use this option to reduce overall autolinking frequency by a given percentage. For example, if you were to set global dampening to 10%, then autolinks would be added only 90% as often as before.</li>
86
- <li><strong>Add a &#8220;Dampener&#8221; column to the Content Links editor</strong> &mdash; Check this box and click &#8220;Save Changes&#8221; to add a new column to the &#8220;Content Links&#8221; editor table that will let you apply the dampening effect to individual autolinks. If you&#8217;ve also enabled the global dampening option, this will let you override the global value for individual links. (For example, you can disable dampening for just one of your links by setting the Dampener field to 0%.)</li>
87
- </ul>
88
- </li>
89
- <li><strong>Tag Restrictions</strong> &mdash; By default, Deeplink Juggernaut will not autolink a particular anchor text if that anchor text is found in a header or in a code block. You can further customize these exceptions by adding HTML tags to the list.</li>
90
- <li><strong>Siloing</strong> &mdash; If you enable the siloing feature for a given post type (such as posts or pages), then items of that post type will only be able to autolink to a webpage on your site if it falls within a category, tag, or term shared by that item. For example, you can set it up so that posts in Category A can&#8217;t autolink to anything on your site with the exception of other posts in Category A and the Category A archive. Autolinks to external sites will not be affected, since the siloing setting will not affect autolinks that have a URL in the Destination box.</li>
91
- <li><strong>CSS Class for Autolinks</strong> &mdash; If you want to apply CSS styling to Content Links generated by Deeplink Juggernaut, type in a class name here (e.g. &#8220;autolink&#8221;).</li>
92
- </ul>
93
- ", 'seo-ultimate')));
94
-
95
- $screen->add_help_tab(array(
96
- 'id' => 'su-autolinks-footer-links'
97
- , 'title' => __('Footer Links Tab', 'seo-ultimate')
98
- , 'content' => __("
99
- <p>To add a footer link, fill in the fields and then click &#8220;Save Changes.&#8221; Once you do so, you can edit your new footer link or add another one.</p>
100
-
101
- <ul>
102
- <li><p><strong>Link Location</strong> &mdash; If you want to add a footer link across your entire site, leave this box blank. Otherwise, type in the location on your site where you want the footer link to appear.</p>
103
- <p>If you only want the footer link to appear on&hellip;</p>
104
- <ul>
105
- <li>&hellip;A particular post, page, attachment, or category/tag/term/author archive, just type in the item&#8217;s name and then select it from the dropdown.</li>
106
- <li>&hellip;Your blog homepage, just type in &#8220;home&#8221; and select &#8220;Blog Homepage&#8221; from the dropdown.</li>
107
- <li>&hellip;A particular URL on your site, just type or paste it into the box.</li>
108
- </ul>
109
- </li>
110
- <li><p><strong>Match child content</strong> &mdash; What this does depends on what type of Link Location you specified.</p>
111
- <ul>
112
- <li>If the Link Location is a category/tag/term archive, then the footer link will also be added to posts within that term.</li>
113
- <li>If the Link Location is an author archive, then the footer link will also be added to posts written by that author.</li>
114
- <li>If the Link Location is a URL, then the footer link will also be added to URLs that begin with whatever URL you entered.</li>
115
- </ul>
116
- </li>
117
- <li><strong>Negative match</strong> &mdash; This will cause the footer link to be inserted on webpages <em>other than</em> the Link Location and (if the appropriate box is checked) its child content.</li>
118
- <li><strong>Anchor Text</strong> &mdash; Deeplink Juggernaut insert this text into your site&#8217;s footer and will link that text to the webpage or item you specify in the Destination box. The Anchor Text should be a keyword that you want the Destination page to rank for.</li>
119
- <li><p><strong>Destination</strong> &mdash; This is the box where you specify the webpage where you want the auto-generated hyperlinks to point.</p>
120
- <ul>
121
- <li>To link to a post, page, attachment, category, tag, term, or author on your site, just type in its name and then select it from the dropdown.</li>
122
- <li>To link to your blog homepage, just type in &#8220;home&#8221; and select &#8220;Blog Homepage&#8221; from the dropdown.</li>
123
- <li>To link to one of the aliased URLs you created with the Link Mask Generator, just type in part of the original URL or alias URL and then select the link mask from the dropdown.</li>
124
- <li>To link to some other webpage, just type or paste in its URL in the box.</li>
125
- </ul>
126
- </li>
127
- <li><strong>Title Attribute</strong> &mdash; The link&#8217;s title attribute is the text that will appear when the visitor&#8217;s mouse pointer hovers over the link. Totally optional.</li>
128
- <li><strong>Nofollow</strong> &mdash; Checking this will add the <code>rel=&quot;nofollow&quot;</code> attribute to all instances of this footer link. You should enable this only if you&#8217;re creating an automatic affiliate link.</li>
129
- <li><strong>New window</strong> &mdash; Checking this will make the link destination open up in a new window when the footer link is clicked.</li>
130
- <li><strong>Delete</strong> &mdash; To delete an autolink, tick its &#8220;Delete&#8221; checkbox and then click &#8220;Save Changes.&#8221;</li>
131
- </ul>
132
- ", 'seo-ultimate')));
133
-
134
- $screen->add_help_tab(array(
135
- 'id' => 'su-autolinks-footer-link-settings'
136
- , 'title' => __('Footer Link Settings Tab', 'seo-ultimate')
137
- , 'content' => __("
138
- <p>The following options are available on the Footer Link Settings tab:</p>
139
-
140
- <ul>
141
- <li><strong>Link Section Format</strong> &mdash; Lets you customize the text/HTML that will surround the list of links outputted in your site&#8217;s footer (represented by the <code>{links}</code> variable).</li>
142
- <li><strong>Link Format</strong> &mdash; Lets you specify text or HTML that will surround each individual link (represented by the <code>{link}</code> variable).</li>
143
- <li><strong>Link Separator</strong> &mdash; Lets you specify text or HTML that will separate each individual link.</li>
144
- </ul>
145
- ", 'seo-ultimate')));
146
-
147
- $screen->add_help_tab(array(
148
- 'id' => 'su-autolinks-faq'
149
- , 'title' => __('FAQ', 'seo-ultimate')
150
- , 'content' => __("
151
- <ul>
152
- <li><strong>What happens if I autolink to a post and then delete the post later?</strong><br />Deeplink Juggernaut will disable all autolinks that point to the deleted post. Deeplink Juggernaut will keep the autolink in the list though, so that you can point it somewhere else.</li>
153
- <li><strong>What happens if I autolink to a draft post?</strong><br />Don&#8217;t worry: Deeplink Juggernaut won&#8217;t actually autolink to it until the post is published.</li>
154
- <li><strong>Does Deeplink Juggernaut edit my posts&#8217; content as it is stored in the database?</strong><br />No. Autolinks are added dynamically. This means all the autolinks will go away if you disable Deeplink Juggernaut or deactivate SEO Ultimate.</li>
155
- <li><strong>How does the Dampener work?</strong><br />When the Dampener is in effect, Deeplink Juggernaut creates a hash for each autolink and creates a hash for each post/page/etc. on your site. In order for the autolink to be added to the content of a post/page, the two hashes have to be compatible with each other. If the Dampener is set to 70%, then the hashes will match and the autolink will be applied approximately 30% of the time. This hash system results in a pseudo-random dampening effect that will always have a consistent outcome for any given anchor/post combination.</li>
156
- <li><strong>Can I still use the Footer Links feature if my theme has a widgetized footer?</strong><br />Yes. Make sure the &#8220;SEO Ultimate Widgets&#8221; module is enabled in the SEO Ultimate <a href='admin.php?page=seo' target='_blank'>Module Manager</a>, then go to your <a href='widgets.php' target='_blank'>Widgets</a> page and add the &#8220;Footer Links&#8221; widget.
157
- </ul>
158
- ", 'seo-ultimate')));
159
-
160
- $screen->add_help_tab(array(
161
- 'id' => 'su-autolinks-troubleshooting'
162
- , 'title' => __('Troubleshooting', 'seo-ultimate')
163
- , 'content' => __("
164
- <ul>
165
- <li><strong>I configured a Content Link, but the anchor text isn&#8217;t being linked on my site.</strong><br />You likely enabled a setting on the &#8220;Content Link Settings&#8221; tab that is preventing the autolink from being applied.</li>
166
- <li><strong>I have Content Links configured for &#8220;widgets&#8221; and &#8220;blue widgets,&#8221; but when the phrase &#8220;blue widgets&#8221; appears on my site, only the word &#8220;widgets&#8221; is being linked. Why is that?</strong><br />Deeplink Juggernaut always links longer anchor texts first, so if this is happening, then the &#8220;blue widgets&#8221; autolink must have been disabled in that particular instance due to a Quantity Restriction or the Dampener effect being applied.</li>
167
- <li><strong>Why aren&#8217;t my footer links appearing?</strong><br />Check to make sure your theme is <a href='http://johnlamansky.com/wordpress/theme-plugin-hooks/' target='_blank'>plugin-friendly</a>. Also, check the &#8220;Footer Link Settings&#8221; tab and make sure that the &#8220;Link Section Format&#8221; field includes the <code>{links}</code> variable and that the &#8220;Link Format&#8221; field includes the <code>{link}</code> variable.</li>
168
- </ul>
169
- ", 'seo-ultimate')));
170
-
171
- }
172
- }
173
-
174
- }
175
  ?>
1
+ <?php
2
+ /**
3
+ * Deeplink Juggernaut Module
4
+ *
5
+ * @since 1.8
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_Autolinks extends SU_Module {
11
+ static function get_module_title() { return __('Deeplink Juggernaut', 'seo-ultimate'); }
12
+ static function get_menu_title() { return __('Deeplink Juggernaut', 'seo-ultimate'); }
13
+
14
+ function add_help_tabs($screen) {
15
+
16
+ $screen->add_help_tab(array(
17
+ 'id' => 'su-autolinks-overview'
18
+ , 'title' => __('Overview', 'seo-ultimate')
19
+ , 'content' => __("
20
+ <ul>
21
+ <li><strong>What it does:</strong> Deeplink Juggernaut lets you automatically generate hyperlinks in your site&#8217;s content and footer.</li>
22
+ <li><strong>Why it helps:</strong> Search engines use the anchor text of hyperlinks to determine the topicality of the webpage to which the link points. Deeplink Juggernaut lets you automatically generate hyperlinks to various pages on your site, which can help increase the linked page&#8217;s ranking for the term used in the anchor text.</li>
23
+ <li><strong>How to use it:</strong> The Content Links section lets you automatically link words or phrases in your site&#8217;s content to a target page of your choosing. The Footer Links section lets you add links in the footer of your entire site or just a particular set of webpages.</li>
24
+ </ul>
25
+ ", 'seo-ultimate')));
26
+
27
+ $screen->add_help_tab(array(
28
+ 'id' => 'su-autolinks-content-links'
29
+ , 'title' => __('Content Links Tab', 'seo-ultimate')
30
+ , 'content' => __("
31
+ <p>To add an autolink, fill in the fields and then click &#8220;Save Changes.&#8221; Once you do so, you can edit your new autolink or add another one.</p>
32
+
33
+ <ul>
34
+ <li><strong>Anchor Text</strong> &mdash; Deeplink Juggernaut will scan your site&#8217;s content for the word or phrase you put in this box, and then hyperlink instances of that word or phrase to the webpage or item you specify in the Destination box. The Anchor Text should be a keyword that you want the Destination page to rank for.</li>
35
+ <li><p><strong>Destination</strong> &mdash; This is the box where you specify the webpage where you want the auto-generated hyperlinks to point.</p>
36
+ <ul>
37
+ <li>To link to a post, page, attachment, category, tag, term, or author on your site, just type in its name and then select it from the dropdown.</li>
38
+ <li>To link to your blog homepage, just type in &#8220;home&#8221; and select &#8220;Blog Homepage&#8221; from the dropdown.</li>
39
+ <li>To link to one of the aliased URLs you created with the Link Mask Generator, just type in part of the original URL or alias URL and then select the link mask from the dropdown.</li>
40
+ <li>To link to some other webpage, just type or paste in its URL in the box.</li>
41
+ </ul>
42
+ </li>
43
+ <li><strong>Title Attribute</strong> &mdash; The link&#8217;s title attribute is the text that will appear when the visitor&#8217;s mouse pointer hovers over the link. Totally optional.</li>
44
+ <li><p><strong>Dampener:</strong> If the anchor text you specify occurs many times throughout your site&#8217;s content, you may wish to reduce the overall frequency with which the anchor text is hyperlinked. You can reduce the autolinking frequency by a percentage with the Dampener field. For example:</p>
45
+ <ul>
46
+ <li>0% dampening will have no effect.</li>
47
+ <li>50% dampening means the anchor text will be autolinked approximately half as often as it otherwise would be.</li>
48
+ <li>90% dampening means the anchor text will be autolinked only 10% as often as it otherwise would be.</li>
49
+ <li>100% dampening means the anchor text won&#8217;t be linked at all.</li>
50
+ </ul>
51
+ <p>The &#8220;Dampener&#8221; column will only appear if you&#8217;ve enabled it under the &#8220;Content Link Settings&#8221; tab.</p>
52
+ </li>
53
+ <li><strong>Nofollow</strong> &mdash; Checking this will add the <code>rel=&quot;nofollow&quot;</code> attribute to all autolinks generated for that anchor text. You should enable this only if you&#8217;re creating an automatic affiliate link.</li>
54
+ <li><strong>New window</strong> &mdash; Checking this will make the link destination open up in a new window when the autolink is clicked.</li>
55
+ <li><strong>Delete</strong> &mdash; To delete an autolink, tick its &#8220;Delete&#8221; checkbox and then click &#8220;Save Changes.&#8221;</li>
56
+ </ul>
57
+ ", 'seo-ultimate')));
58
+
59
+ $screen->add_help_tab(array(
60
+ 'id' => 'su-autolinks-content-link-settings'
61
+ , 'title' => __('Content Link Settings Tab', 'seo-ultimate')
62
+ , 'content' => __("
63
+ <p>The following options are available on the Content Link Settings tab:</p>
64
+
65
+ <ul>
66
+ <li><strong>Add Autolinks to...</strong> &mdash; You can stop Deeplink Juggernaut from adding hyperlinks to the content of items of a given post type by unchecking the post type&#8217;s checkbox.</li>
67
+ <li>
68
+ <p><strong>Self-Linking</strong></p>
69
+ <ul>
70
+ <li><strong>Allow posts to link to themselves</strong> &mdash; This permits Deeplink Juggernaut to add a link to the content of a given post/page even if the link is pointing to the URL of that post/page.</li>
71
+ <li><strong>Allow posts to link to the URL by which the visitor is accessing the post</strong> &mdash; There are lots of URLs by which you can access any given post/page on your site. You can access posts/pages via the homepage URL, your site&#8217;s many archive URLs, or the URLs of the posts/pages themselves. If you have an autolink that points to the homepage, and if Deeplink Juggernaut were to add that link to the content of posts when those posts are accessed from the homepage, then the homepage would be linking to itself. By default, Deeplink Juggernaut won&#8217;t let this happen. But if you&#8217;re okay with that sort of behavior, you can enable it by checking this box.</li>
72
+ </ul>
73
+ </li>
74
+ <li>
75
+ <p><strong>Quantity Restrictions</strong></p>
76
+ <ul>
77
+ <li><strong>Don&#8217;t add any more than ___ autolinks per post/page/etc.</strong> &mdash; Use this option to cap the total number of autolinks (for all anchor texts combined) that can be added to the content of any one item.</li>
78
+ <li><strong>Don&#8217;t link the same anchor text any more than ___ times per post/page/etc.</strong> &mdash; Use this option to cap the number of times that each anchor text can be autolinked in the content of any one item.</li>
79
+ <li><strong>Don&#8217;t link to the same destination any more than ___ times per post/page/etc.</strong> &mdash; Use this option to cap the number of autolinks that any one URL can get within the content of any one item. (This is different from the previous option because you can have multiple anchor texts pointing to the same place.)</li>
80
+ </ul>
81
+ </li>
82
+ <li>
83
+ <p><strong>Additional Dampening Effect</strong></p>
84
+ <ul>
85
+ <li><strong>Globally decrease autolinking frequency by ___%</strong> &mdash; If you have massive amounts of content on your site (e.g. thousands of posts), the &#8220;Quantity Restrictions&#8221; settings may not be sufficient to reign in the number of autolinks being generated. If that is the case, you can use this option to reduce overall autolinking frequency by a given percentage. For example, if you were to set global dampening to 10%, then autolinks would be added only 90% as often as before.</li>
86
+ <li><strong>Add a &#8220;Dampener&#8221; column to the Content Links editor</strong> &mdash; Check this box and click &#8220;Save Changes&#8221; to add a new column to the &#8220;Content Links&#8221; editor table that will let you apply the dampening effect to individual autolinks. If you&#8217;ve also enabled the global dampening option, this will let you override the global value for individual links. (For example, you can disable dampening for just one of your links by setting the Dampener field to 0%.)</li>
87
+ </ul>
88
+ </li>
89
+ <li><strong>Tag Restrictions</strong> &mdash; By default, Deeplink Juggernaut will not autolink a particular anchor text if that anchor text is found in a header or in a code block. You can further customize these exceptions by adding HTML tags to the list.</li>
90
+ <li><strong>Siloing</strong> &mdash; If you enable the siloing feature for a given post type (such as posts or pages), then items of that post type will only be able to autolink to a webpage on your site if it falls within a category, tag, or term shared by that item. For example, you can set it up so that posts in Category A can&#8217;t autolink to anything on your site with the exception of other posts in Category A and the Category A archive. Autolinks to external sites will not be affected, since the siloing setting will not affect autolinks that have a URL in the Destination box.</li>
91
+ <li><strong>CSS Class for Autolinks</strong> &mdash; If you want to apply CSS styling to Content Links generated by Deeplink Juggernaut, type in a class name here (e.g. &#8220;autolink&#8221;).</li>
92
+ </ul>
93
+ ", 'seo-ultimate')));
94
+
95
+ $screen->add_help_tab(array(
96
+ 'id' => 'su-autolinks-footer-links'
97
+ , 'title' => __('Footer Links Tab', 'seo-ultimate')
98
+ , 'content' => __("
99
+ <p>To add a footer link, fill in the fields and then click &#8220;Save Changes.&#8221; Once you do so, you can edit your new footer link or add another one.</p>
100
+
101
+ <ul>
102
+ <li><p><strong>Link Location</strong> &mdash; If you want to add a footer link across your entire site, leave this box blank. Otherwise, type in the location on your site where you want the footer link to appear.</p>
103
+ <p>If you only want the footer link to appear on&hellip;</p>
104
+ <ul>
105
+ <li>&hellip;A particular post, page, attachment, or category/tag/term/author archive, just type in the item&#8217;s name and then select it from the dropdown.</li>
106
+ <li>&hellip;Your blog homepage, just type in &#8220;home&#8221; and select &#8220;Blog Homepage&#8221; from the dropdown.</li>
107
+ <li>&hellip;A particular URL on your site, just type or paste it into the box.</li>
108
+ </ul>
109
+ </li>
110
+ <li><p><strong>Match child content</strong> &mdash; What this does depends on what type of Link Location you specified.</p>
111
+ <ul>
112
+ <li>If the Link Location is a category/tag/term archive, then the footer link will also be added to posts within that term.</li>
113
+ <li>If the Link Location is an author archive, then the footer link will also be added to posts written by that author.</li>
114
+ <li>If the Link Location is a URL, then the footer link will also be added to URLs that begin with whatever URL you entered.</li>
115
+ </ul>
116
+ </li>
117
+ <li><strong>Negative match</strong> &mdash; This will cause the footer link to be inserted on webpages <em>other than</em> the Link Location and (if the appropriate box is checked) its child content.</li>
118
+ <li><strong>Anchor Text</strong> &mdash; Deeplink Juggernaut insert this text into your site&#8217;s footer and will link that text to the webpage or item you specify in the Destination box. The Anchor Text should be a keyword that you want the Destination page to rank for.</li>
119
+ <li><p><strong>Destination</strong> &mdash; This is the box where you specify the webpage where you want the auto-generated hyperlinks to point.</p>
120
+ <ul>
121
+ <li>To link to a post, page, attachment, category, tag, term, or author on your site, just type in its name and then select it from the dropdown.</li>
122
+ <li>To link to your blog homepage, just type in &#8220;home&#8221; and select &#8220;Blog Homepage&#8221; from the dropdown.</li>
123
+ <li>To link to one of the aliased URLs you created with the Link Mask Generator, just type in part of the original URL or alias URL and then select the link mask from the dropdown.</li>
124
+ <li>To link to some other webpage, just type or paste in its URL in the box.</li>
125
+ </ul>
126
+ </li>
127
+ <li><strong>Title Attribute</strong> &mdash; The link&#8217;s title attribute is the text that will appear when the visitor&#8217;s mouse pointer hovers over the link. Totally optional.</li>
128
+ <li><strong>Nofollow</strong> &mdash; Checking this will add the <code>rel=&quot;nofollow&quot;</code> attribute to all instances of this footer link. You should enable this only if you&#8217;re creating an automatic affiliate link.</li>
129
+ <li><strong>New window</strong> &mdash; Checking this will make the link destination open up in a new window when the footer link is clicked.</li>
130
+ <li><strong>Delete</strong> &mdash; To delete an autolink, tick its &#8220;Delete&#8221; checkbox and then click &#8220;Save Changes.&#8221;</li>
131
+ </ul>
132
+ ", 'seo-ultimate')));
133
+
134
+ $screen->add_help_tab(array(
135
+ 'id' => 'su-autolinks-footer-link-settings'
136
+ , 'title' => __('Footer Link Settings Tab', 'seo-ultimate')
137
+ , 'content' => __("
138
+ <p>The following options are available on the Footer Link Settings tab:</p>
139
+
140
+ <ul>
141
+ <li><strong>Link Section Format</strong> &mdash; Lets you customize the text/HTML that will surround the list of links outputted in your site&#8217;s footer (represented by the <code>{links}</code> variable).</li>
142
+ <li><strong>Link Format</strong> &mdash; Lets you specify text or HTML that will surround each individual link (represented by the <code>{link}</code> variable).</li>
143
+ <li><strong>Link Separator</strong> &mdash; Lets you specify text or HTML that will separate each individual link.</li>
144
+ </ul>
145
+ ", 'seo-ultimate')));
146
+
147
+ $screen->add_help_tab(array(
148
+ 'id' => 'su-autolinks-faq'
149
+ , 'title' => __('FAQ', 'seo-ultimate')
150
+ , 'content' => __("
151
+ <ul>
152
+ <li><strong>What happens if I autolink to a post and then delete the post later?</strong><br />Deeplink Juggernaut will disable all autolinks that point to the deleted post. Deeplink Juggernaut will keep the autolink in the list though, so that you can point it somewhere else.</li>
153
+ <li><strong>What happens if I autolink to a draft post?</strong><br />Don&#8217;t worry: Deeplink Juggernaut won&#8217;t actually autolink to it until the post is published.</li>
154
+ <li><strong>Does Deeplink Juggernaut edit my posts&#8217; content as it is stored in the database?</strong><br />No. Autolinks are added dynamically. This means all the autolinks will go away if you disable Deeplink Juggernaut or deactivate SEO Ultimate.</li>
155
+ <li><strong>How does the Dampener work?</strong><br />When the Dampener is in effect, Deeplink Juggernaut creates a hash for each autolink and creates a hash for each post/page/etc. on your site. In order for the autolink to be added to the content of a post/page, the two hashes have to be compatible with each other. If the Dampener is set to 70%, then the hashes will match and the autolink will be applied approximately 30% of the time. This hash system results in a pseudo-random dampening effect that will always have a consistent outcome for any given anchor/post combination.</li>
156
+ <li><strong>Can I still use the Footer Links feature if my theme has a widgetized footer?</strong><br />Yes. Make sure the &#8220;SEO Ultimate Widgets&#8221; module is enabled in the SEO Ultimate <a href='admin.php?page=seo' target='_blank'>Module Manager</a>, then go to your <a href='widgets.php' target='_blank'>Widgets</a> page and add the &#8220;Footer Links&#8221; widget.
157
+ </ul>
158
+ ", 'seo-ultimate')));
159
+
160
+ $screen->add_help_tab(array(
161
+ 'id' => 'su-autolinks-troubleshooting'
162
+ , 'title' => __('Troubleshooting', 'seo-ultimate')
163
+ , 'content' => __("
164
+ <ul>
165
+ <li><strong>I configured a Content Link, but the anchor text isn&#8217;t being linked on my site.</strong><br />You likely enabled a setting on the &#8220;Content Link Settings&#8221; tab that is preventing the autolink from being applied.</li>
166
+ <li><strong>I have Content Links configured for &#8220;widgets&#8221; and &#8220;blue widgets,&#8221; but when the phrase &#8220;blue widgets&#8221; appears on my site, only the word &#8220;widgets&#8221; is being linked. Why is that?</strong><br />Deeplink Juggernaut always links longer anchor texts first, so if this is happening, then the &#8220;blue widgets&#8221; autolink must have been disabled in that particular instance due to a Quantity Restriction or the Dampener effect being applied.</li>
167
+ <li><strong>Why aren&#8217;t my footer links appearing?</strong><br />Check to make sure your theme is <a href='http://johnlamansky.com/wordpress/theme-plugin-hooks/' target='_blank'>plugin-friendly</a>. Also, check the &#8220;Footer Link Settings&#8221; tab and make sure that the &#8220;Link Section Format&#8221; field includes the <code>{links}</code> variable and that the &#8220;Link Format&#8221; field includes the <code>{link}</code> variable.</li>
168
+ </ul>
169
+ ", 'seo-ultimate')));
170
+
171
+ }
172
+ }
173
+
174
+ }
175
  ?>
modules/autolinks/content-autolinks-settings.php CHANGED
@@ -1,95 +1,95 @@
1
- <?php
2
- /**
3
- * Content Deeplink Juggernaut Settings Module
4
- *
5
- * @since 2.2
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_ContentAutolinksSettings extends SU_Module {
11
-
12
- static function get_parent_module() { return 'autolinks'; }
13
- static function get_child_order() { return 20; }
14
- static function is_independent_module() { return false; }
15
-
16
- static function get_module_title() { return __('Content Deeplink Juggernaut Settings', 'seo-ultimate'); }
17
- function get_module_subtitle() { return __('Content Link Settings', 'seo-ultimate'); }
18
-
19
- function get_default_settings() {
20
-
21
- $defaults = array(
22
- 'dampen_sitewide_lpa_value' => 50
23
- , 'enable_perlink_dampen_sitewide_lpa' => ($this->get_setting('enable_link_limits') !== null)
24
- , 'enable_self_links' => false
25
- , 'enable_current_url_links' => $this->get_setting('enable_self_links', false)
26
- , 'limit_lpp_value' => 5
27
- , 'limit_lpa_value' => 2
28
- , 'limit_lpu_value' => 1
29
- , 'linkfree_tags' => 'code,pre,kbd,h1,h2,h3,h4,h5,h6'
30
- );
31
-
32
- $defaults = array_merge($defaults, array_fill_keys(suarr::aprintf(false, 'autolink_posttype_%s', get_post_types(array('public' => true), 'names')), true));
33
-
34
- return $defaults;
35
- }
36
-
37
- function admin_page_contents() {
38
- $this->admin_form_table_start();
39
-
40
- $this->checkboxes(
41
- suarr::aprintf('autolink_posttype_%s', false, suarr::simplify(get_post_types(array('public' => true), 'objects'), 'name', array('labels', 'name')))
42
- , __('Add Autolinks to...', 'seo-ultimate'));
43
-
44
- $this->checkboxes(array(
45
- 'enable_self_links' => __('Allow posts to link to themselves', 'seo-ultimate')
46
- , 'enable_current_url_links' => __('Allow posts to link to the URL by which the visitor is accessing the post', 'seo-ultimate')
47
- ), __('Self-Linking', 'seo-ultimate'));
48
-
49
- $this->checkboxes(array(
50
- 'limit_lpp' => __('Don&#8217;t add any more than %d autolinks per post/page/etc.', 'seo-ultimate')
51
- , 'limit_lpa' => __('Don&#8217;t link the same anchor text any more than %d times per post/page/etc.', 'seo-ultimate')
52
- , 'limit_lpu' => __('Don&#8217;t link to the same destination any more than %d times per post/page/etc.', 'seo-ultimate')
53
- ), __('Quantity Restrictions', 'seo-ultimate'));
54
-
55
- $legacy_sitewide_lpa_in_use = $this->plugin->get_module_var('content-autolinks', 'legacy_sitewide_lpa_in_use', false);
56
- $this->checkboxes(array(
57
- 'dampen_sitewide_lpa' => __('Globally decrease autolinking frequency by %d%', 'seo-ultimate')
58
- , 'enable_perlink_dampen_sitewide_lpa' => array(
59
- 'description' => __('Add a &#8220;Dampener&#8221; column to the Content Links editor to let me customize frequency dampening on a per-link basis', 'seo-ultimate')
60
- , 'disabled' => $legacy_sitewide_lpa_in_use
61
- , 'checked' => $legacy_sitewide_lpa_in_use ? true : null
62
- )
63
- ), __('Additional Dampening Effect', 'seo-ultimate'));
64
-
65
- $this->textbox('linkfree_tags', __('Tag Restrictions', 'seo-ultimate'), $this->get_default_setting('linkfree_tags'), false, array('help_text' => __('Don&#8217;t add autolinks to text within these HTML tags <em>(separate with commas)</em>:', 'seo-ultimate')));
66
-
67
- $siloing_checkboxes = array();
68
- $post_types = get_post_types(array('public' => true), 'objects');
69
- foreach ($post_types as $post_type) {
70
- $taxonomies = suwp::get_object_taxonomies($post_type->name);
71
- if (count($taxonomies)) {
72
- $siloing_checkboxes['dest_limit_' . $post_type->name] = sprintf(
73
- __('%s can only link to internal destinations that share at least one...', 'seo-ultimate')
74
- , $post_type->labels->name
75
- );
76
-
77
- foreach ($taxonomies as $taxonomy) {
78
- $siloing_checkboxes['dest_limit_' . $post_type->name . '_within_' . $taxonomy->name] = array(
79
- 'description' => $taxonomy->labels->singular_name
80
- , 'indent' => true
81
- );
82
- }
83
- }
84
- }
85
-
86
- $this->checkboxes($siloing_checkboxes, __('Siloing', 'seo-ultimate'));
87
-
88
- $this->textbox('autolink_class', __('CSS Class for Autolinks', 'seo-ultimate'));
89
-
90
- $this->admin_form_table_end();
91
- }
92
- }
93
-
94
- }
95
  ?>
1
+ <?php
2
+ /**
3
+ * Content Deeplink Juggernaut Settings Module
4
+ *
5
+ * @since 2.2
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_ContentAutolinksSettings extends SU_Module {
11
+
12
+ static function get_parent_module() { return 'autolinks'; }
13
+ static function get_child_order() { return 20; }
14
+ static function is_independent_module() { return false; }
15
+
16
+ static function get_module_title() { return __('Content Deeplink Juggernaut Settings', 'seo-ultimate'); }
17
+ function get_module_subtitle() { return __('Content Link Settings', 'seo-ultimate'); }
18
+
19
+ function get_default_settings() {
20
+
21
+ $defaults = array(
22
+ 'dampen_sitewide_lpa_value' => 50
23
+ , 'enable_perlink_dampen_sitewide_lpa' => ($this->get_setting('enable_link_limits') !== null)
24
+ , 'enable_self_links' => false
25
+ , 'enable_current_url_links' => $this->get_setting('enable_self_links', false)
26
+ , 'limit_lpp_value' => 5
27
+ , 'limit_lpa_value' => 2
28
+ , 'limit_lpu_value' => 1
29
+ , 'linkfree_tags' => 'code,pre,kbd,h1,h2,h3,h4,h5,h6'
30
+ );
31
+
32
+ $defaults = array_merge($defaults, array_fill_keys(suarr::aprintf(false, 'autolink_posttype_%s', get_post_types(array('public' => true), 'names')), true));
33
+
34
+ return $defaults;
35
+ }
36
+
37
+ function admin_page_contents() {
38
+ $this->admin_form_table_start();
39
+
40
+ $this->checkboxes(
41
+ suarr::aprintf('autolink_posttype_%s', false, suarr::simplify(get_post_types(array('public' => true), 'objects'), 'name', array('labels', 'name')))
42
+ , __('Add Autolinks to...', 'seo-ultimate'));
43
+
44
+ $this->checkboxes(array(
45
+ 'enable_self_links' => __('Allow posts to link to themselves', 'seo-ultimate')
46
+ , 'enable_current_url_links' => __('Allow posts to link to the URL by which the visitor is accessing the post', 'seo-ultimate')
47
+ ), __('Self-Linking', 'seo-ultimate'));
48
+
49
+ $this->checkboxes(array(
50
+ 'limit_lpp' => __('Don&#8217;t add any more than %d autolinks per post/page/etc.', 'seo-ultimate')
51
+ , 'limit_lpa' => __('Don&#8217;t link the same anchor text any more than %d times per post/page/etc.', 'seo-ultimate')
52
+ , 'limit_lpu' => __('Don&#8217;t link to the same destination any more than %d times per post/page/etc.', 'seo-ultimate')
53
+ ), __('Quantity Restrictions', 'seo-ultimate'));
54
+
55
+ $legacy_sitewide_lpa_in_use = $this->plugin->get_module_var('content-autolinks', 'legacy_sitewide_lpa_in_use', false);
56
+ $this->checkboxes(array(
57
+ 'dampen_sitewide_lpa' => __('Globally decrease autolinking frequency by %d%', 'seo-ultimate')
58
+ , 'enable_perlink_dampen_sitewide_lpa' => array(
59
+ 'description' => __('Add a &#8220;Dampener&#8221; column to the Content Links editor to let me customize frequency dampening on a per-link basis', 'seo-ultimate')
60
+ , 'disabled' => $legacy_sitewide_lpa_in_use
61
+ , 'checked' => $legacy_sitewide_lpa_in_use ? true : null
62
+ )
63
+ ), __('Additional Dampening Effect', 'seo-ultimate'));
64
+
65
+ $this->textbox('linkfree_tags', __('Tag Restrictions', 'seo-ultimate'), $this->get_default_setting('linkfree_tags'), false, array('help_text' => __('Don&#8217;t add autolinks to text within these HTML tags <em>(separate with commas)</em>:', 'seo-ultimate')));
66
+
67
+ $siloing_checkboxes = array();
68
+ $post_types = get_post_types(array('public' => true), 'objects');
69
+ foreach ($post_types as $post_type) {
70
+ $taxonomies = suwp::get_object_taxonomies($post_type->name);
71
+ if (count($taxonomies)) {
72
+ $siloing_checkboxes['dest_limit_' . $post_type->name] = sprintf(
73
+ __('%s can only link to internal destinations that share at least one...', 'seo-ultimate')
74
+ , $post_type->labels->name
75
+ );
76
+
77
+ foreach ($taxonomies as $taxonomy) {
78
+ $siloing_checkboxes['dest_limit_' . $post_type->name . '_within_' . $taxonomy->name] = array(
79
+ 'description' => $taxonomy->labels->singular_name
80
+ , 'indent' => true
81
+ );
82
+ }
83
+ }
84
+ }
85
+
86
+ $this->checkboxes($siloing_checkboxes, __('Siloing', 'seo-ultimate'));
87
+
88
+ $this->textbox('autolink_class', __('CSS Class for Autolinks', 'seo-ultimate'));
89
+
90
+ $this->admin_form_table_end();
91
+ }
92
+ }
93
+
94
+ }
95
  ?>
modules/autolinks/content-autolinks.php CHANGED
@@ -103,7 +103,8 @@ class SU_ContentAutolinks extends SU_Module {
103
  $dest_limit = $from_post_type ? (bool)$this->get_setting('dest_limit_' . $from_post_type, false) : false;
104
  $dest_limit_taxonomies = array();
105
  if ($dest_limit) {
106
- $from_post_type_taxonomies = suwp::get_object_taxonomy_names($from_post_type);
 
107
  foreach ($from_post_type_taxonomies as $from_post_type_taxonomy) {
108
  if ($this->get_setting('dest_limit_' . $from_post_type . '_within_' . $from_post_type_taxonomy, false))
109
  $dest_limit_taxonomies[] = $from_post_type_taxonomy;
@@ -490,4 +491,4 @@ class SU_ContentAutolinks extends SU_Module {
490
  }
491
 
492
  }
493
- ?>
103
  $dest_limit = $from_post_type ? (bool)$this->get_setting('dest_limit_' . $from_post_type, false) : false;
104
  $dest_limit_taxonomies = array();
105
  if ($dest_limit) {
106
+ //$from_post_type_taxonomies = suwp::get_object_taxonomy_names($from_post_type);
107
+ $from_post_type_taxonomies = suwp::get_taxonomy_names($from_post_type);
108
  foreach ($from_post_type_taxonomies as $from_post_type_taxonomy) {
109
  if ($this->get_setting('dest_limit_' . $from_post_type . '_within_' . $from_post_type_taxonomy, false))
110
  $dest_limit_taxonomies[] = $from_post_type_taxonomy;
491
  }
492
 
493
  }
494
+ ?>
modules/autolinks/footer-autolinks-settings.php CHANGED
@@ -1,40 +1,40 @@
1
- <?php
2
- /**
3
- * Footer Deeplink Juggernaut Settings Module
4
- *
5
- * @since 6.5
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_FooterAutolinksSettings extends SU_Module {
11
-
12
- static function get_parent_module() { return 'autolinks'; }
13
- static function get_child_order() { return 40; }
14
- static function is_independent_module() { return false; }
15
-
16
- static function get_module_title() { return __('Footer Deeplink Juggernaut Settings', 'seo-ultimate'); }
17
- function get_module_subtitle() { return __('Footer Link Settings', 'seo-ultimate'); }
18
-
19
- function get_default_settings() {
20
- return array(
21
- 'footer_link_section_format' => '<div id="su-footer-links" style="text-align: center;">{links}</div>'
22
- , 'footer_link_format' => '{link}'
23
- , 'footer_link_sep' => ' | '
24
- );
25
- }
26
-
27
- function admin_page_contents() {
28
- $this->admin_subheader(__('HTML Formats', 'seo-ultimate'));
29
- $this->admin_form_table_start();
30
- $this->textareas(array(
31
- 'footer_link_section_format' => __('Link Section Format', 'seo-ultimate')
32
- , 'footer_link_format' => __('Link Format', 'seo-ultimate')
33
- ));
34
- $this->textbox('footer_link_sep', __('Link Separator', 'seo-ultimate'));
35
- $this->admin_form_table_end();
36
- }
37
- }
38
-
39
- }
40
  ?>
1
+ <?php
2
+ /**
3
+ * Footer Deeplink Juggernaut Settings Module
4
+ *
5
+ * @since 6.5
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_FooterAutolinksSettings extends SU_Module {
11
+
12
+ static function get_parent_module() { return 'autolinks'; }
13
+ static function get_child_order() { return 40; }
14
+ static function is_independent_module() { return false; }
15
+
16
+ static function get_module_title() { return __('Footer Deeplink Juggernaut Settings', 'seo-ultimate'); }
17
+ function get_module_subtitle() { return __('Footer Link Settings', 'seo-ultimate'); }
18
+
19
+ function get_default_settings() {
20
+ return array(
21
+ 'footer_link_section_format' => '<div id="su-footer-links" style="text-align: center;">{links}</div>'
22
+ , 'footer_link_format' => '{link}'
23
+ , 'footer_link_sep' => ' | '
24
+ );
25
+ }
26
+
27
+ function admin_page_contents() {
28
+ $this->admin_subheader(__('HTML Formats', 'seo-ultimate'));
29
+ $this->admin_form_table_start();
30
+ $this->textareas(array(
31
+ 'footer_link_section_format' => __('Link Section Format', 'seo-ultimate')
32
+ , 'footer_link_format' => __('Link Format', 'seo-ultimate')
33
+ ));
34
+ $this->textbox('footer_link_sep', __('Link Separator', 'seo-ultimate'));
35
+ $this->admin_form_table_end();
36
+ }
37
+ }
38
+
39
+ }
40
  ?>
modules/autolinks/footer-autolinks.php CHANGED
@@ -1,227 +1,227 @@
1
- <?php
2
- /**
3
- * Footer Deeplink Juggernaut Module
4
- *
5
- * @since 6.5
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_FooterAutolinks extends SU_Module {
11
-
12
- static function get_parent_module() { return 'autolinks'; }
13
- static function get_child_order() { return 30; }
14
- static function is_independent_module() { return false; }
15
-
16
- static function get_module_title() { return __('Footer Deeplink Juggernaut', 'seo-ultimate'); }
17
- function get_module_subtitle() { return __('Footer Links', 'seo-ultimate'); }
18
-
19
- var $already_outputted = false;
20
-
21
- function init() {
22
- add_action('wp_footer', array(&$this, 'autolink_footer'));
23
- }
24
-
25
- function autolink_footer($args=array()) {
26
-
27
- if ($this->already_outputted) return;
28
-
29
- extract(wp_parse_args($args, array(
30
- 'footer_link_section_format' => $this->get_setting('footer_link_section_format', '{links}')
31
- , 'footer_link_format' => $this->get_setting('footer_link_format', '{link}')
32
- , 'footer_link_sep' => $this->get_setting('footer_link_sep', ' | ')
33
- )), EXTR_SKIP);
34
-
35
- $links = $this->get_setting('footer_links', array());
36
- suarr::vksort($links, 'anchor');
37
-
38
- $link_html = array();
39
-
40
- foreach ($links as $link_data) {
41
-
42
- if (isset($link_data['from']) && count($link_data['from']))
43
- $from = $link_data['from'][0];
44
- else
45
- $from = array('');
46
-
47
- $from_match_children = (isset($link_data['from_match_children']) && $link_data['from_match_children']);
48
- $from_match_negative = (isset($link_data['from_match_negative']) && $link_data['from_match_negative']);
49
-
50
- if (!isset($link_data['to'])) $link_data['to'] = '';
51
-
52
- list($from_genus, $from_type, $from_id) = $this->jlsuggest_value_explode($from);
53
-
54
- $is_from = $from_match_negative;
55
- switch ($from_genus) {
56
- case 'posttype':
57
-
58
- $post_ids = array($from_id);
59
-
60
- if ($from_match_children)
61
- $post_ids[] = wp_get_post_parent_id($from_id); //Requires WordPress 3.1
62
-
63
- foreach ($post_ids as $post_id) {
64
- if (is_single($post_id) || is_page($post_id)) {
65
- $is_from = !$from_match_negative;
66
- break;
67
- }
68
- }
69
- break;
70
-
71
- case 'taxonomy':
72
-
73
- if ( suwp::is_tax($from_type, $from_id) //Is
74
- || ($from_match_children && is_singular() && has_term($from_id, $from_type)) //In
75
- )
76
- $is_from = !$from_match_negative;
77
- break;
78
-
79
- case 'home':
80
- if (is_home())
81
- $is_from = !$from_match_negative;
82
- break;
83
-
84
- case 'author':
85
- if ( is_author($from_id)
86
- || ($from_match_children && is_singular() && get_the_author_meta('id') == $from_id)
87
- )
88
- $is_from = !$from_match_negative;
89
- break;
90
-
91
- case 'url':
92
-
93
- if ($from_id) {
94
- if ( suurl::equal(suurl::current(), $from_id)
95
- || ($from_match_children && sustr::startswith(suurl::current(), $from_id))
96
- )
97
- $is_from = !$from_match_negative;
98
-
99
- } else
100
- $is_from = true; //No "from" restriction
101
-
102
- break;
103
- }
104
-
105
- if (!$is_from)
106
- continue;
107
-
108
- $h_anchor = esc_html($link_data['anchor']);
109
- $rel = $link_data['nofollow'] ? ' rel="nofollow"' : '';
110
- $target = ($link_data['target'] == 'blank') ? ' target="_blank"' : '';
111
- $title = strlen($a_titletext = su_esc_attr($link_data['title'])) ? " title=\"$a_titletext\"" : '';
112
-
113
- $a_url = su_esc_attr($this->jlsuggest_value_to_url($link_data['to']));
114
-
115
- if (strlen(trim($h_anchor)) && strlen(trim((string)$a_url)) && $a_url != 'http://')
116
- $link_html[] = str_replace('{link}', "<a href=\"$a_url\"$title$rel$target>$h_anchor</a>", $footer_link_format);
117
- }
118
-
119
- echo str_replace('{links}', implode($footer_link_sep, $link_html), $footer_link_section_format);
120
- }
121
-
122
- function admin_page_init() {
123
- $this->jlsuggest_init();
124
- }
125
-
126
- function admin_page_contents() {
127
-
128
- $links = $this->get_setting('footer_links', array());
129
- $num_links = count($links);
130
-
131
- if ($this->is_action('update')) {
132
-
133
- $links = array();
134
-
135
- for ($i=0; $i <= $num_links; $i++) {
136
-
137
- $anchor = stripslashes($_POST["footer_link_{$i}_anchor"]);
138
- $from = array(stripslashes($_POST["footer_link_{$i}_from"]));
139
- $from_match_children = isset($_POST["footer_link_{$i}_from_match_children"]) ? (intval($_POST["footer_link_{$i}_from_match_children"]) == 1) : false;
140
- $from_match_negative = isset($_POST["footer_link_{$i}_from_match_negative"]) ? (intval($_POST["footer_link_{$i}_from_match_negative"]) == 1) : false;
141
- $to = stripslashes($_POST["footer_link_{$i}_to"]);
142
- $title = stripslashes($_POST["footer_link_{$i}_title"]);
143
- $target = empty($_POST["footer_link_{$i}_target"]) ? 'self' : 'blank';
144
-
145
- $nofollow = isset($_POST["footer_link_{$i}_nofollow"]) ? (intval($_POST["footer_link_{$i}_nofollow"]) == 1) : false;
146
- $delete = isset($_POST["footer_link_{$i}_delete"]) ? (intval($_POST["footer_link_{$i}_delete"]) == 1) : false;
147
-
148
- if (!$delete && (strlen($anchor) || $to))
149
- $links[] = compact('anchor', 'from', 'from_match_children', 'from_match_negative', 'to', 'title', 'nofollow', 'target');
150
- }
151
- $this->update_setting('footer_links', $links);
152
-
153
- $num_links = count($links);
154
- }
155
-
156
- if ($num_links > 0) {
157
- $this->admin_subheader(__('Edit Existing Links', 'seo-ultimate'));
158
- $this->footer_links_form(0, $links);
159
- }
160
-
161
- $this->admin_subheader(__('Add a New Link', 'seo-ultimate'));
162
- $this->footer_links_form($num_links, array(array()), false);
163
- }
164
-
165
- function footer_links_form($start_id = 0, $links, $delete_option = true) {
166
-
167
- //Set headers
168
- $headers = array(
169
- 'link-from' => __('Link Location <em>(optional)</em>', 'seo-ultimate')
170
- , 'link-from-match' => ''
171
- , 'link-anchor' => __('Anchor Text', 'seo-ultimate')
172
- , 'link-to' => __('Destination', 'seo-ultimate')
173
- , 'link-title' => __('Title Attribute <em>(optional)</em>', 'seo-ultimate')
174
- , 'link-options' => __('Options', 'seo-ultimate')
175
- );
176
- if ($delete_option) $headers['link-delete'] = __('Delete', 'seo-ultimate');
177
-
178
- //Begin table; output headers
179
- $this->admin_wftable_start($headers);
180
-
181
- //Cycle through links
182
- $i = $start_id;
183
- foreach ($links as $link) {
184
-
185
- if (!isset($link['anchor'])) $link['anchor'] = '';
186
- if (!isset($link['from'][0])) $link['from'][0] = '';
187
- if (!isset($link['from_match_children'])) $link['from_match_children'] = false;
188
- if (!isset($link['from_match_negative'])) $link['from_match_negative'] = false;
189
- if (!isset($link['to'])) $link['to'] = '';
190
- if (!isset($link['title'])) $link['title'] = '';
191
- if (!isset($link['nofollow'])) $link['nofollow'] = false;
192
- if (!isset($link['target'])) $link['target'] = '';
193
-
194
- $cells = array(
195
- 'link-from' => $this->get_jlsuggest_box("footer_link_{$i}_from", $link['from'][0], 'types=posttype,taxonomy,home,author')
196
- , 'link-from-match' =>
197
- $this->get_input_element('checkbox', "footer_link_{$i}_from_match_children", $link['from_match_children'] == 1, str_replace(' ', '&nbsp;', __('Match child content', 'seo-ultimate')))
198
- .'<br />'
199
- .$this->get_input_element('checkbox', "footer_link_{$i}_from_match_negative", $link['from_match_negative'] == 1, str_replace(' ', '&nbsp;', __('Negative match', 'seo-ultimate')))
200
- /*, 'link-from-match' => $this->get_input_element('dropdown', "footer_link_{$i}_from_match", $link['from_match'], array(
201
- 'is' => __('If this:', 'seo-ultimate')
202
- , 'is,in' => __('If this or child:', 'seo-ultimate')
203
- , '!:is' => __('If not this:', 'seo-ultimate')
204
- , '!:is,in' => __('If not this and not child:', 'seo-ultimate')
205
- ))*/
206
- , 'link-anchor' => $this->get_input_element('textbox', "footer_link_{$i}_anchor", $link['anchor'])
207
- , 'link-to' => $this->get_jlsuggest_box("footer_link_{$i}_to", $link['to'])
208
- , 'link-title' => $this->get_input_element('textbox', "footer_link_{$i}_title", $link['title'])
209
- , 'link-options' =>
210
- $this->get_input_element('checkbox', "footer_link_{$i}_nofollow", $link['nofollow'], str_replace(' ', '&nbsp;', __('Nofollow', 'seo-ultimate')))
211
- .'<br />'
212
- .$this->get_input_element('checkbox', "footer_link_{$i}_target", $link['target'] == 'blank', str_replace(' ', '&nbsp;', __('New window', 'seo-ultimate')))
213
- );
214
- if ($delete_option)
215
- $cells['link-delete'] = $this->get_input_element('checkbox', "footer_link_{$i}_delete");
216
-
217
- $this->table_row($cells, $i, 'link');
218
-
219
- $i++;
220
- }
221
-
222
- $this->admin_wftable_end();
223
- }
224
- }
225
-
226
- }
227
  ?>
1
+ <?php
2
+ /**
3
+ * Footer Deeplink Juggernaut Module
4
+ *
5
+ * @since 6.5
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_FooterAutolinks extends SU_Module {
11
+
12
+ static function get_parent_module() { return 'autolinks'; }
13
+ static function get_child_order() { return 30; }
14
+ static function is_independent_module() { return false; }
15
+
16
+ static function get_module_title() { return __('Footer Deeplink Juggernaut', 'seo-ultimate'); }
17
+ function get_module_subtitle() { return __('Footer Links', 'seo-ultimate'); }
18
+
19
+ var $already_outputted = false;
20
+
21
+ function init() {
22
+ add_action('wp_footer', array(&$this, 'autolink_footer'));
23
+ }
24
+
25
+ function autolink_footer($args=array()) {
26
+
27
+ if ($this->already_outputted) return;
28
+
29
+ extract(wp_parse_args($args, array(
30
+ 'footer_link_section_format' => $this->get_setting('footer_link_section_format', '{links}')
31
+ , 'footer_link_format' => $this->get_setting('footer_link_format', '{link}')
32
+ , 'footer_link_sep' => $this->get_setting('footer_link_sep', ' | ')
33
+ )), EXTR_SKIP);
34
+
35
+ $links = $this->get_setting('footer_links', array());
36
+ suarr::vksort($links, 'anchor');
37
+
38
+ $link_html = array();
39
+
40
+ foreach ($links as $link_data) {
41
+
42
+ if (isset($link_data['from']) && count($link_data['from']))
43
+ $from = $link_data['from'][0];
44
+ else
45
+ $from = array('');
46
+
47
+ $from_match_children = (isset($link_data['from_match_children']) && $link_data['from_match_children']);
48
+ $from_match_negative = (isset($link_data['from_match_negative']) && $link_data['from_match_negative']);
49
+
50
+ if (!isset($link_data['to'])) $link_data['to'] = '';
51
+
52
+ list($from_genus, $from_type, $from_id) = $this->jlsuggest_value_explode($from);
53
+
54
+ $is_from = $from_match_negative;
55
+ switch ($from_genus) {
56
+ case 'posttype':
57
+
58
+ $post_ids = array($from_id);
59
+
60
+ if ($from_match_children)
61
+ $post_ids[] = wp_get_post_parent_id($from_id); //Requires WordPress 3.1
62
+
63
+ foreach ($post_ids as $post_id) {
64
+ if (is_single($post_id) || is_page($post_id)) {
65
+ $is_from = !$from_match_negative;
66
+ break;
67
+ }
68
+ }
69
+ break;
70
+
71
+ case 'taxonomy':
72
+
73
+ if ( suwp::is_tax($from_type, $from_id) //Is
74
+ || ($from_match_children && is_singular() && has_term($from_id, $from_type)) //In
75
+ )
76
+ $is_from = !$from_match_negative;
77
+ break;
78
+
79
+ case 'home':
80
+ if (is_home())
81
+ $is_from = !$from_match_negative;
82
+ break;
83
+
84
+ case 'author':
85
+ if ( is_author($from_id)
86
+ || ($from_match_children && is_singular() && get_the_author_meta('id') == $from_id)
87
+ )
88
+ $is_from = !$from_match_negative;
89
+ break;
90
+
91
+ case 'url':
92
+
93
+ if ($from_id) {
94
+ if ( suurl::equal(suurl::current(), $from_id)
95
+ || ($from_match_children && sustr::startswith(suurl::current(), $from_id))
96
+ )
97
+ $is_from = !$from_match_negative;
98
+
99
+ } else
100
+ $is_from = true; //No "from" restriction
101
+
102
+ break;
103
+ }
104
+
105
+ if (!$is_from)
106
+ continue;
107
+
108
+ $h_anchor = esc_html($link_data['anchor']);
109
+ $rel = $link_data['nofollow'] ? ' rel="nofollow"' : '';
110
+ $target = ($link_data['target'] == 'blank') ? ' target="_blank"' : '';
111
+ $title = strlen($a_titletext = su_esc_attr($link_data['title'])) ? " title=\"$a_titletext\"" : '';
112
+
113
+ $a_url = su_esc_attr($this->jlsuggest_value_to_url($link_data['to']));
114
+
115
+ if (strlen(trim($h_anchor)) && strlen(trim((string)$a_url)) && $a_url != 'http://')
116
+ $link_html[] = str_replace('{link}', "<a href=\"$a_url\"$title$rel$target>$h_anchor</a>", $footer_link_format);
117
+ }
118
+
119
+ echo str_replace('{links}', implode($footer_link_sep, $link_html), $footer_link_section_format);
120
+ }
121
+
122
+ function admin_page_init() {
123
+ $this->jlsuggest_init();
124
+ }
125
+
126
+ function admin_page_contents() {
127
+
128
+ $links = $this->get_setting('footer_links', array());
129
+ $num_links = count($links);
130
+
131
+ if ($this->is_action('update')) {
132
+
133
+ $links = array();
134
+
135
+ for ($i=0; $i <= $num_links; $i++) {
136
+
137
+ $anchor = stripslashes($_POST["footer_link_{$i}_anchor"]);
138
+ $from = array(stripslashes($_POST["footer_link_{$i}_from"]));
139
+ $from_match_children = isset($_POST["footer_link_{$i}_from_match_children"]) ? (intval($_POST["footer_link_{$i}_from_match_children"]) == 1) : false;
140
+ $from_match_negative = isset($_POST["footer_link_{$i}_from_match_negative"]) ? (intval($_POST["footer_link_{$i}_from_match_negative"]) == 1) : false;
141
+ $to = stripslashes($_POST["footer_link_{$i}_to"]);
142
+ $title = stripslashes($_POST["footer_link_{$i}_title"]);
143
+ $target = empty($_POST["footer_link_{$i}_target"]) ? 'self' : 'blank';
144
+
145
+ $nofollow = isset($_POST["footer_link_{$i}_nofollow"]) ? (intval($_POST["footer_link_{$i}_nofollow"]) == 1) : false;
146
+ $delete = isset($_POST["footer_link_{$i}_delete"]) ? (intval($_POST["footer_link_{$i}_delete"]) == 1) : false;
147
+
148
+ if (!$delete && (strlen($anchor) || $to))
149
+ $links[] = compact('anchor', 'from', 'from_match_children', 'from_match_negative', 'to', 'title', 'nofollow', 'target');
150
+ }
151
+ $this->update_setting('footer_links', $links);
152
+
153
+ $num_links = count($links);
154
+ }
155
+
156
+ if ($num_links > 0) {
157
+ $this->admin_subheader(__('Edit Existing Links', 'seo-ultimate'));
158
+ $this->footer_links_form(0, $links);
159
+ }
160
+
161
+ $this->admin_subheader(__('Add a New Link', 'seo-ultimate'));
162
+ $this->footer_links_form($num_links, array(array()), false);
163
+ }
164
+
165
+ function footer_links_form($start_id = 0, $links, $delete_option = true) {
166
+
167
+ //Set headers
168
+ $headers = array(
169
+ 'link-from' => __('Link Location <em>(optional)</em>', 'seo-ultimate')
170
+ , 'link-from-match' => ''
171
+ , 'link-anchor' => __('Anchor Text', 'seo-ultimate')
172
+ , 'link-to' => __('Destination', 'seo-ultimate')
173
+ , 'link-title' => __('Title Attribute <em>(optional)</em>', 'seo-ultimate')
174
+ , 'link-options' => __('Options', 'seo-ultimate')
175
+ );
176
+ if ($delete_option) $headers['link-delete'] = __('Delete', 'seo-ultimate');
177
+
178
+ //Begin table; output headers
179
+ $this->admin_wftable_start($headers);
180
+
181
+ //Cycle through links
182
+ $i = $start_id;
183
+ foreach ($links as $link) {
184
+
185
+ if (!isset($link['anchor'])) $link['anchor'] = '';
186
+ if (!isset($link['from'][0])) $link['from'][0] = '';
187
+ if (!isset($link['from_match_children'])) $link['from_match_children'] = false;
188
+ if (!isset($link['from_match_negative'])) $link['from_match_negative'] = false;
189
+ if (!isset($link['to'])) $link['to'] = '';
190
+ if (!isset($link['title'])) $link['title'] = '';
191
+ if (!isset($link['nofollow'])) $link['nofollow'] = false;
192
+ if (!isset($link['target'])) $link['target'] = '';
193
+
194
+ $cells = array(
195
+ 'link-from' => $this->get_jlsuggest_box("footer_link_{$i}_from", $link['from'][0], 'types=posttype,taxonomy,home,author')
196
+ , 'link-from-match' =>
197
+ $this->get_input_element('checkbox', "footer_link_{$i}_from_match_children", $link['from_match_children'] == 1, str_replace(' ', '&nbsp;', __('Match child content', 'seo-ultimate')))
198
+ .'<br />'
199
+ .$this->get_input_element('checkbox', "footer_link_{$i}_from_match_negative", $link['from_match_negative'] == 1, str_replace(' ', '&nbsp;', __('Negative match', 'seo-ultimate')))
200
+ /*, 'link-from-match' => $this->get_input_element('dropdown', "footer_link_{$i}_from_match", $link['from_match'], array(
201
+ 'is' => __('If this:', 'seo-ultimate')
202
+ , 'is,in' => __('If this or child:', 'seo-ultimate')
203
+ , '!:is' => __('If not this:', 'seo-ultimate')
204
+ , '!:is,in' => __('If not this and not child:', 'seo-ultimate')
205
+ ))*/
206
+ , 'link-anchor' => $this->get_input_element('textbox', "footer_link_{$i}_anchor", $link['anchor'])
207
+ , 'link-to' => $this->get_jlsuggest_box("footer_link_{$i}_to", $link['to'])
208
+ , 'link-title' => $this->get_input_element('textbox', "footer_link_{$i}_title", $link['title'])
209
+ , 'link-options' =>
210
+ $this->get_input_element('checkbox', "footer_link_{$i}_nofollow", $link['nofollow'], str_replace(' ', '&nbsp;', __('Nofollow', 'seo-ultimate')))
211
+ .'<br />'
212
+ .$this->get_input_element('checkbox', "footer_link_{$i}_target", $link['target'] == 'blank', str_replace(' ', '&nbsp;', __('New window', 'seo-ultimate')))
213
+ );
214
+ if ($delete_option)
215
+ $cells['link-delete'] = $this->get_input_element('checkbox', "footer_link_{$i}_delete");
216
+
217
+ $this->table_row($cells, $i, 'link');
218
+
219
+ $i++;
220
+ }
221
+
222
+ $this->admin_wftable_end();
223
+ }
224
+ }
225
+
226
+ }
227
  ?>
modules/autolinks/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/canonical/canonical.php CHANGED
@@ -1,237 +1,237 @@
1
- <?php
2
- /**
3
- * Canonicalizer Module
4
- *
5
- * @since 0.3
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_Canonical extends SU_Module {
11
-
12
- static function get_module_title() { return __('Canonicalizer', 'seo-ultimate'); }
13
-
14
- static function get_parent_module() { return 'misc'; }
15
- function get_settings_key() { return 'canonical'; }
16
-
17
- function init() {
18
- add_filter('su_get_setting-canonical-canonical_url_scheme', array(&$this, 'filter_canonical_url_scheme'));
19
-
20
- //If the canonical tags are enabled, then...
21
- if ($this->get_setting('link_rel_canonical')) {
22
-
23
- //...remove WordPress's default canonical tags (since they only handle posts/pages/attachments)
24
- remove_action('wp_head', 'rel_canonical');
25
-
26
- //...and add our custom canonical tags.
27
- add_action('su_head', array(&$this, 'link_rel_canonical_tag'));
28
- }
29
-
30
- if ($this->get_setting('http_link_rel_canonical'))
31
- add_action('template_redirect', array(&$this, 'http_link_rel_canonical'), 11, 0);
32
-
33
- //Should we remove nonexistent pagination?
34
- if ($this->get_setting('remove_nonexistent_pagination'))
35
- add_action('template_redirect', array(&$this, 'remove_nonexistent_pagination'), 11);
36
- }
37
-
38
- function admin_page_contents() {
39
- $this->child_admin_form_start();
40
- $this->checkboxes(array(
41
- 'link_rel_canonical' => __('Generate <code>&lt;link rel=&quot;canonical&quot; /&gt;</code> meta tags', 'seo-ultimate')
42
- , 'http_link_rel_canonical' => __('Send <code>rel=&quot;canonical&quot;</code> HTTP headers', 'seo-ultimate')
43
- ), __('Canonical URL Generation', 'seo-ultimate'));
44
- $this->radiobuttons('canonical_url_scheme', array(
45
- '' => __('Use <code>http://</code> or <code>https://</code> depending on how the visitor accessed the page', 'seo-ultimate')
46
- , 'http' => __('Make all canonical URLs begin with <code>http://</code>', 'seo-ultimate')
47
- , 'https' => __('Make all canonical URLs begin with <code>https://</code>', 'seo-ultimate')
48
- ), __('Canonical URL Scheme', 'seo-ultimate'));
49
- $this->checkboxes(array(
50
- 'remove_nonexistent_pagination' => __('Redirect requests for nonexistent pagination', 'seo-ultimate')
51
- ), __('Automated 301 Redirects', 'seo-ultimate'));
52
- $this->child_admin_form_end();
53
- }
54
-
55
- function link_rel_canonical_tag() {
56
- //Display the canonical tag if a canonical URL is available
57
- if ($url = $this->get_canonical_url()) {
58
- $url = su_esc_attr($url);
59
- echo "\t<link rel=\"canonical\" href=\"$url\" />\n";
60
- }
61
- }
62
-
63
- function http_link_rel_canonical() {
64
- if (headers_sent())
65
- return;
66
-
67
- if ($url = $this->get_canonical_url()) {
68
- $url = su_esc_attr($url);
69
- header("Link: <$url>; rel=\"canonical\"", false);
70
- }
71
- }
72
-
73
- /**
74
- * Returns the canonical URL to put in the link-rel-canonical tag.
75
- *
76
- * This function is modified from the GPL-licensed {@link http://wordpress.org/extend/plugins/canonical/ Canonical URLs} plugin,
77
- * which in turn was heavily based on the {@link http://svn.fucoder.com/fucoder/permalink-redirect/ Permalink Redirect} plugin.
78
- */
79
- function get_canonical_url() {
80
- global $wp_query, $wp_rewrite;
81
-
82
- //404s and search results don't have canonical URLs
83
- if ($wp_query->is_404 || $wp_query->is_search) return false;
84
-
85
- //Are there posts in the current Loop?
86
- $haspost = count($wp_query->posts) > 0;
87
-
88
- //Handling special case with '?m=yyyymmddHHMMSS'.
89
- if (get_query_var('m')) {
90
- $m = preg_replace('/[^0-9]/', '', get_query_var('m'));
91
- switch (strlen($m)) {
92
- case 4: // Yearly
93
- $link = get_year_link($m);
94
- break;
95
- case 6: // Monthly
96
- $link = get_month_link(substr($m, 0, 4), substr($m, 4, 2));
97
- break;
98
- case 8: // Daily
99
- $link = get_day_link(substr($m, 0, 4), substr($m, 4, 2),
100
- substr($m, 6, 2));
101
- break;
102
- default:
103
- //Since there is no code for producing canonical archive links for is_time, we will give up and not try to produce a link.
104
- return false;
105
- }
106
-
107
- //Posts and pages
108
- } elseif (($wp_query->is_single || $wp_query->is_page) && $haspost) {
109
- $post = $wp_query->posts[0];
110
- $link = get_permalink($post->ID);
111
- if (is_front_page()) $link = trailingslashit($link);
112
-
113
- //Author archives
114
- } elseif ($wp_query->is_author && $haspost) {
115
- $author = get_userdata(get_query_var('author'));
116
- if ($author === false) return false;
117
- $link = get_author_posts_url($author->ID, $author->user_nicename);
118
-
119
- //Category archives
120
- } elseif ($wp_query->is_category && $haspost) {
121
- $link = get_category_link(get_query_var('cat'));
122
-
123
- //Tag archives
124
- } else if ($wp_query->is_tag && $haspost) {
125
- $tag = get_term_by('slug',get_query_var('tag'),'post_tag');
126
- if (!empty($tag->term_id)) $link = get_tag_link($tag->term_id);
127
-
128
- //Day archives
129
- } elseif ($wp_query->is_day && $haspost) {
130
- $link = get_day_link(get_query_var('year'),
131
- get_query_var('monthnum'),
132
- get_query_var('day'));
133
-
134
- //Month archives
135
- } elseif ($wp_query->is_month && $haspost) {
136
- $link = get_month_link(get_query_var('year'),
137
- get_query_var('monthnum'));
138
-
139
- //Year archives
140
- } elseif ($wp_query->is_year && $haspost) {
141
- $link = get_year_link(get_query_var('year'));
142
-
143
- //Homepage
144
- } elseif ($wp_query->is_home) {
145
- if ((get_option('show_on_front') == 'page') && ($pageid = get_option('page_for_posts')))
146
- $link = trailingslashit(get_permalink($pageid));
147
- else
148
- $link = trailingslashit(get_option('home'));
149
-
150
- //Other
151
- } else
152
- return false;
153
-
154
- //Handle pagination
155
- $page = get_query_var('paged');
156
- if ($page && $page > 1) {
157
- if ($wp_rewrite->using_permalinks()) {
158
- $link = trailingslashit($link) ."page/$page";
159
- $link = user_trailingslashit($link, 'paged');
160
- } else {
161
- $link = add_query_arg( 'paged', $page, $link );
162
- }
163
- }
164
-
165
- //Handle protocol change
166
- if ($scheme = $this->get_setting('canonical_url_scheme', 'http'))
167
- $link = preg_replace('@^https?://@', "$scheme://", $link);
168
-
169
- //Return the canonical URL
170
- return $link;
171
- }
172
-
173
- function remove_nonexistent_pagination() {
174
-
175
- if (!is_admin()) {
176
-
177
- global $wp_rewrite, $wp_query;
178
-
179
- $url = suurl::current();
180
-
181
- if (is_singular()) {
182
- $num = absint(get_query_var('page'));
183
- $post = $wp_query->get_queried_object();
184
- $max = count(explode('<!--nextpage-->', $post->post_content));
185
-
186
- if ($max > 0 && ($num == 1 || ($num > 1 && $num > $max))) {
187
-
188
- if ($wp_rewrite->using_permalinks())
189
- wp_redirect(preg_replace('|/[0-9]{1,9}/?$|', '/', $url), 301);
190
- else
191
- wp_redirect(remove_query_arg('page', $url), 301);
192
- }
193
-
194
- } elseif (is_404() && $num = absint(get_query_var('paged'))) {
195
-
196
- if ($wp_rewrite->using_permalinks())
197
- wp_redirect(preg_replace('|/page/[0-9]{1,9}/?$|', '/', $url), 301);
198
- else
199
- wp_redirect(remove_query_arg('paged', $url), 301);
200
- }
201
- }
202
- }
203
-
204
- function filter_canonical_url_scheme($scheme) {
205
- return sustr::preg_filter('a-z', $scheme);
206
- }
207
-
208
- function add_help_tabs($screen) {
209
-
210
- $overview = __("
211
- <ul>
212
- <li><strong>What it does:</strong> Canonicalizer will point Google to the correct URL for your homepage and each of your posts, Pages, categories, tags, date archives, and author archives.</li>
213
- <li><strong>Why it helps:</strong> 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 and won&#8217;t penalize you for having two identical pages on your site.</li>
214
- <li><strong>How to use it:</strong> Just check the three checkboxes. If your site is accessible using both <code>http://</code> and <code>https://</code>, be sure to set the preferred one under &#8220;Canonical URL Scheme.&#8221;</li>
215
- </ul>
216
- ", 'seo-ultimate');
217
-
218
- if ($this->has_enabled_parent()) {
219
- $screen->add_help_tab(array(
220
- 'id' => 'su-canonical-help'
221
- , 'title' => __('Canonicalizer', 'seo-ultimate')
222
- , 'content' =>
223
- '<h3>' . __('Overview', 'seo-ultimate') . '</h3>' . $overview
224
- ));
225
- } else {
226
-
227
- $screen->add_help_tab(array(
228
- 'id' => 'su-canonical-overview'
229
- , 'title' => __('Overview', 'seo-ultimate')
230
- , 'content' => $overview));
231
-
232
- }
233
- }
234
- }
235
-
236
- }
237
  ?>
1
+ <?php
2
+ /**
3
+ * Canonicalizer Module
4
+ *
5
+ * @since 0.3
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_Canonical extends SU_Module {
11
+
12
+ static function get_module_title() { return __('Canonicalizer', 'seo-ultimate'); }
13
+
14
+ static function get_parent_module() { return 'misc'; }
15
+ function get_settings_key() { return 'canonical'; }
16
+
17
+ function init() {
18
+ add_filter('su_get_setting-canonical-canonical_url_scheme', array(&$this, 'filter_canonical_url_scheme'));
19
+
20
+ //If the canonical tags are enabled, then...
21
+ if ($this->get_setting('link_rel_canonical')) {
22
+
23
+ //...remove WordPress's default canonical tags (since they only handle posts/pages/attachments)
24
+ remove_action('wp_head', 'rel_canonical');
25
+
26
+ //...and add our custom canonical tags.
27
+ add_action('su_head', array(&$this, 'link_rel_canonical_tag'));
28
+ }
29
+
30
+ if ($this->get_setting('http_link_rel_canonical'))
31
+ add_action('template_redirect', array(&$this, 'http_link_rel_canonical'), 11, 0);
32
+
33
+ //Should we remove nonexistent pagination?
34
+ if ($this->get_setting('remove_nonexistent_pagination'))
35
+ add_action('template_redirect', array(&$this, 'remove_nonexistent_pagination'), 11);
36
+ }
37
+
38
+ function admin_page_contents() {
39
+ $this->child_admin_form_start();
40
+ $this->checkboxes(array(
41
+ 'link_rel_canonical' => __('Generate <code>&lt;link rel=&quot;canonical&quot; /&gt;</code> meta tags', 'seo-ultimate')
42
+ , 'http_link_rel_canonical' => __('Send <code>rel=&quot;canonical&quot;</code> HTTP headers', 'seo-ultimate')
43
+ ), __('Canonical URL Generation', 'seo-ultimate'));
44
+ $this->radiobuttons('canonical_url_scheme', array(
45
+ '' => __('Use <code>http://</code> or <code>https://</code> depending on how the visitor accessed the page', 'seo-ultimate')
46
+ , 'http' => __('Make all canonical URLs begin with <code>http://</code>', 'seo-ultimate')
47
+ , 'https' => __('Make all canonical URLs begin with <code>https://</code>', 'seo-ultimate')
48
+ ), __('Canonical URL Scheme', 'seo-ultimate'));
49
+ $this->checkboxes(array(
50
+ 'remove_nonexistent_pagination' => __('Redirect requests for nonexistent pagination', 'seo-ultimate')
51
+ ), __('Automated 301 Redirects', 'seo-ultimate'));
52
+ $this->child_admin_form_end();
53
+ }
54
+
55
+ function link_rel_canonical_tag() {
56
+ //Display the canonical tag if a canonical URL is available
57
+ if ($url = $this->get_canonical_url()) {
58
+ $url = su_esc_attr($url);
59
+ echo "\t<link rel=\"canonical\" href=\"$url\" />\n";
60
+ }
61
+ }
62
+
63
+ function http_link_rel_canonical() {
64
+ if (headers_sent())
65
+ return;
66
+
67
+ if ($url = $this->get_canonical_url()) {
68
+ $url = su_esc_attr($url);
69
+ header("Link: <$url>; rel=\"canonical\"", false);
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Returns the canonical URL to put in the link-rel-canonical tag.
75
+ *
76
+ * This function is modified from the GPL-licensed {@link http://wordpress.org/extend/plugins/canonical/ Canonical URLs} plugin,
77
+ * which in turn was heavily based on the {@link http://svn.fucoder.com/fucoder/permalink-redirect/ Permalink Redirect} plugin.
78
+ */
79
+ function get_canonical_url() {
80
+ global $wp_query, $wp_rewrite;
81
+
82
+ //404s and search results don't have canonical URLs
83
+ if ($wp_query->is_404 || $wp_query->is_search) return false;
84
+
85
+ //Are there posts in the current Loop?
86
+ $haspost = count($wp_query->posts) > 0;
87
+
88
+ //Handling special case with '?m=yyyymmddHHMMSS'.
89
+ if (get_query_var('m')) {
90
+ $m = preg_replace('/[^0-9]/', '', get_query_var('m'));
91
+ switch (strlen($m)) {
92
+ case 4: // Yearly
93
+ $link = get_year_link($m);
94
+ break;
95
+ case 6: // Monthly
96
+ $link = get_month_link(substr($m, 0, 4), substr($m, 4, 2));
97
+ break;
98
+ case 8: // Daily
99
+ $link = get_day_link(substr($m, 0, 4), substr($m, 4, 2),
100
+ substr($m, 6, 2));
101
+ break;
102
+ default:
103
+ //Since there is no code for producing canonical archive links for is_time, we will give up and not try to produce a link.
104
+ return false;
105
+ }
106
+
107
+ //Posts and pages
108
+ } elseif (($wp_query->is_single || $wp_query->is_page) && $haspost) {
109
+ $post = $wp_query->posts[0];
110
+ $link = get_permalink($post->ID);
111
+ if (is_front_page()) $link = trailingslashit($link);
112
+
113
+ //Author archives
114
+ } elseif ($wp_query->is_author && $haspost) {
115
+ $author = get_userdata(get_query_var('author'));
116
+ if ($author === false) return false;
117
+ $link = get_author_posts_url($author->ID, $author->user_nicename);
118
+
119
+ //Category archives
120
+ } elseif ($wp_query->is_category && $haspost) {
121
+ $link = get_category_link(get_query_var('cat'));
122
+
123
+ //Tag archives
124
+ } else if ($wp_query->is_tag && $haspost) {
125
+ $tag = get_term_by('slug',get_query_var('tag'),'post_tag');
126
+ if (!empty($tag->term_id)) $link = get_tag_link($tag->term_id);
127
+
128
+ //Day archives
129
+ } elseif ($wp_query->is_day && $haspost) {
130
+ $link = get_day_link(get_query_var('year'),
131
+ get_query_var('monthnum'),
132
+ get_query_var('day'));
133
+
134
+ //Month archives
135
+ } elseif ($wp_query->is_month && $haspost) {
136
+ $link = get_month_link(get_query_var('year'),
137
+ get_query_var('monthnum'));
138
+
139
+ //Year archives
140
+ } elseif ($wp_query->is_year && $haspost) {
141
+ $link = get_year_link(get_query_var('year'));
142
+
143
+ //Homepage
144
+ } elseif ($wp_query->is_home) {
145
+ if ((get_option('show_on_front') == 'page') && ($pageid = get_option('page_for_posts')))
146
+ $link = trailingslashit(get_permalink($pageid));
147
+ else
148
+ $link = trailingslashit(get_option('home'));
149
+
150
+ //Other
151
+ } else
152
+ return false;
153
+
154
+ //Handle pagination
155
+ $page = get_query_var('paged');
156
+ if ($page && $page > 1) {
157
+ if ($wp_rewrite->using_permalinks()) {
158
+ $link = trailingslashit($link) ."page/$page";
159
+ $link = user_trailingslashit($link, 'paged');
160
+ } else {
161
+ $link = add_query_arg( 'paged', $page, $link );
162
+ }
163
+ }
164
+
165
+ //Handle protocol change
166
+ if ($scheme = $this->get_setting('canonical_url_scheme', 'http'))
167
+ $link = preg_replace('@^https?://@', "$scheme://", $link);
168
+
169
+ //Return the canonical URL
170
+ return $link;
171
+ }
172
+
173
+ function remove_nonexistent_pagination() {
174
+
175
+ if (!is_admin()) {
176
+
177
+ global $wp_rewrite, $wp_query;
178
+
179
+ $url = suurl::current();
180
+
181
+ if (is_singular()) {
182
+ $num = absint(get_query_var('page'));
183
+ $post = $wp_query->get_queried_object();
184
+ $max = count(explode('<!--nextpage-->', $post->post_content));
185
+
186
+ if ($max > 0 && ($num == 1 || ($num > 1 && $num > $max))) {
187
+
188
+ if ($wp_rewrite->using_permalinks())
189
+ wp_redirect(preg_replace('|/[0-9]{1,9}/?$|', '/', $url), 301);
190
+ else
191
+ wp_redirect(remove_query_arg('page', $url), 301);
192
+ }
193
+
194
+ } elseif (is_404() && $num = absint(get_query_var('paged'))) {
195
+
196
+ if ($wp_rewrite->using_permalinks())
197
+ wp_redirect(preg_replace('|/page/[0-9]{1,9}/?$|', '/', $url), 301);
198
+ else
199
+ wp_redirect(remove_query_arg('paged', $url), 301);
200
+ }
201
+ }
202
+ }
203
+
204
+ function filter_canonical_url_scheme($scheme) {
205
+ return sustr::preg_filter('a-z', $scheme);
206
+ }
207
+
208
+ function add_help_tabs($screen) {
209
+
210
+ $overview = __("
211
+ <ul>
212
+ <li><strong>What it does:</strong> Canonicalizer will point Google to the correct URL for your homepage and each of your posts, Pages, categories, tags, date archives, and author archives.</li>
213
+ <li><strong>Why it helps:</strong> 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 and won&#8217;t penalize you for having two identical pages on your site.</li>
214
+ <li><strong>How to use it:</strong> Just check the three checkboxes. If your site is accessible using both <code>http://</code> and <code>https://</code>, be sure to set the preferred one under &#8220;Canonical URL Scheme.&#8221;</li>
215
+ </ul>
216
+ ", 'seo-ultimate');
217
+
218
+ if ($this->has_enabled_parent()) {
219
+ $screen->add_help_tab(array(
220
+ 'id' => 'su-canonical-help'
221
+ , 'title' => __('Canonicalizer', 'seo-ultimate')
222
+ , 'content' =>
223
+ '<h3>' . __('Overview', 'seo-ultimate') . '</h3>' . $overview
224
+ ));
225
+ } else {
226
+
227
+ $screen->add_help_tab(array(
228
+ 'id' => 'su-canonical-overview'
229
+ , 'title' => __('Overview', 'seo-ultimate')
230
+ , 'content' => $overview));
231
+
232
+ }
233
+ }
234
+ }
235
+
236
+ }
237
  ?>
modules/canonical/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/class.su-importmodule.php CHANGED
@@ -1,200 +1,200 @@
1
- <?php
2
- /**
3
- * Import Module
4
- *
5
- * @abstract
6
- * @since 1.5
7
- */
8
-
9
- if (class_exists('SU_Module')) {
10
-
11
- class SU_ImportModule extends SU_Module {
12
-
13
- var $error = false;
14
-
15
- function get_menu_parent() { return 'su-import-modules'; }
16
-
17
- function get_op_title() { return $this->get_module_title(); }
18
- function get_op_abbr() { return $this->get_module_title(); }
19
- function get_import_desc() { return ''; }
20
-
21
- function get_default_settings() {
22
- return array(
23
- 'import_postmeta' => true
24
- , 'postmeta_bothexist_action' => 'skip'
25
- , 'after_post_import' => 'nothing'
26
- );
27
- }
28
-
29
- function admin_page() {
30
- $this->admin_page_start('tools');
31
-
32
- if ($this->is_action('update')) {
33
- ob_start();
34
- $this->admin_page_contents();
35
- ob_end_clean();
36
-
37
- $this->import_page_contents();
38
- } else
39
- $this->admin_page_contents();
40
-
41
- $this->admin_page_end();
42
- }
43
-
44
- function admin_page_postmeta() {
45
-
46
- $name = $this->get_op_title();
47
- $abbr = $this->get_op_abbr();
48
-
49
- $this->textblock('<strong>'.__('Import Post Fields', 'seo-ultimate').'</strong> &mdash; '.
50
- sprintf(__('Post fields store the SEO data for your posts/pages (i.e. your custom title tags, meta descriptions, and meta keywords). If you provided custom titles/descriptions/keywords to %s, this importer can move that data over to SEO Ultimate.', 'seo-ultimate'), $name)
51
- );
52
- $this->admin_form_indent_start();
53
- $this->admin_form_group_start(__('Conflict Resolution Mode', 'seo-ultimate'));
54
- $this->textblock(sprintf(__('What should the import tool do if it tries to move over a post&#8217;s %s data, but different data already exists in the corresponding SEO Ultimate fields?', 'seo-ultimate'), $abbr));
55
- $this->radiobuttons('postmeta_bothexist_action', array(
56
- 'skip' => __('Skip that post and leave all data as-is (default).', 'seo-ultimate')
57
- , 'delete_su' => sprintf(__('Delete the SEO Ultimate data and replace it with the %s data.', 'seo-ultimate'), $abbr)
58
- , 'delete_op' => sprintf(__('Keep the SEO Ultimate data and delete the %s data.', 'seo-ultimate'), $abbr)
59
- ));
60
- $this->admin_form_group_end();
61
- $this->admin_form_group_start(__('Deletion Preference', 'seo-ultimate'));
62
- $this->textblock(sprintf(__('When the migration tool successfully copies a post&#8217;s %1$s data over to SEO Ultimate, what should it do with the old %1$s data?', 'seo-ultimate'), $abbr));
63
- $this->radiobuttons('after_post_import', array(
64
- 'delete_op' => sprintf(__('Delete the %s data.', 'seo-ultimate'), $abbr)
65
- , 'nothing' => sprintf(__('Leave behind the duplicate %s data (default).', 'seo-ultimate'), $abbr)
66
- ));
67
- $this->admin_form_group_end();
68
- $this->admin_form_indent_end();
69
- }
70
-
71
- function admin_form_end($button = null, $table = true) {
72
- if ($button === null) $button = __('Import Now', 'seo-ultimate');
73
- parent::admin_form_end($button, $table);
74
-
75
- $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()));
76
- }
77
-
78
- function import_page_contents() {
79
-
80
- echo "<div id='import-status'>\n";
81
- $this->do_import();
82
-
83
- if (!$this->error)
84
- $this->import_status('success', __('Import complete.', 'seo-ultimate'));
85
-
86
- echo "</div>\n";
87
-
88
- if ($this->error) {
89
- echo '<p><a href="admin.php?page=su-import-aiosp" class="button-secondary">';
90
- _e('Return to import page', 'seo-ultimate');
91
- } elseif ($this->plugin->module_exists('settings')) {
92
- echo '<p><a href="options-general.php?page=seo-ultimate#su-import" class="button-secondary">';
93
- _e('Return to settings page', 'seo-ultimate');
94
- } else {
95
- echo '<p><a href="admin.php?page=seo" class="button-secondary">';
96
- _e('Return to SEO page', 'seo-ultimate');
97
- }
98
- echo "</a></p>\n";
99
- }
100
-
101
- function import_status($type, $message) {
102
- if (strcmp($type, 'error') == 0) $this->error = true;
103
- $this->print_mini_message($type, $message);
104
- }
105
-
106
- function import_option($module, $key, $option) {
107
- if (!isset($this->settings[$module][$key]) || $this->get_setting('overwrite_su')) {
108
- $this->settings[$module][$key] = get_option($option);
109
- if ($this->get_setting('delete_import')) delete_option($option);
110
- }
111
- }
112
-
113
- function do_import_deactivate($path) {
114
- if (is_plugin_active($path)) {
115
- deactivate_plugins($path);
116
- $this->import_status('success', sprintf(__('Deactivated %s.', 'seo-ultimate'), $this->get_op_title()));
117
- }
118
- }
119
-
120
- function do_import_postmeta($postmeta_fields, $disabled_field=false) {
121
-
122
- $name = $this->get_op_title();
123
- $abbr = $this->get_op_abbr();
124
-
125
- global $wpdb;
126
- $posts = $wpdb->get_results("SELECT `ID` FROM {$wpdb->posts}");
127
-
128
- $numposts = 0;
129
- $numfields = 0;
130
- $numsudels = 0;
131
- $numopdels = 0;
132
-
133
- foreach ($posts as $p) {
134
-
135
- //Skip posts with "disabled" data
136
- if ($disabled_field && get_post_meta($p->ID, $disabled_field, true) === 'on')
137
- $numskipped++;
138
- else {
139
-
140
- foreach ($postmeta_fields as $op_field => $su_field) {
141
-
142
- if (strlen($op_value = get_post_meta($p->ID, $op_field, true))) {
143
-
144
- $delete_op = false;
145
-
146
- if (strlen(get_post_meta($p->ID, $su_field, true))) {
147
- //Conflict: SEO Ultimate field already exists
148
-
149
- switch ($this->get_setting('postmeta_bothexist_action')) {
150
- case 'skip': continue 2; break;
151
- case 'delete_su': $numsudels++; break;
152
- case 'delete_op': $delete_op = true; break;
153
- }
154
- }
155
-
156
- //Import the other plugin's data if we're not supposed to delete it.
157
- if (!$delete_op)
158
- update_post_meta($p->ID, $su_field, $op_value);
159
-
160
- //Delete the other plugin's data if the user has instructed us to do so
161
- if ($delete_op || $this->get_setting('after_post_import') == 'delete_op') {
162
- delete_post_meta($p->ID, $op_field, $op_value);
163
- $numopdels++;
164
- }
165
-
166
- $numfields++;
167
- }
168
- }
169
- }
170
-
171
- $numposts++;
172
- }
173
-
174
- $this->import_status('success', sprintf(_n(
175
- 'Imported a total of %d fields for one post/page/revision.',
176
- 'Imported a total of %1$d fields for %2$d posts/pages/revisions.',
177
- $numposts, 'seo-ultimate'), $numfields, $numposts));
178
-
179
- if ($numskipped > 0)
180
- $this->import_status('info', sprintf(_n(
181
- 'Skipped one post with disabled %2$s data.',
182
- 'Skipped %1$d posts with disabled %2$s data.',
183
- $numskipped, 'seo-ultimate'), $numskipped, $abbr));
184
-
185
- if ($numsudels > 0)
186
- $this->import_status('info', sprintf(_n(
187
- 'Overwrote one SEO Ultimate field with %2$s data, as instructed by the settings you chose.',
188
- 'Overwrote %1$d SEO Ultimate fields with %2$s data, as instructed by the settings you chose.',
189
- $numsudels, 'seo-ultimate'), $numsudels, $abbr));
190
-
191
- if ($numopdels > 0)
192
- $this->import_status('info', sprintf(_n(
193
- 'Deleted one %2$s field, as instructed by the settings you chose.',
194
- 'Deleted %1$d %2$s fields, as instructed by the settings you chose.',
195
- $numopdels, 'seo-ultimate'), $numopdels, $abbr));
196
- }
197
- }
198
-
199
- }
200
  ?>
1
+ <?php
2
+ /**
3
+ * Import Module
4
+ *
5
+ * @abstract
6
+ * @since 1.5
7
+ */
8
+
9
+ if (class_exists('SU_Module')) {
10
+
11
+ class SU_ImportModule extends SU_Module {
12
+
13
+ var $error = false;
14
+
15
+ function get_menu_parent() { return 'su-import-modules'; }
16
+
17
+ function get_op_title() { return $this->get_module_title(); }
18
+ function get_op_abbr() { return $this->get_module_title(); }
19
+ function get_import_desc() { return ''; }
20
+
21
+ function get_default_settings() {
22
+ return array(
23
+ 'import_postmeta' => true
24
+ , 'postmeta_bothexist_action' => 'skip'
25
+ , 'after_post_import' => 'nothing'
26
+ );
27
+ }
28
+
29
+ function admin_page() {
30
+ $this->admin_page_start('tools');
31
+
32
+ if ($this->is_action('update')) {
33
+ ob_start();
34
+ $this->admin_page_contents();
35
+ ob_end_clean();
36
+
37
+ $this->import_page_contents();
38
+ } else
39
+ $this->admin_page_contents();
40
+
41
+ $this->admin_page_end();
42
+ }
43
+
44
+ function admin_page_postmeta() {
45
+
46
+ $name = $this->get_op_title();
47
+ $abbr = $this->get_op_abbr();
48
+
49
+ $this->textblock('<strong>'.__('Import Post Fields', 'seo-ultimate').'</strong> &mdash; '.
50
+ sprintf(__('Post fields store the SEO data for your posts/pages (i.e. your custom title tags, meta descriptions, and meta keywords). If you provided custom titles/descriptions/keywords to %s, this importer can move that data over to SEO Ultimate.', 'seo-ultimate'), $name)
51
+ );
52
+ $this->admin_form_indent_start();
53
+ $this->admin_form_group_start(__('Conflict Resolution Mode', 'seo-ultimate'));
54
+ $this->textblock(sprintf(__('What should the import tool do if it tries to move over a post&#8217;s %s data, but different data already exists in the corresponding SEO Ultimate fields?', 'seo-ultimate'), $abbr));
55
+ $this->radiobuttons('postmeta_bothexist_action', array(
56
+ 'skip' => __('Skip that post and leave all data as-is (default).', 'seo-ultimate')
57
+ , 'delete_su' => sprintf(__('Delete the SEO Ultimate data and replace it with the %s data.', 'seo-ultimate'), $abbr)
58
+ , 'delete_op' => sprintf(__('Keep the SEO Ultimate data and delete the %s data.', 'seo-ultimate'), $abbr)
59
+ ));
60
+ $this->admin_form_group_end();
61
+ $this->admin_form_group_start(__('Deletion Preference', 'seo-ultimate'));
62
+ $this->textblock(sprintf(__('When the migration tool successfully copies a post&#8217;s %1$s data over to SEO Ultimate, what should it do with the old %1$s data?', 'seo-ultimate'), $abbr));
63
+ $this->radiobuttons('after_post_import', array(
64
+ 'delete_op' => sprintf(__('Delete the %s data.', 'seo-ultimate'), $abbr)
65
+ , 'nothing' => sprintf(__('Leave behind the duplicate %s data (default).', 'seo-ultimate'), $abbr)
66
+ ));
67
+ $this->admin_form_group_end();
68
+ $this->admin_form_indent_end();
69
+ }
70
+
71
+ function admin_form_end($button = null, $table = true) {
72
+ if ($button === null) $button = __('Import Now', 'seo-ultimate');
73
+ parent::admin_form_end($button, $table);
74
+
75
+ $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()));
76
+ }
77
+
78
+ function import_page_contents() {
79
+
80
+ echo "<div id='import-status'>\n";
81
+ $this->do_import();
82
+
83
+ if (!$this->error)
84
+ $this->import_status('success', __('Import complete.', 'seo-ultimate'));
85
+
86
+ echo "</div>\n";
87
+
88
+ if ($this->error) {
89
+ echo '<p><a href="admin.php?page=su-import-aiosp" class="button-secondary">';
90
+ _e('Return to import page', 'seo-ultimate');
91
+ } elseif ($this->plugin->module_exists('settings')) {
92
+ echo '<p><a href="options-general.php?page=seo-ultimate#su-import" class="button-secondary">';
93
+ _e('Return to settings page', 'seo-ultimate');
94
+ } else {
95
+ echo '<p><a href="admin.php?page=seo" class="button-secondary">';
96
+ _e('Return to SEO page', 'seo-ultimate');
97
+ }
98
+ echo "</a></p>\n";
99
+ }
100
+
101
+ function import_status($type, $message) {
102
+ if (strcmp($type, 'error') == 0) $this->error = true;
103
+ $this->print_mini_message($type, $message);
104
+ }
105
+
106
+ function import_option($module, $key, $option) {
107
+ if (!isset($this->settings[$module][$key]) || $this->get_setting('overwrite_su')) {
108
+ $this->settings[$module][$key] = get_option($option);
109
+ if ($this->get_setting('delete_import')) delete_option($option);
110
+ }
111
+ }
112
+
113
+ function do_import_deactivate($path) {
114
+ if (is_plugin_active($path)) {
115
+ deactivate_plugins($path);
116
+ $this->import_status('success', sprintf(__('Deactivated %s.', 'seo-ultimate'), $this->get_op_title()));
117
+ }
118
+ }
119
+
120
+ function do_import_postmeta($postmeta_fields, $disabled_field=false) {
121
+
122
+ $name = $this->get_op_title();
123
+ $abbr = $this->get_op_abbr();
124
+
125
+ global $wpdb;
126
+ $posts = $wpdb->get_results("SELECT `ID` FROM {$wpdb->posts}");
127
+
128
+ $numposts = 0;
129
+ $numfields = 0;
130
+ $numsudels = 0;
131
+ $numopdels = 0;
132
+
133
+ foreach ($posts as $p) {
134
+
135
+ //Skip posts with "disabled" data
136
+ if ($disabled_field && get_post_meta($p->ID, $disabled_field, true) === 'on')
137
+ $numskipped++;
138
+ else {
139
+
140
+ foreach ($postmeta_fields as $op_field => $su_field) {
141
+
142
+ if (strlen($op_value = get_post_meta($p->ID, $op_field, true))) {
143
+
144
+ $delete_op = false;
145
+
146
+ if (strlen(get_post_meta($p->ID, $su_field, true))) {
147
+ //Conflict: SEO Ultimate field already exists
148
+
149
+ switch ($this->get_setting('postmeta_bothexist_action')) {
150
+ case 'skip': continue 2; break;
151
+ case 'delete_su': $numsudels++; break;
152
+ case 'delete_op': $delete_op = true; break;
153
+ }
154
+ }
155
+
156
+ //Import the other plugin's data if we're not supposed to delete it.
157
+ if (!$delete_op)
158
+ update_post_meta($p->ID, $su_field, $op_value);
159
+
160
+ //Delete the other plugin's data if the user has instructed us to do so
161
+ if ($delete_op || $this->get_setting('after_post_import') == 'delete_op') {
162
+ delete_post_meta($p->ID, $op_field, $op_value);
163
+ $numopdels++;
164
+ }
165
+
166
+ $numfields++;
167
+ }
168
+ }
169
+ }
170
+
171
+ $numposts++;
172
+ }
173
+
174
+ $this->import_status('success', sprintf(_n(
175
+ 'Imported a total of %d fields for one post/page/revision.',
176
+ 'Imported a total of %1$d fields for %2$d posts/pages/revisions.',
177
+ $numposts, 'seo-ultimate'), $numfields, $numposts));
178
+
179
+ if ($numskipped > 0)
180
+ $this->import_status('info', sprintf(_n(
181
+ 'Skipped one post with disabled %2$s data.',
182
+ 'Skipped %1$d posts with disabled %2$s data.',
183
+ $numskipped, 'seo-ultimate'), $numskipped, $abbr));
184
+
185
+ if ($numsudels > 0)
186
+ $this->import_status('info', sprintf(_n(
187
+ 'Overwrote one SEO Ultimate field with %2$s data, as instructed by the settings you chose.',
188
+ 'Overwrote %1$d SEO Ultimate fields with %2$s data, as instructed by the settings you chose.',
189
+ $numsudels, 'seo-ultimate'), $numsudels, $abbr));
190
+
191
+ if ($numopdels > 0)
192
+ $this->import_status('info', sprintf(_n(
193
+ 'Deleted one %2$s field, as instructed by the settings you chose.',
194
+ 'Deleted %1$d %2$s fields, as instructed by the settings you chose.',
195
+ $numopdels, 'seo-ultimate'), $numopdels, $abbr));
196
+ }
197
+ }
198
+
199
+ }
200
  ?>
modules/class.su-module.php CHANGED
@@ -1,3066 +1,3073 @@
1
- <?php
2
- /**
3
- * The pseudo-abstract class upon which all modules are based.
4
- *
5
- * @abstract
6
- * @since 0.1
7
- */
8
- class SU_Module {
9
-
10
- /********** VARIABLES **********/
11
-
12
- /**
13
- * @since 0.1
14
- * @var string
15
- */
16
- var $module_key;
17
-
18
- /**
19
- * Stores the parent module (an SU_Module object) if this module has a parent.
20
- *
21
- * @since 1.5
22
- * @var SU_Module
23
- */
24
- var $parent_module = null;
25
-
26
- /**
27
- * Stores any child modules as an array of SU_Module objects.
28
- *
29
- * @since 1.5
30
- * @var array
31
- */
32
- var $modules = array();
33
-
34
- /**
35
- * Stores the module file's URL.
36
- *
37
- * @since 0.1
38
- * @var string
39
- */
40
- var $module_url;
41
-
42
- /**
43
- * Stores the URL to the directory containing the module file. Has trailing slash.
44
- *
45
- * @since 1.5
46
- * @var string
47
- */
48
- var $module_dir_url;
49
-
50
- /**
51
- * Stores the module file's URL relative to the plugin directory.
52
- *
53
- * @since 2.1
54
- * @var string
55
- */
56
- var $module_rel_url;
57
-
58
- /**
59
- * Stores the URL to the directory containing the module file, relative to the plugin directory. Has trailing slash.
60
- *
61
- * @since 2.1
62
- * @var string
63
- */
64
- var $module_dir_rel_url;
65
-
66
- /**
67
- * Stores the module's plugin page hook (the full hook with seo_page_ prefix).
68
- * A reconstructed value of the get_plugin_page_hook() function, which is only available after admin init.
69
- *
70
- * @since 0.1
71
- * @var string
72
- */
73
- var $plugin_page_hook;
74
-
75
- /**
76
- * Contains messages that are waiting to be displayed to the user.
77
- *
78
- * @since 0.1
79
- * @var array
80
- */
81
- var $messages = array();
82
-
83
- /**
84
- * Stores the plugin object by reference.
85
- *
86
- * @since 1.5
87
- */
88
- var $plugin = null;
89
-
90
-
91
- /********** CONSTRUCTOR FUNCTION **********/
92
-
93
- /**
94
- * PHP4 constructor that points to the likely-overloaded PHP5 constructor.
95
- *
96
- * @since 0.1
97
- * @uses __construct()
98
- */
99
- /*function SU_Module() {
100
- $this->__construct();
101
- }*/
102
-
103
-
104
- /********** PSEUDO-ABSTRACT FUNCTIONS **********/
105
-
106
- /**
107
- * PHP5 constructor.
108
- *
109
- * @since 0.1
110
- */
111
- function __construct() { }
112
-
113
- /**
114
- * The module's official title.
115
- *
116
- * @since 1.5
117
- *
118
- * @return string
119
- */
120
- static function get_module_title() { return ''; }
121
-
122
- /**
123
- * The title to be used by parent modules.
124
- *
125
- * @since 1.5
126
- *
127
- * @return string
128
- */
129
- function get_module_subtitle() { return isset($this) ? $this->get_module_title() : ''; }
130
-
131
- /**
132
- * The title of the admin page, which is displayed in the <title> and <h2> tags.
133
- * Is the same as the menu title by default.
134
- *
135
- * @since 0.1
136
- *
137
- * @return string The title shown on this module's admin page.
138
- */
139
- function get_page_title() { return isset($this) ? $this->get_module_title() : ''; }
140
-
141
- /**
142
- * The title that appears on the administration navigation menu.
143
- *
144
- * @since 0.1
145
- *
146
- * @return string The title shown on the admin menu.
147
- */
148
-
149
- static function get_menu_title() { return isset($this) ? $this->get_module_title() : ''; }
150
-
151
- /**
152
- * Determines where this module's admin page should appear relative to those of other modules.
153
- * If two modules have the same menu position index, they are sorted alphabetically.
154
- *
155
- * @since 0.1
156
- *
157
- * @return int The menu position index.
158
- */
159
- static function get_menu_pos() { return 10; }
160
-
161
- /**
162
- * Determines where this module's admin contents should appear on the parent page relative to those of other sibling modules.
163
- * If two modules have the same order index, they are sorted alphabetically.
164
- *
165
- * @since 1.5
166
- *
167
- * @return int The child order index.
168
- */
169
- static function get_child_order() { return 999; }
170
-
171
- /**
172
- * The number that should be displayed in a bubble next to the module's menu title.
173
- * A return value of zero means no bubble is shown.
174
- *
175
- * @since 0.1
176
- *
177
- * @return int The number that should be displayed.
178
- */
179
- function get_menu_count() {
180
- $count = 0;
181
- foreach ($this->modules as $key => $module) {
182
- $count += $this->modules[$key]->get_menu_count();
183
- }
184
- return $count;
185
- }
186
-
187
- /**
188
- * Whether or not the module will ever return a non-zero menu count.
189
- *
190
- * @since 1.5
191
- *
192
- * @return boolean
193
- */
194
- static function has_menu_count() { return false; }
195
-
196
- /**
197
- * A descriptive label of the menu count.
198
- *
199
- * @since 0.3
200
- *
201
- * @return string The label.
202
- */
203
- function get_menu_count_label() { return ''; }
204
-
205
- /**
206
- * Indicates under which top-level menu this module's admin page should go.
207
- * Examples: seo (This plugin's SEO menu), options-general.php (The Settings menu)
208
- *
209
- * @since 0.1
210
- *
211
- * @return string The value to pass to WordPress's add_submenu_page() function.
212
- */
213
- function get_menu_parent(){ return 'seo'; }
214
-
215
- /**
216
- * Returns the hook of this module's menu parent.
217
- * Examples: seo (This plugin's SEO menu), settings (The Settings menu), toplevel (The toplevel)
218
- *
219
- * @since 0.1
220
- *
221
- * @return string The hook of the module's menu parent.
222
- */
223
- function get_menu_parent_hook() { return $this->get_menu_parent(); }
224
-
225
- /**
226
- * @since 7.2.5
227
- */
228
- function belongs_in_admin($admin_scope = null) {
229
-
230
- if ($admin_scope === null)
231
- $admin_scope = suwp::get_admin_scope();
232
-
233
- switch ($admin_scope) {
234
- case 'blog':
235
- return true;
236
- break;
237
- case 'network':
238
- case 'user':
239
- default:
240
- return false;
241
- break;
242
- }
243
- }
244
-
245
- /**
246
- * The status (enabled/silenced/hidden) of the module when the module is newly added to the plugin.
247
- *
248
- * @since 1.5
249
- *
250
- * @return int Either SU_MODULE_ENABLED, SU_MODULE_SILENCED, or SU_MODULE_HIDDEN.
251
- */
252
- function get_default_status() { return SU_MODULE_ENABLED; }
253
-
254
- /**
255
- * The module key of this module's parent. Defaults to false (no parent).
256
- *
257
- * @since 0.3
258
- *
259
- * @return string|bool
260
- */
261
- static function get_parent_module() { return false; }
262
-
263
- /**
264
- * Returns an array of admin page tabs; the label is the key and the callback is the value.
265
- *
266
- * @since 1.5
267
- *
268
- * @return array
269
- */
270
- function get_admin_page_tabs() { return array(); }
271
-
272
- /**
273
- * Whether or not the module can "exist on its own."
274
- * Determines whether or not the module appears in the Module Manager.
275
- *
276
- * @since 1.5
277
- *
278
- * @return bool
279
- */
280
- static function is_independent_module() {
281
- return true;
282
- }
283
-
284
- /**
285
- * The array key of the plugin's settings array in which this module's settings are stored.
286
- *
287
- * @since 1.5
288
- *
289
- * @return string
290
- */
291
- function get_settings_key() {
292
- if (isset($this)) {
293
- if (strlen($parent = $this->get_parent_module()) && !$this->is_independent_module())
294
- return $this->plugin->modules[$parent]->get_settings_key();
295
- else
296
- return $this->get_module_key();
297
- } else {
298
- if (strlen($parent = self::get_parent_module()) && !self::is_independent_module()) {
299
- global $seo_ultimate;
300
- return $seo_ultimate->modules[$parent]->get_settings_key();
301
- } else {
302
- if (strlen($parent = self::get_parent_module()) && !self::is_independent_module()) {
303
- global $seo_ultimate;
304
- return $seo_ultimate->get_module_key();
305
- } else {
306
- return false;
307
- }
308
- }
309
- }
310
- }
311
-
312
- /**
313
- * Whether or not this module should be the default screen for the "SEO" menu.
314
- *
315
- * @since 1.5
316
- * @return bool
317
- */
318
- function is_menu_default() { return false; }
319
-
320
- /**
321
- * Called after the module has been constructed and its variables have been filled.
322
- *
323
- * @since 3.9
324
- */
325
- function load() {}
326
-
327
- /**
328
- * Called at WordPress's init hook.
329
- *
330
- * @since 0.1
331
- */
332
- function init() {}
333
-
334
- /**
335
- * Called under 3 circumstances:
336
- * 1. When the SEO Ultimate plugin is activated (not necessarily for the first time)
337
- * 2. When a module is newly registered in the database, which can happen for two reasons:
338
- * a. The plugin is activated *for the first time*
339
- * b. The module has been newly added via a plugin upgrade
340
- * 3. When the module is re-enabled in the Module Manager after being disabled.
341
- *
342
- * Note that this function will be called twice when the plugin is activated for the first time, since this will make #1 and #2 both true.
343
- * If the plugin is deactivated and then reactivated, only #1 will be true.
344
- *
345
- * WARNING: Do not use "$this" in the activate() function. It will not work under condition #3. Check for isset($this) and if false, use self:: instead.
346
- *
347
- * @since 0.1
348
- */
349
- function activate() { }
350
-
351
- /**
352
- * Called under 2 circumstances:
353
- * 1. When the SEO Ultimate plugin is deactivated or uninstalled.
354
- * 2. When the module is disabled in the Module Manager.
355
- *
356
- * @since 7.2.8
357
- */
358
- function deactivate() { }
359
-
360
- /**
361
- * Called when SEO Ultimate has just been upgraded to a new version.
362
- *
363
- * @since 2.1
364
- */
365
- function upgrade() { }
366
-
367
- /**
368
- * Returns an array of default settings. The defaults will be saved in the database if the settings don't exist.
369
- *
370
- * @since 0.1
371
- *
372
- * @return array The default settings. (The setting name is the key, and the default value is the array value.)
373
- */
374
- function get_default_settings() { return array(); }
375
-
376
- /**
377
- * Is called at WordPress' admin_init hook when this module's admin page is showing.
378
- *
379
- * @since 6.0
380
- */
381
- function admin_page_init() { }
382
-
383
- /**
384
- * Is called at WordPress' admin_init hook when the post editor is loaded.
385
- *
386
- * @since 7.3
387
- */
388
- function editor_init() { }
389
-
390
- /**
391
- * The contents of the administration page.
392
- *
393
- * @since 0.1
394
- */
395
- function admin_page_contents() {
396
- $this->children_admin_page_tabs_form();
397
- }
398
-
399
- /**
400
- * Returns a list of possible admin table columns that should be registered in "Screen Options"
401
- *
402
- * @since 2.1
403
- *
404
- * @return array
405
- */
406
- function get_admin_table_columns() {
407
- return array();
408
- }
409
-
410
- /**
411
- * Called at WordPress's load-{page} hook for this module's admin page.
412
- *
413
- * @since 7.0
414
- */
415
- function load_hook() {
416
- $this->add_help_tabs(get_current_screen());
417
- }
418
-
419
- /**
420
- * @since 7.0
421
- */
422
- function add_help_tabs($screen) { }
423
-
424
- /**
425
- * Adds the module's post meta box field HTML to the array.
426
- *
427
- * @since 0.1
428
- *
429
- * @param array $fields The fields array.
430
- * @return array The updated fields array.
431
- */
432
- function postmeta_fields($fields, $screen) { return $fields; }
433
-
434
- /********** INITIALIZATION FUNCTIONALITY **********/
435
-
436
- /**
437
- * If settings are unset, apply the defaults if available.
438
- *
439
- * @since 0.5
440
- * @uses get_default_settings()
441
- * @uses get_setting()
442
- * @uses update_setting()
443
- */
444
- function load_default_settings() {
445
-
446
- $defaults = $this->get_default_settings();
447
- foreach ($defaults as $setting => $default) {
448
- if ($this->get_setting($setting, "{reset}") === "{reset}") {
449
- $this->update_setting($setting, $default, null, null);
450
- }
451
- }
452
- }
453
-
454
-
455
- /********** MODULE FUNCTIONS **********/
456
-
457
- /**
458
- * Returns the array key of the module.
459
- *
460
- * @since 0.1
461
- * @uses $module_key
462
- *
463
- * @return string The module key.
464
- */
465
- function get_module_key() {
466
- if ($this->module_key)
467
- return $this->module_key;
468
- else
469
- //This error will only be triggered if someone has seriously messed with the plugin architecture
470
- die("An SEO Ultimate module did not initialize properly. Perhaps you're trying to load an SEO Ultimate module independent of the plugin?");
471
- }
472
-
473
- /**
474
- * Returns the key of the parent module if there is one; if not, the key of the current module.
475
- *
476
- * @since 2.1
477
- *
478
- * @return string
479
- */
480
- function get_module_or_parent_key() {
481
- return $this->has_enabled_parent() ? $this->get_parent_module() : $this->get_module_key();
482
- }
483
-
484
- /**
485
- * Returns true only if this module has a parent AND that parent is enabled.
486
- *
487
- * @since 7.0
488
- *
489
- * @return bool
490
- */
491
- function has_enabled_parent() {
492
- return (strlen($p = $this->get_parent_module()) && $this->plugin->module_exists($p));
493
- }
494
-
495
- /**
496
- * Returns the absolute URL of the module's admin page.
497
- *
498
- * @since 0.7
499
- *
500
- * @param string|false $key The key of the module for which to generate the admin URL. Optional.
501
- * @return string The absolute URL to the admin page.
502
- */
503
- function get_admin_url($key = false) {
504
-
505
- $anchor = '';
506
- if ($key === false) {
507
- if (($key = $this->get_parent_module()) && $this->plugin->module_exists($key)) {
508
-
509
- $tabs = $this->get_admin_page_tabs();
510
- if (!is_array($tabs))
511
- return false;
512
-
513
- if (count($tabs)) {
514
- $first_tab = reset($tabs);
515
- $anchor = '#' . $first_tab['id'];
516
- } else {
517
- $anchor = '#' . $this->plugin->key_to_hook($this->get_module_key());
518
- }
519
- } else
520
- $key = $this->get_module_key();
521
- }
522
-
523
- if (!$this->plugin->call_module_func($key, 'belongs_in_admin', $belongs_in_admin) || !$belongs_in_admin)
524
- return false;
525
-
526
- if (!$this->plugin->call_module_func($key, 'get_menu_title', $menu_title) || !$menu_title)
527
- return false;
528
-
529
- $basepage = 'admin.php';
530
- if ($this->plugin->call_module_func($key, 'get_menu_parent', $custom_basepage) && sustr::endswith($custom_basepage, '.php'))
531
- $basepage = $custom_basepage;
532
-
533
- if (is_network_admin() && $this->belongs_in_admin('network'))
534
- $admin_url = 'network_admin_url';
535
- else
536
- $admin_url = 'admin_url';
537
-
538
- return $admin_url($basepage.'?page='.$this->plugin->key_to_hook($key).$anchor);
539
- }
540
-
541
- /**
542
- * Returns an <a> link to the module's admin page, if the module is enabled.
543
- *
544
- * @since 1.0
545
- * @uses get_admin_url()
546
- *
547
- * @param string|false $key The key of the module for which to generate the admin URL.
548
- * @param string $label The text to go inside the <a> element.
549
- * @return string The <a> element, if the module exists; otherwise, the label by itself.
550
- */
551
- function get_admin_link($key, $label) {
552
-
553
- if ($key == false || $this->plugin->module_exists($key))
554
- return sprintf('<a href="%s">%s</a>', $this->get_admin_url($key), $label);
555
- else
556
- return $label;
557
- }
558
-
559
- /**
560
- * Returns a boolean indicating whether the user is currently viewing this module's admin page.
561
- *
562
- * @since 1.1.1
563
- *
564
- * @return bool Whether the user is currently viewing this module's admin page.
565
- */
566
- function is_module_admin_page() {
567
- if (is_admin()) {
568
- global $plugin_page;
569
- if (strcmp($plugin_page, $this->plugin->key_to_hook($this->get_module_or_parent_key())) == 0) return true;
570
- }
571
-
572
- return false;
573
- }
574
-
575
- /**
576
- * Returns the filename of the module's icon URL.
577
- *
578
- * @since 1.5
579
- *
580
- * @return string
581
- */
582
- function get_menu_icon_filename() {
583
- $filenames = array(
584
- $this->get_settings_key()
585
- , $this->get_module_key()
586
- , $this->get_parent_module()
587
- );
588
-
589
- foreach ($filenames as $filename) {
590
- $image = $this->module_dir_url.$filename.'.png';
591
- if (is_readable($image)) return $image;
592
- }
593
-
594
- return '';
595
- }
596
-
597
-
598
- /********** CHILD MODULE FUNCTIONS **********/
599
-
600
- /**
601
- * Finds child modules of this module and fills $this->modules accordingly.
602
- *
603
- * @since 1.5
604
- */
605
- function load_child_modules() {
606
- foreach ($this->plugin->modules as $key => $x_module) {
607
- if ($key != $this->get_module_key()) {
608
- $module =& $this->plugin->modules[$key];
609
- if ($module->get_parent_module() == $this->get_module_key()) {
610
- $module->parent_module =& $this;
611
- $this->modules[$key] =& $module;
612
- }
613
- }
614
- }
615
-
616
- if (count($this->modules) > 0)
617
- @uasort($this->modules, array(&$this, 'module_sort_callback'));
618
- }
619
-
620
- /**
621
- * Returns an array of this module's admin tabs plus those of its children.
622
- *
623
- * @since 1.5
624
- * @return array
625
- */
626
- function get_children_admin_page_tabs() {
627
- $tabs = $this->get_admin_page_tabs();
628
- if (!is_array($tabs)) $tabs = array();
629
-
630
- foreach ($this->modules as $key => $x_module) {
631
- $module =& $this->modules[$key];
632
-
633
- if ($module->belongs_in_admin()) {
634
- $child_tabs = $module->get_admin_page_tabs();
635
-
636
- if (is_array($child_tabs)) {
637
-
638
- if (empty($child_tabs))
639
- $child_tabs[] = array(
640
- 'title' => $module->get_module_subtitle()
641
- , 'id' => $this->plugin->key_to_hook($key)
642
- , 'callback' => array(&$module, 'admin_page_contents')
643
- );
644
-
645
- foreach ($child_tabs as $child_tab) {
646
- if (is_array($child_tab) && !is_array($child_tab['callback']))
647
- $child_tab['callback'] = array(&$module, $child_tab['callback']);
648
-
649
- $tabs[] = $child_tab;
650
- }
651
- }
652
- }
653
- }
654
-
655
- return $tabs;
656
- }
657
-
658
- /**
659
- * Outputs this module's admin tabs plus those of its children.
660
- *
661
- * @since 1.5
662
- */
663
- function children_admin_page_tabs() {
664
- if (count($tabs = $this->get_children_admin_page_tabs()))
665
- $this->admin_page_tabs($tabs);
666
- }
667
-
668
- /**
669
- * Outputs a form containing this module's admin tabs plus those of its children.
670
- *
671
- * @since 1.5
672
- */
673
- function children_admin_page_tabs_form() {
674
- if (count($tabs = $this->get_children_admin_page_tabs())) {
675
- echo "\n\n<div class='row'>\n";
676
- echo "\n\n<div class='col-sm-8 col-md-9'>\n";
677
-
678
- $this->admin_form_start(false, false);
679
- $this->admin_page_tabs($tabs);
680
- $this->admin_form_end(null, false);
681
-
682
- echo "\n\n</div>\n";
683
- echo "\n\n<div class='col-sm-4 col-md-3'>\n";
684
- $this->promo_sdf_banners();
685
- echo "\n\n</div>\n";
686
- echo "\n\n</div>\n";
687
- }
688
- }
689
-
690
- /**
691
- * Outputs the admin pages of this module's children, one after the other.
692
- *
693
- * @since 1.5
694
- */
695
- function children_admin_pages() {
696
- foreach ($this->modules as $key => $x_module) {
697
- echo "<div id='" . $this->plugin->key_to_hook($key) . "'>\n";
698
- $this->modules[$key]->admin_subheader($this->modules[$key]->get_module_subtitle());
699
- $this->modules[$key]->admin_page_contents();
700
- echo "</div>\n";
701
- }
702
- }
703
-
704
- /**
705
- * Outputs a form containing the admin pages of this module's children, outputted one after the other.
706
- *
707
- * @since 1.5
708
- */
709
- function children_admin_pages_form() {
710
- if (count($this->modules)) {
711
- $this->admin_form_start(false, false);
712
- $this->children_admin_pages();
713
- $this->admin_form_end(null, false);
714
- } else
715
- $this->print_message('warning', sprintf(__('All the modules on this page have been disabled. You can re-enable them using the <a href="%s">Module Manager</a>.', 'seo-ultimate'), $this->get_admin_url('modules')));
716
- }
717
-
718
- /**
719
- * Compares two modules to determine which of the two should be displayed first on the parent page.
720
- * Sorts by child order first, and title second.
721
- * Works as a uasort() callback.
722
- *
723
- * @since 1.5
724
- * @uses SU_Module::get_child_order()
725
- * @uses SU_Module::get_module_subtitle()
726
- *
727
- * @param SU_Module $a The first module to compare.
728
- * @param SU_Module $b The second module to compare.
729
- * @return int This will be -1 if $a comes first, or 1 if $b comes first.
730
- */
731
- function module_sort_callback($a, $b) {
732
-
733
- if ($a->get_child_order() == $b->get_child_order()) {
734
- return strcmp($a->get_module_subtitle(), $b->get_module_subtitle());
735
- }
736
-
737
- return ($a->get_child_order() < $b->get_child_order()) ? -1 : 1;
738
- }
739
-
740
- /********** SETTINGS FUNCTIONS **********/
741
-
742
- /**
743
- * Retrieves the given setting from a module's settings array.
744
- *
745
- * @since 0.1
746
- * @uses get_settings_key()
747
- *
748
- * @param string $key The name of the setting to retrieve.
749
- * @param mixed $default What should be returned if the setting does not exist. Optional.
750
- * @param string|null $module The module to which the setting belongs. Defaults to the current module's settings key. Optional.
751
- * @return mixed The value of the setting, or the $default variable.
752
- */
753
- function get_setting($key, $default=null, $module=null, $sneakpeak=false) {
754
- if (!$module) $module = $this->get_settings_key();
755
-
756
- $msdata = (array)get_option("seo_ultimate_module_$module", array());
757
-
758
- if ($sneakpeak && $this->is_action('update'))
759
- $setting = stripslashes(isset($_POST[$key]) ? $_POST[$key] : null);
760
- elseif (isset($msdata[$key]))
761
- $setting = $msdata[$key];
762
- else
763
- $setting = $default;
764
-
765
- $setting = apply_filters("su_get_setting-$module", $setting, $key);
766
- $setting = apply_filters("su_get_setting-$module-$key", $setting, $key);
767
-
768
- return $setting;
769
- }
770
-
771
- /**
772
- * Sets a value in the module's settings array.
773
- *
774
- * @since 0.1
775
- * @uses get_settings_key()
776
- *
777
- * @param string $key The key of the setting to be changed.
778
- * @param string $value The new value to assign to the setting.
779
- * @param string|null $module The module to which the setting belongs. Defaults to the current module's settings key. Optional.
780
- */
781
- function update_setting($key, $value, $module=null, $array_key=null) {
782
- if (!$module) $module = $this->get_settings_key();
783
-
784
- $msdata = (array)get_option("seo_ultimate_module_$module", array());
785
-
786
- $use_custom = apply_filters("su_custom_update_setting-$module-$key", false, $value, $key) ||
787
- apply_filters("su_custom_update_setting-$module", false, $value, $key);
788
-
789
- if (!$use_custom) {
790
- if ($array_key)
791
- $msdata[$key][$array_key] = $value;
792
- else
793
- $msdata[$key] = $value;
794
- }
795
-
796
- update_option("seo_ultimate_module_$module", $msdata);
797
- }
798
-
799
- /**
800
- * Gets a setting's value, deletes the setting, and returns the value.
801
- *
802
- * @since 2.1
803
- * @uses get_settings_key()
804
- *
805
- * @param string $key The name of the setting to retrieve/delete.
806
- * @param mixed $default What should be returned if the setting does not exist. Optional.
807
- * @param string|null $module The module to which the setting belongs. Defaults to the current module's settings key. Optional.
808
- * @return mixed The value of the setting, or the $default variable.
809
- */
810
- function flush_setting($key, $default=null, $module=null) {
811
- $setting = $this->get_setting($key, $default, $module); //We need to retrieve the setting before deleting it
812
- $this->delete_setting($key, $module);
813
- return $setting;
814
- }
815
-
816
- /**
817
- * Deletes a module setting.
818
- *
819
- * @since 2.1
820
- * @uses get_settings_key()
821
- *
822
- * @param string $key The name of the setting to delete.
823
- * @param string|null $module The module to which the setting belongs. Defaults to the current module's settings key. Optional.
824
- */
825
- function delete_setting($key, $module=null, $array_key = null) {
826
- if (!$module) $module = $this->get_settings_key();
827
-
828
- $msdata = (array)get_option("seo_ultimate_module_$module", array());
829
-
830
- if (isset($msdata[$key])) {
831
- if ($array_key) {
832
- if (isset($msdata[$key][$array_key]))
833
- unset($msdata[$key][$array_key]);
834
- } else {
835
- unset($msdata[$key]);
836
- }
837
- }
838
- }
839
-
840
- /**
841
- * Returns a default setting. Only use this function if a default is indeed provided!
842
- *
843
- * @since 1.3
844
- * @uses get_default_settings()
845
- *
846
- * @param string $key The name of the setting whose default to retrieve.
847
- * @return mixed The default value for the setting.
848
- */
849
- function get_default_setting($key) {
850
- $defaults = $this->get_default_settings();
851
- return $defaults[$key];
852
- }
853
-
854
-
855
- /********** ADMIN PAGE FUNCTIONS **********/
856
-
857
- /**
858
- * Displays the beginning, contents, and end of the module's administration page.
859
- *
860
- * @since 0.1
861
- * @uses admin_page_start()
862
- * @uses admin_page_contents()
863
- * @uses admin_page_end()
864
- */
865
- function admin_page() {
866
- if (!apply_filters('su_custom_admin_page-'.$this->get_module_key(), false)) {
867
- $this->admin_page_start();
868
- $this->admin_page_contents();
869
- $this->admin_page_end();
870
- }
871
- }
872
-
873
- /**
874
- * Outputs the starting code for an administration page:
875
- * wrapper, ID'd <div>, icon, and title
876
- *
877
- * @since 0.1
878
- * @uses admin_footer() Hooked into WordPress's in_admin_footer action.
879
- * @uses get_module_key()
880
- * @uses get_page_title()
881
- *
882
- * @param string $icon The ID that should be applied to the icon element. The icon is loaded via CSS based on the ID. Optional.
883
- */
884
- function admin_page_start($icon = 'options-general') {
885
-
886
- //Add our custom footer attribution
887
- add_action('in_admin_footer', array(&$this, 'admin_footer'));
888
-
889
- //Output the beginning of the admin screen
890
- echo "<div class=\"wrap\">\n";
891
-
892
- if (strcmp($pclass = strtolower(get_parent_class($this)), 'su_module') != 0)
893
- $class = ' '.str_replace('_', '-', $pclass);
894
- else
895
- $class = '';
896
-
897
- echo "<div id=\"su-".su_esc_attr($this->get_module_key())."\" class=\"sdf-admin$class\">\n";
898
- screen_icon($icon);
899
- echo "\n<h2>".$this->get_page_title()."</h2>\n";
900
- }
901
-
902
- /**
903
- * Outputs an administration page subheader (an <h4> tag).
904
- *
905
- * @since 0.1
906
- *
907
- * @param string $title The text to output.
908
- */
909
- function admin_subheader($title, $id=false) {
910
- if ($id) $id = ' id="' . su_esc_attr($id) . '"';
911
- echo "<h4 class='su-subheader'$id>$title</h4>\n";
912
- }
913
-
914
- /**
915
- * Outputs an administration form table subheader.
916
- *
917
- * @since 0.1
918
- *
919
- * @param string $title The text to output.
920
- */
921
- function admin_form_subheader($title) {
922
- echo "<tr><th colspan='2'><strong>$title</strong></th></tr>\n";
923
- }
924
-
925
- /**
926
- * Outputs the ending code for an administration page.
927
- *
928
- * @since 0.1
929
- */
930
- function admin_page_end() {
931
- echo "\n</div>\n</div>\n";
932
- }
933
-
934
- /**
935
- * Outputs a tab control and loads the current tab.
936
- *
937
- * @since 0.7
938
- *
939
- * @param array $tabs Array (id => __, title => __, callback => __)
940
- * @param bool $table Whether or not the tab contents should be wrapped in a form table.
941
- */
942
- function admin_page_tabs($tabs=array(), $table=false) {
943
- $this->plugin->tabs($tabs, $table, $this);
944
- }
945
-
946
- /**
947
- * Adds the hook necessary to initialize the admin page tabs.
948
- *
949
- * @since 0.8
950
- */
951
- function admin_page_tabs_init() {
952
- add_action('admin_enqueue_scripts', array(&$this, 'admin_page_tabs_js'));
953
- }
954
-
955
- /**
956
- * Enqueues the JavaScript needed for the admin page tabs.
957
- *
958
- * @since 0.8
959
- * @uses is_module_admin_page()
960
- */
961
- function admin_page_tabs_js() {
962
- if ($this->is_module_admin_page())
963
- wp_enqueue_script('jquery-ui-tabs');
964
- }
965
-
966
- /**
967
- * Adds plugin/module information to the admin footer.
968
- *
969
- * @since 0.1
970
- * @uses SU_PLUGIN_URI
971
- * @uses SU_PLUGIN_NAME
972
- * @uses SU_AUTHOR_URI
973
- * @uses SU_AUTHOR
974
- */
975
- function admin_footer() {
976
- printf(__('%1$s | %2$s %3$s by %4$s', 'seo-ultimate'),
977
- $this->get_module_title(),
978
- '<a href="'.SU_PLUGIN_URI.'" target="_blank" rel="nofollow">'.__(SU_PLUGIN_NAME, 'seo-ultimate').'</a>',
979
- SU_VERSION,
980
- '<a href="'.SU_AUTHOR_URI.'" target="_blank" rel="nofollow">'.__(SU_AUTHOR, 'seo-ultimate').'</a>'
981
- );
982
-
983
- echo "<br />";
984
- }
985
-
986
- /**
987
- * Returns tabs for post/taxonomy meta editing tables.
988
- *
989
- * @since 2.9
990
- * @uses get_postmeta_edit_tabs()
991
- * @uses get_taxmeta_edit_tabs()
992
- *
993
- * @param array $fields The array of meta fields that the user can edit with the tables.
994
- */
995
- function get_meta_edit_tabs($fields) {
996
- return array_merge(
997
- $this->get_postmeta_edit_tabs($fields)
998
- ,$this->get_taxmeta_edit_tabs($fields)
999
- );
1000
- }
1001
-
1002
- /**
1003
- * Returns tabs for post meta editing tables.
1004
- *
1005
- * @since 2.9
1006
- *
1007
- * @param array $fields The array of meta fields that the user can edit with the tables.
1008
- */
1009
- function get_postmeta_edit_tabs($fields) {
1010
-
1011
- $types = get_post_types(array('public' => true), 'objects');
1012
-
1013
- //Turn the types array into a tabs array
1014
- $tabs = array();
1015
- foreach ($types as $type)
1016
- $tabs[$type->name] = array(
1017
- 'title' => $type->labels->name
1018
- , 'id' => 'su-' . $type->name
1019
- , 'callback' => array('meta_edit_tab', 'post', 'su-' . $type->name, $type->name, $type->labels->singular_name, $fields)
1020
- );
1021
- return $tabs;
1022
- }
1023
-
1024
- /**
1025
- * Returns tabs for taxonomy meta editing tables.
1026
- *
1027
- * @since 2.9
1028
- *
1029
- * @param array $fields The array of meta fields that the user can edit with the tables.
1030
- */
1031
- function get_taxmeta_edit_tabs($fields) {
1032
- $types = suwp::get_taxonomies();
1033
-
1034
- //Turn the types array into a tabs array
1035
- $tabs = array();
1036
- foreach ($types as $name => $type) {
1037
- if ($type->labels->name) {
1038
- $tabs[] = array(
1039
- 'title' => $type->labels->name
1040
- , 'id' => 'su-' . $name
1041
- , 'callback' => array('meta_edit_tab', 'term', 'su-' . $name, $name, $type->labels->singular_name, $fields)
1042
- );
1043
- }
1044
- }
1045
- return $tabs;
1046
- }
1047
-
1048
- /**
1049
- * Outputs the contents of a meta editing tab.
1050
- *
1051
- * @since 2.9
1052
- */
1053
- function meta_edit_tab($genus, $tab, $type, $type_label, $fields) {
1054
- if (!$this->meta_edit_table($genus, $tab, $type, $type_label, $fields))
1055
- $this->print_message('info', __('Your site currently doesn&#8217;t have any public items of this type.', 'seo-ultimate'));
1056
- }
1057
-
1058
- /**
1059
- * Outputs the contents of a meta editing table.
1060
- *
1061
- * @since 2.9
1062
- *
1063
- * @param string $genus The type of object being handled (either 'post' or 'term')
1064
- * @param string $tab The ID of the current tab; used to generate a URL hash (e.g. #$tab)
1065
- * @param string $type The type of post/taxonomy type being edited (examples: post, page, attachment, category, post_tag)
1066
- * @param string $type_label The singular label for the post/taxonomy type (examples: Post, Page, Attachment, Category, Post Tag)
1067
- * @param array $fields The array of meta fields that the user can edit with the tables. The data for each meta field are stored in an array with these elements: "type" (can be textbox, textarea, or checkbox), "name" (the meta field, e.g. title or description), "term_settings_key" (the key of the setting for cases when term meta data are stored in the settings array), and "label" (the internationalized label of the field, e.g. "Meta Description" or "Title Tag")
1068
- */
1069
- function meta_edit_table($genus, $tab, $type, $type_label, $fields) {
1070
-
1071
- //Pseudo-constant
1072
- $per_page = 100;
1073
-
1074
- //Sanitize parameters
1075
- if (!is_array($fields) || !count($fields)) return false;
1076
- if (!isset($fields[0]) || !is_array($fields[0])) $fields = array($fields);
1077
-
1078
- //Get search query
1079
- $type_s = $type . '_s';
1080
- $search = isset($_REQUEST[$type_s]) ? $_REQUEST[$type_s] : '';
1081
-
1082
- //Save meta if applicable
1083
- if ($is_update = ($this->is_action('update') && !strlen(trim($search)))) {
1084
- foreach ($_POST as $key => $value) {
1085
- $value = stripslashes($value);
1086
- if (sustr::startswith($key, $genus.'_'))
1087
- foreach ($fields as $field)
1088
- if (preg_match("/{$genus}_([0-9]+)_{$field['name']}/", $key, $matches)) {
1089
- $id = (int)$matches[1];
1090
- switch ($genus) {
1091
- case 'post': update_post_meta($id, "_su_{$field['name']}", $value); break;
1092
- case 'term': $this->update_setting($field['term_settings_key'], $value, null, $id); break;
1093
- }
1094
- continue 2; //Go to next $_POST item
1095
- }
1096
- }
1097
- }
1098
-
1099
- $pagenum = isset( $_GET[$type . '_paged'] ) ? absint( $_GET[$type . '_paged'] ) : 0;
1100
- if ( empty($pagenum) ) $pagenum = 1;
1101
-
1102
- //Load up the objects based on the genus
1103
- switch ($genus) {
1104
- case 'post':
1105
-
1106
- //Get the posts
1107
- wp(array(
1108
- 'post_type' => $type
1109
- , 'posts_per_page' => $per_page
1110
- , 'post_status' => 'any'
1111
- , 'paged' => $pagenum
1112
- , 'order' => 'ASC'
1113
- , 'orderby' => 'title'
1114
- , 's' => $search
1115
- ));
1116
- global $wp_query;
1117
- $objects = &$wp_query->posts;
1118
-
1119
- $num_pages = $wp_query->max_num_pages;
1120
- $total_objects = $wp_query->found_posts;
1121
-
1122
- break;
1123
-
1124
- case 'term':
1125
- $objects = get_terms($type, array('search' => $search));
1126
- $total_objects = count($objects);
1127
- $num_pages = ceil($total_objects / $per_page);
1128
- $objects = array_slice($objects, $per_page * ($pagenum-1), $per_page);
1129
- break;
1130
- default:
1131
- return false;
1132
- break;
1133
- }
1134
-
1135
- if ($total_objects < 1) return false;
1136
-
1137
- echo "\n<div class='su-meta-edit-table'>\n";
1138
-
1139
- $page_links = paginate_links( array(
1140
- 'base' => add_query_arg( $type . '_paged', '%#%' ) . '#' . $tab
1141
- , 'format' => ''
1142
- , 'prev_text' => __('&laquo;')
1143
- , 'next_text' => __('&raquo;')
1144
- , 'total' => $num_pages
1145
- , 'current' => $pagenum
1146
- ));
1147
-
1148
- if ( $page_links ) {
1149
- $page_links_text = '<div class="tablenav"><div class="tablenav-pages">';
1150
- $page_links_text .= sprintf( '<span class="displaying-num">' . __( 'Displaying %s&#8211;%s of %s' ) . '</span>%s',
1151
- number_format_i18n( ( $pagenum - 1 ) * $per_page + 1 ),
1152
- number_format_i18n( min( $pagenum * $per_page, $total_objects ) ),
1153
- number_format_i18n( $total_objects ),
1154
- $page_links
1155
- );
1156
- $page_links_text .= "</div></div>\n";
1157
-
1158
- echo $page_links_text;
1159
- } else $page_links_text = '';
1160
-
1161
- //Get object identification headers
1162
- $headers = array(
1163
- 'actions' => __('Actions', 'seo-ultimate')
1164
- , 'id' => __('ID', 'seo-ultimate')
1165
- , 'name' => $type_label
1166
- );
1167
-
1168
- //Get meta field headers
1169
- foreach ($fields as $field) {
1170
- $headers[$field['name']] = $field['label'];
1171
- }
1172
-
1173
- //Output all headers
1174
- $this->admin_wftable_start($headers);
1175
-
1176
- //Output rows
1177
- foreach ($objects as $object) {
1178
-
1179
- switch ($genus) {
1180
- case 'post':
1181
- $id = intval($object->ID);
1182
- $name = $object->post_title;
1183
- $view_url = get_permalink($id);
1184
- $edit_url = get_edit_post_link($id);
1185
-
1186
- $status_obj = get_post_status_object($object->post_status);
1187
- switch ($object->post_status) {
1188
- case 'publish': $status = ''; break;
1189
- case 'inherit': $status = ''; break;
1190
- case 'auto-draft': continue; break;
1191
- default: $status = $status_obj->label; break;
1192
- }
1193
-
1194
- if ($status)
1195
- $name .= "<span class='su-meta-table-post-status'> &mdash; $status</span>";
1196
-
1197
- break;
1198
- case 'term':
1199
- $id = intval($object->term_id);
1200
- $name = $object->name;
1201
- $view_url = get_term_link($id, $type);
1202
- $edit_url = suwp::get_edit_term_link($id, $type);
1203
- break;
1204
- default: return false; break;
1205
- }
1206
-
1207
- $view_url = su_esc_attr($view_url);
1208
- $edit_url = su_esc_attr($edit_url);
1209
-
1210
- $actions = array(sprintf('<a href="%s">%s</a>', $view_url, __('View', 'seo-ultimate')));
1211
- if ($edit_url)
1212
- $actions[] = sprintf('<a href="%s">%s</a>', $edit_url, __('Edit', 'seo-ultimate'));
1213
- $actions = implode(' | ', $actions);
1214
-
1215
- $cells = compact('actions', 'id', 'name');
1216
-
1217
- //Get meta field cells
1218
- foreach ($fields as $field) {
1219
- $inputid = "{$genus}_{$id}_{$field['name']}";
1220
-
1221
- switch ($genus) {
1222
- case 'post':
1223
- $value = $this->get_postmeta($field['name'], $id);
1224
- break;
1225
- case 'term':
1226
- $value = $this->get_setting($field['term_settings_key'], array());
1227
- $value = isset($value[$id]) ? $value[$id] : null;
1228
- break;
1229
- }
1230
-
1231
- if ($is_update && $field['type'] == 'checkbox' && $value == '1' && !isset($_POST[$inputid]))
1232
- switch ($genus) {
1233
- case 'post': delete_post_meta($id, "_su_{$field['name']}"); $value = 0; break;
1234
- case 'term': $this->update_setting($field['term_settings_key'], false, null, $id); break;
1235
- }
1236
-
1237
- $cells[$field['name']] = $this->get_input_element(
1238
- $field['type'] //Type
1239
- , $inputid
1240
- , $value
1241
- , isset($field['options']) ? $field['options'] : false
1242
- );
1243
- }
1244
-
1245
- //Output all cells
1246
- $this->table_row($cells, $id, $type);
1247
- }
1248
-
1249
- //End table
1250
- $this->admin_wftable_end();
1251
-
1252
- echo $page_links_text;
1253
-
1254
- echo "</div>\n";
1255
-
1256
- return true;
1257
- }
1258
-
1259
- /**
1260
- * Returns the HTML for a given type of input element, without any surrounding <td> elements etc.
1261
- *
1262
- * @since 2.9
1263
- *
1264
- * @param string $type The type of input element (can be textbox, textarea, or checkbox)
1265
- * @param string $inputid The name/ID of the input element
1266
- * @param string $value The current value of the field
1267
- * @return string
1268
- */
1269
- function get_input_element($type, $name, $value=null, $extra=false, $inputid=true) {
1270
- if ($value === null) $value = $this->get_setting($name);
1271
-
1272
- if ($inputid === true) $inputid = $name;
1273
- if (strlen($inputid)) $inputid = " id='".su_esc_attr($inputid)."'";
1274
-
1275
- //Get HTML element
1276
- switch ($type) {
1277
- case 'textbox':
1278
- $value = su_esc_editable_html($value);
1279
- $placeholder = $extra ? " placeholder='" . su_esc_attr($extra) . "'" : '';
1280
- return "<input name='$name'$inputid value='$value'$placeholder type='text' class='form-control input-sm textbox regular-text' />";
1281
- break;
1282
- case 'textarea':
1283
- $value = su_esc_editable_html($value);
1284
- return "<textarea name='$name'$inputid type='text' rows='3' cols='50' class='textarea form-control regular-text'>$value</textarea>";
1285
- break;
1286
- case 'checkbox':
1287
- $checked = $value ? " checked='checked'" : '';
1288
- $html = "<input name='$name'$inputid value='1' type='checkbox' class='checkbox'$checked />";
1289
- if (is_string($extra)) {
1290
- $extra = su_esc_html($extra);
1291
- $html = "<label>$html&nbsp;$extra</label>";
1292
- }
1293
- return $html;
1294
- break;
1295
- case 'dropdown':
1296
- $html = "<select name='$name'$inputid onchange='javascript:su_toggle_select_children(this)' class='dropdown'>";
1297
- if (is_array($extra)) $html .= suhtml::option_tags($extra, $value); else $html .= $extra;
1298
- $html .= "</select>";
1299
- return $html;
1300
- break;
1301
- case 'hidden':
1302
- return "<input name='$name'$inputid value='$value' type='hidden' />";
1303
- break;
1304
- case 'jlsuggest':
1305
- $params = isset($extra['params']) ? $extra['params'] : '';
1306
- $placeholder = isset($extra['placeholder']) ? $extra['placeholder'] : '';
1307
-
1308
- return $this->get_jlsuggest_box($name, $value, $params, $placeholder);
1309
- break;
1310
- }
1311
-
1312
- return '';
1313
- }
1314
-
1315
- /**
1316
- * Creates an admin form subsection.
1317
- *
1318
- * @since 3.8
1319
- * @uses get_setting()
1320
- * @see get_input_element()
1321
- *
1322
- * @param string $field
1323
- * @param string|null $current_value
1324
- * @param string $trigger_value
1325
- * @param string $html
1326
- * @return string
1327
- */
1328
- function get_admin_form_subsection($field, $current_value, $trigger_value, $html) {
1329
- if ($current_value === null) $current_value = $this->get_setting($field);
1330
- $hidden = ($current_value == $trigger_value) ? '' : ' hidden';
1331
-
1332
- $field = su_esc_attr($field);
1333
- $trigger_value = su_esc_attr($trigger_value);
1334
- $html = "<div class='su_{$field}_{$trigger_value}_subsection$hidden'>$html</div>";
1335
- return $html;
1336
- }
1337
-
1338
- /**
1339
- * Creates multiple admin form subsections.
1340
- *
1341
- * @since 3.8
1342
- * @uses get_admin_form_subsection()
1343
- * @see get_input_element()
1344
- *
1345
- * @param string $field
1346
- * @param array $subsections Array of ($field => $trigger_value)
1347
- * @return string
1348
- */
1349
- function get_admin_form_subsections($field, $current_value, $subsections) {
1350
- $allhtml = '';
1351
- if (!in_array($current_value, $subsection_keys = array_keys($subsections))) $current_value = $subsection_keys[0];
1352
- foreach ($subsections as $trigger_value => $html)
1353
- $allhtml .= $this->get_admin_form_subsection($field, $current_value, $trigger_value, $html);
1354
- return $allhtml;
1355
- }
1356
-
1357
-
1358
- /********** ADMIN FORM FUNCTIONS **********/
1359
-
1360
- /**
1361
- * Begins an administration form.
1362
- * Outputs a subheader if provided, queues a success message upon settings update, outputs queued messages,
1363
- * opens a form tag, outputs a nonce field and other WordPress fields, and begins a form table.
1364
- *
1365
- * @since 0.1
1366
- * @uses SEO_Ultimate::key_to_hook()
1367
- * @uses get_module_key()
1368
- * @uses admin_subheader()
1369
- * @uses is_action()
1370
- * @uses print_message()
1371
- * @uses get_parent_module()
1372
- *
1373
- * @param mixed $header The text of the subheader that should go right before the form. Optional.
1374
- * @param boolean $table Whether or not to start a form table.
1375
- */
1376
- function admin_form_start($header = false, $table = true, $form = true) {
1377
-
1378
- if ($header) $this->admin_subheader($header);
1379
-
1380
- if ($form) {
1381
- $hook = $this->plugin->key_to_hook($this->get_module_or_parent_key());
1382
- if ($this->is_action('update')) $this->print_message('success', __('Settings updated.', 'seo-ultimate'));
1383
- echo "<form id='su-admin-form' class='form-horizontal' method='post' action='?page=$hook'>\n";
1384
- settings_fields($hook);
1385
- }
1386
-
1387
- echo "\n";
1388
- //if ($table) echo "<table class='form-table'>\n";
1389
- }
1390
-
1391
- /**
1392
- * Ends an administration form.
1393
- * Closes the table tag, outputs a "Save Changes" button, and closes the form tag.
1394
- *
1395
- * @since 0.1
1396
- * @uses get_parent_module()
1397
- *
1398
- * @param string|false $button The label of the submit button.
1399
- * @param boolean $table Whether or not a form table should be ended.
1400
- */
1401
- function admin_form_end($button = null, $table = true) {
1402
-
1403
- if ($button === null) $button = __('Save Changes'); //This string is used in normal WP, so we don't need a textdomain
1404
- //if ($table) echo "</table>\n";
1405
-
1406
- if ($button !== false) {
1407
- ?>
1408
- <p class="submit">
1409
- <input type="submit" class="button-primary" value="<?php echo $button ?>" />
1410
- </p>
1411
- </form>
1412
- <?php
1413
- }
1414
- }
1415
-
1416
- /**
1417
- * Begins an admin form table.
1418
- *
1419
- * @since 1.5
1420
- */
1421
- function admin_form_table_start() {
1422
- //echo "<table class='form-table'>\n";
1423
- }
1424
-
1425
- /**
1426
- * Ends an admin form table
1427
- *
1428
- * @since 1.5
1429
- */
1430
- function admin_form_table_end() {
1431
- //echo "</table>\n";
1432
- }
1433
-
1434
- /**
1435
- * @since 5.8
1436
- */
1437
- function child_admin_form_start($table=true) {
1438
- if ($this->get_parent_module() && $this->plugin->module_exists($this->get_parent_module())) {
1439
- if ($table) $this->admin_form_table_start();
1440
- } else {
1441
- $this->admin_form_start(false, $table);
1442
- }
1443
- }
1444
-
1445
- /**
1446
- * @since 5.8
1447
- */
1448
- function child_admin_form_end($table=true) {
1449
- if ($this->get_parent_module() && $this->plugin->module_exists($this->get_parent_module())) {
1450
- if ($table) $this->admin_form_table_end();
1451
- } else {
1452
- $this->admin_form_end(null, $table);
1453
- }
1454
- }
1455
-
1456
- /**
1457
- * Begins a "widefat" WordPress table.
1458
- *
1459
- * @since 1.8
1460
- *
1461
- * @param $headers Array of (CSS class => Internationalized column title)
1462
- */
1463
- function admin_wftable_start($headers = false) {
1464
- echo "\n<table class='widefat' cellspacing='0'>\n";
1465
- if ($headers)
1466
- $this->table_column_headers($headers);
1467
- else {
1468
- echo "\t<thead><tr>\n";
1469
- print_column_headers($this->plugin_page_hook);
1470
- echo "\t</tr></thead>\n";
1471
- echo "\t<tfoot><tr>\n";
1472
- print_column_headers($this->plugin_page_hook);
1473
- echo "\t</tr></tfoot>\n";
1474
- }
1475
- echo "\t<tbody>\n";
1476
- }
1477
-
1478
- /**
1479
- * Outputs a <tr> of <th scope="col"></th> tags based on an array of column headers.
1480
- *
1481
- * @since 2.1
1482
- *
1483
- * @param $headers Array of (CSS class => Internationalized column title)
1484
- */
1485
- function table_column_headers($headers) {
1486
- echo "\t<thead><tr>\n";
1487
- $mk = $this->get_module_key();
1488
- foreach ($headers as $class => $header) {
1489
- $class = is_numeric($class) ? '' : " class='su-$mk-$class su-$class'";
1490
- echo "\t\t<th scope='col'$class>$header</th>\n";
1491
- }
1492
- echo "\t</tr></thead>\n";
1493
- }
1494
-
1495
- /**
1496
- * Outputs <td> tags based on an array of cell data.
1497
- *
1498
- * @since 2.1
1499
- *
1500
- * @param $headers Array of (CSS class => Cell data)
1501
- */
1502
- function table_cells($cells) {
1503
-
1504
- if (count($this->get_admin_table_columns())) {
1505
- $columns = get_column_headers($this->plugin_page_hook);
1506
- $hidden = get_hidden_columns($this->plugin_page_hook);
1507
- foreach ( $columns as $column_name => $column_display_name ) {
1508
- $class = "class=\"$column_name column-$column_name\"";
1509
- $style = in_array($column_name, $hidden) ? ' style="display:none;"' : '';
1510
- echo "\t\t<td $class$style>".$cells[$column_name]."</td>\n";
1511
- }
1512
- } elseif (is_array($cells) && count($cells)) {
1513
- foreach ($cells as $class => $content) {
1514
- $class = is_numeric($class) ? '' : " class='su-$class'";
1515
- echo "\t\t<td$class>$content</td>\n";
1516
- }
1517
- }
1518
- }
1519
-
1520
- /**
1521
- * Outputs a <tr> tag with <td> children.
1522
- *
1523
- * @since 2.9
1524
- */
1525
- function table_row($cells, $id, $class) {
1526
- $mk = $this->get_module_key();
1527
- echo "\t<tr id='su-$mk-$id' class='su-$mk-$class'>\n";
1528
- $this->table_cells($cells);
1529
- echo "\t</tr>\n";
1530
- }
1531
-
1532
- /**
1533
- * Ends a "widefat" WordPress table.
1534
- *
1535
- * @since 1.8
1536
- */
1537
- function admin_wftable_end() {
1538
- echo "\t</tbody>\n</table>\n";
1539
- }
1540
-
1541
- /**
1542
- * Outputs the HTML that begins an admin form group.
1543
- *
1544
- * @since 1.5
1545
- *
1546
- * @param string $title The title of the group.
1547
- * @param bool $newtable Whether to open a new <table> element.
1548
- */
1549
- function admin_form_group_start($title, $newtable=true) {
1550
- echo "<div class='form-group'>\n<label class='col-sm-4 col-md-4 control-label'>$title</label><div class='col-sm-4 col-md-4'>\n";
1551
- }
1552
-
1553
- /**
1554
- * Outputs the HTML that ends an admin form group.
1555
- *
1556
- * @since 1.5
1557
- *
1558
- * @param bool $newtable Whether to close a <table> element.
1559
- */
1560
- function admin_form_group_end($newtable=true) {
1561
- echo "</div>\n<div class='col-sm-4 col-md-4 help-text'>\n</div>\n</div>\n";
1562
- }
1563
-
1564
- function admin_form_indent_start() {
1565
- echo "<div class='form-group'><div class='col-md-12'>";
1566
- }
1567
-
1568
- function admin_form_indent_end() {
1569
- echo "</div></div>";
1570
- }
1571
-
1572
- /**
1573
- * Outputs a text block into an admin form.
1574
- *
1575
- * @since 1.5
1576
- *
1577
- * @param string $text
1578
- */
1579
- function textblock($text) {
1580
- echo "<div class='form-group su-admin-form-textblock'>\n<div class='col-md-12'>\n";
1581
- echo $text;
1582
- echo "\n</div>\n</div>\n";
1583
- }
1584
-
1585
- /**
1586
- * Outputs a group of checkboxes into an admin form, and saves the values into the database after form submission.
1587
- *
1588
- * @since 0.1
1589
- * @uses is_action()
1590
- * @uses update_setting()
1591
- * @uses get_module_key()
1592
- * @uses get_setting()
1593
- *
1594
- * @param array $checkboxes An array of checkboxes. (Field/setting IDs are the keys, and descriptions are the values.)
1595
- * @param mixed $grouptext The text to display in a table cell to the left of the one containing the checkboxes. Optional.
1596
- */
1597
- function checkboxes($checkboxes, $grouptext=false, $args=array()) {
1598
-
1599
- extract(wp_parse_args($args, array(
1600
- 'output_tr' => true
1601
- )));
1602
-
1603
- //Save checkbox settings after form submission
1604
- if ($this->is_action('update')) {
1605
- foreach ($checkboxes as $name => $desc) {
1606
- $new_value = isset($_POST[$name]) ? ($_POST[$name] == '1') : false;
1607
-
1608
- if (is_array($desc)) {
1609
- $disabled = isset($desc['disabled']) ? $desc['disabled'] : false;
1610
- $desc = isset($desc['description']) ? $desc['description'] : '';
1611
- } else {
1612
- $disabled = false;
1613
- }
1614
-
1615
- if (!$disabled)
1616
- $this->update_setting($name, $new_value);
1617
-
1618
- if (strpos($desc, '%d') !== false) {
1619
- $name .= '_value';
1620
- $this->update_setting($name, sustr::to_int($_POST[$name]));
1621
- }
1622
- }
1623
- }
1624
-
1625
- if ($grouptext)
1626
- $this->admin_form_group_start($grouptext, false);
1627
- elseif ($output_tr)
1628
- echo "<div class='form-group su-admin-form-checkbox'>\n<div class='col-md-12'>\n";
1629
-
1630
- if (is_array($checkboxes)) {
1631
- foreach ($checkboxes as $name => $desc) {
1632
-
1633
- if (is_array($desc)) {
1634
- $indent = isset($desc['indent']) ? $desc['indent'] : false;
1635
- $disabled = isset($desc['disabled']) ? $desc['disabled'] : false;
1636
- $checked = isset($desc['checked']) ? $desc['checked'] : null;
1637
- $desc = $desc['description'];
1638
- } else {
1639
- $indent = false;
1640
- $disabled = false;
1641
- $checked = null;
1642
- }
1643
-
1644
- register_setting($this->get_module_key(), $name, array('sustr', 'to_int'));
1645
- $name = su_esc_attr($name);
1646
-
1647
- if (strpos($desc, '%d') === false) {
1648
- $onclick = '';
1649
- } else {
1650
- $int_var_name = $name.'_value';
1651
- $int_var_value = sustr::to_int($this->get_setting($int_var_name));
1652
- if ($this->get_setting($name) === true) $sfdisabled = ''; else $sfdisabled = "readonly='readonly' ";
1653
- $desc = str_replace('%d', "</label><input name='$int_var_name' id='$int_var_name' class='form-control input-sm nowidth-input' type='text' value='$int_var_value' size='2' maxlength='3' $sfdisabled/><label for='$name'>", $desc);
1654
- $desc = str_replace("<label for='$name'></label>", '', $desc);
1655
- $onclick = " onclick=\"javascript:document.getElementById('$int_var_name').readOnly=!this.checked;\"";
1656
- }
1657
-
1658
- if ($indent) $labelclass = " class='su-indent'"; else $labelclass = '';
1659
- echo "<div class='checkbox'><label for='$name'$labelclass><input name='$name' id='$name' type='checkbox' value='1'";
1660
- if ($checked !== false && ($checked === true || $this->get_setting($name) === true)) echo " checked='checked'";
1661
- if ($disabled) echo " disabled='disabled'";
1662
- echo "$onclick /> $desc</label></div>\n";
1663
- }
1664
- }
1665
-
1666
- if ($grouptext) {
1667
- $this->admin_form_group_end(false);
1668
- } elseif ($output_tr) {
1669
- echo "</div>\n</div>\n";
1670
- }
1671
- }
1672
-
1673
- /**
1674
- * Outputs a single checkbox into an admin form and saves its value into the database after form submission.
1675
- *
1676
- * @since 1.5
1677
- * @uses checkboxes()
1678
- *
1679
- * @param string $id The field/setting ID.
1680
- * @param string $desc The checkbox's label.
1681
- * @param mixed $grouptext The text to display in a table cell to the left of the one containing the checkbox. Optional.
1682
- * @return string The HTML that would render the checkbox.
1683
- */
1684
- function checkbox($id, $desc, $grouptext = false, $args=array()) {
1685
- $this->checkboxes(array($id => $desc), $grouptext, $args);
1686
- }
1687
-
1688
- /**
1689
- * Outputs a set of radio buttons into an admin form and saves the set's value into the database after form submission.
1690
- *
1691
- * @since 1.5
1692
- * @uses is_action()
1693
- * @uses update_setting()
1694
- * @uses admin_form_group_start()
1695
- * @uses admin_form_group_end()
1696
- * @uses su_esc_attr()
1697
- * @uses get_setting()
1698
- *
1699
- * @param string $name The name of the set of radio buttons.
1700
- * @param array $values The keys of this array are the radio button values, and the array values are the label strings.
1701
- * @param string|false $grouptext The text to display in a table cell to the left of the one containing the radio buttons. Optional.
1702
- */
1703
- function radiobuttons($name, $values, $grouptext=false) {
1704
-
1705
- //Save radio button setting after form submission
1706
- if ($this->is_action('update') && isset($_POST[$name]))
1707
- $this->update_setting($name, $_POST[$name]);
1708
-
1709
- if ($grouptext)
1710
- $this->admin_form_group_start($grouptext, false);
1711
- else
1712
- echo "<tr valign='top' class='su-admin-form-radio'>\n<td colspan='2'>\n";
1713
-
1714
- if (is_array($values)) {
1715
-
1716
- register_setting($this->get_module_key(), $name);
1717
- $name = su_esc_attr($name);
1718
-
1719
- $first = true;
1720
- foreach ($values as $value => $desc) {
1721
-
1722
- $value = su_esc_attr($value);
1723
- $id = "{$name}_{$value}";
1724
-
1725
- $current = (strcmp($this->get_setting($name), $value) == 0);
1726
- $class = $first ? 'first' : ''; $first = false;
1727
- if ($current) $class .= ' current-setting';
1728
- $class = trim($class);
1729
- if ($class) $class = " class='$class'";
1730
-
1731
- extract($this->insert_subfield_textboxes($name, $desc));
1732
-
1733
- echo "<div class='radio'><label for='$id'$class><input name='$name' id='$id' type='radio' value='$value'";
1734
- if ($current) echo " checked='checked'";
1735
- echo " /> $label";
1736
-
1737
- if (!sustr::has($label, '</label>')) echo '</label>';
1738
- echo "</div>\n";
1739
- }
1740
- }
1741
-
1742
- if ($grouptext)
1743
- $this->admin_form_group_end(false);
1744
- }
1745
-
1746
- /**
1747
- * Outputs a dropdown into an admin form and saves the dropdown's value into the database after form submission.
1748
- *
1749
- * @since 3.7
1750
- * @uses is_action()
1751
- * @uses update_setting()
1752
- * @uses admin_form_group_start()
1753
- * @uses admin_form_group_end()
1754
- * @uses su_esc_attr()
1755
- * @uses get_setting()
1756
- *
1757
- * @param string $name The name of the setting which the dropdown is supposed to set.
1758
- * @param array $values The keys of this array are the possible dropdown option values, and the array values are the option label strings.
1759
- * @param string|false $grouptext The text to display in a table cell to the left of the one containing the dropdown. Optional.
1760
- * @param string $text A printf-style format string in which "%s" is replaced with the dropdown. Use this to put text before or after the dropdown.
1761
- */
1762
- function dropdown($name, $values, $grouptext=false, $text='%s', $args=array()) {
1763
-
1764
- $in_table = isset($args['in_table']) ? $args['in_table'] : true;
1765
-
1766
- //Save dropdown setting after form submission
1767
- if ($this->is_action('update') && isset($_POST[$name]))
1768
- $this->update_setting($name, $_POST[$name]);
1769
-
1770
- if ($grouptext)
1771
- $this->admin_form_group_start($grouptext, false);
1772
- elseif ($in_table)
1773
- echo "<div class='form-group su-admin-form-dropdown'>\n<div class='col-sm-4 col-md-4'>\n";
1774
-
1775
- if (is_array($values)) {
1776
-
1777
- register_setting($this->get_module_key(), $name);
1778
-
1779
- $name = su_esc_attr($name);
1780
- $dropdown = "<select name='$name' id='$name'>\n"
1781
- . suhtml::option_tags($values, $this->get_setting($name))
1782
- . "</select>";
1783
- printf($text, $dropdown);
1784
- }
1785
-
1786
- if ($grouptext)
1787
- $this->admin_form_group_end();
1788
- elseif ($in_table)
1789
- echo "</div>\n<div class='col-sm-4 col-md-4 help-text'>\n</div>\n</div>\n";
1790
- }
1791
-
1792
- /**
1793
- * @since 3.0
1794
- */
1795
- function insert_subfield_textboxes($name, $label, $enabled = true) {
1796
-
1797
- $pattern = '/%(d|s)({([a-z0-9_-]+)})?/';
1798
-
1799
- if (preg_match($pattern, $label, $matches)) {
1800
- $is_int_field = ($matches[1] == 'd');
1801
- $sfname = $name.'_value';
1802
-
1803
- if (isset($matches[3]))
1804
- $sfname = $matches[3];
1805
-
1806
- if ($this->is_action('update'))
1807
- $sfvalue = stripslashes($_POST[$sfname]);
1808
- else
1809
- $sfvalue = $this->get_setting($sfname);
1810
-
1811
- if ($is_int_field)
1812
- $sfvalue = sustr::to_int($sfvalue);
1813
-
1814
- if ($this->is_action('update'))
1815
- $this->update_setting($sfname, $sfvalue);
1816
-
1817
- if ($enabled) $disabled = ''; else $disabled = " readonly='readonly'";
1818
-
1819
- $esfvalue = su_esc_attr($sfvalue);
1820
- $field_html = "</label><input class='textbox subfield form-control input-sm' name='$sfname' id='$sfname' type='text' value='$esfvalue'$disabled";
1821
- if ($is_int_field) $field_html .= " size='2' maxlength='3'";
1822
- $field_html .= " /><label for='$name'>";
1823
-
1824
- $label = preg_replace($pattern, $field_html, $label);
1825
- $label = preg_replace("@<label for='$name'>$@", '', $label);
1826
-
1827
- $onclick = " onclick=\"javascript:document.getElementById('$sfname').readOnly=!this.checked;\"";
1828
- } else
1829
- $onclick = '';
1830
-
1831
- return compact('label', 'onclick');
1832
- }
1833
-
1834
- /**
1835
- * Outputs a group of textboxes into an admin form, and saves the values into the database after form submission.
1836
- * Can also display a "Reset" link next to each textbox that reverts its value to a specified default.
1837
- *
1838
- * @since 0.1
1839
- * @uses is_action()
1840
- * @uses update_setting()
1841
- * @uses get_module_key()
1842
- * @uses get_setting()
1843
- *
1844
- * @param array $textboxes An array of textboxes. (Field/setting IDs are the keys, and descriptions are the values.)
1845
- * @param array $defaults An array of default textbox values that trigger "Reset" links. (The field/setting ID is the key, and the default value is the value.) Optional.
1846
- * @param mixed $grouptext The text to display in a table cell to the left of the one containing the textboxes. Optional.
1847
- */
1848
- function textboxes($textboxes, $defaults=array(), $grouptext=false, $args=array(), $textbox_args=array()) {
1849
-
1850
- $is_tree_parent = isset($args['is_tree_parent']) ? $args['is_tree_parent'] : false;
1851
- $is_ec_tree = isset($args['is_ec_tree']) ? $args['is_ec_tree'] : false;
1852
- $tree_level = isset($args['tree_level']) ? $args['tree_level'] : false;
1853
- $disabled = isset($args['disabled']) ? $args['disabled'] : false;
1854
- $in_table = isset($args['in_table']) ? $args['in_table'] : true;
1855
- $help_text = isset($args['help_text']) ? $args['help_text'] : false;
1856
- $callout = isset($args['callout']) ? $args['callout'] : false;
1857
-
1858
- if (!$disabled && $this->is_action('update')) {
1859
- foreach ($textboxes as $id => $title) {
1860
- if (isset($_POST[$id]))
1861
- $this->update_setting($id, stripslashes($_POST[$id]));
1862
- }
1863
- }
1864
-
1865
- $indentattrs = $indenttoggle = $hidden = '';
1866
- if ($tree_level !== false) {
1867
- $indentattrs = " class='su-indent su-indent-level-{$tree_level}'";
1868
- if ($is_ec_tree) {
1869
- if ($is_tree_parent)
1870
- $indenttoggle = "<span class='su-child-fields-toggle'>+</span> ";
1871
- else
1872
- $indenttoggle = "<span class='su-child-fields-toggle-filler'> </span> ";
1873
-
1874
- if ($tree_level > 1)
1875
- $hidden = " style='display: none;'";
1876
- }
1877
- }
1878
-
1879
- if ($grouptext) $this->admin_form_group_start($grouptext, false);
1880
-
1881
- foreach ($textboxes as $id => $title) {
1882
-
1883
- $before = isset($textbox_args[$id]['before']) ? $textbox_args[$id]['before'] : '';
1884
- $after = isset($textbox_args[$id]['after']) ? $textbox_args[$id]['after'] : '';
1885
- $placeholder = isset($textbox_args[$id]['placeholder']) ? $textbox_args[$id]['placeholder'] : '';
1886
-
1887
- register_setting($this->get_module_key(), $id);
1888
- $value = su_esc_editable_html($this->get_setting($id));
1889
- $id = su_esc_attr($id);
1890
- $resetmessage = su_esc_attr(__('Are you sure you want to replace the textbox contents with this default value?', 'seo-ultimate'));
1891
-
1892
- if ($callout)
1893
- echo "<div class='bs-callout bs-callout-grey'><h4>$callout</h4></div>\n";
1894
-
1895
- if ($grouptext)
1896
- echo "<div class='form-group'><label class='col-sm-4 col-md-4 control-label' for='$id'>$title</label>\n<div class='col-sm-4 col-md-4'>\n";
1897
- elseif ($in_table && strpos($title, '</a>') === false)
1898
- echo "<div class='form-group'$indentattrs$hidden>\n<label class='col-sm-4 col-md-4 control-label' for='$id'><span class='su-field-label-text'>$title</span></label>\n<div class='col-sm-4 col-md-4'>\n";
1899
- elseif ($in_table)
1900
- echo "<div class='form-group'$indentattrs$hidden>\n<label class='col-sm-4 col-md-4 control-label' for='$id'><span class='su-field-label-text'>$title</span></label>\n<div class='col-sm-4 col-md-4'>\n";
1901
-
1902
- echo $before;
1903
-
1904
- echo "<input name='$id' id='$id' type='text' value='$value' class='form-control input-sm regular-text' ";
1905
-
1906
- if ($placeholder) {
1907
- $a_placeholder = su_esc_attr($placeholder);
1908
- echo "placeholder='$placeholder' ";
1909
- }
1910
-
1911
- if ($disabled)
1912
- echo "disabled='disabled' />";
1913
- elseif (isset($defaults[$id])) {
1914
- $default = su_esc_editable_html($defaults[$id]);
1915
- echo "onkeyup=\"javascript:su_textbox_value_changed(this, '$default', '{$id}_reset')\" />";
1916
- echo "&nbsp;<a href=\"#\" id=\"{$id}_reset\" onclick=\"javascript:su_reset_textbox('$id', '$default', '$resetmessage', this); return false;\"";
1917
- if ($default == $value) echo ' class="hidden"';
1918
- echo ">";
1919
- _e('Reset', 'seo-ultimate');
1920
- echo "</a>";
1921
-
1922
- if (isset($args['open_url_value_link']))
1923
- echo ' |';
1924
- } else {
1925
- echo "/>";
1926
- }
1927
-
1928
- if (isset($args['open_url_value_link'])) {
1929
- echo " <a href='#' onclick=\"javascript:window.open(document.getElementById('$id').value);return false;\">";
1930
- echo su_esc_html($args['open_url_value_link']);
1931
- echo '</a>';
1932
- }
1933
-
1934
- echo $after;
1935
-
1936
- if ($grouptext)
1937
- echo "</div>\n";
1938
- elseif ($in_table)
1939
- echo "</div>\n";
1940
-
1941
- if ($help_text)
1942
- echo "<div class='col-sm-4 col-md-4'>$help_text</div>\n</div>\n";
1943
- else
1944
- echo "<div class='col-sm-4 col-md-4'></div>\n</div>\n";
1945
- }
1946
-
1947
- if ($grouptext) $this->admin_form_group_end(false);
1948
- }
1949
-
1950
- /**
1951
- * Outputs a single textbox into an admin form and saves its value into the database after form submission.
1952
- *
1953
- * @since 0.1
1954
- * @uses textboxes()
1955
- *
1956
- * @param string $id The field/setting ID.
1957
- * @param string $title The label of the HTML element.
1958
- * @param string|false $default The default textbox value. Setting this will trigger a "Reset" link. Optional.
1959
- * @return string The HTML that would render the textbox.
1960
- */
1961
- function textbox($id, $title, $default=false, $grouptext=false, $args=array(), $textbox_args=array()) {
1962
- if ($default === false) $default = array(); else $default = array($id => $default);
1963
- $this->textboxes(array($id => $title), $default, $grouptext, $args, array($id => $textbox_args));
1964
- }
1965
-
1966
- /**
1967
- * Outputs a group of textareas into an admin form, and saves the values into the database after form submission.
1968
- *
1969
- * @since 0.1
1970
- * @uses is_action()
1971
- * @uses update_setting()
1972
- * @uses get_module_key()
1973
- * @uses get_setting()
1974
- *
1975
- * @param array $textareas An array of textareas. (Field/setting IDs are the keys, and descriptions are the values.)
1976
- * @param int $rows The value of the textareas' rows attribute.
1977
- * @param int $cols The value of the textareas' cols attribute.
1978
- */
1979
- function textareas($textareas, $rows = 5, $cols = 30, $args=array()) {
1980
-
1981
- $disabled = isset($args['disabled']) ? $args['disabled'] : false;
1982
-
1983
- if (!$disabled && $this->is_action('update')) {
1984
- foreach ($textareas as $id => $title) {
1985
- if (isset($_POST[$id]))
1986
- $this->update_setting($id, stripslashes($_POST[$id]));
1987
- }
1988
- }
1989
-
1990
- foreach ($textareas as $id => $title) {
1991
- register_setting($this->get_module_key(), $id);
1992
- $value = su_esc_editable_html($this->get_setting($id));
1993
- $id = su_esc_attr($id);
1994
-
1995
- echo "<div class='form-group'>\n";
1996
- if ($title) echo "<label class='col-sm-4 col-md-4 control-label' for='$id'>$title</label>\n";
1997
- echo "<div class='col-sm-4 col-md-4'>";
1998
- echo "<textarea name='$id' id='$id' type='text' class='form-control regular-text' cols='$cols' rows='$rows'";
1999
- if ($disabled) echo " disabled='disabled'";
2000
- echo ">$value</textarea>";
2001
- echo "</div>\n<div class='col-sm-4 col-md-4 help-text'>\n</div>\n</div>\n";
2002
- }
2003
- }
2004
-
2005
- /**
2006
- * Outputs a single textarea into an admin form and saves its value into the database after form submission.
2007
- *
2008
- * @since 0.1
2009
- * @uses textareas()
2010
- *
2011
- * @param string $id The field/setting ID.
2012
- * @param string $title The label of the HTML element.
2013
- * @param int $rows The value of the textarea's rows attribute.
2014
- * @param int $cols The value of the textarea's cols attribute.
2015
- * @return string The HTML that would render the textarea.
2016
- */
2017
- function textarea($id, $title = '', $rows = 5, $cols = 30) {
2018
- $this->textareas(array($id => $title), $rows, $cols);
2019
- }
2020
-
2021
- /**
2022
- * @since 7.3
2023
- */
2024
- function jlsuggest_boxes($jls_boxes) {
2025
-
2026
- if ($this->is_action('update')) {
2027
- foreach ($jls_boxes as $jls_box) {
2028
-
2029
- if (!isset($jls_box['id']))
2030
- continue;
2031
-
2032
- $id = $jls_box['id'];
2033
-
2034
- if (isset($_POST[$id]))
2035
- $this->update_setting($id, stripslashes($_POST[$id]));
2036
- }
2037
- }
2038
-
2039
- foreach ($jls_boxes as $jls_box) {
2040
-
2041
- if (!isset($jls_box['id']))
2042
- continue;
2043
-
2044
- $jls_box = wp_parse_args($jls_box, array(
2045
- 'title' => ''
2046
- , 'params' => ''
2047
- ));
2048
-
2049
- extract($jls_box, EXTR_SKIP);
2050
-
2051
- register_setting($this->get_module_key(), $id);
2052
-
2053
- echo "<div class='form-group'>\n";
2054
- if ($title) echo "<label class='col-sm-4 col-md-4 control-label' for='$id'>$title</label>\n";
2055
- echo "<div class='col-sm-4 col-md-4'>";
2056
- echo $this->get_jlsuggest_box($id, $this->get_setting($id), $params);
2057
- echo "</div>\n<div class='col-sm-4 col-md-4 help-text'>\n</div>\n</div>\n";
2058
- }
2059
- }
2060
-
2061
- /**
2062
- * @since 7.3
2063
- */
2064
- function jlsuggest_box($id, $title, $params='') {
2065
- $this->jlsuggest_boxes(array(compact('id', 'title', 'params')));
2066
- }
2067
- /**
2068
- * @since 7.6.3
2069
- */
2070
- function medialib_boxes($media_boxes) {
2071
-
2072
- if ($this->is_action('update')) {
2073
- foreach ($media_boxes as $media_box) {
2074
-
2075
- if (!isset($media_box['id']))
2076
- continue;
2077
-
2078
- $id = $media_box['id'];
2079
-
2080
- if (isset($_POST[$id]))
2081
- $this->update_setting($id, stripslashes($_POST[$id]));
2082
- }
2083
- }
2084
-
2085
- foreach ($media_boxes as $media_box) {
2086
-
2087
- if (!isset($media_box['id']))
2088
- continue;
2089
-
2090
- $media_box = wp_parse_args($media_box, array(
2091
- 'title' => ''
2092
- , 'params' => ''
2093
- ));
2094
-
2095
- extract($media_box, EXTR_SKIP);
2096
-
2097
- register_setting($this->get_module_key(), $id);
2098
-
2099
- echo "<div class='form-group'>\n";
2100
- if ($title) echo "<label class='col-sm-4 col-md-4 control-label' for='$id'>$title</label>\n";
2101
- echo "<div class='col-sm-4 col-md-4'>";
2102
- echo "<div class='input-group'>
2103
- <input id='".su_esc_attr($id)."' name='".su_esc_attr($id)."' type='text' class='wpu-image form-control' size='40' value='".$this->get_setting($id)."'>
2104
- <span class='input-group-btn'>
2105
- <span class='btn btn-custom btn-file wpu-media-upload'>
2106
- <i class='fa fa-upload'></i> Upload Image <input type='file'>
2107
- </span>
2108
- </span>
2109
- </div>";
2110
- echo "</div>\n<div class='col-sm-4 col-md-4 help-text'>\n</div>\n</div>\n";
2111
- }
2112
- }
2113
-
2114
- /**
2115
- * @since 7.6.3
2116
- */
2117
- function medialib_box($id, $title, $params='') {
2118
- $this->medialib_boxes(array(compact('id', 'title', 'params')));
2119
- }
2120
-
2121
- /********** ADMIN SECURITY FUNCTIONS **********/
2122
-
2123
- /**
2124
- * Determines if a particular nonce-secured admin action is being executed.
2125
- *
2126
- * @since 0.1
2127
- * @uses SEO_Ultimate::key_to_hook()
2128
- * @uses get_module_key()
2129
- * @uses nonce_validates()
2130
- *
2131
- * @param string $action The name of the action to check.
2132
- * @return bool Whether or not the action is being executed.
2133
- */
2134
- function is_action($action) {
2135
- if (!isset($_GET['object']) || !($object = $_GET['object'])) $object = false;
2136
- return (
2137
- !empty($_GET['page'])
2138
- && (
2139
- ( strcasecmp($_GET['page'], $this->plugin->key_to_hook($this->get_module_key())) == 0 ) //Is $this module being shown?
2140
- || ( strlen($this->get_parent_module()) && strcasecmp($_GET['page'], $this->plugin->key_to_hook($this->get_parent_module())) == 0) //Is the parent module being shown?
2141
- )
2142
- && (
2143
- (!empty($_GET['action']) && $_GET['action'] == $action)
2144
- || (!empty($_POST['action']) && $_POST['action'] == $action)
2145
- ) //Is this $action being executed?
2146
- && $this->nonce_validates($action, $object) //Is the nonce valid?
2147
- );
2148
- }
2149
-
2150
- /**
2151
- * Determines whether a nonce is valid.
2152
- *
2153
- * @since 0.1
2154
- * @uses get_nonce_handle()
2155
- *
2156
- * @param string $action The name of the action.
2157
- * @param mixed $id The ID of the object being acted upon. Optional.
2158
- * @return bool Whether or not the nonce is valid.
2159
- */
2160
- function nonce_validates($action, $id = false) {
2161
- return check_admin_referer($this->get_nonce_handle($action, $id));
2162
- }
2163
-
2164
- /**
2165
- * Generates a unique name for a nonce.
2166
- *
2167
- * @since 0.1
2168
- * @uses get_parent_module()
2169
- * @uses get_module_key()
2170
- * @uses SU_PLUGIN_NAME
2171
- *
2172
- * @param string $action The name of the action.
2173
- * @param mixed $id The ID of the object being acted upon. Optional.
2174
- * @return The handle to use for the nonce.
2175
- */
2176
- function get_nonce_handle($action, $id = false) {
2177
-
2178
- $key = $this->get_parent_module();
2179
- if (!$key || !$this->plugin->module_exists($key)) $key = $this->get_module_key();
2180
-
2181
- $hook = $this->plugin->key_to_hook($key);
2182
-
2183
- if (strcmp($action, 'update') == 0) {
2184
- //We use the settings_fields() function, which outputs a nonce in this particular format.
2185
- return "$hook-options";
2186
- } else {
2187
- if ($id) $id = '-'.md5($id); else $id = '';
2188
- $handle = SU_PLUGIN_NAME."-$hook-$action$id";
2189
- return strtolower(str_replace(' ', '-', $handle));
2190
- }
2191
- }
2192
-
2193
- /**
2194
- * Returns a GET-action URL with an appended nonce.
2195
- *
2196
- * @since 0.1
2197
- * @uses get_module_key()
2198
- * @uses get_nonce_handle()
2199
- *
2200
- * @param string $action The name of the action.
2201
- * @param mixed $id The ID of the object being acted upon. Optional.
2202
- * @return The URL to use in an <a> tag.
2203
- */
2204
- function get_nonce_url($action, $object=false) {
2205
- $action = urlencode($action);
2206
- if ($object) $objectqs = '&object='.urlencode($object); else $objectqs = '';
2207
-
2208
- $hook = $this->plugin->key_to_hook($this->get_module_or_parent_key());
2209
-
2210
- //We don't need to escape ampersands since wp_nonce_url will do that for us
2211
- return wp_nonce_url("?page=$hook&action=$action$objectqs",
2212
- $this->get_nonce_handle($action, $object));
2213
- }
2214
-
2215
-
2216
- /********** ADMIN MESSAGE FUNCTIONS **********/
2217
-
2218
- /**
2219
- * Print a message (and any previously-queued messages) right away.
2220
- *
2221
- * @since 0.1
2222
- * @uses queue_message()
2223
- * @uses print_messages()
2224
- *
2225
- * @param string $type The message's type. Valid values are success, error, warning, and info.
2226
- * @param string $message The message text.
2227
- */
2228
- function print_message($type, $message) {
2229
- $this->queue_message($type, $message);
2230
- $this->print_messages();
2231
- }
2232
-
2233
- /**
2234
- * Adds a message to the queue.
2235
- *
2236
- * @since 0.1
2237
- * @uses $messages
2238
- *
2239
- * @param string $type The message's type. Valid values are success, error, warning, and info.
2240
- * @param string $message The message text.
2241
- */
2242
- function queue_message($type, $message) {
2243
- $this->messages[$type][] = $message;
2244
- }
2245
-
2246
- /**
2247
- * Prints all queued messages and flushes the queue.
2248
- *
2249
- * @since 0.1
2250
- * @uses $messages
2251
- */
2252
- function print_messages() {
2253
- foreach ($this->messages as $type => $messages) {
2254
- $messages = implode('<br />', $messages);
2255
- if ($messages) {
2256
- $type = su_esc_attr($type);
2257
- echo "<div class='su-message'><p class='su-$type'>$messages</p></div>\n";
2258
- }
2259
- }
2260
-
2261
- $this->messages = array();
2262
- }
2263
-
2264
- /**
2265
- * Prints a mini-style message.
2266
- *
2267
- * @since 2.1
2268
- */
2269
- function print_mini_message($type, $message) {
2270
- $type = su_esc_attr($type);
2271
- echo "<div class='su-status su-$type'>$message</div>";
2272
- }
2273
-
2274
- /********** ADMIN META FUNCTIONS **********/
2275
-
2276
- /**
2277
- * Gets a specified meta value of the current post (i.e. the post currently being edited in the admin,
2278
- * the post being shown, the post now in the loop, or the post with specified ID).
2279
- *
2280
- * @since 0.1
2281
- *
2282
- * @param string $key The meta key to fetch.
2283
- * @param mixed $id The ID number of the post/page.
2284
- * @return string The meta value requested.
2285
- */
2286
- function get_postmeta($key, $id=false) {
2287
-
2288
- if (!$id) {
2289
- //This code is different from suwp::get_post_id();
2290
- if (is_admin()) {
2291
- $id = empty($_REQUEST['post']) ? false : intval($_REQUEST['post']);
2292
- global $post;
2293
- } elseif (in_the_loop()) {
2294
- $id = intval(get_the_ID());
2295
- global $post;
2296
- } elseif (is_singular()) {
2297
- global $wp_query;
2298
- $id = $wp_query->get_queried_object_id();
2299
- $post = $wp_query->get_queried_object();
2300
- }
2301
- }
2302
-
2303
- if ($id) {
2304
-
2305
- if (isset($post) && $post)
2306
- $_post = $post;
2307
- else
2308
- $_post = get_post($id);
2309
-
2310
- $value = get_post_meta($id, "_su_$key", true);
2311
- $value = apply_filters("su_get_postmeta", $value, $key, $_post);
2312
- $value = apply_filters("su_get_postmeta-$key", $value, $key, $_post);
2313
- } else
2314
- $value = '';
2315
-
2316
- return $value;
2317
- }
2318
-
2319
- /**
2320
- * Generates the HTML for multiple post meta textboxes.
2321
- *
2322
- * @since 0.1
2323
- * @uses get_postmeta()
2324
- *
2325
- * @param array $textboxes An array of textboxes. (Field/setting IDs are the keys, and descriptions are the values.)
2326
- * @return string The HTML that would render the textboxes.
2327
- */
2328
- function get_postmeta_textboxes($textboxes, $textbox_args=array(), $grouptext=false) {
2329
-
2330
- $html = '';
2331
-
2332
- if ($grouptext) {
2333
- $h_grouptext = esc_html($grouptext);
2334
- $html = "<div class='form-group su textbox'>\n<h4 class='col-sm-4 col-md-4 control-label'>$h_grouptext</h4>\n<div class='col-sm-4 col-md-4'></div>\n<div class='col-sm-4 col-md-4 help-text'>\n</div>\n</div>\n";
2335
- }
2336
-
2337
- foreach ($textboxes as $id => $title) {
2338
-
2339
- $type = isset($textbox_args[$id]['type']) ? $textbox_args[$id]['type'] : 'text';
2340
- $input_clss = ($type == 'text') ? 'input-sm ' : '';
2341
-
2342
- register_setting('seo-ultimate', $id);
2343
- $value = su_esc_editable_html($this->get_postmeta($id));
2344
- $id = "_su_".su_esc_attr($id);
2345
-
2346
- $e_title = su_esc_attr($title);
2347
-
2348
- $html = "<div class='form-group su textbox'>\n<label class='col-sm-4 col-md-4 control-label' for='$id'>$title</label>\n<div class='col-sm-4 col-md-4'><input name='$id' id='$id' type='$type' value='$value' class='"
2349
- . $input_clss."form-control regular-text' tabindex='2' />\n"
2350
- . "</div>\n<div class='col-sm-4 col-md-4 help-text'>\n</div>\n</div>\n";
2351
- }
2352
-
2353
- if ($grouptext) {
2354
- $h_grouptext = esc_html($grouptext);
2355
- //$html .= "</table></td>\n</tr>\n";
2356
- }
2357
-
2358
- return $html;
2359
- }
2360
-
2361
- /**
2362
- * Generates the HTML for a single post meta textbox.
2363
- *
2364
- * @since 0.1
2365
- * @uses get_postmeta_textboxes()
2366
- *
2367
- * @param string $id The ID of the HTML element.
2368
- * @param string $title The label of the HTML element.
2369
- * @return string The HTML that would render the textbox.
2370
- */
2371
- function get_postmeta_textbox($id, $title, $args=array()) {
2372
- return $this->get_postmeta_textboxes(array($id => $title), array($id => $args));
2373
- }
2374
-
2375
- /**
2376
- * Generates the HTML for multiple post meta textareas.
2377
- *
2378
- * @since 3.9
2379
- * @uses get_postmeta()
2380
- *
2381
- * @param array $textareas An array of textareas. (Field/setting IDs are the keys, and descriptions are the values.)
2382
- * @return string The HTML that would render the textareas.
2383
- */
2384
- function get_postmeta_textareas($textareas) {
2385
-
2386
- $html = '';
2387
-
2388
- foreach ($textareas as $id => $title) {
2389
-
2390
- register_setting('seo-ultimate', $id);
2391
- $value = su_esc_editable_html($this->get_postmeta($id));
2392
- $id = "_su_".su_esc_attr($id);
2393
-
2394
- $html = "<div class='form-group su textarea'>\n<label class='col-sm-4 col-md-4 control-label' for='$id'>$title</label>\n<div class='col-sm-4 col-md-4'><textarea name='$id' id='$id' class='form-control regular-text' tabindex='2' cols='60' rows='3'>$value</textarea>\n"
2395
- ."</div>\n<div class='col-sm-4 col-md-4 help-text'>\n</div>\n</div>\n";
2396
- }
2397
-
2398
- return $html;
2399
- }
2400
-
2401
- /**
2402
- * Generates the HTML for a single post meta textarea.
2403
- *
2404
- * @since 3.9
2405
- * @uses get_postmeta_textareas()
2406
- *
2407
- * @param string $id The ID of the HTML element.
2408
- * @param string $title The label of the HTML element.
2409
- * @return string The HTML that would render the textarea.
2410
- */
2411
- function get_postmeta_textarea($id, $title) {
2412
- return $this->get_postmeta_textareas(array($id => $title));
2413
- }
2414
-
2415
- /**
2416
- * Generates the HTML for a group of post meta checkboxes.
2417
- *
2418
- * @since 0.1
2419
- * @uses get_module_key()
2420
- * @uses get_postmeta()
2421
- *
2422
- * @param array $checkboxes An array of checkboxes. (Field/setting IDs are the keys, and descriptions are the values.)
2423
- * @param string $grouptext The text to display in a table cell to the left of the one containing the checkboxes.
2424
- */
2425
- function get_postmeta_checkboxes($checkboxes, $grouptext) {
2426
-
2427
- $valign = (is_array($checkboxes) && count($checkboxes) > 1) ? 'top' : 'middle';
2428
- $html = "<div class='form-group su checkboxes'>\n<label class='col-sm-4 col-md-4 control-label'>$grouptext</label>\n<div class='col-sm-4 col-md-4'>\n";
2429
-
2430
- if (is_array($checkboxes)) {
2431
- foreach ($checkboxes as $name => $desc) {
2432
-
2433
- register_setting('seo-ultimate', $name);
2434
- $checked = ($this->get_postmeta($name) == 1);
2435
- $name = "_su_".su_esc_attr($name);
2436
-
2437
- $html .= "<div class='checkbox'><label for='$name'><input name='$name' id='$name' type='checkbox' tabindex='2' value='1'";
2438
- if ($checked) $html .= " checked='checked'";
2439
- $html .= " /> $desc</label></div>\n";
2440
- }
2441
- }
2442
-
2443
- $html .= "</div>\n<div class='col-sm-4 col-md-4 help-text'>\n</div>\n</div>\n";
2444
-
2445
- return $html;
2446
- }
2447
-
2448
- /**
2449
- * Generates the HTML for a single post meta checkbox.
2450
- *
2451
- * @since 0.1
2452
- * @uses get_postmeta_checkboxes()
2453
- *
2454
- * @param string $id The ID of the HTML element.
2455
- * @param string $title The label of the HTML element.
2456
- * @param string $grouptext The text to display in a table cell to the left of the one containing the checkboxes.
2457
- * @return string The HTML that would render the textbox.
2458
- */
2459
- function get_postmeta_checkbox($id, $title, $grouptext) {
2460
- return $this->get_postmeta_checkboxes(array($id => $title), $grouptext);
2461
- }
2462
-
2463
- /**
2464
- * Generates the HTML for a single <select> post meta dropdown.
2465
- *
2466
- * @since 2.5
2467
- * @uses get_module_key()
2468
- * @uses get_postmeta()
2469
- *
2470
- * @param string $name The name of the <select> element.
2471
- * @param array $options An array of options, where the array keys are the <option> values and the array values are the labels (<option> contents).
2472
- * @param string $grouptext The text to display in a table cell to the left of the one containing the dropdown.
2473
- * @return string $html
2474
- */
2475
- function get_postmeta_dropdown($name, $options, $grouptext) {
2476
-
2477
- register_setting('seo-ultimate', $name);
2478
- $current = $this->get_postmeta($name);
2479
- if ($current === '') {
2480
- $current = reset($options);
2481
- }
2482
- $name = "_su_".su_esc_attr($name);
2483
-
2484
- $html = "<div class='form-group su dropdown'>\n<label class='col-sm-4 col-md-4 control-label' for='$name'>$grouptext</label>\n<div class='col-sm-4 col-md-4'>\n";
2485
- $html .= "<select name='$name' id='$name' onchange='javascript:su_toggle_select_children(this)'>\n";
2486
- $html .= suhtml::option_tags($options, $current);
2487
- $html .= "</select>\n";
2488
- $html .= "</div>\n<div class='col-sm-4 col-md-4 help-text'></div>\n</div>\n";
2489
-
2490
- return $html;
2491
- }
2492
-
2493
- /**
2494
- * Generates the HTML for multiple post meta JLSuggest boxes.
2495
- *
2496
- * @since 7.3
2497
- *
2498
- * @param array $jls_boxes An array of JLSuggest boxes. (Field/setting IDs are the keys, and descriptions are the values.)
2499
- * @return string The HTML for the JLSuggest boxes.
2500
- */
2501
- function get_postmeta_jlsuggest_boxes($jls_boxes) {
2502
-
2503
- $html = '';
2504
-
2505
- foreach ($jls_boxes as $jls_box) {
2506
-
2507
- if (!isset($jls_box['id']) || !isset($jls_box['title']))
2508
- continue;
2509
-
2510
- $id = $jls_box['id'];
2511
- $title = $jls_box['title'];
2512
- $params = isset($jls_box['params']) ? $jls_box['params'] : false;
2513
-
2514
- register_setting('seo-ultimate', $id);
2515
- $value = su_esc_editable_html($this->get_postmeta($id));
2516
- $id = "_su_".su_esc_attr($id);
2517
-
2518
- $html .= "<div class='form-group su jlsuggestbox'>\n<label class='col-sm-4 col-md-4 control-label' for='$id'>$title</label>\n"
2519
- ."<div class='col-sm-4 col-md-4 su'>";
2520
- $html .= $this->get_jlsuggest_box($id, $value, $params);
2521
- $html .= "</div>\n<div class='col-sm-4 col-md-4 help-text'>\n</div>\n</div>\n";
2522
- }
2523
-
2524
- return $html;
2525
- }
2526
-
2527
- /**
2528
- * Generates the HTML for a single post meta JLSuggest box.
2529
- *
2530
- * @since 7.3
2531
- * @uses get_postmeta_jlsuggest_boxes()
2532
- *
2533
- * @param string $id The ID of the HTML element.
2534
- * @param string $title The label of the HTML element.
2535
- * @param string $params The value of the su:params attribute of the JLSuggest box (optional).
2536
- * @return string The HTML that would render the JLSuggest box.
2537
- */
2538
- function get_postmeta_jlsuggest_box($id, $title, $params=false) {
2539
- $jls_box = compact('id', 'title', 'params');
2540
- return $this->get_postmeta_jlsuggest_boxes(array($jls_box));
2541
- }
2542
-
2543
- /**
2544
- * Generates the HTML for multiple post meta mediaupload boxes.
2545
- *
2546
- * @since 7.6.3
2547
- *
2548
- * @param array $media_boxes An array of mediaupload boxes. (Field/setting IDs are the keys, and descriptions are the values.)
2549
- * @return string The HTML for the mediaupload boxes.
2550
- */
2551
- function get_postmeta_medialib_boxes($media_boxes) {
2552
-
2553
- $html = '';
2554
-
2555
- foreach ($media_boxes as $media_box) {
2556
-
2557
- if (!isset($media_box['id']) || !isset($media_box['title']))
2558
- continue;
2559
-
2560
- $id = $media_box['id'];
2561
- $title = $media_box['title'];
2562
-
2563
- register_setting('seo-ultimate', $id);
2564
- $value = su_esc_editable_html($this->get_postmeta($id));
2565
- $id = "_su_".su_esc_attr($id);
2566
-
2567
- $html .= "<div class='form-group su'>\n<label class='col-sm-4 col-md-4 control-label' for='$id'>$title</label>\n"
2568
- ."<div class='col-sm-4 col-md-4 su'>";
2569
- $html .= "<div class='input-group'>
2570
- <input id='".su_esc_attr($id)."' name='".su_esc_attr($id)."' type='text' class='wpu-image form-control' size='40' value='".$value."'>
2571
- <span class='input-group-btn'>
2572
- <span class='btn btn-custom btn-file wpu-media-upload'>
2573
- <i class='fa fa-upload'></i> Upload Image <input type='file'>
2574
- </span>
2575
- </span>
2576
- </div>";
2577
- $html .= "</div>\n<div class='col-sm-4 col-md-4 help-text'>\n</div>\n</div>\n";
2578
- }
2579
-
2580
- return $html;
2581
- }
2582
-
2583
- /**
2584
- * Generates the HTML for a single post meta mediaupload box.
2585
- *
2586
- * @since 7.6.3
2587
- * @uses get_postmeta_medialib_boxes()
2588
- *
2589
- * @param string $id The ID of the HTML element.
2590
- * @param string $title The label of the HTML element.
2591
- * @return string The HTML that would render the mediaupload box.
2592
- */
2593
- function get_postmeta_medialib_box($id, $title) {
2594
- $media_box = compact('id', 'title');
2595
- return $this->get_postmeta_medialib_boxes(array($media_box));
2596
- }
2597
-
2598
- /**
2599
- * Turns a <tr> into a post meta subsection.
2600
- *
2601
- * @since 2.5
2602
- * @uses get_postmeta
2603
- *
2604
- * @param string $field
2605
- * @param string $value
2606
- * @param string $html
2607
- * @return string $html
2608
- */
2609
- function get_postmeta_subsection($field, $value, $html) {
2610
- $hidden = ($this->get_postmeta($field) == $value) ? '' : ' hidden';
2611
-
2612
- $field = su_esc_attr($field);
2613
- $value = su_esc_attr($value);
2614
- $html = str_replace("<div class='form-group ", "<div class='form-group su_{$field}_{$value}_subsection$hidden ", $html);
2615
- return $html;
2616
- }
2617
-
2618
- /**
2619
- * Gets a specified meta value of the current term.
2620
- *
2621
- * @since 5.4
2622
- *
2623
- * @param string $key The database setting where the metadata is stored. The function will add a "taxonomy_" prefix.
2624
- * @param mixed $id The ID number of the post/page.
2625
- * @return string The meta value requested.
2626
- */
2627
- function get_termmeta($key, $id=false, $module=false) {
2628
-
2629
- global $wp_query;
2630
-
2631
- if (!$id && suwp::is_tax())
2632
- $id = $wp_query->get_queried_object_id();
2633
-
2634
- if (!$id)
2635
- return null;
2636
-
2637
- $tax_meta = $this->get_setting(sustr::startwith($key, 'taxonomy_'), array(), $module);
2638
-
2639
- if (is_array($tax_meta) && isset($tax_meta[$id]))
2640
- return $tax_meta[$id];
2641
-
2642
- return null;
2643
- }
2644
-
2645
- /********** CRON FUNCTION **********/
2646
-
2647
- /**
2648
- * Creates a cron job if it doesn't already exists, and ensures it runs at the scheduled time.
2649
- * Should be called in a module's init() function.
2650
- *
2651
- * @since 0.1
2652
- * @uses get_module_key()
2653
- *
2654
- * @param string $function The name of the module function that should be run.
2655
- * @param string $recurrence How often the job should be run. Valid values are hourly, twicedaily, and daily.
2656
- */
2657
- function cron($function, $recurrence) {
2658
-
2659
- $mk = $this->get_module_key();
2660
-
2661
- $hook = "su-$mk-".str_replace('_', '-', $function);
2662
- $start = time();
2663
-
2664
- if (wp_next_scheduled($hook) === false) {
2665
- //This is a new cron job
2666
-
2667
- //Schedule the event
2668
- wp_schedule_event($start, $recurrence, $hook);
2669
-
2670
- //Make a record of it
2671
- $psdata = (array)get_option('seo_ultimate', array());
2672
- $psdata['cron'][$mk][$function] = array($hook, $start, $recurrence);
2673
- update_option('seo_ultimate', $psdata);
2674
-
2675
- //Run the event now
2676
- call_user_func(array($this, $function));
2677
- }
2678
-
2679
- add_action($hook, array(&$this, $function));
2680
- }
2681
-
2682
- /********** JLSUGGEST **********/
2683
-
2684
- /**
2685
- * Initializes JLSuggest.
2686
- * Must be called in the admin_page_init() function of the module that wants to use JLSuggest.
2687
- *
2688
- * @since 6.0
2689
- * @uses jlsuggest_xml_ns()
2690
- * @uses SEO_Ultimate::queue_js()
2691
- * @uses SEO_Ultimate::queue_css()
2692
- */
2693
- function jlsuggest_init() {
2694
- add_action('admin_xml_ns', array(&$this, 'jlsuggest_xml_ns'));
2695
- $this->plugin->queue_js ('includes', 'encoder');
2696
- $this->plugin->queue_js ('includes/jlsuggest', 'jlsuggest');
2697
- $this->plugin->queue_css('includes/jlsuggest', 'jlsuggest');
2698
- }
2699
-
2700
- /**
2701
- * Outputs the SEO Ultimate XMLNS used by JLSuggest.
2702
- *
2703
- * @since 6.0
2704
- */
2705
- function jlsuggest_xml_ns() {
2706
- echo ' xmlns:su="http://johnlamansky.com/xmlns/seo-ultimate" ';
2707
- }
2708
-
2709
- /**
2710
- * Explodes a JLSuggest database string into an array with the destination type and the destination ID.
2711
- *
2712
- * @since 6.0
2713
- *
2714
- * @param $valstr The database string, e.g. http://example.com or obj_posttype_post/1
2715
- * @return array
2716
- */
2717
- function jlsuggest_value_explode($valstr) {
2718
-
2719
- if (is_array($valstr)) {
2720
-
2721
- if (count($valstr) == 3)
2722
- return $valstr;
2723
-
2724
- } elseif (is_string($valstr)) {
2725
-
2726
- if (sustr::startswith($valstr, 'obj_')) {
2727
- $valstr = sustr::ltrim_str($valstr, 'obj_');
2728
-
2729
- $valarr = explode('/', $valstr);
2730
- if (count($valarr) == 2) {
2731
- $valarr_type = explode('_', $valarr[0], 2);
2732
- if (count($valarr_type) == 2)
2733
- return array($valarr_type[0], $valarr_type[1], $valarr[1]);
2734
- else
2735
- return array($valarr[0], null, $valarr[1]);
2736
- } else
2737
- return array($valstr, null, null);
2738
- } else {
2739
- return array('url', null, $valstr);
2740
- }
2741
- }
2742
-
2743
- return array('url', null, '');
2744
- }
2745
-
2746
- /**
2747
- * Returns the HTML code for a JLSuggest textbox
2748
- *
2749
- * @since 6.0
2750
- *
2751
- * @param string $name The value of the textbox's name/ID attributes
2752
- * @param string $value The current database string associated with this textbox
2753
- */
2754
- function get_jlsuggest_box($name, $value, $params='', $placeholder='') {
2755
-
2756
- list($to_genus, $to_type, $to_id) = $this->jlsuggest_value_explode($value);
2757
-
2758
- $text_dest = '';
2759
- $disabled = false;
2760
-
2761
- switch ($to_genus) {
2762
-
2763
- case 'posttype':
2764
- $selected_post = get_post($to_id);
2765
- if ($selected_post) {
2766
- $selected_post_type = get_post_type_object($selected_post->post_type);
2767
- $text_dest = $selected_post->post_title . '<span class="type">&nbsp;&mdash;&nbsp;'.$selected_post_type->labels->singular_name.'</span>';
2768
- } else {
2769
- $selected_post_type = get_post_type_object($to_type);
2770
- if ($selected_post_type)
2771
- $text_dest = sprintf(__('A Deleted %s', 'seo-ultimate'), $selected_post_type->labels->singular_name);
2772
- else
2773
- $text_dest = __('A Deleted Post', 'seo-ultimate');
2774
- $text_dest = '<span class="type">' . $text_dest . '</span>';
2775
- $disabled = true;
2776
- }
2777
- break;
2778
- case 'taxonomy':
2779
- if ($selected_taxonomy = get_taxonomy($to_type)) {
2780
- if ($selected_term = get_term($to_id, $selected_taxonomy->name)) {
2781
- $text_dest = $selected_term->name . '<span class="type">&nbsp;&mdash;&nbsp;'.$selected_taxonomy->labels->singular_name.'</span>';
2782
- } else {
2783
- $text_dest = sprintf(__('A Deleted %s', 'seo-ultimate'), $selected_taxonomy->labels->singular_name);
2784
- $text_dest = '<span class="type">' . $text_dest . '</span>';
2785
- $disabled = true;
2786
- }
2787
- } else {
2788
- $text_dest = __('A Deleted Term', 'seo-ultimate');
2789
- $text_dest = '<span class="type">' . $text_dest . '</span>';
2790
- $disabled = true;
2791
- }
2792
- break;
2793
- case 'home':
2794
- $text_dest = __('Blog Homepage', 'seo-ultimate');
2795
- break;
2796
- case 'author':
2797
- if (is_user_member_of_blog($to_id)) {
2798
- $selected_author = get_userdata($to_id);
2799
- $text_dest = $selected_author->user_login . '<span class="type">&nbsp;&mdash;&nbsp;'.__('Author', 'seo-ultimate').'</span>';
2800
- } else {
2801
- $text_dest = __('A Deleted User', 'seo-ultimate');
2802
- $text_dest = '<span class="type">' . $text_dest . '</span>';
2803
- $disabled = true;
2804
- }
2805
- break;
2806
- case 'internal-link-alias':
2807
-
2808
- $alias_dir = $this->get_setting('alias_dir', 'go', 'internal-link-aliases');
2809
- $aliases = $this->get_setting('aliases', array(), 'internal-link-aliases');
2810
-
2811
- if (isset($aliases[$to_id]['to'])) {
2812
- $h_alias_to = su_esc_html($aliases[$to_id]['to']);
2813
- $text_dest = "/$alias_dir/$h_alias_to/" . '<span class="type">&nbsp;&mdash;&nbsp;';
2814
-
2815
- if ($this->plugin->module_exists('internal-link-aliases')) {
2816
- $text_dest .= __('Link Mask', 'seo-ultimate');
2817
- } else {
2818
- $text_dest .= __('Link Mask (Disabled)', 'seo-ultimate');
2819
- $disabled = true;
2820
- }
2821
- $text_dest .= '</span>';
2822
- } else {
2823
- $text_dest = __('A Deleted Link Mask', 'seo-ultimate');
2824
- $text_dest = '<span class="type">' . $text_dest . '</span>';
2825
- $disabled = true;
2826
- }
2827
-
2828
- break;
2829
- }
2830
-
2831
- $is_url = (('url' == $to_genus) && !$text_dest);
2832
-
2833
- $to_genus_type = implode('_', array_filter(array($to_genus, $to_type)));
2834
- $obj = 'obj_' . implode('/', array_filter(array($to_genus_type, $to_id)));
2835
-
2836
- //URL textbox
2837
- //(hide if object is selected)
2838
- $html = "<input name='$name' id='$name' value='";
2839
- $html .= su_esc_editable_html($is_url ? $to_id : $obj);
2840
- $html .= "'";
2841
-
2842
- if ($params) {
2843
- $e_params = su_esc_attr($params);
2844
- $html .= " su:params='$e_params'";
2845
- }
2846
-
2847
- if ($placeholder) {
2848
- $e_placeholder = su_esc_attr($placeholder);
2849
- $html .= " placeholder='$e_placeholder'";
2850
- }
2851
-
2852
- $html .= " type='text' class='form-control input-sm textbox regular-text jlsuggest'";
2853
- $html .= ' title="' . __('Type a URL or start typing the name of an item on your site', 'seo-ultimate') . '"';
2854
- $html .= $is_url ? '' : ' style="display:none;" ';
2855
- $html .= ' />';
2856
-
2857
- //Object box
2858
- //(hide if URL is entered)
2859
- $disabled = $disabled ? ' jlsuggest-disabled' : '';
2860
- $html .= "<div class='jls_text_dest$disabled'";
2861
- $html .= $is_url ? ' style="display:none;" ' : '';
2862
- $html .= '>';
2863
- $html .= '<div class="jls_text_dest_text">';
2864
- $html .= $text_dest;
2865
- $html .= '</div>';
2866
- $html .= '<div><a href="#" onclick="javascript:return false;" class="jls_text_dest_close" title="'.__('Remove this location from this textbox', 'seo-ultimate').'">'.__('X', 'seo-ultimate').'</a></div>';
2867
- $html .= '</div>';
2868
-
2869
- return $html;
2870
- }
2871
-
2872
- /**
2873
- * Converts a JLSuggest database string into a URL.
2874
- *
2875
- * @since 6.0
2876
- *
2877
- * @param string $value The JLSuggest database string to convert.
2878
- * @param bool $get_src_if_media Whether to get the URL to the actual media item rather than the URL to its WP-powered singular page, if the item is an attachment.
2879
- * @return string The URL of the referenced destination
2880
- */
2881
- function jlsuggest_value_to_url($value, $get_src_if_media=false) {
2882
-
2883
- list($to_genus, $to_type, $to_id) = $this->jlsuggest_value_explode($value);
2884
-
2885
- switch ($to_genus) {
2886
- case 'url':
2887
- return $to_id; break;
2888
- case 'posttype':
2889
- $to_id = (int)$to_id;
2890
- switch (get_post_status($to_id)) {
2891
- case 'publish':
2892
- if ($get_src_if_media && 'attachment' == get_post_type($to_id))
2893
- return wp_get_attachment_url($to_id);
2894
-
2895
- return get_permalink($to_id);
2896
- case false: //Post doesn't exist
2897
- default: //Post exists but isn't published
2898
- return false;
2899
- }
2900
- break;
2901
- case 'taxonomy':
2902
- $to_id = (int)$to_id;
2903
- $term_link = get_term_link($to_id, $to_type);
2904
- if ($term_link && !is_wp_error($term_link)) return $term_link;
2905
- return false;
2906
- break;
2907
- case 'home':
2908
- return suwp::get_blog_home_url(); break;
2909
- case 'author':
2910
- $to_id = (int)$to_id;
2911
- if (is_user_member_of_blog($to_id))
2912
- return get_author_posts_url($to_id);
2913
- return false;
2914
- break;
2915
- case 'internal-link-alias':
2916
- if ($this->plugin->module_exists('internal-link-aliases')) {
2917
- $alias_dir = $this->get_setting('alias_dir', 'go', 'internal-link-aliases');
2918
- $aliases = $this->get_setting('aliases', array(),'internal-link-aliases');
2919
-
2920
- if (isset($aliases[$to_id]['to'])) {
2921
- $u_alias_to = urlencode($aliases[$to_id]['to']);
2922
- return get_bloginfo('url') . "/$alias_dir/$u_alias_to/";
2923
- }
2924
- }
2925
- return false;
2926
- break;
2927
- }
2928
-
2929
- return false;
2930
- }
2931
-
2932
-
2933
- /**
2934
- * @since 7.6
2935
- */
2936
- function should_show_sdf_theme_promo() {
2937
- return $this->is_sdf_theme_promo_applicable() && $this->get_setting('sdf_theme','', 'settings');
2938
- }
2939
-
2940
- /**
2941
- * @since 7.6
2942
- */
2943
- function is_sdf_theme_promo_applicable() {
2944
- //If the current user can install themes and if SDF isn't already uploaded...
2945
- if (current_user_can('install_themes') && (wp_get_theme('seodesign')->errors() === false)){
2946
- $theme = wp_get_theme(); // gets the current theme
2947
- return ('SEO Design Framework' == $theme->name || 'seodesign' == $theme->template || 'seodesign' == $theme->parent_theme) ? false : true;
2948
- }
2949
- else{
2950
- return true;
2951
- }
2952
- }
2953
-
2954
-
2955
- /**
2956
- * Display the RSS entries in a list.
2957
- *
2958
- * @since 7.6.2
2959
- *
2960
- * @param string|array|object $rss RSS url.
2961
- * @param array $args Widget arguments.
2962
- */
2963
- function promo_sdf_banners_rss_output( $rss, $args = array() ) {
2964
- if ( is_string( $rss ) ) {
2965
- $rss = fetch_feed($rss);
2966
- } elseif ( is_array($rss) && isset($rss['url']) ) {
2967
- $args = $rss;
2968
- $rss = fetch_feed($rss['url']);
2969
- } elseif ( !is_object($rss) ) {
2970
- return;
2971
- }
2972
-
2973
- if ( is_wp_error($rss) ) {
2974
- if ( is_admin() || current_user_can('manage_options') )
2975
- echo '<p>' . sprintf( __('<strong>RSS Error</strong>: %s'), $rss->get_error_message() ) . '</p>';
2976
- return;
2977
- }
2978
-
2979
- $default_args = array( 'show_author' => 0, 'show_date' => 0, 'show_summary' => 0 );
2980
- $args = wp_parse_args( $args, $default_args );
2981
- extract( $args, EXTR_SKIP );
2982
-
2983
- $items = (int) $items;
2984
- if ( $items < 1 || 20 < $items )
2985
- $items = 10;
2986
- $show_summary = (int) $show_summary;
2987
- $show_author = (int) $show_author;
2988
- $show_date = (int) $show_date;
2989
-
2990
- if ( !$rss->get_item_quantity() ) {
2991
- echo '<ul><li>' . __( 'An error has occurred, which probably means the feed is down. Try again later.' ) . '</li></ul>';
2992
- $rss->__destruct();
2993
- unset($rss);
2994
- return;
2995
- }
2996
-
2997
- foreach ( $rss->get_items(0, $items) as $item ) {
2998
- $link = $item->get_link();
2999
- while ( stristr($link, 'http') != $link )
3000
- $link = substr($link, 1);
3001
- $link = esc_url(strip_tags($link));
3002
- $title = esc_attr(strip_tags($item->get_title()));
3003
- if ( empty($title) )
3004
- $title = '';
3005
-
3006
- $desc = str_replace( array("\n", "\r"), ' ', esc_attr( strip_tags( @html_entity_decode( $item->get_description(), ENT_QUOTES, get_option('blog_charset') ) ) ) );
3007
- $excerpt = wp_html_excerpt( $desc, 120 );
3008
-
3009
- // Append ellipsis. Change existing [...] to [&hellip;].
3010
- if ( '[...]' == substr( $excerpt, -5 ) )
3011
- $excerpt = substr( $excerpt, 0, -5 ) . '[&hellip;]';
3012
- elseif ( '[&hellip;]' != substr( $excerpt, -10 ) && $desc != $excerpt )
3013
- $excerpt .= ' [&hellip;]';
3014
-
3015
- $excerpt = esc_html( $excerpt );
3016
-
3017
- if ( $show_summary ) {
3018
- $summary = "<p>$excerpt</p>";
3019
- } else {
3020
- $summary = '';
3021
- }
3022
-
3023
- $date = '';
3024
- if ( $show_date ) {
3025
- $date = $item->get_date( 'U' );
3026
-
3027
- if ( $date ) {
3028
- $date = ' <span class="rss-date">' . date_i18n( get_option( 'date_format' ), $date ) . '</span>';
3029
- }
3030
- }
3031
-
3032
- $author = '';
3033
- if ( $show_author ) {
3034
- $author = $item->get_author();
3035
- if ( is_object($author) ) {
3036
- $author = $author->get_name();
3037
- $author = ' <cite>' . esc_html( strip_tags( $author ) ) . '</cite>';
3038
- }
3039
- }
3040
-
3041
- if ( $link == '' ) {
3042
- echo "<h3>$title</h3>{$summary}";
3043
- } else {
3044
- echo "<h3>$title</h3>{$summary}<p><a class='btn btn-large btn-warning' href='$link' target='_blank' rel='nofollow'>Read More</a></p>";
3045
- }
3046
- }
3047
- $rss->__destruct();
3048
- unset($rss);
3049
- }
3050
-
3051
- /**
3052
- * @since 7.6.2
3053
- */
3054
- function promo_sdf_banners() {
3055
-
3056
- if ($this->should_show_sdf_theme_promo()) {
3057
- ?>
3058
- <div id="sds_promo_blog_post" class="hide">
3059
- <?php $this->promo_sdf_banners_rss_output( 'http://feeds.seodesignsolutions.com/SeoDesignSolutionsBlog', array('show_summary' => 1, 'show_date' => 0, 'items' => 1) ); ?>
3060
- </div>
3061
- <div id="sdf-promo-carousel"></div>
3062
- <?php
3063
- }
3064
- }
3065
- }
 
 
 
 
 
 
 
3066
  ?>
1
+ <?php
2
+ /**
3
+ * The pseudo-abstract class upon which all modules are based.
4
+ *
5
+ * @abstract
6
+ * @since 0.1
7
+ */
8
+ class SU_Module {
9
+
10
+ /********** VARIABLES **********/
11
+
12
+ /**
13
+ * @since 0.1
14
+ * @var string
15
+ */
16
+ var $module_key;
17
+
18
+ /**
19
+ * Stores the parent module (an SU_Module object) if this module has a parent.
20
+ *
21
+ * @since 1.5
22
+ * @var SU_Module
23
+ */
24
+ var $parent_module = null;
25
+
26
+ /**
27
+ * Stores any child modules as an array of SU_Module objects.
28
+ *
29
+ * @since 1.5
30
+ * @var array
31
+ */
32
+ var $modules = array();
33
+
34
+ /**
35
+ * Stores the module file's URL.
36
+ *
37
+ * @since 0.1
38
+ * @var string
39
+ */
40
+ var $module_url;
41
+
42
+ /**
43
+ * Stores the URL to the directory containing the module file. Has trailing slash.
44
+ *
45
+ * @since 1.5
46
+ * @var string
47
+ */
48
+ var $module_dir_url;
49
+
50
+ /**
51
+ * Stores the module file's URL relative to the plugin directory.
52
+ *
53
+ * @since 2.1
54
+ * @var string
55
+ */
56
+ var $module_rel_url;
57
+
58
+ /**
59
+ * Stores the URL to the directory containing the module file, relative to the plugin directory. Has trailing slash.
60
+ *
61
+ * @since 2.1
62
+ * @var string
63
+ */
64
+ var $module_dir_rel_url;
65
+
66
+ /**
67
+ * Stores the module's plugin page hook (the full hook with seo_page_ prefix).
68
+ * A reconstructed value of the get_plugin_page_hook() function, which is only available after admin init.
69
+ *
70
+ * @since 0.1
71
+ * @var string
72
+ */
73
+ var $plugin_page_hook;
74
+
75
+ /**
76
+ * Contains messages that are waiting to be displayed to the user.
77
+ *
78
+ * @since 0.1
79
+ * @var array
80
+ */
81
+ var $messages = array();
82
+
83
+ /**
84
+ * Stores the plugin object by reference.
85
+ *
86
+ * @since 1.5
87
+ */
88
+ var $plugin = null;
89
+
90
+
91
+ /********** CONSTRUCTOR FUNCTION **********/
92
+
93
+ /**
94
+ * PHP4 constructor that points to the likely-overloaded PHP5 constructor.
95
+ *
96
+ * @since 0.1
97
+ * @uses __construct()
98
+ */
99
+ /*function SU_Module() {
100
+ $this->__construct();
101
+ }*/
102
+
103
+
104
+ /********** PSEUDO-ABSTRACT FUNCTIONS **********/
105
+
106
+ /**
107
+ * PHP5 constructor.
108
+ *
109
+ * @since 0.1
110
+ */
111
+ function __construct() { }
112
+
113
+ /**
114
+ * The module's official title.
115
+ *
116
+ * @since 1.5
117
+ *
118
+ * @return string
119
+ */
120
+ static function get_module_title() { return ''; }
121
+
122
+ /**
123
+ * The title to be used by parent modules.
124
+ *
125
+ * @since 1.5
126
+ *
127
+ * @return string
128
+ */
129
+ function get_module_subtitle() { return isset($this) ? $this->get_module_title() : ''; }
130
+
131
+ /**
132
+ * The title of the admin page, which is displayed in the <title> and <h2> tags.
133
+ * Is the same as the menu title by default.
134
+ *
135
+ * @since 0.1
136
+ *
137
+ * @return string The title shown on this module's admin page.
138
+ */
139
+ function get_page_title() { return isset($this) ? $this->get_module_title() : ''; }
140
+
141
+ /**
142
+ * The title that appears on the administration navigation menu.
143
+ *
144
+ * @since 0.1
145
+ *
146
+ * @return string The title shown on the admin menu.
147
+ */
148
+
149
+ static function get_menu_title() { return isset($this) ? $this->get_module_title() : ''; }
150
+
151
+ /**
152
+ * Determines where this module's admin page should appear relative to those of other modules.
153
+ * If two modules have the same menu position index, they are sorted alphabetically.
154
+ *
155
+ * @since 0.1
156
+ *
157
+ * @return int The menu position index.
158
+ */
159
+ static function get_menu_pos() { return 10; }
160
+
161
+ /**
162
+ * Determines where this module's admin contents should appear on the parent page relative to those of other sibling modules.
163
+ * If two modules have the same order index, they are sorted alphabetically.
164
+ *
165
+ * @since 1.5
166
+ *
167
+ * @return int The child order index.
168
+ */
169
+ static function get_child_order() { return 999; }
170
+
171
+ /**
172
+ * The number that should be displayed in a bubble next to the module's menu title.
173
+ * A return value of zero means no bubble is shown.
174
+ *
175
+ * @since 0.1
176
+ *
177
+ * @return int The number that should be displayed.
178
+ */
179
+ function get_menu_count() {
180
+ $count = 0;
181
+ foreach ($this->modules as $key => $module) {
182
+ $count += $this->modules[$key]->get_menu_count();
183
+ }
184
+ return $count;
185
+ }
186
+
187
+ /**
188
+ * Whether or not the module will ever return a non-zero menu count.
189
+ *
190
+ * @since 1.5
191
+ *
192
+ * @return boolean
193
+ */
194
+ static function has_menu_count() { return false; }
195
+
196
+ /**
197
+ * A descriptive label of the menu count.
198
+ *
199
+ * @since 0.3
200
+ *
201
+ * @return string The label.
202
+ */
203
+ function get_menu_count_label() { return ''; }
204
+
205
+ /**
206
+ * Indicates under which top-level menu this module's admin page should go.
207
+ * Examples: seo (This plugin's SEO menu), options-general.php (The Settings menu)
208
+ *
209
+ * @since 0.1
210
+ *
211
+ * @return string The value to pass to WordPress's add_submenu_page() function.
212
+ */
213
+ function get_menu_parent(){ return 'seo'; }
214
+
215
+ /**
216
+ * Returns the hook of this module's menu parent.
217
+ * Examples: seo (This plugin's SEO menu), settings (The Settings menu), toplevel (The toplevel)
218
+ *
219
+ * @since 0.1
220
+ *
221
+ * @return string The hook of the module's menu parent.
222
+ */
223
+ function get_menu_parent_hook() { return $this->get_menu_parent(); }
224
+
225
+ /**
226
+ * @since 7.2.5
227
+ */
228
+ function belongs_in_admin($admin_scope = null) {
229
+
230
+ if ($admin_scope === null)
231
+ $admin_scope = suwp::get_admin_scope();
232
+
233
+ switch ($admin_scope) {
234
+ case 'blog':
235
+ return true;
236
+ break;
237
+ case 'network':
238
+ case 'user':
239
+ default:
240
+ return false;
241
+ break;
242
+ }
243
+ }
244
+
245
+ /**
246
+ * The status (enabled/silenced/hidden) of the module when the module is newly added to the plugin.
247
+ *
248
+ * @since 1.5
249
+ *
250
+ * @return int Either SU_MODULE_ENABLED, SU_MODULE_SILENCED, or SU_MODULE_HIDDEN.
251
+ */
252
+ function get_default_status() { return SU_MODULE_ENABLED; }
253
+
254
+ /**
255
+ * The module key of this module's parent. Defaults to false (no parent).
256
+ *
257
+ * @since 0.3
258
+ *
259
+ * @return string|bool
260
+ */
261
+ static function get_parent_module() { return false; }
262
+
263
+ /**
264
+ * Returns an array of admin page tabs; the label is the key and the callback is the value.
265
+ *
266
+ * @since 1.5
267
+ *
268
+ * @return array
269
+ */
270
+ function get_admin_page_tabs() { return array(); }
271
+
272
+ /**
273
+ * Whether or not the module can "exist on its own."
274
+ * Determines whether or not the module appears in the Module Manager.
275
+ *
276
+ * @since 1.5
277
+ *
278
+ * @return bool
279
+ */
280
+ static function is_independent_module() {
281
+ return true;
282
+ }
283
+
284
+ /**
285
+ * The array key of the plugin's settings array in which this module's settings are stored.
286
+ *
287
+ * @since 1.5
288
+ *
289
+ * @return string
290
+ */
291
+ function get_settings_key() {
292
+ if (isset($this)) {
293
+ if (strlen($parent = $this->get_parent_module()) && !$this->is_independent_module())
294
+ return $this->plugin->modules[$parent]->get_settings_key();
295
+ else
296
+ return $this->get_module_key();
297
+ } else {
298
+ if (strlen($parent = self::get_parent_module()) && !self::is_independent_module()) {
299
+ global $seo_ultimate;
300
+ return $seo_ultimate->modules[$parent]->get_settings_key();
301
+ } else {
302
+ if (strlen($parent = self::get_parent_module()) && !self::is_independent_module()) {
303
+ global $seo_ultimate;
304
+ return $seo_ultimate->get_module_key();
305
+ } else {
306
+ return false;
307
+ }
308
+ }
309
+ }
310
+ }
311
+
312
+ /**
313
+ * Whether or not this module should be the default screen for the "SEO" menu.
314
+ *
315
+ * @since 1.5
316
+ * @return bool
317
+ */
318
+ function is_menu_default() { return false; }
319
+
320
+ /**
321
+ * Called after the module has been constructed and its variables have been filled.
322
+ *
323
+ * @since 3.9
324
+ */
325
+ function load() {}
326
+
327
+ /**
328
+ * Called at WordPress's init hook.
329
+ *
330
+ * @since 0.1
331
+ */
332
+ function init() {}
333
+
334
+ /**
335
+ * Called under 3 circumstances:
336
+ * 1. When the SEO Ultimate plugin is activated (not necessarily for the first time)
337
+ * 2. When a module is newly registered in the database, which can happen for two reasons:
338
+ * a. The plugin is activated *for the first time*
339
+ * b. The module has been newly added via a plugin upgrade
340
+ * 3. When the module is re-enabled in the Module Manager after being disabled.
341
+ *
342
+ * Note that this function will be called twice when the plugin is activated for the first time, since this will make #1 and #2 both true.
343
+ * If the plugin is deactivated and then reactivated, only #1 will be true.
344
+ *
345
+ * WARNING: Do not use "$this" in the activate() function. It will not work under condition #3. Check for isset($this) and if false, use self:: instead.
346
+ *
347
+ * @since 0.1
348
+ */
349
+ function activate() { }
350
+
351
+ /**
352
+ * Called under 2 circumstances:
353
+ * 1. When the SEO Ultimate plugin is deactivated or uninstalled.
354
+ * 2. When the module is disabled in the Module Manager.
355
+ *
356
+ * @since 7.2.8
357
+ */
358
+ function deactivate() { }
359
+
360
+ /**
361
+ * Called when SEO Ultimate has just been upgraded to a new version.
362
+ *
363
+ * @since 2.1
364
+ */
365
+ function upgrade() { }
366
+
367
+ /**
368
+ * Returns an array of default settings. The defaults will be saved in the database if the settings don't exist.
369
+ *
370
+ * @since 0.1
371
+ *
372
+ * @return array The default settings. (The setting name is the key, and the default value is the array value.)
373
+ */
374
+ function get_default_settings() { return array(); }
375
+
376
+ /**
377
+ * Is called at WordPress' admin_init hook when this module's admin page is showing.
378
+ *
379
+ * @since 6.0
380
+ */
381
+ function admin_page_init() { }
382
+
383
+ /**
384
+ * Is called at WordPress' admin_init hook when the post editor is loaded.
385
+ *
386
+ * @since 7.3
387
+ */
388
+ function editor_init() { }
389
+
390
+ /**
391
+ * The contents of the administration page.
392
+ *
393
+ * @since 0.1
394
+ */
395
+ function admin_page_contents() {
396
+ $this->children_admin_page_tabs_form();
397
+ }
398
+
399
+ /**
400
+ * Returns a list of possible admin table columns that should be registered in "Screen Options"
401
+ *
402
+ * @since 2.1
403
+ *
404
+ * @return array
405
+ */
406
+ function get_admin_table_columns() {
407
+ return array();
408
+ }
409
+
410
+ /**
411
+ * Called at WordPress's load-{page} hook for this module's admin page.
412
+ *
413
+ * @since 7.0
414
+ */
415
+ function load_hook() {
416
+ $this->add_help_tabs(get_current_screen());
417
+ }
418
+
419
+ /**
420
+ * @since 7.0
421
+ */
422
+ function add_help_tabs($screen) { }
423
+
424
+ /**
425
+ * Adds the module's post meta box field HTML to the array.
426
+ *
427
+ * @since 0.1
428
+ *
429
+ * @param array $fields The fields array.
430
+ * @return array The updated fields array.
431
+ */
432
+ function postmeta_fields($fields, $screen) { return $fields; }
433
+
434
+ /********** INITIALIZATION FUNCTIONALITY **********/
435
+
436
+ /**
437
+ * If settings are unset, apply the defaults if available.
438
+ *
439
+ * @since 0.5
440
+ * @uses get_default_settings()
441
+ * @uses get_setting()
442
+ * @uses update_setting()
443
+ */
444
+ function load_default_settings() {
445
+
446
+ $defaults = $this->get_default_settings();
447
+ foreach ($defaults as $setting => $default) {
448
+ if ($this->get_setting($setting, "{reset}") === "{reset}") {
449
+ $this->update_setting($setting, $default, null, null);
450
+ }
451
+ }
452
+ }
453
+
454
+
455
+ /********** MODULE FUNCTIONS **********/
456
+
457
+ /**
458
+ * Returns the array key of the module.
459
+ *
460
+ * @since 0.1
461
+ * @uses $module_key
462
+ *
463
+ * @return string The module key.
464
+ */
465
+ function get_module_key() {
466
+ if ($this->module_key)
467
+ return $this->module_key;
468
+ else
469
+ //This error will only be triggered if someone has seriously messed with the plugin architecture
470
+ die("An SEO Ultimate module did not initialize properly. Perhaps you're trying to load an SEO Ultimate module independent of the plugin?");
471
+ }
472
+
473
+ /**
474
+ * Returns the key of the parent module if there is one; if not, the key of the current module.
475
+ *
476
+ * @since 2.1
477
+ *
478
+ * @return string
479
+ */
480
+ function get_module_or_parent_key() {
481
+ return $this->has_enabled_parent() ? $this->get_parent_module() : $this->get_module_key();
482
+ }
483
+
484
+ /**
485
+ * Returns true only if this module has a parent AND that parent is enabled.
486
+ *
487
+ * @since 7.0
488
+ *
489
+ * @return bool
490
+ */
491
+ function has_enabled_parent() {
492
+ return (strlen($p = $this->get_parent_module()) && $this->plugin->module_exists($p));
493
+ }
494
+
495
+ /**
496
+ * Returns the absolute URL of the module's admin page.
497
+ *
498
+ * @since 0.7
499
+ *
500
+ * @param string|false $key The key of the module for which to generate the admin URL. Optional.
501
+ * @return string The absolute URL to the admin page.
502
+ */
503
+ function get_admin_url($key = false) {
504
+
505
+ $anchor = '';
506
+ if ($key === false) {
507
+ if (($key = $this->get_parent_module()) && $this->plugin->module_exists($key)) {
508
+
509
+ $tabs = $this->get_admin_page_tabs();
510
+ if (!is_array($tabs))
511
+ return false;
512
+
513
+ if (count($tabs)) {
514
+ $first_tab = reset($tabs);
515
+ $anchor = '#' . $first_tab['id'];
516
+ } else {
517
+ $anchor = '#' . $this->plugin->key_to_hook($this->get_module_key());
518
+ }
519
+ } else
520
+ $key = $this->get_module_key();
521
+ }
522
+
523
+ if (!$this->plugin->call_module_func($key, 'belongs_in_admin', $belongs_in_admin) || !$belongs_in_admin)
524
+ return false;
525
+
526
+ if (!$this->plugin->call_module_func($key, 'get_menu_title', $menu_title) || !$menu_title)
527
+ return false;
528
+
529
+ $basepage = 'admin.php';
530
+ if ($this->plugin->call_module_func($key, 'get_menu_parent', $custom_basepage) && sustr::endswith($custom_basepage, '.php'))
531
+ $basepage = $custom_basepage;
532
+
533
+ if (is_network_admin() && $this->belongs_in_admin('network'))
534
+ $admin_url = 'network_admin_url';
535
+ else
536
+ $admin_url = 'admin_url';
537
+
538
+ return $admin_url($basepage.'?page='.$this->plugin->key_to_hook($key).$anchor);
539
+ }
540
+
541
+ /**
542
+ * Returns an <a> link to the module's admin page, if the module is enabled.
543
+ *
544
+ * @since 1.0
545
+ * @uses get_admin_url()
546
+ *
547
+ * @param string|false $key The key of the module for which to generate the admin URL.
548
+ * @param string $label The text to go inside the <a> element.
549
+ * @return string The <a> element, if the module exists; otherwise, the label by itself.
550
+ */
551
+ function get_admin_link($key, $label) {
552
+
553
+ if ($key == false || $this->plugin->module_exists($key))
554
+ return sprintf('<a href="%s">%s</a>', $this->get_admin_url($key), $label);
555
+ else
556
+ return $label;
557
+ }
558
+
559
+ /**
560
+ * Returns a boolean indicating whether the user is currently viewing this module's admin page.
561
+ *
562
+ * @since 1.1.1
563
+ *
564
+ * @return bool Whether the user is currently viewing this module's admin page.
565
+ */
566
+ function is_module_admin_page() {
567
+ if (is_admin()) {
568
+ global $plugin_page;
569
+ if (strcmp($plugin_page, $this->plugin->key_to_hook($this->get_module_or_parent_key())) == 0) return true;
570
+ }
571
+
572
+ return false;
573
+ }
574
+
575
+ /**
576
+ * Returns the filename of the module's icon URL.
577
+ *
578
+ * @since 1.5
579
+ *
580
+ * @return string
581
+ */
582
+ function get_menu_icon_filename() {
583
+ $filenames = array(
584
+ $this->get_settings_key()
585
+ , $this->get_module_key()
586
+ , $this->get_parent_module()
587
+ );
588
+
589
+ foreach ($filenames as $filename) {
590
+ $image = $this->module_dir_url.$filename.'.png';
591
+ if (is_readable($image)) return $image;
592
+ }
593
+
594
+ return '';
595
+ }
596
+
597
+
598
+ /********** CHILD MODULE FUNCTIONS **********/
599
+
600
+ /**
601
+ * Finds child modules of this module and fills $this->modules accordingly.
602
+ *
603
+ * @since 1.5
604
+ */
605
+ function load_child_modules() {
606
+ foreach ($this->plugin->modules as $key => $x_module) {
607
+ if ($key != $this->get_module_key()) {
608
+ $module =& $this->plugin->modules[$key];
609
+ if ($module->get_parent_module() == $this->get_module_key()) {
610
+ $module->parent_module =& $this;
611
+ $this->modules[$key] =& $module;
612
+ }
613
+ }
614
+ }
615
+
616
+ if (count($this->modules) > 0)
617
+ @uasort($this->modules, array(&$this, 'module_sort_callback'));
618
+ }
619
+
620
+ /**
621
+ * Returns an array of this module's admin tabs plus those of its children.
622
+ *
623
+ * @since 1.5
624
+ * @return array
625
+ */
626
+ function get_children_admin_page_tabs() {
627
+ $tabs = $this->get_admin_page_tabs();
628
+ if (!is_array($tabs)) $tabs = array();
629
+
630
+ foreach ($this->modules as $key => $x_module) {
631
+ $module =& $this->modules[$key];
632
+
633
+ if ($module->belongs_in_admin()) {
634
+ $child_tabs = $module->get_admin_page_tabs();
635
+
636
+ if (is_array($child_tabs)) {
637
+
638
+ if (empty($child_tabs))
639
+ $child_tabs[] = array(
640
+ 'title' => $module->get_module_subtitle()
641
+ , 'id' => $this->plugin->key_to_hook($key)
642
+ , 'callback' => array(&$module, 'admin_page_contents')
643
+ );
644
+
645
+ foreach ($child_tabs as $child_tab) {
646
+ if (is_array($child_tab) && !is_array($child_tab['callback']))
647
+ $child_tab['callback'] = array(&$module, $child_tab['callback']);
648
+
649
+ $tabs[] = $child_tab;
650
+ }
651
+ }
652
+ }
653
+ }
654
+
655
+ return $tabs;
656
+ }
657
+
658
+ /**
659
+ * Outputs this module's admin tabs plus those of its children.
660
+ *
661
+ * @since 1.5
662
+ */
663
+ function children_admin_page_tabs() {
664
+ if (count($tabs = $this->get_children_admin_page_tabs()))
665
+ $this->admin_page_tabs($tabs);
666
+ }
667
+
668
+ /**
669
+ * Outputs a form containing this module's admin tabs plus those of its children.
670
+ *
671
+ * @since 1.5
672
+ */
673
+ function children_admin_page_tabs_form() {
674
+ if (count($tabs = $this->get_children_admin_page_tabs())) {
675
+ echo "\n\n<div class='row'>\n";
676
+ echo "\n\n<div class='col-sm-8 col-md-9'>\n";
677
+
678
+ $this->admin_form_start(false, false);
679
+ $this->admin_page_tabs($tabs);
680
+ $this->admin_form_end(null, false);
681
+
682
+ echo "\n\n</div>\n";
683
+ echo "\n\n<div class='col-sm-4 col-md-3'>\n";
684
+ $this->promo_sdf_banners();
685
+ echo "\n\n</div>\n";
686
+ echo "\n\n</div>\n";
687
+ }
688
+ }
689
+
690
+ /**
691
+ * Outputs the admin pages of this module's children, one after the other.
692
+ *
693
+ * @since 1.5
694
+ */
695
+ function children_admin_pages() {
696
+ foreach ($this->modules as $key => $x_module) {
697
+ echo "<div id='" . $this->plugin->key_to_hook($key) . "'>\n";
698
+ $this->modules[$key]->admin_subheader($this->modules[$key]->get_module_subtitle());
699
+ $this->modules[$key]->admin_page_contents();
700
+ echo "</div>\n";
701
+ }
702
+ }
703
+
704
+ /**
705
+ * Outputs a form containing the admin pages of this module's children, outputted one after the other.
706
+ *
707
+ * @since 1.5
708
+ */
709
+ function children_admin_pages_form() {
710
+ if (count($this->modules)) {
711
+ $this->admin_form_start(false, false);
712
+ $this->children_admin_pages();
713
+ $this->admin_form_end(null, false);
714
+ } else
715
+ $this->print_message('warning', sprintf(__('All the modules on this page have been disabled. You can re-enable them using the <a href="%s">Module Manager</a>.', 'seo-ultimate'), $this->get_admin_url('modules')));
716
+ }
717
+
718
+ /**
719
+ * Compares two modules to determine which of the two should be displayed first on the parent page.
720
+ * Sorts by child order first, and title second.
721
+ * Works as a uasort() callback.
722
+ *
723
+ * @since 1.5
724
+ * @uses SU_Module::get_child_order()
725
+ * @uses SU_Module::get_module_subtitle()
726
+ *
727
+ * @param SU_Module $a The first module to compare.
728
+ * @param SU_Module $b The second module to compare.
729
+ * @return int This will be -1 if $a comes first, or 1 if $b comes first.
730
+ */
731
+ function module_sort_callback($a, $b) {
732
+
733
+ if ($a->get_child_order() == $b->get_child_order()) {
734
+ return strcmp($a->get_module_subtitle(), $b->get_module_subtitle());
735
+ }
736
+
737
+ return ($a->get_child_order() < $b->get_child_order()) ? -1 : 1;
738
+ }
739
+
740
+ /********** SETTINGS FUNCTIONS **********/
741
+
742
+ /**
743
+ * Retrieves the given setting from a module's settings array.
744
+ *
745
+ * @since 0.1
746
+ * @uses get_settings_key()
747
+ *
748
+ * @param string $key The name of the setting to retrieve.
749
+ * @param mixed $default What should be returned if the setting does not exist. Optional.
750
+ * @param string|null $module The module to which the setting belongs. Defaults to the current module's settings key. Optional.
751
+ * @return mixed The value of the setting, or the $default variable.
752
+ */
753
+ function get_setting($key, $default=null, $module=null, $sneakpeak=false) {
754
+ if (!$module) $module = $this->get_settings_key();
755
+
756
+ $msdata = (array)get_option("seo_ultimate_module_$module", array());
757
+
758
+ if ($sneakpeak && $this->is_action('update'))
759
+ $setting = stripslashes(isset($_POST[$key]) ? $_POST[$key] : null);
760
+ elseif (isset($msdata[$key]))
761
+ $setting = $msdata[$key];
762
+ else
763
+ $setting = $default;
764
+
765
+ $setting = apply_filters("su_get_setting-$module", $setting, $key);
766
+ $setting = apply_filters("su_get_setting-$module-$key", $setting, $key);
767
+
768
+ return $setting;
769
+ }
770
+
771
+ /**
772
+ * Sets a value in the module's settings array.
773
+ *
774
+ * @since 0.1
775
+ * @uses get_settings_key()
776
+ *
777
+ * @param string $key The key of the setting to be changed.
778
+ * @param string $value The new value to assign to the setting.
779
+ * @param string|null $module The module to which the setting belongs. Defaults to the current module's settings key. Optional.
780
+ */
781
+ function update_setting($key, $value, $module=null, $array_key=null) {
782
+ if (!$module) $module = $this->get_settings_key();
783
+
784
+ $msdata = (array)get_option("seo_ultimate_module_$module", array());
785
+
786
+ $use_custom = apply_filters("su_custom_update_setting-$module-$key", false, $value, $key) ||
787
+ apply_filters("su_custom_update_setting-$module", false, $value, $key);
788
+
789
+ if (!$use_custom) {
790
+ if ($array_key)
791
+ $msdata[$key][$array_key] = $value;
792
+ else
793
+ $msdata[$key] = $value;
794
+ }
795
+
796
+ update_option("seo_ultimate_module_$module", $msdata);
797
+ }
798
+
799
+ /**
800
+ * Gets a setting's value, deletes the setting, and returns the value.
801
+ *
802
+ * @since 2.1
803
+ * @uses get_settings_key()
804
+ *
805
+ * @param string $key The name of the setting to retrieve/delete.
806
+ * @param mixed $default What should be returned if the setting does not exist. Optional.
807
+ * @param string|null $module The module to which the setting belongs. Defaults to the current module's settings key. Optional.
808
+ * @return mixed The value of the setting, or the $default variable.
809
+ */
810
+ function flush_setting($key, $default=null, $module=null) {
811
+ $setting = $this->get_setting($key, $default, $module); //We need to retrieve the setting before deleting it
812
+ $this->delete_setting($key, $module);
813
+ return $setting;
814
+ }
815
+
816
+ /**
817
+ * Deletes a module setting.
818
+ *
819
+ * @since 2.1
820
+ * @uses get_settings_key()
821
+ *
822
+ * @param string $key The name of the setting to delete.
823
+ * @param string|null $module The module to which the setting belongs. Defaults to the current module's settings key. Optional.
824
+ */
825
+ function delete_setting($key, $module=null, $array_key = null) {
826
+ if (!$module) $module = $this->get_settings_key();
827
+
828
+ $msdata = (array)get_option("seo_ultimate_module_$module", array());
829
+
830
+ if (isset($msdata[$key])) {
831
+ if ($array_key) {
832
+ if (isset($msdata[$key][$array_key]))
833
+ unset($msdata[$key][$array_key]);
834
+ } else {
835
+ unset($msdata[$key]);
836
+ }
837
+ }
838
+ }
839
+
840
+ /**
841
+ * Returns a default setting. Only use this function if a default is indeed provided!
842
+ *
843
+ * @since 1.3
844
+ * @uses get_default_settings()
845
+ *
846
+ * @param string $key The name of the setting whose default to retrieve.
847
+ * @return mixed The default value for the setting.
848
+ */
849
+ function get_default_setting($key) {
850
+ $defaults = $this->get_default_settings();
851
+ return $defaults[$key];
852
+ }
853
+
854
+
855
+ /********** ADMIN PAGE FUNCTIONS **********/
856
+
857
+ /**
858
+ * Displays the beginning, contents, and end of the module's administration page.
859
+ *
860
+ * @since 0.1
861
+ * @uses admin_page_start()
862
+ * @uses admin_page_contents()
863
+ * @uses admin_page_end()
864
+ */
865
+ function admin_page() {
866
+ if (!apply_filters('su_custom_admin_page-'.$this->get_module_key(), false)) {
867
+ $this->admin_page_start();
868
+ $this->admin_page_contents();
869
+ $this->admin_page_end();
870
+ }
871
+ }
872
+
873
+ /**
874
+ * Outputs the starting code for an administration page:
875
+ * wrapper, ID'd <div>, icon, and title
876
+ *
877
+ * @since 0.1
878
+ * @uses admin_footer() Hooked into WordPress's in_admin_footer action.
879
+ * @uses get_module_key()
880
+ * @uses get_page_title()
881
+ *
882
+ * @param string $icon The ID that should be applied to the icon element. The icon is loaded via CSS based on the ID. Optional.
883
+ */
884
+ function admin_page_start($icon = 'options-general') {
885
+
886
+ //Add our custom footer attribution
887
+ add_action('in_admin_footer', array(&$this, 'admin_footer'));
888
+
889
+ //Output the beginning of the admin screen
890
+ echo "<div class=\"wrap\">\n";
891
+
892
+ if (strcmp($pclass = strtolower(get_parent_class($this)), 'su_module') != 0)
893
+ $class = ' '.str_replace('_', '-', $pclass);
894
+ else
895
+ $class = '';
896
+
897
+ echo "<div id=\"su-".su_esc_attr($this->get_module_key())."\" class=\"sdf-admin$class\">\n";
898
+ screen_icon($icon);
899
+ echo "\n<h2>".$this->get_page_title()."</h2>\n";
900
+ }
901
+
902
+ /**
903
+ * Outputs an administration page subheader (an <h4> tag).
904
+ *
905
+ * @since 0.1
906
+ *
907
+ * @param string $title The text to output.
908
+ */
909
+ function admin_subheader($title, $id=false) {
910
+ if ($id) $id = ' id="' . su_esc_attr($id) . '"';
911
+ echo "<h4 class='su-subheader'$id>$title</h4>\n";
912
+ }
913
+
914
+ /**
915
+ * Outputs an administration form table subheader.
916
+ *
917
+ * @since 0.1
918
+ *
919
+ * @param string $title The text to output.
920
+ */
921
+ function admin_form_subheader($title) {
922
+ echo "<tr><th colspan='2'><strong>$title</strong></th></tr>\n";
923
+ }
924
+
925
+ /**
926
+ * Outputs the ending code for an administration page.
927
+ *
928
+ * @since 0.1
929
+ */
930
+ function admin_page_end() {
931
+ echo "\n</div>\n</div>\n";
932
+ }
933
+
934
+ /**
935
+ * Outputs a tab control and loads the current tab.
936
+ *
937
+ * @since 0.7
938
+ *
939
+ * @param array $tabs Array (id => __, title => __, callback => __)
940
+ * @param bool $table Whether or not the tab contents should be wrapped in a form table.
941
+ */
942
+ function admin_page_tabs($tabs=array(), $table=false) {
943
+ $this->plugin->tabs($tabs, $table, $this);
944
+ }
945
+
946
+ /**
947
+ * Adds the hook necessary to initialize the admin page tabs.
948
+ *
949
+ * @since 0.8
950
+ */
951
+ function admin_page_tabs_init() {
952
+ add_action('admin_enqueue_scripts', array(&$this, 'admin_page_tabs_js'));
953
+ }
954
+
955
+ /**
956
+ * Enqueues the JavaScript needed for the admin page tabs.
957
+ *
958
+ * @since 0.8
959
+ * @uses is_module_admin_page()
960
+ */
961
+ function admin_page_tabs_js() {
962
+ if ($this->is_module_admin_page())
963
+ wp_enqueue_script('jquery-ui-tabs');
964
+ }
965
+
966
+ /**
967
+ * Adds plugin/module information to the admin footer.
968
+ *
969
+ * @since 0.1
970
+ * @uses SU_PLUGIN_URI
971
+ * @uses SU_PLUGIN_NAME
972
+ * @uses SU_AUTHOR_URI
973
+ * @uses SU_AUTHOR
974
+ */
975
+ function admin_footer() {
976
+ printf(__('%1$s | %2$s %3$s by %4$s', 'seo-ultimate'),
977
+ $this->get_module_title(),
978
+ '<a href="'.SU_PLUGIN_URI.'" target="_blank" rel="nofollow">'.__(SU_PLUGIN_NAME, 'seo-ultimate').'</a>',
979
+ SU_VERSION,
980
+ '<a href="'.SU_AUTHOR_URI.'" target="_blank" rel="nofollow">'.__(SU_AUTHOR, 'seo-ultimate').'</a>'
981
+ );
982
+
983
+ echo "<br />";
984
+ }
985
+
986
+ /**
987
+ * Returns tabs for post/taxonomy meta editing tables.
988
+ *
989
+ * @since 2.9
990
+ * @uses get_postmeta_edit_tabs()
991
+ * @uses get_taxmeta_edit_tabs()
992
+ *
993
+ * @param array $fields The array of meta fields that the user can edit with the tables.
994
+ */
995
+ function get_meta_edit_tabs($fields) {
996
+ return array_merge(
997
+ $this->get_postmeta_edit_tabs($fields)
998
+ ,$this->get_taxmeta_edit_tabs($fields)
999
+ );
1000
+ }
1001
+
1002
+ /**
1003
+ * Returns tabs for post meta editing tables.
1004
+ *
1005
+ * @since 2.9
1006
+ *
1007
+ * @param array $fields The array of meta fields that the user can edit with the tables.
1008
+ */
1009
+ function get_postmeta_edit_tabs($fields) {
1010
+
1011
+ $types = get_post_types(array('public' => true), 'objects');
1012
+
1013
+ //Turn the types array into a tabs array
1014
+ $tabs = array();
1015
+ foreach ($types as $type)
1016
+ $tabs[$type->name] = array(
1017
+ 'title' => $type->labels->name
1018
+ , 'id' => 'su-' . $type->name
1019
+ , 'callback' => array('meta_edit_tab', 'post', 'su-' . $type->name, $type->name, $type->labels->singular_name, $fields)
1020
+ );
1021
+ return $tabs;
1022
+ }
1023
+
1024
+ /**
1025
+ * Returns tabs for taxonomy meta editing tables.
1026
+ *
1027
+ * @since 2.9
1028
+ *
1029
+ * @param array $fields The array of meta fields that the user can edit with the tables.
1030
+ */
1031
+ function get_taxmeta_edit_tabs($fields) {
1032
+ $types = suwp::get_taxonomies();
1033
+
1034
+ //Turn the types array into a tabs array
1035
+ $tabs = array();
1036
+ foreach ($types as $name => $type) {
1037
+ if ($type->labels->name) {
1038
+ $tabs[] = array(
1039
+ 'title' => $type->labels->name
1040
+ , 'id' => 'su-' . $name
1041
+ , 'callback' => array('meta_edit_tab', 'term', 'su-' . $name, $name, $type->labels->singular_name, $fields)
1042
+ );
1043
+ }
1044
+ }
1045
+ return $tabs;
1046
+ }
1047
+
1048
+ /**
1049
+ * Outputs the contents of a meta editing tab.
1050
+ *
1051
+ * @since 2.9
1052
+ */
1053
+ function meta_edit_tab($genus, $tab, $type, $type_label, $fields) {
1054
+ if (!$this->meta_edit_table($genus, $tab, $type, $type_label, $fields))
1055
+ $this->print_message('info', __('Your site currently doesn&#8217;t have any public items of this type.', 'seo-ultimate'));
1056
+ }
1057
+
1058
+ /**
1059
+ * Outputs the contents of a meta editing table.
1060
+ *
1061
+ * @since 2.9
1062
+ *
1063
+ * @param string $genus The type of object being handled (either 'post' or 'term')
1064
+ * @param string $tab The ID of the current tab; used to generate a URL hash (e.g. #$tab)
1065
+ * @param string $type The type of post/taxonomy type being edited (examples: post, page, attachment, category, post_tag)
1066
+ * @param string $type_label The singular label for the post/taxonomy type (examples: Post, Page, Attachment, Category, Post Tag)
1067
+ * @param array $fields The array of meta fields that the user can edit with the tables. The data for each meta field are stored in an array with these elements: "type" (can be textbox, textarea, or checkbox), "name" (the meta field, e.g. title or description), "term_settings_key" (the key of the setting for cases when term meta data are stored in the settings array), and "label" (the internationalized label of the field, e.g. "Meta Description" or "Title Tag")
1068
+ */
1069
+ function meta_edit_table($genus, $tab, $type, $type_label, $fields) {
1070
+
1071
+ //Pseudo-constant
1072
+ $per_page = 100;
1073
+
1074
+ //Sanitize parameters
1075
+ if (!is_array($fields) || !count($fields)) return false;
1076
+ if (!isset($fields[0]) || !is_array($fields[0])) $fields = array($fields);
1077
+
1078
+ //Get search query
1079
+ $type_s = $type . '_s';
1080
+ $search = isset($_REQUEST[$type_s]) ? $_REQUEST[$type_s] : '';
1081
+
1082
+ //Save meta if applicable
1083
+ if ($is_update = ($this->is_action('update') && !strlen(trim($search)))) {
1084
+ foreach ($_POST as $key => $value) {
1085
+ $value = stripslashes($value);
1086
+ if (sustr::startswith($key, $genus.'_'))
1087
+ foreach ($fields as $field)
1088
+ if (preg_match("/{$genus}_([0-9]+)_{$field['name']}/", $key, $matches)) {
1089
+ $id = (int)$matches[1];
1090
+ switch ($genus) {
1091
+ case 'post': update_post_meta($id, "_su_{$field['name']}", $value); break;
1092
+ case 'term': $this->update_setting($field['term_settings_key'], $value, null, $id); break;
1093
+ }
1094
+ continue 2; //Go to next $_POST item
1095
+ }
1096
+ }
1097
+ }
1098
+
1099
+ $pagenum = isset( $_GET[$type . '_paged'] ) ? absint( $_GET[$type . '_paged'] ) : 0;
1100
+ if ( empty($pagenum) ) $pagenum = 1;
1101
+
1102
+ //Load up the objects based on the genus
1103
+ switch ($genus) {
1104
+ case 'post':
1105
+
1106
+ //Get the posts
1107
+ wp(array(
1108
+ 'post_type' => $type
1109
+ , 'posts_per_page' => $per_page
1110
+ , 'post_status' => 'any'
1111
+ , 'paged' => $pagenum
1112
+ , 'order' => 'ASC'
1113
+ , 'orderby' => 'title'
1114
+ , 's' => $search
1115
+ ));
1116
+ global $wp_query;
1117
+ $objects = &$wp_query->posts;
1118
+
1119
+ $num_pages = $wp_query->max_num_pages;
1120
+ $total_objects = $wp_query->found_posts;
1121
+
1122
+ break;
1123
+
1124
+ case 'term':
1125
+ $objects = get_terms($type, array('search' => $search));
1126
+ $total_objects = count($objects);
1127
+ $num_pages = ceil($total_objects / $per_page);
1128
+ $objects = array_slice($objects, $per_page * ($pagenum-1), $per_page);
1129
+ break;
1130
+ default:
1131
+ return false;
1132
+ break;
1133
+ }
1134
+
1135
+ if ($total_objects < 1) return false;
1136
+
1137
+ echo "\n<div class='su-meta-edit-table'>\n";
1138
+
1139
+ $page_links = paginate_links( array(
1140
+ 'base' => add_query_arg( $type . '_paged', '%#%' ) . '#' . $tab
1141
+ , 'format' => ''
1142
+ , 'prev_text' => __('&laquo;')
1143
+ , 'next_text' => __('&raquo;')
1144
+ , 'total' => $num_pages
1145
+ , 'current' => $pagenum
1146
+ ));
1147
+
1148
+ if ( $page_links ) {
1149
+ $page_links_text = '<div class="tablenav"><div class="tablenav-pages">';
1150
+ $page_links_text .= sprintf( '<span class="displaying-num">' . __( 'Displaying %s&#8211;%s of %s' ) . '</span>%s',
1151
+ number_format_i18n( ( $pagenum - 1 ) * $per_page + 1 ),
1152
+ number_format_i18n( min( $pagenum * $per_page, $total_objects ) ),
1153
+ number_format_i18n( $total_objects ),
1154
+ $page_links
1155
+ );
1156
+ $page_links_text .= "</div></div>\n";
1157
+
1158
+ echo $page_links_text;
1159
+ } else $page_links_text = '';
1160
+
1161
+ //Get object identification headers
1162
+ $headers = array(
1163
+ 'actions' => __('Actions', 'seo-ultimate')
1164
+ , 'id' => __('ID', 'seo-ultimate')
1165
+ , 'name' => $type_label
1166
+ );
1167
+
1168
+ //Get meta field headers
1169
+ foreach ($fields as $field) {
1170
+ $headers[$field['name']] = $field['label'];
1171
+ }
1172
+
1173
+ //Output all headers
1174
+ $this->admin_wftable_start($headers);
1175
+
1176
+ //Output rows
1177
+ foreach ($objects as $object) {
1178
+
1179
+ switch ($genus) {
1180
+ case 'post':
1181
+ $id = intval($object->ID);
1182
+ $name = $object->post_title;
1183
+ $view_url = get_permalink($id);
1184
+ $edit_url = get_edit_post_link($id);
1185
+
1186
+ $status_obj = get_post_status_object($object->post_status);
1187
+ switch ($object->post_status) {
1188
+ case 'publish': $status = ''; break;
1189
+ case 'inherit': $status = ''; break;
1190
+ case 'auto-draft': continue; break;
1191
+ default: $status = $status_obj->label; break;
1192
+ }
1193
+
1194
+ if ($status)
1195
+ $name .= "<span class='su-meta-table-post-status'> &mdash; $status</span>";
1196
+
1197
+ break;
1198
+ case 'term':
1199
+ if (!isset($object->term_taxonomy_id)) {
1200
+ $id = intval($object->term_id);
1201
+ $view_url = get_term_link($id, $type);
1202
+ }
1203
+ else{
1204
+ $id = intval($object->term_taxonomy_id);
1205
+ $view_url = get_term_link(intval($object->term_id), $type);
1206
+ }
1207
+ $name = $object->name;
1208
+
1209
+ $edit_url = suwp::get_edit_term_link($id, $type);
1210
+ break;
1211
+ default: return false; break;
1212
+ }
1213
+
1214
+ $view_url = su_esc_attr($view_url);
1215
+ $edit_url = su_esc_attr($edit_url);
1216
+
1217
+ $actions = array(sprintf('<a href="%s">%s</a>', $view_url, __('View', 'seo-ultimate')));
1218
+ if ($edit_url)
1219
+ $actions[] = sprintf('<a href="%s">%s</a>', $edit_url, __('Edit', 'seo-ultimate'));
1220
+ $actions = implode(' | ', $actions);
1221
+
1222
+ $cells = compact('actions', 'id', 'name');
1223
+
1224
+ //Get meta field cells
1225
+ foreach ($fields as $field) {
1226
+ $inputid = "{$genus}_{$id}_{$field['name']}";
1227
+
1228
+ switch ($genus) {
1229
+ case 'post':
1230
+ $value = $this->get_postmeta($field['name'], $id);
1231
+ break;
1232
+ case 'term':
1233
+ $value = $this->get_setting($field['term_settings_key'], array());
1234
+ $value = isset($value[$id]) ? $value[$id] : null;
1235
+ break;
1236
+ }
1237
+
1238
+ if ($is_update && $field['type'] == 'checkbox' && $value == '1' && !isset($_POST[$inputid]))
1239
+ switch ($genus) {
1240
+ case 'post': delete_post_meta($id, "_su_{$field['name']}"); $value = 0; break;
1241
+ case 'term': $this->update_setting($field['term_settings_key'], false, null, $id); break;
1242
+ }
1243
+
1244
+ $cells[$field['name']] = $this->get_input_element(
1245
+ $field['type'] //Type
1246
+ , $inputid
1247
+ , $value
1248
+ , isset($field['options']) ? $field['options'] : false
1249
+ );
1250
+ }
1251
+
1252
+ //Output all cells
1253
+ $this->table_row($cells, $id, $type);
1254
+ }
1255
+
1256
+ //End table
1257
+ $this->admin_wftable_end();
1258
+
1259
+ echo $page_links_text;
1260
+
1261
+ echo "</div>\n";
1262
+
1263
+ return true;
1264
+ }
1265
+
1266
+ /**
1267
+ * Returns the HTML for a given type of input element, without any surrounding <td> elements etc.
1268
+ *
1269
+ * @since 2.9
1270
+ *
1271
+ * @param string $type The type of input element (can be textbox, textarea, or checkbox)
1272
+ * @param string $inputid The name/ID of the input element
1273
+ * @param string $value The current value of the field
1274
+ * @return string
1275
+ */
1276
+ function get_input_element($type, $name, $value=null, $extra=false, $inputid=true) {
1277
+ if ($value === null) $value = $this->get_setting($name);
1278
+
1279
+ if ($inputid === true) $inputid = $name;
1280
+ if (strlen($inputid)) $inputid = " id='".su_esc_attr($inputid)."'";
1281
+
1282
+ //Get HTML element
1283
+ switch ($type) {
1284
+ case 'textbox':
1285
+ $value = su_esc_editable_html($value);
1286
+ $placeholder = $extra ? " placeholder='" . su_esc_attr($extra) . "'" : '';
1287
+ return "<input name='$name'$inputid value='$value'$placeholder type='text' class='form-control input-sm textbox regular-text' />";
1288
+ break;
1289
+ case 'textarea':
1290
+ $value = su_esc_editable_html($value);
1291
+ return "<textarea name='$name'$inputid type='text' rows='3' cols='50' class='textarea form-control regular-text'>$value</textarea>";
1292
+ break;
1293
+ case 'checkbox':
1294
+ $checked = $value ? " checked='checked'" : '';
1295
+ $html = "<input name='$name'$inputid value='1' type='checkbox' class='checkbox'$checked />";
1296
+ if (is_string($extra)) {
1297
+ $extra = su_esc_html($extra);
1298
+ $html = "<label>$html&nbsp;$extra</label>";
1299
+ }
1300
+ return $html;
1301
+ break;
1302
+ case 'dropdown':
1303
+ $html = "<select name='$name'$inputid onchange='javascript:su_toggle_select_children(this)' class='dropdown'>";
1304
+ if (is_array($extra)) $html .= suhtml::option_tags($extra, $value); else $html .= $extra;
1305
+ $html .= "</select>";
1306
+ return $html;
1307
+ break;
1308
+ case 'hidden':
1309
+ return "<input name='$name'$inputid value='$value' type='hidden' />";
1310
+ break;
1311
+ case 'jlsuggest':
1312
+ $params = isset($extra['params']) ? $extra['params'] : '';
1313
+ $placeholder = isset($extra['placeholder']) ? $extra['placeholder'] : '';
1314
+
1315
+ return $this->get_jlsuggest_box($name, $value, $params, $placeholder);
1316
+ break;
1317
+ }
1318
+
1319
+ return '';
1320
+ }
1321
+
1322
+ /**
1323
+ * Creates an admin form subsection.
1324
+ *
1325
+ * @since 3.8
1326
+ * @uses get_setting()
1327
+ * @see get_input_element()
1328
+ *
1329
+ * @param string $field
1330
+ * @param string|null $current_value
1331
+ * @param string $trigger_value
1332
+ * @param string $html
1333
+ * @return string
1334
+ */
1335
+ function get_admin_form_subsection($field, $current_value, $trigger_value, $html) {
1336
+ if ($current_value === null) $current_value = $this->get_setting($field);
1337
+ $hidden = ($current_value == $trigger_value) ? '' : ' hidden';
1338
+
1339
+ $field = su_esc_attr($field);
1340
+ $trigger_value = su_esc_attr($trigger_value);
1341
+ $html = "<div class='su_{$field}_{$trigger_value}_subsection$hidden'>$html</div>";
1342
+ return $html;
1343
+ }
1344
+
1345
+ /**
1346
+ * Creates multiple admin form subsections.
1347
+ *
1348
+ * @since 3.8
1349
+ * @uses get_admin_form_subsection()
1350
+ * @see get_input_element()
1351
+ *
1352
+ * @param string $field
1353
+ * @param array $subsections Array of ($field => $trigger_value)
1354
+ * @return string
1355
+ */
1356
+ function get_admin_form_subsections($field, $current_value, $subsections) {
1357
+ $allhtml = '';
1358
+ if (!in_array($current_value, $subsection_keys = array_keys($subsections))) $current_value = $subsection_keys[0];
1359
+ foreach ($subsections as $trigger_value => $html)
1360
+ $allhtml .= $this->get_admin_form_subsection($field, $current_value, $trigger_value, $html);
1361
+ return $allhtml;
1362
+ }
1363
+
1364
+
1365
+ /********** ADMIN FORM FUNCTIONS **********/
1366
+
1367
+ /**
1368
+ * Begins an administration form.
1369
+ * Outputs a subheader if provided, queues a success message upon settings update, outputs queued messages,
1370
+ * opens a form tag, outputs a nonce field and other WordPress fields, and begins a form table.
1371
+ *
1372
+ * @since 0.1
1373
+ * @uses SEO_Ultimate::key_to_hook()
1374
+ * @uses get_module_key()
1375
+ * @uses admin_subheader()
1376
+ * @uses is_action()
1377
+ * @uses print_message()
1378
+ * @uses get_parent_module()
1379
+ *
1380
+ * @param mixed $header The text of the subheader that should go right before the form. Optional.
1381
+ * @param boolean $table Whether or not to start a form table.
1382
+ */
1383
+ function admin_form_start($header = false, $table = true, $form = true) {
1384
+
1385
+ if ($header) $this->admin_subheader($header);
1386
+
1387
+ if ($form) {
1388
+ $hook = $this->plugin->key_to_hook($this->get_module_or_parent_key());
1389
+ if ($this->is_action('update')) $this->print_message('success', __('Settings updated.', 'seo-ultimate'));
1390
+ echo "<form id='su-admin-form' class='form-horizontal' method='post' action='?page=$hook'>\n";
1391
+ settings_fields($hook);
1392
+ }
1393
+
1394
+ echo "\n";
1395
+ //if ($table) echo "<table class='form-table'>\n";
1396
+ }
1397
+
1398
+ /**
1399
+ * Ends an administration form.
1400
+ * Closes the table tag, outputs a "Save Changes" button, and closes the form tag.
1401
+ *
1402
+ * @since 0.1
1403
+ * @uses get_parent_module()
1404
+ *
1405
+ * @param string|false $button The label of the submit button.
1406
+ * @param boolean $table Whether or not a form table should be ended.
1407
+ */
1408
+ function admin_form_end($button = null, $table = true) {
1409
+
1410
+ if ($button === null) $button = __('Save Changes'); //This string is used in normal WP, so we don't need a textdomain
1411
+ //if ($table) echo "</table>\n";
1412
+
1413
+ if ($button !== false) {
1414
+ ?>
1415
+ <p class="submit">
1416
+ <input type="submit" class="button-primary" value="<?php echo $button ?>" />
1417
+ </p>
1418
+ </form>
1419
+ <?php
1420
+ }
1421
+ }
1422
+
1423
+ /**
1424
+ * Begins an admin form table.
1425
+ *
1426
+ * @since 1.5
1427
+ */
1428
+ function admin_form_table_start() {
1429
+ //echo "<table class='form-table'>\n";
1430
+ }
1431
+
1432
+ /**
1433
+ * Ends an admin form table
1434
+ *
1435
+ * @since 1.5
1436
+ */
1437
+ function admin_form_table_end() {
1438
+ //echo "</table>\n";
1439
+ }
1440
+
1441
+ /**
1442
+ * @since 5.8
1443
+ */
1444
+ function child_admin_form_start($table=true) {
1445
+ if ($this->get_parent_module() && $this->plugin->module_exists($this->get_parent_module())) {
1446
+ if ($table) $this->admin_form_table_start();
1447
+ } else {
1448
+ $this->admin_form_start(false, $table);
1449
+ }
1450
+ }
1451
+
1452
+ /**
1453
+ * @since 5.8
1454
+ */
1455
+ function child_admin_form_end($table=true) {
1456
+ if ($this->get_parent_module() && $this->plugin->module_exists($this->get_parent_module())) {
1457
+ if ($table) $this->admin_form_table_end();
1458
+ } else {
1459
+ $this->admin_form_end(null, $table);
1460
+ }
1461
+ }
1462
+
1463
+ /**
1464
+ * Begins a "widefat" WordPress table.
1465
+ *
1466
+ * @since 1.8
1467
+ *
1468
+ * @param $headers Array of (CSS class => Internationalized column title)
1469
+ */
1470
+ function admin_wftable_start($headers = false) {
1471
+ echo "\n<table class='widefat' cellspacing='0'>\n";
1472
+ if ($headers)
1473
+ $this->table_column_headers($headers);
1474
+ else {
1475
+ echo "\t<thead><tr>\n";
1476
+ print_column_headers($this->plugin_page_hook);
1477
+ echo "\t</tr></thead>\n";
1478
+ echo "\t<tfoot><tr>\n";
1479
+ print_column_headers($this->plugin_page_hook);
1480
+ echo "\t</tr></tfoot>\n";
1481
+ }
1482
+ echo "\t<tbody>\n";
1483
+ }
1484
+
1485
+ /**
1486
+ * Outputs a <tr> of <th scope="col"></th> tags based on an array of column headers.
1487
+ *
1488
+ * @since 2.1
1489
+ *
1490
+ * @param $headers Array of (CSS class => Internationalized column title)
1491
+ */
1492
+ function table_column_headers($headers) {
1493
+ echo "\t<thead><tr>\n";
1494
+ $mk = $this->get_module_key();
1495
+ foreach ($headers as $class => $header) {
1496
+ $class = is_numeric($class) ? '' : " class='su-$mk-$class su-$class'";
1497
+ echo "\t\t<th scope='col'$class>$header</th>\n";
1498
+ }
1499
+ echo "\t</tr></thead>\n";
1500
+ }
1501
+
1502
+ /**
1503
+ * Outputs <td> tags based on an array of cell data.
1504
+ *
1505
+ * @since 2.1
1506
+ *
1507
+ * @param $headers Array of (CSS class => Cell data)
1508
+ */
1509
+ function table_cells($cells) {
1510
+
1511
+ if (count($this->get_admin_table_columns())) {
1512
+ $columns = get_column_headers($this->plugin_page_hook);
1513
+ $hidden = get_hidden_columns($this->plugin_page_hook);
1514
+ foreach ( $columns as $column_name => $column_display_name ) {
1515
+ $class = "class=\"$column_name column-$column_name\"";
1516
+ $style = in_array($column_name, $hidden) ? ' style="display:none;"' : '';
1517
+ echo "\t\t<td $class$style>".$cells[$column_name]."</td>\n";
1518
+ }
1519
+ } elseif (is_array($cells) && count($cells)) {
1520
+ foreach ($cells as $class => $content) {
1521
+ $class = is_numeric($class) ? '' : " class='su-$class'";
1522
+ echo "\t\t<td$class>$content</td>\n";
1523
+ }
1524
+ }
1525
+ }
1526
+
1527
+ /**
1528
+ * Outputs a <tr> tag with <td> children.
1529
+ *
1530
+ * @since 2.9
1531
+ */
1532
+ function table_row($cells, $id, $class) {
1533
+ $mk = $this->get_module_key();
1534
+ echo "\t<tr id='su-$mk-$id' class='su-$mk-$class'>\n";
1535
+ $this->table_cells($cells);
1536
+ echo "\t</tr>\n";
1537
+ }
1538
+
1539
+ /**
1540
+ * Ends a "widefat" WordPress table.
1541
+ *
1542
+ * @since 1.8
1543
+ */
1544
+ function admin_wftable_end() {
1545
+ echo "\t</tbody>\n</table>\n";
1546
+ }
1547
+
1548
+ /**
1549
+ * Outputs the HTML that begins an admin form group.
1550
+ *
1551
+ * @since 1.5
1552
+ *
1553
+ * @param string $title The title of the group.
1554
+ * @param bool $newtable Whether to open a new <table> element.
1555
+ */
1556
+ function admin_form_group_start($title, $newtable=true) {
1557
+ echo "<div class='form-group'>\n<label class='col-sm-4 col-md-4 control-label'>$title</label><div class='col-sm-4 col-md-4'>\n";
1558
+ }
1559
+
1560
+ /**
1561
+ * Outputs the HTML that ends an admin form group.
1562
+ *
1563
+ * @since 1.5
1564
+ *
1565
+ * @param bool $newtable Whether to close a <table> element.
1566
+ */
1567
+ function admin_form_group_end($newtable=true) {
1568
+ echo "</div>\n<div class='col-sm-4 col-md-4 help-text'>\n</div>\n</div>\n";
1569
+ }
1570
+
1571
+ function admin_form_indent_start() {
1572
+ echo "<div class='form-group'><div class='col-md-12'>";
1573
+ }
1574
+
1575
+ function admin_form_indent_end() {
1576
+ echo "</div></div>";
1577
+ }
1578
+
1579
+ /**
1580
+ * Outputs a text block into an admin form.
1581
+ *
1582
+ * @since 1.5
1583
+ *
1584
+ * @param string $text
1585
+ */
1586
+ function textblock($text) {
1587
+ echo "<div class='form-group su-admin-form-textblock'>\n<div class='col-md-12'>\n";
1588
+ echo $text;
1589
+ echo "\n</div>\n</div>\n";
1590
+ }
1591
+
1592
+ /**
1593
+ * Outputs a group of checkboxes into an admin form, and saves the values into the database after form submission.
1594
+ *
1595
+ * @since 0.1
1596
+ * @uses is_action()
1597
+ * @uses update_setting()
1598
+ * @uses get_module_key()
1599
+ * @uses get_setting()
1600
+ *
1601
+ * @param array $checkboxes An array of checkboxes. (Field/setting IDs are the keys, and descriptions are the values.)
1602
+ * @param mixed $grouptext The text to display in a table cell to the left of the one containing the checkboxes. Optional.
1603
+ */
1604
+ function checkboxes($checkboxes, $grouptext=false, $args=array()) {
1605
+
1606
+ extract(wp_parse_args($args, array(
1607
+ 'output_tr' => true
1608
+ )));
1609
+
1610
+ //Save checkbox settings after form submission
1611
+ if ($this->is_action('update')) {
1612
+ foreach ($checkboxes as $name => $desc) {
1613
+ $new_value = isset($_POST[$name]) ? ($_POST[$name] == '1') : false;
1614
+
1615
+ if (is_array($desc)) {
1616
+ $disabled = isset($desc['disabled']) ? $desc['disabled'] : false;
1617
+ $desc = isset($desc['description']) ? $desc['description'] : '';
1618
+ } else {
1619
+ $disabled = false;
1620
+ }
1621
+
1622
+ if (!$disabled)
1623
+ $this->update_setting($name, $new_value);
1624
+
1625
+ if (strpos($desc, '%d') !== false) {
1626
+ $name .= '_value';
1627
+ $this->update_setting($name, sustr::to_int($_POST[$name]));
1628
+ }
1629
+ }
1630
+ }
1631
+
1632
+ if ($grouptext)
1633
+ $this->admin_form_group_start($grouptext, false);
1634
+ elseif ($output_tr)
1635
+ echo "<div class='form-group su-admin-form-checkbox'>\n<div class='col-md-12'>\n";
1636
+
1637
+ if (is_array($checkboxes)) {
1638
+ foreach ($checkboxes as $name => $desc) {
1639
+
1640
+ if (is_array($desc)) {
1641
+ $indent = isset($desc['indent']) ? $desc['indent'] : false;
1642
+ $disabled = isset($desc['disabled']) ? $desc['disabled'] : false;
1643
+ $checked = isset($desc['checked']) ? $desc['checked'] : null;
1644
+ $desc = $desc['description'];
1645
+ } else {
1646
+ $indent = false;
1647
+ $disabled = false;
1648
+ $checked = null;
1649
+ }
1650
+
1651
+ register_setting($this->get_module_key(), $name, array('sustr', 'to_int'));
1652
+ $name = su_esc_attr($name);
1653
+
1654
+ if (strpos($desc, '%d') === false) {
1655
+ $onclick = '';
1656
+ } else {
1657
+ $int_var_name = $name.'_value';
1658
+ $int_var_value = sustr::to_int($this->get_setting($int_var_name));
1659
+ if ($this->get_setting($name) === true) $sfdisabled = ''; else $sfdisabled = "readonly='readonly' ";
1660
+ $desc = str_replace('%d', "</label><input name='$int_var_name' id='$int_var_name' class='form-control input-sm nowidth-input' type='text' value='$int_var_value' size='2' maxlength='3' $sfdisabled/><label for='$name'>", $desc);
1661
+ $desc = str_replace("<label for='$name'></label>", '', $desc);
1662
+ $onclick = " onclick=\"javascript:document.getElementById('$int_var_name').readOnly=!this.checked;\"";
1663
+ }
1664
+
1665
+ if ($indent) $labelclass = " class='su-indent'"; else $labelclass = '';
1666
+ echo "<div class='checkbox'><label for='$name'$labelclass><input name='$name' id='$name' type='checkbox' value='1'";
1667
+ if ($checked !== false && ($checked === true || $this->get_setting($name) === true)) echo " checked='checked'";
1668
+ if ($disabled) echo " disabled='disabled'";
1669
+ echo "$onclick /> $desc</label></div>\n";
1670
+ }
1671
+ }
1672
+
1673
+ if ($grouptext) {
1674
+ $this->admin_form_group_end(false);
1675
+ } elseif ($output_tr) {
1676
+ echo "</div>\n</div>\n";
1677
+ }
1678
+ }
1679
+
1680
+ /**
1681
+ * Outputs a single checkbox into an admin form and saves its value into the database after form submission.
1682
+ *
1683
+ * @since 1.5
1684
+ * @uses checkboxes()
1685
+ *
1686
+ * @param string $id The field/setting ID.
1687
+ * @param string $desc The checkbox's label.
1688
+ * @param mixed $grouptext The text to display in a table cell to the left of the one containing the checkbox. Optional.
1689
+ * @return string The HTML that would render the checkbox.
1690
+ */
1691
+ function checkbox($id, $desc, $grouptext = false, $args=array()) {
1692
+ $this->checkboxes(array($id => $desc), $grouptext, $args);
1693
+ }
1694
+
1695
+ /**
1696
+ * Outputs a set of radio buttons into an admin form and saves the set's value into the database after form submission.
1697
+ *
1698
+ * @since 1.5
1699
+ * @uses is_action()
1700
+ * @uses update_setting()
1701
+ * @uses admin_form_group_start()
1702
+ * @uses admin_form_group_end()
1703
+ * @uses su_esc_attr()
1704
+ * @uses get_setting()
1705
+ *
1706
+ * @param string $name The name of the set of radio buttons.
1707
+ * @param array $values The keys of this array are the radio button values, and the array values are the label strings.
1708
+ * @param string|false $grouptext The text to display in a table cell to the left of the one containing the radio buttons. Optional.
1709
+ */
1710
+ function radiobuttons($name, $values, $grouptext=false) {
1711
+
1712
+ //Save radio button setting after form submission
1713
+ if ($this->is_action('update') && isset($_POST[$name]))
1714
+ $this->update_setting($name, $_POST[$name]);
1715
+
1716
+ if ($grouptext)
1717
+ $this->admin_form_group_start($grouptext, false);
1718
+ else
1719
+ echo "<tr valign='top' class='su-admin-form-radio'>\n<td colspan='2'>\n";
1720
+
1721
+ if (is_array($values)) {
1722
+
1723
+ register_setting($this->get_module_key(), $name);
1724
+ $name = su_esc_attr($name);
1725
+
1726
+ $first = true;
1727
+ foreach ($values as $value => $desc) {
1728
+
1729
+ $value = su_esc_attr($value);
1730
+ $id = "{$name}_{$value}";
1731
+
1732
+ $current = (strcmp($this->get_setting($name), $value) == 0);
1733
+ $class = $first ? 'first' : ''; $first = false;
1734
+ if ($current) $class .= ' current-setting';
1735
+ $class = trim($class);
1736
+ if ($class) $class = " class='$class'";
1737
+
1738
+ extract($this->insert_subfield_textboxes($name, $desc));
1739
+
1740
+ echo "<div class='radio'><label for='$id'$class><input name='$name' id='$id' type='radio' value='$value'";
1741
+ if ($current) echo " checked='checked'";
1742
+ echo " /> $label";
1743
+
1744
+ if (!sustr::has($label, '</label>')) echo '</label>';
1745
+ echo "</div>\n";
1746
+ }
1747
+ }
1748
+
1749
+ if ($grouptext)
1750
+ $this->admin_form_group_end(false);
1751
+ }
1752
+
1753
+ /**
1754
+ * Outputs a dropdown into an admin form and saves the dropdown's value into the database after form submission.
1755
+ *
1756
+ * @since 3.7
1757
+ * @uses is_action()
1758
+ * @uses update_setting()
1759
+ * @uses admin_form_group_start()
1760
+ * @uses admin_form_group_end()
1761
+ * @uses su_esc_attr()
1762
+ * @uses get_setting()
1763
+ *
1764
+ * @param string $name The name of the setting which the dropdown is supposed to set.
1765
+ * @param array $values The keys of this array are the possible dropdown option values, and the array values are the option label strings.
1766
+ * @param string|false $grouptext The text to display in a table cell to the left of the one containing the dropdown. Optional.
1767
+ * @param string $text A printf-style format string in which "%s" is replaced with the dropdown. Use this to put text before or after the dropdown.
1768
+ */
1769
+ function dropdown($name, $values, $grouptext=false, $text='%s', $args=array()) {
1770
+
1771
+ $in_table = isset($args['in_table']) ? $args['in_table'] : true;
1772
+
1773
+ //Save dropdown setting after form submission
1774
+ if ($this->is_action('update') && isset($_POST[$name]))
1775
+ $this->update_setting($name, $_POST[$name]);
1776
+
1777
+ if ($grouptext)
1778
+ $this->admin_form_group_start($grouptext, false);
1779
+ elseif ($in_table)
1780
+ echo "<div class='form-group su-admin-form-dropdown'>\n<div class='col-sm-4 col-md-4'>\n";
1781
+
1782
+ if (is_array($values)) {
1783
+
1784
+ register_setting($this->get_module_key(), $name);
1785
+
1786
+ $name = su_esc_attr($name);
1787
+ $dropdown = "<select name='$name' id='$name'>\n"
1788
+ . suhtml::option_tags($values, $this->get_setting($name))
1789
+ . "</select>";
1790
+ printf($text, $dropdown);
1791
+ }
1792
+
1793
+ if ($grouptext)
1794
+ $this->admin_form_group_end();
1795
+ elseif ($in_table)
1796
+ echo "</div>\n<div class='col-sm-4 col-md-4 help-text'>\n</div>\n</div>\n";
1797
+ }
1798
+
1799
+ /**
1800
+ * @since 3.0
1801
+ */
1802
+ function insert_subfield_textboxes($name, $label, $enabled = true) {
1803
+
1804
+ $pattern = '/%(d|s)({([a-z0-9_-]+)})?/';
1805
+
1806
+ if (preg_match($pattern, $label, $matches)) {
1807
+ $is_int_field = ($matches[1] == 'd');
1808
+ $sfname = $name.'_value';
1809
+
1810
+ if (isset($matches[3]))
1811
+ $sfname = $matches[3];
1812
+
1813
+ if ($this->is_action('update'))
1814
+ $sfvalue = stripslashes($_POST[$sfname]);
1815
+ else
1816
+ $sfvalue = $this->get_setting($sfname);
1817
+
1818
+ if ($is_int_field)
1819
+ $sfvalue = sustr::to_int($sfvalue);
1820
+
1821
+ if ($this->is_action('update'))
1822
+ $this->update_setting($sfname, $sfvalue);
1823
+
1824
+ if ($enabled) $disabled = ''; else $disabled = " readonly='readonly'";
1825
+
1826
+ $esfvalue = su_esc_attr($sfvalue);
1827
+ $field_html = "</label><input class='textbox subfield form-control input-sm' name='$sfname' id='$sfname' type='text' value='$esfvalue'$disabled";
1828
+ if ($is_int_field) $field_html .= " size='2' maxlength='3'";
1829
+ $field_html .= " /><label for='$name'>";
1830
+
1831
+ $label = preg_replace($pattern, $field_html, $label);
1832
+ $label = preg_replace("@<label for='$name'>$@", '', $label);
1833
+
1834
+ $onclick = " onclick=\"javascript:document.getElementById('$sfname').readOnly=!this.checked;\"";
1835
+ } else
1836
+ $onclick = '';
1837
+
1838
+ return compact('label', 'onclick');
1839
+ }
1840
+
1841
+ /**
1842
+ * Outputs a group of textboxes into an admin form, and saves the values into the database after form submission.
1843
+ * Can also display a "Reset" link next to each textbox that reverts its value to a specified default.
1844
+ *
1845
+ * @since 0.1
1846
+ * @uses is_action()
1847
+ * @uses update_setting()
1848
+ * @uses get_module_key()
1849
+ * @uses get_setting()
1850
+ *
1851
+ * @param array $textboxes An array of textboxes. (Field/setting IDs are the keys, and descriptions are the values.)
1852
+ * @param array $defaults An array of default textbox values that trigger "Reset" links. (The field/setting ID is the key, and the default value is the value.) Optional.
1853
+ * @param mixed $grouptext The text to display in a table cell to the left of the one containing the textboxes. Optional.
1854
+ */
1855
+ function textboxes($textboxes, $defaults=array(), $grouptext=false, $args=array(), $textbox_args=array()) {
1856
+
1857
+ $is_tree_parent = isset($args['is_tree_parent']) ? $args['is_tree_parent'] : false;
1858
+ $is_ec_tree = isset($args['is_ec_tree']) ? $args['is_ec_tree'] : false;
1859
+ $tree_level = isset($args['tree_level']) ? $args['tree_level'] : false;
1860
+ $disabled = isset($args['disabled']) ? $args['disabled'] : false;
1861
+ $in_table = isset($args['in_table']) ? $args['in_table'] : true;
1862
+ $help_text = isset($args['help_text']) ? $args['help_text'] : false;
1863
+ $callout = isset($args['callout']) ? $args['callout'] : false;
1864
+
1865
+ if (!$disabled && $this->is_action('update')) {
1866
+ foreach ($textboxes as $id => $title) {
1867
+ if (isset($_POST[$id]))
1868
+ $this->update_setting($id, stripslashes($_POST[$id]));
1869
+ }
1870
+ }
1871
+
1872
+ $indentattrs = $indenttoggle = $hidden = '';
1873
+ if ($tree_level !== false) {
1874
+ $indentattrs = " class='su-indent su-indent-level-{$tree_level}'";
1875
+ if ($is_ec_tree) {
1876
+ if ($is_tree_parent)
1877
+ $indenttoggle = "<span class='su-child-fields-toggle'>+</span> ";
1878
+ else
1879
+ $indenttoggle = "<span class='su-child-fields-toggle-filler'> </span> ";
1880
+
1881
+ if ($tree_level > 1)
1882
+ $hidden = " style='display: none;'";
1883
+ }
1884
+ }
1885
+
1886
+ if ($grouptext) $this->admin_form_group_start($grouptext, false);
1887
+
1888
+ foreach ($textboxes as $id => $title) {
1889
+
1890
+ $before = isset($textbox_args[$id]['before']) ? $textbox_args[$id]['before'] : '';
1891
+ $after = isset($textbox_args[$id]['after']) ? $textbox_args[$id]['after'] : '';
1892
+ $placeholder = isset($textbox_args[$id]['placeholder']) ? $textbox_args[$id]['placeholder'] : '';
1893
+
1894
+ register_setting($this->get_module_key(), $id);
1895
+ $value = su_esc_editable_html($this->get_setting($id));
1896
+ $id = su_esc_attr($id);
1897
+ $resetmessage = su_esc_attr(__('Are you sure you want to replace the textbox contents with this default value?', 'seo-ultimate'));
1898
+
1899
+ if ($callout)
1900
+ echo "<div class='bs-callout bs-callout-grey'><h4>$callout</h4></div>\n";
1901
+
1902
+ if ($grouptext)
1903
+ echo "<div class='form-group'><label class='col-sm-4 col-md-4 control-label' for='$id'>$title</label>\n<div class='col-sm-4 col-md-4'>\n";
1904
+ elseif ($in_table && strpos($title, '</a>') === false)
1905
+ echo "<div class='form-group'$indentattrs$hidden>\n<label class='col-sm-4 col-md-4 control-label' for='$id'><span class='su-field-label-text'>$title</span></label>\n<div class='col-sm-4 col-md-4'>\n";
1906
+ elseif ($in_table)
1907
+ echo "<div class='form-group'$indentattrs$hidden>\n<label class='col-sm-4 col-md-4 control-label' for='$id'><span class='su-field-label-text'>$title</span></label>\n<div class='col-sm-4 col-md-4'>\n";
1908
+
1909
+ echo $before;
1910
+
1911
+ echo "<input name='$id' id='$id' type='text' value='$value' class='form-control input-sm regular-text' ";
1912
+
1913
+ if ($placeholder) {
1914
+ $a_placeholder = su_esc_attr($placeholder);
1915
+ echo "placeholder='$placeholder' ";
1916
+ }
1917
+
1918
+ if ($disabled)
1919
+ echo "disabled='disabled' />";
1920
+ elseif (isset($defaults[$id])) {
1921
+ $default = su_esc_editable_html($defaults[$id]);
1922
+ echo "onkeyup=\"javascript:su_textbox_value_changed(this, '$default', '{$id}_reset')\" />";
1923
+ echo "&nbsp;<a href=\"#\" id=\"{$id}_reset\" onclick=\"javascript:su_reset_textbox('$id', '$default', '$resetmessage', this); return false;\"";
1924
+ if ($default == $value) echo ' class="hidden"';
1925
+ echo ">";
1926
+ _e('Reset', 'seo-ultimate');
1927
+ echo "</a>";
1928
+
1929
+ if (isset($args['open_url_value_link']))
1930
+ echo ' |';
1931
+ } else {
1932
+ echo "/>";
1933
+ }
1934
+
1935
+ if (isset($args['open_url_value_link'])) {
1936
+ echo " <a href='#' onclick=\"javascript:window.open(document.getElementById('$id').value);return false;\">";
1937
+ echo su_esc_html($args['open_url_value_link']);
1938
+ echo '</a>';
1939
+ }
1940
+
1941
+ echo $after;
1942
+
1943
+ if ($grouptext)
1944
+ echo "</div>\n";
1945
+ elseif ($in_table)
1946
+ echo "</div>\n";
1947
+
1948
+ if ($help_text)
1949
+ echo "<div class='col-sm-4 col-md-4'>$help_text</div>\n</div>\n";
1950
+ else
1951
+ echo "<div class='col-sm-4 col-md-4'></div>\n</div>\n";
1952
+ }
1953
+
1954
+ if ($grouptext) $this->admin_form_group_end(false);
1955
+ }
1956
+
1957
+ /**
1958
+ * Outputs a single textbox into an admin form and saves its value into the database after form submission.
1959
+ *
1960
+ * @since 0.1
1961
+ * @uses textboxes()
1962
+ *
1963
+ * @param string $id The field/setting ID.
1964
+ * @param string $title The label of the HTML element.
1965
+ * @param string|false $default The default textbox value. Setting this will trigger a "Reset" link. Optional.
1966
+ * @return string The HTML that would render the textbox.
1967
+ */
1968
+ function textbox($id, $title, $default=false, $grouptext=false, $args=array(), $textbox_args=array()) {
1969
+ if ($default === false) $default = array(); else $default = array($id => $default);
1970
+ $this->textboxes(array($id => $title), $default, $grouptext, $args, array($id => $textbox_args));
1971
+ }
1972
+
1973
+ /**
1974
+ * Outputs a group of textareas into an admin form, and saves the values into the database after form submission.
1975
+ *
1976
+ * @since 0.1
1977
+ * @uses is_action()
1978
+ * @uses update_setting()
1979
+ * @uses get_module_key()
1980
+ * @uses get_setting()
1981
+ *
1982
+ * @param array $textareas An array of textareas. (Field/setting IDs are the keys, and descriptions are the values.)
1983
+ * @param int $rows The value of the textareas' rows attribute.
1984
+ * @param int $cols The value of the textareas' cols attribute.
1985
+ */
1986
+ function textareas($textareas, $rows = 5, $cols = 30, $args=array()) {
1987
+
1988
+ $disabled = isset($args['disabled']) ? $args['disabled'] : false;
1989
+
1990
+ if (!$disabled && $this->is_action('update')) {
1991
+ foreach ($textareas as $id => $title) {
1992
+ if (isset($_POST[$id]))
1993
+ $this->update_setting($id, stripslashes($_POST[$id]));
1994
+ }
1995
+ }
1996
+
1997
+ foreach ($textareas as $id => $title) {
1998
+ register_setting($this->get_module_key(), $id);
1999
+ $value = su_esc_editable_html($this->get_setting($id));
2000
+ $id = su_esc_attr($id);
2001
+
2002
+ echo "<div class='form-group'>\n";
2003
+ if ($title) echo "<label class='col-sm-4 col-md-4 control-label' for='$id'>$title</label>\n";
2004
+ echo "<div class='col-sm-4 col-md-4'>";
2005
+ echo "<textarea name='$id' id='$id' type='text' class='form-control regular-text' cols='$cols' rows='$rows'";
2006
+ if ($disabled) echo " disabled='disabled'";
2007
+ echo ">$value</textarea>";
2008
+ echo "</div>\n<div class='col-sm-4 col-md-4 help-text'>\n</div>\n</div>\n";
2009
+ }
2010
+ }
2011
+
2012
+ /**
2013
+ * Outputs a single textarea into an admin form and saves its value into the database after form submission.
2014
+ *
2015
+ * @since 0.1
2016
+ * @uses textareas()
2017
+ *
2018
+ * @param string $id The field/setting ID.
2019
+ * @param string $title The label of the HTML element.
2020
+ * @param int $rows The value of the textarea's rows attribute.
2021
+ * @param int $cols The value of the textarea's cols attribute.
2022
+ * @return string The HTML that would render the textarea.
2023
+ */
2024
+ function textarea($id, $title = '', $rows = 5, $cols = 30) {
2025
+ $this->textareas(array($id => $title), $rows, $cols);
2026
+ }
2027
+
2028
+ /**
2029
+ * @since 7.3
2030
+ */
2031
+ function jlsuggest_boxes($jls_boxes) {
2032
+
2033
+ if ($this->is_action('update')) {
2034
+ foreach ($jls_boxes as $jls_box) {
2035
+
2036
+ if (!isset($jls_box['id']))
2037
+ continue;
2038
+
2039
+ $id = $jls_box['id'];
2040
+
2041
+ if (isset($_POST[$id]))
2042
+ $this->update_setting($id, stripslashes($_POST[$id]));
2043
+ }
2044
+ }
2045
+
2046
+ foreach ($jls_boxes as $jls_box) {
2047
+
2048
+ if (!isset($jls_box['id']))
2049
+ continue;
2050
+
2051
+ $jls_box = wp_parse_args($jls_box, array(
2052
+ 'title' => ''
2053
+ , 'params' => ''
2054
+ ));
2055
+
2056
+ extract($jls_box, EXTR_SKIP);
2057
+
2058
+ register_setting($this->get_module_key(), $id);
2059
+
2060
+ echo "<div class='form-group'>\n";
2061
+ if ($title) echo "<label class='col-sm-4 col-md-4 control-label' for='$id'>$title</label>\n";
2062
+ echo "<div class='col-sm-4 col-md-4'>";
2063
+ echo $this->get_jlsuggest_box($id, $this->get_setting($id), $params);
2064
+ echo "</div>\n<div class='col-sm-4 col-md-4 help-text'>\n</div>\n</div>\n";
2065
+ }
2066
+ }
2067
+
2068
+ /**
2069
+ * @since 7.3
2070
+ */
2071
+ function jlsuggest_box($id, $title, $params='') {
2072
+ $this->jlsuggest_boxes(array(compact('id', 'title', 'params')));
2073
+ }
2074
+ /**
2075
+ * @since 7.6.3
2076
+ */
2077
+ function medialib_boxes($media_boxes) {
2078
+
2079
+ if ($this->is_action('update')) {
2080
+ foreach ($media_boxes as $media_box) {
2081
+
2082
+ if (!isset($media_box['id']))
2083
+ continue;
2084
+
2085
+ $id = $media_box['id'];
2086
+
2087
+ if (isset($_POST[$id]))
2088
+ $this->update_setting($id, stripslashes($_POST[$id]));
2089
+ }
2090
+ }
2091
+
2092
+ foreach ($media_boxes as $media_box) {
2093
+
2094
+ if (!isset($media_box['id']))
2095
+ continue;
2096
+
2097
+ $media_box = wp_parse_args($media_box, array(
2098
+ 'title' => ''
2099
+ , 'params' => ''
2100
+ ));
2101
+
2102
+ extract($media_box, EXTR_SKIP);
2103
+
2104
+ register_setting($this->get_module_key(), $id);
2105
+
2106
+ echo "<div class='form-group'>\n";
2107
+ if ($title) echo "<label class='col-sm-4 col-md-4 control-label' for='$id'>$title</label>\n";
2108
+ echo "<div class='col-sm-4 col-md-4'>";
2109
+ echo "<div class='input-group'>
2110
+ <input id='".su_esc_attr($id)."' name='".su_esc_attr($id)."' type='text' class='wpu-image form-control' size='40' value='".$this->get_setting($id)."'>
2111
+ <span class='input-group-btn'>
2112
+ <span class='btn btn-custom btn-file wpu-media-upload'>
2113
+ <i class='fa fa-upload'></i> Upload Image <input type='file'>
2114
+ </span>
2115
+ </span>
2116
+ </div>";
2117
+ echo "</div>\n<div class='col-sm-4 col-md-4 help-text'>\n</div>\n</div>\n";
2118
+ }
2119
+ }
2120
+
2121
+ /**
2122
+ * @since 7.6.3
2123
+ */
2124
+ function medialib_box($id, $title, $params='') {
2125
+ $this->medialib_boxes(array(compact('id', 'title', 'params')));
2126
+ }
2127
+
2128
+ /********** ADMIN SECURITY FUNCTIONS **********/
2129
+
2130
+ /**
2131
+ * Determines if a particular nonce-secured admin action is being executed.
2132
+ *
2133
+ * @since 0.1
2134
+ * @uses SEO_Ultimate::key_to_hook()
2135
+ * @uses get_module_key()
2136
+ * @uses nonce_validates()
2137
+ *
2138
+ * @param string $action The name of the action to check.
2139
+ * @return bool Whether or not the action is being executed.
2140
+ */
2141
+ function is_action($action) {
2142
+ if (!isset($_GET['object']) || !($object = $_GET['object'])) $object = false;
2143
+ return (
2144
+ !empty($_GET['page'])
2145
+ && (
2146
+ ( strcasecmp($_GET['page'], $this->plugin->key_to_hook($this->get_module_key())) == 0 ) //Is $this module being shown?
2147
+ || ( strlen($this->get_parent_module()) && strcasecmp($_GET['page'], $this->plugin->key_to_hook($this->get_parent_module())) == 0) //Is the parent module being shown?
2148
+ )
2149
+ && (
2150
+ (!empty($_GET['action']) && $_GET['action'] == $action)
2151
+ || (!empty($_POST['action']) && $_POST['action'] == $action)
2152
+ ) //Is this $action being executed?
2153
+ && $this->nonce_validates($action, $object) //Is the nonce valid?
2154
+ );
2155
+ }
2156
+
2157
+ /**
2158
+ * Determines whether a nonce is valid.
2159
+ *
2160
+ * @since 0.1
2161
+ * @uses get_nonce_handle()
2162
+ *
2163
+ * @param string $action The name of the action.
2164
+ * @param mixed $id The ID of the object being acted upon. Optional.
2165
+ * @return bool Whether or not the nonce is valid.
2166
+ */
2167
+ function nonce_validates($action, $id = false) {
2168
+ return check_admin_referer($this->get_nonce_handle($action, $id));
2169
+ }
2170
+
2171
+ /**
2172
+ * Generates a unique name for a nonce.
2173
+ *
2174
+ * @since 0.1
2175
+ * @uses get_parent_module()
2176
+ * @uses get_module_key()
2177
+ * @uses SU_PLUGIN_NAME
2178
+ *
2179
+ * @param string $action The name of the action.
2180
+ * @param mixed $id The ID of the object being acted upon. Optional.
2181
+ * @return The handle to use for the nonce.
2182
+ */
2183
+ function get_nonce_handle($action, $id = false) {
2184
+
2185
+ $key = $this->get_parent_module();
2186
+ if (!$key || !$this->plugin->module_exists($key)) $key = $this->get_module_key();
2187
+
2188
+ $hook = $this->plugin->key_to_hook($key);
2189
+
2190
+ if (strcmp($action, 'update') == 0) {
2191
+ //We use the settings_fields() function, which outputs a nonce in this particular format.
2192
+ return "$hook-options";
2193
+ } else {
2194
+ if ($id) $id = '-'.md5($id); else $id = '';
2195
+ $handle = SU_PLUGIN_NAME."-$hook-$action$id";
2196
+ return strtolower(str_replace(' ', '-', $handle));
2197
+ }
2198
+ }
2199
+
2200
+ /**
2201
+ * Returns a GET-action URL with an appended nonce.
2202
+ *
2203
+ * @since 0.1
2204
+ * @uses get_module_key()
2205
+ * @uses get_nonce_handle()
2206
+ *
2207
+ * @param string $action The name of the action.
2208
+ * @param mixed $id The ID of the object being acted upon. Optional.
2209
+ * @return The URL to use in an <a> tag.
2210
+ */
2211
+ function get_nonce_url($action, $object=false) {
2212
+ $action = urlencode($action);
2213
+ if ($object) $objectqs = '&object='.urlencode($object); else $objectqs = '';
2214
+
2215
+ $hook = $this->plugin->key_to_hook($this->get_module_or_parent_key());
2216
+
2217
+ //We don't need to escape ampersands since wp_nonce_url will do that for us
2218
+ return wp_nonce_url("?page=$hook&action=$action$objectqs",
2219
+ $this->get_nonce_handle($action, $object));
2220
+ }
2221
+
2222
+
2223
+ /********** ADMIN MESSAGE FUNCTIONS **********/
2224
+
2225
+ /**
2226
+ * Print a message (and any previously-queued messages) right away.
2227
+ *
2228
+ * @since 0.1
2229
+ * @uses queue_message()
2230
+ * @uses print_messages()
2231
+ *
2232
+ * @param string $type The message's type. Valid values are success, error, warning, and info.
2233
+ * @param string $message The message text.
2234
+ */
2235
+ function print_message($type, $message) {
2236
+ $this->queue_message($type, $message);
2237
+ $this->print_messages();
2238
+ }
2239
+
2240
+ /**
2241
+ * Adds a message to the queue.
2242
+ *
2243
+ * @since 0.1
2244
+ * @uses $messages
2245
+ *
2246
+ * @param string $type The message's type. Valid values are success, error, warning, and info.
2247
+ * @param string $message The message text.
2248
+ */
2249
+ function queue_message($type, $message) {
2250
+ $this->messages[$type][] = $message;
2251
+ }
2252
+
2253
+ /**
2254
+ * Prints all queued messages and flushes the queue.
2255
+ *
2256
+ * @since 0.1
2257
+ * @uses $messages
2258
+ */
2259
+ function print_messages() {
2260
+ foreach ($this->messages as $type => $messages) {
2261
+ $messages = implode('<br />', $messages);
2262
+ if ($messages) {
2263
+ $type = su_esc_attr($type);
2264
+ echo "<div class='su-message'><p class='su-$type'>$messages</p></div>\n";
2265
+ }
2266
+ }
2267
+
2268
+ $this->messages = array();
2269
+ }
2270
+
2271
+ /**
2272
+ * Prints a mini-style message.
2273
+ *
2274
+ * @since 2.1
2275
+ */
2276
+ function print_mini_message($type, $message) {
2277
+ $type = su_esc_attr($type);
2278
+ echo "<div class='su-status su-$type'>$message</div>";
2279
+ }
2280
+
2281
+ /********** ADMIN META FUNCTIONS **********/
2282
+
2283
+ /**
2284
+ * Gets a specified meta value of the current post (i.e. the post currently being edited in the admin,
2285
+ * the post being shown, the post now in the loop, or the post with specified ID).
2286
+ *
2287
+ * @since 0.1
2288
+ *
2289
+ * @param string $key The meta key to fetch.
2290
+ * @param mixed $id The ID number of the post/page.
2291
+ * @return string The meta value requested.
2292
+ */
2293
+ function get_postmeta($key, $id=false) {
2294
+
2295
+ if (!$id) {
2296
+ //This code is different from suwp::get_post_id();
2297
+ if (is_admin()) {
2298
+ $id = empty($_REQUEST['post']) ? false : intval($_REQUEST['post']);
2299
+ global $post;
2300
+ } elseif (in_the_loop()) {
2301
+ $id = intval(get_the_ID());
2302
+ global $post;
2303
+ } elseif (is_singular()) {
2304
+ global $wp_query;
2305
+ $id = $wp_query->get_queried_object_id();
2306
+ $post = $wp_query->get_queried_object();
2307
+ }
2308
+ }
2309
+
2310
+ if ($id) {
2311
+
2312
+ if (isset($post) && $post)
2313
+ $_post = $post;
2314
+ else
2315
+ $_post = get_post($id);
2316
+
2317
+ $value = get_post_meta($id, "_su_$key", true);
2318
+ $value = apply_filters("su_get_postmeta", $value, $key, $_post);
2319
+ $value = apply_filters("su_get_postmeta-$key", $value, $key, $_post);
2320
+ } else
2321
+ $value = '';
2322
+
2323
+ return $value;
2324
+ }
2325
+
2326
+ /**
2327
+ * Generates the HTML for multiple post meta textboxes.
2328
+ *
2329
+ * @since 0.1
2330
+ * @uses get_postmeta()
2331
+ *
2332
+ * @param array $textboxes An array of textboxes. (Field/setting IDs are the keys, and descriptions are the values.)
2333
+ * @return string The HTML that would render the textboxes.
2334
+ */
2335
+ function get_postmeta_textboxes($textboxes, $textbox_args=array(), $grouptext=false) {
2336
+
2337
+ $html = '';
2338
+
2339
+ if ($grouptext) {
2340
+ $h_grouptext = esc_html($grouptext);
2341
+ $html = "<div class='form-group su textbox'>\n<h4 class='col-sm-4 col-md-4 control-label'>$h_grouptext</h4>\n<div class='col-sm-4 col-md-4'></div>\n<div class='col-sm-4 col-md-4 help-text'>\n</div>\n</div>\n";
2342
+ }
2343
+
2344
+ foreach ($textboxes as $id => $title) {
2345
+
2346
+ $type = isset($textbox_args[$id]['type']) ? $textbox_args[$id]['type'] : 'text';
2347
+ $input_clss = ($type == 'text') ? 'input-sm ' : '';
2348
+
2349
+ register_setting('seo-ultimate', $id);
2350
+ $value = su_esc_editable_html($this->get_postmeta($id));
2351
+ $id = "_su_".su_esc_attr($id);
2352
+
2353
+ $e_title = su_esc_attr($title);
2354
+
2355
+ $html = "<div class='form-group su textbox'>\n<label class='col-sm-4 col-md-4 control-label' for='$id'>$title</label>\n<div class='col-sm-4 col-md-4'><input name='$id' id='$id' type='$type' value='$value' class='"
2356
+ . $input_clss."form-control regular-text' tabindex='2' />\n"
2357
+ . "</div>\n<div class='col-sm-4 col-md-4 help-text'>\n</div>\n</div>\n";
2358
+ }
2359
+
2360
+ if ($grouptext) {
2361
+ $h_grouptext = esc_html($grouptext);
2362
+ //$html .= "</table></td>\n</tr>\n";
2363
+ }
2364
+
2365
+ return $html;
2366
+ }
2367
+
2368
+ /**
2369
+ * Generates the HTML for a single post meta textbox.
2370
+ *
2371
+ * @since 0.1
2372
+ * @uses get_postmeta_textboxes()
2373
+ *
2374
+ * @param string $id The ID of the HTML element.
2375
+ * @param string $title The label of the HTML element.
2376
+ * @return string The HTML that would render the textbox.
2377
+ */
2378
+ function get_postmeta_textbox($id, $title, $args=array()) {
2379
+ return $this->get_postmeta_textboxes(array($id => $title), array($id => $args));
2380
+ }
2381
+
2382
+ /**
2383
+ * Generates the HTML for multiple post meta textareas.
2384
+ *
2385
+ * @since 3.9
2386
+ * @uses get_postmeta()
2387
+ *
2388
+ * @param array $textareas An array of textareas. (Field/setting IDs are the keys, and descriptions are the values.)
2389
+ * @return string The HTML that would render the textareas.
2390
+ */
2391
+ function get_postmeta_textareas($textareas) {
2392
+
2393
+ $html = '';
2394
+
2395
+ foreach ($textareas as $id => $title) {
2396
+
2397
+ register_setting('seo-ultimate', $id);
2398
+ $value = su_esc_editable_html($this->get_postmeta($id));
2399
+ $id = "_su_".su_esc_attr($id);
2400
+
2401
+ $html = "<div class='form-group su textarea'>\n<label class='col-sm-4 col-md-4 control-label' for='$id'>$title</label>\n<div class='col-sm-4 col-md-4'><textarea name='$id' id='$id' class='form-control regular-text' tabindex='2' cols='60' rows='3'>$value</textarea>\n"
2402
+ ."</div>\n<div class='col-sm-4 col-md-4 help-text'>\n</div>\n</div>\n";
2403
+ }
2404
+
2405
+ return $html;
2406
+ }
2407
+
2408
+ /**
2409
+ * Generates the HTML for a single post meta textarea.
2410
+ *
2411
+ * @since 3.9
2412
+ * @uses get_postmeta_textareas()
2413
+ *
2414
+ * @param string $id The ID of the HTML element.
2415
+ * @param string $title The label of the HTML element.
2416
+ * @return string The HTML that would render the textarea.
2417
+ */
2418
+ function get_postmeta_textarea($id, $title) {
2419
+ return $this->get_postmeta_textareas(array($id => $title));
2420
+ }
2421
+
2422
+ /**
2423
+ * Generates the HTML for a group of post meta checkboxes.
2424
+ *
2425
+ * @since 0.1
2426
+ * @uses get_module_key()
2427
+ * @uses get_postmeta()
2428
+ *
2429
+ * @param array $checkboxes An array of checkboxes. (Field/setting IDs are the keys, and descriptions are the values.)
2430
+ * @param string $grouptext The text to display in a table cell to the left of the one containing the checkboxes.
2431
+ */
2432
+ function get_postmeta_checkboxes($checkboxes, $grouptext) {
2433
+
2434
+ $valign = (is_array($checkboxes) && count($checkboxes) > 1) ? 'top' : 'middle';
2435
+ $html = "<div class='form-group su checkboxes'>\n<label class='col-sm-4 col-md-4 control-label'>$grouptext</label>\n<div class='col-sm-4 col-md-4'>\n";
2436
+
2437
+ if (is_array($checkboxes)) {
2438
+ foreach ($checkboxes as $name => $desc) {
2439
+
2440
+ register_setting('seo-ultimate', $name);
2441
+ $checked = ($this->get_postmeta($name) == 1);
2442
+ $name = "_su_".su_esc_attr($name);
2443
+
2444
+ $html .= "<div class='checkbox'><label for='$name'><input name='$name' id='$name' type='checkbox' tabindex='2' value='1'";
2445
+ if ($checked) $html .= " checked='checked'";
2446
+ $html .= " /> $desc</label></div>\n";
2447
+ }
2448
+ }
2449
+
2450
+ $html .= "</div>\n<div class='col-sm-4 col-md-4 help-text'>\n</div>\n</div>\n";
2451
+
2452
+ return $html;
2453
+ }
2454
+
2455
+ /**
2456
+ * Generates the HTML for a single post meta checkbox.
2457
+ *
2458
+ * @since 0.1
2459
+ * @uses get_postmeta_checkboxes()
2460
+ *
2461
+ * @param string $id The ID of the HTML element.
2462
+ * @param string $title The label of the HTML element.
2463
+ * @param string $grouptext The text to display in a table cell to the left of the one containing the checkboxes.
2464
+ * @return string The HTML that would render the textbox.
2465
+ */
2466
+ function get_postmeta_checkbox($id, $title, $grouptext) {
2467
+ return $this->get_postmeta_checkboxes(array($id => $title), $grouptext);
2468
+ }
2469
+
2470
+ /**
2471
+ * Generates the HTML for a single <select> post meta dropdown.
2472
+ *
2473
+ * @since 2.5
2474
+ * @uses get_module_key()
2475
+ * @uses get_postmeta()
2476
+ *
2477
+ * @param string $name The name of the <select> element.
2478
+ * @param array $options An array of options, where the array keys are the <option> values and the array values are the labels (<option> contents).
2479
+ * @param string $grouptext The text to display in a table cell to the left of the one containing the dropdown.
2480
+ * @return string $html
2481
+ */
2482
+ function get_postmeta_dropdown($name, $options, $grouptext) {
2483
+
2484
+ register_setting('seo-ultimate', $name);
2485
+ $current = $this->get_postmeta($name);
2486
+ if ($current === '') {
2487
+ $current = reset($options);
2488
+ }
2489
+ $name = "_su_".su_esc_attr($name);
2490
+
2491
+ $html = "<div class='form-group su dropdown'>\n<label class='col-sm-4 col-md-4 control-label' for='$name'>$grouptext</label>\n<div class='col-sm-4 col-md-4'>\n";
2492
+ $html .= "<select name='$name' id='$name' onchange='javascript:su_toggle_select_children(this)'>\n";
2493
+ $html .= suhtml::option_tags($options, $current);
2494
+ $html .= "</select>\n";
2495
+ $html .= "</div>\n<div class='col-sm-4 col-md-4 help-text'></div>\n</div>\n";
2496
+
2497
+ return $html;
2498
+ }
2499
+
2500
+ /**
2501
+ * Generates the HTML for multiple post meta JLSuggest boxes.
2502
+ *
2503
+ * @since 7.3
2504
+ *
2505
+ * @param array $jls_boxes An array of JLSuggest boxes. (Field/setting IDs are the keys, and descriptions are the values.)
2506
+ * @return string The HTML for the JLSuggest boxes.
2507
+ */
2508
+ function get_postmeta_jlsuggest_boxes($jls_boxes) {
2509
+
2510
+ $html = '';
2511
+
2512
+ foreach ($jls_boxes as $jls_box) {
2513
+
2514
+ if (!isset($jls_box['id']) || !isset($jls_box['title']))
2515
+ continue;
2516
+
2517
+ $id = $jls_box['id'];
2518
+ $title = $jls_box['title'];
2519
+ $params = isset($jls_box['params']) ? $jls_box['params'] : false;
2520
+
2521
+ register_setting('seo-ultimate', $id);
2522
+ $value = su_esc_editable_html($this->get_postmeta($id));
2523
+ $id = "_su_".su_esc_attr($id);
2524
+
2525
+ $html .= "<div class='form-group su jlsuggestbox'>\n<label class='col-sm-4 col-md-4 control-label' for='$id'>$title</label>\n"
2526
+ ."<div class='col-sm-4 col-md-4 su'>";
2527
+ $html .= $this->get_jlsuggest_box($id, $value, $params);
2528
+ $html .= "</div>\n<div class='col-sm-4 col-md-4 help-text'>\n</div>\n</div>\n";
2529
+ }
2530
+
2531
+ return $html;
2532
+ }
2533
+
2534
+ /**
2535
+ * Generates the HTML for a single post meta JLSuggest box.
2536
+ *
2537
+ * @since 7.3
2538
+ * @uses get_postmeta_jlsuggest_boxes()
2539
+ *
2540
+ * @param string $id The ID of the HTML element.
2541
+ * @param string $title The label of the HTML element.
2542
+ * @param string $params The value of the su:params attribute of the JLSuggest box (optional).
2543
+ * @return string The HTML that would render the JLSuggest box.
2544
+ */
2545
+ function get_postmeta_jlsuggest_box($id, $title, $params=false) {
2546
+ $jls_box = compact('id', 'title', 'params');
2547
+ return $this->get_postmeta_jlsuggest_boxes(array($jls_box));
2548
+ }
2549
+
2550
+ /**
2551
+ * Generates the HTML for multiple post meta mediaupload boxes.
2552
+ *
2553
+ * @since 7.6.3
2554
+ *
2555
+ * @param array $media_boxes An array of mediaupload boxes. (Field/setting IDs are the keys, and descriptions are the values.)
2556
+ * @return string The HTML for the mediaupload boxes.
2557
+ */
2558
+ function get_postmeta_medialib_boxes($media_boxes) {
2559
+
2560
+ $html = '';
2561
+
2562
+ foreach ($media_boxes as $media_box) {
2563
+
2564
+ if (!isset($media_box['id']) || !isset($media_box['title']))
2565
+ continue;
2566
+
2567
+ $id = $media_box['id'];
2568
+ $title = $media_box['title'];
2569
+
2570
+ register_setting('seo-ultimate', $id);
2571
+ $value = su_esc_editable_html($this->get_postmeta($id));
2572
+ $id = "_su_".su_esc_attr($id);
2573
+
2574
+ $html .= "<div class='form-group su'>\n<label class='col-sm-4 col-md-4 control-label' for='$id'>$title</label>\n"
2575
+ ."<div class='col-sm-4 col-md-4 su'>";
2576
+ $html .= "<div class='input-group'>
2577
+ <input id='".su_esc_attr($id)."' name='".su_esc_attr($id)."' type='text' class='wpu-image form-control' size='40' value='".$value."'>
2578
+ <span class='input-group-btn'>
2579
+ <span class='btn btn-custom btn-file wpu-media-upload'>
2580
+ <i class='fa fa-upload'></i> Upload Image <input type='file'>
2581
+ </span>
2582
+ </span>
2583
+ </div>";
2584
+ $html .= "</div>\n<div class='col-sm-4 col-md-4 help-text'>\n</div>\n</div>\n";
2585
+ }
2586
+
2587
+ return $html;
2588
+ }
2589
+
2590
+ /**
2591
+ * Generates the HTML for a single post meta mediaupload box.
2592
+ *
2593
+ * @since 7.6.3
2594
+ * @uses get_postmeta_medialib_boxes()
2595
+ *
2596
+ * @param string $id The ID of the HTML element.
2597
+ * @param string $title The label of the HTML element.
2598
+ * @return string The HTML that would render the mediaupload box.
2599
+ */
2600
+ function get_postmeta_medialib_box($id, $title) {
2601
+ $media_box = compact('id', 'title');
2602
+ return $this->get_postmeta_medialib_boxes(array($media_box));
2603
+ }
2604
+
2605
+ /**
2606
+ * Turns a <tr> into a post meta subsection.
2607
+ *
2608
+ * @since 2.5
2609
+ * @uses get_postmeta
2610
+ *
2611
+ * @param string $field
2612
+ * @param string $value
2613
+ * @param string $html
2614
+ * @return string $html
2615
+ */
2616
+ function get_postmeta_subsection($field, $value, $html) {
2617
+ $hidden = ($this->get_postmeta($field) == $value) ? '' : ' hidden';
2618
+
2619
+ $field = su_esc_attr($field);
2620
+ $value = su_esc_attr($value);
2621
+ $html = str_replace("<div class='form-group ", "<div class='form-group su_{$field}_{$value}_subsection$hidden ", $html);
2622
+ return $html;
2623
+ }
2624
+
2625
+ /**
2626
+ * Gets a specified meta value of the current term.
2627
+ *
2628
+ * @since 5.4
2629
+ *
2630
+ * @param string $key The database setting where the metadata is stored. The function will add a "taxonomy_" prefix.
2631
+ * @param mixed $id The ID number of the post/page.
2632
+ * @return string The meta value requested.
2633
+ */
2634
+ function get_termmeta($key, $id=false, $module=false) {
2635
+
2636
+ global $wp_query;
2637
+
2638
+ if (!$id && suwp::is_tax())
2639
+ $id = $wp_query->get_queried_object_id();
2640
+
2641
+ if (!$id)
2642
+ return null;
2643
+
2644
+ $tax_meta = $this->get_setting(sustr::startwith($key, 'taxonomy_'), array(), $module);
2645
+
2646
+ if (is_array($tax_meta) && isset($tax_meta[$id]))
2647
+ return $tax_meta[$id];
2648
+
2649
+ return null;
2650
+ }
2651
+
2652
+ /********** CRON FUNCTION **********/
2653
+
2654
+ /**
2655
+ * Creates a cron job if it doesn't already exists, and ensures it runs at the scheduled time.
2656
+ * Should be called in a module's init() function.
2657
+ *
2658
+ * @since 0.1
2659
+ * @uses get_module_key()
2660
+ *
2661
+ * @param string $function The name of the module function that should be run.
2662
+ * @param string $recurrence How often the job should be run. Valid values are hourly, twicedaily, and daily.
2663
+ */
2664
+ function cron($function, $recurrence) {
2665
+
2666
+ $mk = $this->get_module_key();
2667
+
2668
+ $hook = "su-$mk-".str_replace('_', '-', $function);
2669
+ $start = time();
2670
+
2671
+ if (wp_next_scheduled($hook) === false) {
2672
+ //This is a new cron job
2673
+
2674
+ //Schedule the event
2675
+ wp_schedule_event($start, $recurrence, $hook);
2676
+
2677
+ //Make a record of it
2678
+ $psdata = (array)get_option('seo_ultimate', array());
2679
+ $psdata['cron'][$mk][$function] = array($hook, $start, $recurrence);
2680
+ update_option('seo_ultimate', $psdata);
2681
+
2682
+ //Run the event now
2683
+ call_user_func(array($this, $function));
2684
+ }
2685
+
2686
+ add_action($hook, array(&$this, $function));
2687
+ }
2688
+
2689
+ /********** JLSUGGEST **********/
2690
+
2691
+ /**
2692
+ * Initializes JLSuggest.
2693
+ * Must be called in the admin_page_init() function of the module that wants to use JLSuggest.
2694
+ *
2695
+ * @since 6.0
2696
+ * @uses jlsuggest_xml_ns()
2697
+ * @uses SEO_Ultimate::queue_js()
2698
+ * @uses SEO_Ultimate::queue_css()
2699
+ */
2700
+ function jlsuggest_init() {
2701
+ add_action('admin_xml_ns', array(&$this, 'jlsuggest_xml_ns'));
2702
+ $this->plugin->queue_js ('includes', 'encoder');
2703
+ $this->plugin->queue_js ('includes/jlsuggest', 'jlsuggest');
2704
+ $this->plugin->queue_css('includes/jlsuggest', 'jlsuggest');
2705
+ }
2706
+
2707
+ /**
2708
+ * Outputs the SEO Ultimate XMLNS used by JLSuggest.
2709
+ *
2710
+ * @since 6.0
2711
+ */
2712
+ function jlsuggest_xml_ns() {
2713
+ echo ' xmlns:su="http://johnlamansky.com/xmlns/seo-ultimate" ';
2714
+ }
2715
+
2716
+ /**
2717
+ * Explodes a JLSuggest database string into an array with the destination type and the destination ID.
2718
+ *
2719
+ * @since 6.0
2720
+ *
2721
+ * @param $valstr The database string, e.g. http://example.com or obj_posttype_post/1
2722
+ * @return array
2723
+ */
2724
+ function jlsuggest_value_explode($valstr) {
2725
+
2726
+ if (is_array($valstr)) {
2727
+
2728
+ if (count($valstr) == 3)
2729
+ return $valstr;
2730
+
2731
+ } elseif (is_string($valstr)) {
2732
+
2733
+ if (sustr::startswith($valstr, 'obj_')) {
2734
+ $valstr = sustr::ltrim_str($valstr, 'obj_');
2735
+
2736
+ $valarr = explode('/', $valstr);
2737
+ if (count($valarr) == 2) {
2738
+ $valarr_type = explode('_', $valarr[0], 2);
2739
+ if (count($valarr_type) == 2)
2740
+ return array($valarr_type[0], $valarr_type[1], $valarr[1]);
2741
+ else
2742
+ return array($valarr[0], null, $valarr[1]);
2743
+ } else
2744
+ return array($valstr, null, null);
2745
+ } else {
2746
+ return array('url', null, $valstr);
2747
+ }
2748
+ }
2749
+
2750
+ return array('url', null, '');
2751
+ }
2752
+
2753
+ /**
2754
+ * Returns the HTML code for a JLSuggest textbox
2755
+ *
2756
+ * @since 6.0
2757
+ *
2758
+ * @param string $name The value of the textbox's name/ID attributes
2759
+ * @param string $value The current database string associated with this textbox
2760
+ */
2761
+ function get_jlsuggest_box($name, $value, $params='', $placeholder='') {
2762
+
2763
+ list($to_genus, $to_type, $to_id) = $this->jlsuggest_value_explode($value);
2764
+
2765
+ $text_dest = '';
2766
+ $disabled = false;
2767
+
2768
+ switch ($to_genus) {
2769
+
2770
+ case 'posttype':
2771
+ $selected_post = get_post($to_id);
2772
+ if ($selected_post) {
2773
+ $selected_post_type = get_post_type_object($selected_post->post_type);
2774
+ $text_dest = $selected_post->post_title . '<span class="type">&nbsp;&mdash;&nbsp;'.$selected_post_type->labels->singular_name.'</span>';
2775
+ } else {
2776
+ $selected_post_type = get_post_type_object($to_type);
2777
+ if ($selected_post_type)
2778
+ $text_dest = sprintf(__('A Deleted %s', 'seo-ultimate'), $selected_post_type->labels->singular_name);
2779
+ else
2780
+ $text_dest = __('A Deleted Post', 'seo-ultimate');
2781
+ $text_dest = '<span class="type">' . $text_dest . '</span>';
2782
+ $disabled = true;
2783
+ }
2784
+ break;
2785
+ case 'taxonomy':
2786
+ if ($selected_taxonomy = get_taxonomy($to_type)) {
2787
+ if ($selected_term = get_term($to_id, $selected_taxonomy->name)) {
2788
+ $text_dest = $selected_term->name . '<span class="type">&nbsp;&mdash;&nbsp;'.$selected_taxonomy->labels->singular_name.'</span>';
2789
+ } else {
2790
+ $text_dest = sprintf(__('A Deleted %s', 'seo-ultimate'), $selected_taxonomy->labels->singular_name);
2791
+ $text_dest = '<span class="type">' . $text_dest . '</span>';
2792
+ $disabled = true;
2793
+ }
2794
+ } else {
2795
+ $text_dest = __('A Deleted Term', 'seo-ultimate');
2796
+ $text_dest = '<span class="type">' . $text_dest . '</span>';
2797
+ $disabled = true;
2798
+ }
2799
+ break;
2800
+ case 'home':
2801
+ $text_dest = __('Blog Homepage', 'seo-ultimate');
2802
+ break;
2803
+ case 'author':
2804
+ if (is_user_member_of_blog($to_id)) {
2805
+ $selected_author = get_userdata($to_id);
2806
+ $text_dest = $selected_author->user_login . '<span class="type">&nbsp;&mdash;&nbsp;'.__('Author', 'seo-ultimate').'</span>';
2807
+ } else {
2808
+ $text_dest = __('A Deleted User', 'seo-ultimate');
2809
+ $text_dest = '<span class="type">' . $text_dest . '</span>';
2810
+ $disabled = true;
2811
+ }
2812
+ break;
2813
+ case 'internal-link-alias':
2814
+
2815
+ $alias_dir = $this->get_setting('alias_dir', 'go', 'internal-link-aliases');
2816
+ $aliases = $this->get_setting('aliases', array(), 'internal-link-aliases');
2817
+
2818
+ if (isset($aliases[$to_id]['to'])) {
2819
+ $h_alias_to = su_esc_html($aliases[$to_id]['to']);
2820
+ $text_dest = "/$alias_dir/$h_alias_to/" . '<span class="type">&nbsp;&mdash;&nbsp;';
2821
+
2822
+ if ($this->plugin->module_exists('internal-link-aliases')) {
2823
+ $text_dest .= __('Link Mask', 'seo-ultimate');
2824
+ } else {
2825
+ $text_dest .= __('Link Mask (Disabled)', 'seo-ultimate');
2826
+ $disabled = true;
2827
+ }
2828
+ $text_dest .= '</span>';
2829
+ } else {
2830
+ $text_dest = __('A Deleted Link Mask', 'seo-ultimate');
2831
+ $text_dest = '<span class="type">' . $text_dest . '</span>';
2832
+ $disabled = true;
2833
+ }
2834
+
2835
+ break;
2836
+ }
2837
+
2838
+ $is_url = (('url' == $to_genus) && !$text_dest);
2839
+
2840
+ $to_genus_type = implode('_', array_filter(array($to_genus, $to_type)));
2841
+ $obj = 'obj_' . implode('/', array_filter(array($to_genus_type, $to_id)));
2842
+
2843
+ //URL textbox
2844
+ //(hide if object is selected)
2845
+ $html = "<input name='$name' id='$name' value='";
2846
+ $html .= su_esc_editable_html($is_url ? $to_id : $obj);
2847
+ $html .= "'";
2848
+
2849
+ if ($params) {
2850
+ $e_params = su_esc_attr($params);
2851
+ $html .= " su:params='$e_params'";
2852
+ }
2853
+
2854
+ if ($placeholder) {
2855
+ $e_placeholder = su_esc_attr($placeholder);
2856
+ $html .= " placeholder='$e_placeholder'";
2857
+ }
2858
+
2859
+ $html .= " type='text' class='form-control input-sm textbox regular-text jlsuggest'";
2860
+ $html .= ' title="' . __('Type a URL or start typing the name of an item on your site', 'seo-ultimate') . '"';
2861
+ $html .= $is_url ? '' : ' style="display:none;" ';
2862
+ $html .= ' />';
2863
+
2864
+ //Object box
2865
+ //(hide if URL is entered)
2866
+ $disabled = $disabled ? ' jlsuggest-disabled' : '';
2867
+ $html .= "<div class='jls_text_dest$disabled'";
2868
+ $html .= $is_url ? ' style="display:none;" ' : '';
2869
+ $html .= '>';
2870
+ $html .= '<div class="jls_text_dest_text">';
2871
+ $html .= $text_dest;
2872
+ $html .= '</div>';
2873
+ $html .= '<div><a href="#" onclick="javascript:return false;" class="jls_text_dest_close" title="'.__('Remove this location from this textbox', 'seo-ultimate').'">'.__('X', 'seo-ultimate').'</a></div>';
2874
+ $html .= '</div>';
2875
+
2876
+ return $html;
2877
+ }
2878
+
2879
+ /**
2880
+ * Converts a JLSuggest database string into a URL.
2881
+ *
2882
+ * @since 6.0
2883
+ *
2884
+ * @param string $value The JLSuggest database string to convert.
2885
+ * @param bool $get_src_if_media Whether to get the URL to the actual media item rather than the URL to its WP-powered singular page, if the item is an attachment.
2886
+ * @return string The URL of the referenced destination
2887
+ */
2888
+ function jlsuggest_value_to_url($value, $get_src_if_media=false) {
2889
+
2890
+ list($to_genus, $to_type, $to_id) = $this->jlsuggest_value_explode($value);
2891
+
2892
+ switch ($to_genus) {
2893
+ case 'url':
2894
+ return $to_id; break;
2895
+ case 'posttype':
2896
+ $to_id = (int)$to_id;
2897
+ switch (get_post_status($to_id)) {
2898
+ case 'publish':
2899
+ if ($get_src_if_media && 'attachment' == get_post_type($to_id))
2900
+ return wp_get_attachment_url($to_id);
2901
+
2902
+ return get_permalink($to_id);
2903
+ case false: //Post doesn't exist
2904
+ default: //Post exists but isn't published
2905
+ return false;
2906
+ }
2907
+ break;
2908
+ case 'taxonomy':
2909
+ $to_id = (int)$to_id;
2910
+ $term_link = get_term_link($to_id, $to_type);
2911
+ if ($term_link && !is_wp_error($term_link)) return $term_link;
2912
+ return false;
2913
+ break;
2914
+ case 'home':
2915
+ return suwp::get_blog_home_url(); break;
2916
+ case 'author':
2917
+ $to_id = (int)$to_id;
2918
+ if (is_user_member_of_blog($to_id))
2919
+ return get_author_posts_url($to_id);
2920
+ return false;
2921
+ break;
2922
+ case 'internal-link-alias':
2923
+ if ($this->plugin->module_exists('internal-link-aliases')) {
2924
+ $alias_dir = $this->get_setting('alias_dir', 'go', 'internal-link-aliases');
2925
+ $aliases = $this->get_setting('aliases', array(),'internal-link-aliases');
2926
+
2927
+ if (isset($aliases[$to_id]['to'])) {
2928
+ $u_alias_to = urlencode($aliases[$to_id]['to']);
2929
+ return get_bloginfo('url') . "/$alias_dir/$u_alias_to/";
2930
+ }
2931
+ }
2932
+ return false;
2933
+ break;
2934
+ }
2935
+
2936
+ return false;
2937
+ }
2938
+
2939
+
2940
+ /**
2941
+ * @since 7.6
2942
+ */
2943
+ function should_show_sdf_theme_promo() {
2944
+ return $this->is_sdf_theme_promo_applicable() && $this->get_setting('sdf_theme','', 'settings');
2945
+ }
2946
+
2947
+ /**
2948
+ * @since 7.6
2949
+ */
2950
+ function is_sdf_theme_promo_applicable() {
2951
+ //If the current user can install themes and if SDF isn't already uploaded...
2952
+ if (current_user_can('install_themes') && (wp_get_theme('seodesign')->errors() === false)){
2953
+ $theme = wp_get_theme(); // gets the current theme
2954
+ return ('SEO Design Framework' == $theme->name || 'seodesign' == $theme->template || 'seodesign' == $theme->parent_theme) ? false : true;
2955
+ }
2956
+ else{
2957
+ return true;
2958
+ }
2959
+ }
2960
+
2961
+
2962
+ /**
2963
+ * Display the RSS entries in a list.
2964
+ *
2965
+ * @since 7.6.2
2966
+ *
2967
+ * @param string|array|object $rss RSS url.
2968
+ * @param array $args Widget arguments.
2969
+ */
2970
+ function promo_sdf_banners_rss_output( $rss, $args = array() ) {
2971
+ if ( is_string( $rss ) ) {
2972
+ $rss = fetch_feed($rss);
2973
+ } elseif ( is_array($rss) && isset($rss['url']) ) {
2974
+ $args = $rss;
2975
+ $rss = fetch_feed($rss['url']);
2976
+ } elseif ( !is_object($rss) ) {
2977
+ return;
2978
+ }
2979
+
2980
+ if ( is_wp_error($rss) ) {
2981
+ if ( is_admin() || current_user_can('manage_options') )
2982
+ echo '<p>' . sprintf( __('<strong>RSS Error</strong>: %s'), $rss->get_error_message() ) . '</p>';
2983
+ return;
2984
+ }
2985
+
2986
+ $default_args = array( 'show_author' => 0, 'show_date' => 0, 'show_summary' => 0 );
2987
+ $args = wp_parse_args( $args, $default_args );
2988
+ extract( $args, EXTR_SKIP );
2989
+
2990
+ $items = (int) $items;
2991
+ if ( $items < 1 || 20 < $items )
2992
+ $items = 10;
2993
+ $show_summary = (int) $show_summary;
2994
+ $show_author = (int) $show_author;
2995
+ $show_date = (int) $show_date;
2996
+
2997
+ if ( !$rss->get_item_quantity() ) {
2998
+ echo '<ul><li>' . __( 'An error has occurred, which probably means the feed is down. Try again later.' ) . '</li></ul>';
2999
+ $rss->__destruct();
3000
+ unset($rss);
3001
+ return;
3002
+ }
3003
+
3004
+ foreach ( $rss->get_items(0, $items) as $item ) {
3005
+ $link = $item->get_link();
3006
+ while ( stristr($link, 'http') != $link )
3007
+ $link = substr($link, 1);
3008
+ $link = esc_url(strip_tags($link));
3009
+ $title = esc_attr(strip_tags($item->get_title()));
3010
+ if ( empty($title) )
3011
+ $title = '';
3012
+
3013
+ $desc = str_replace( array("\n", "\r"), ' ', esc_attr( strip_tags( @html_entity_decode( $item->get_description(), ENT_QUOTES, get_option('blog_charset') ) ) ) );
3014
+ $excerpt = wp_html_excerpt( $desc, 120 );
3015
+
3016
+ // Append ellipsis. Change existing [...] to [&hellip;].
3017
+ if ( '[...]' == substr( $excerpt, -5 ) )
3018
+ $excerpt = substr( $excerpt, 0, -5 ) . '[&hellip;]';
3019
+ elseif ( '[&hellip;]' != substr( $excerpt, -10 ) && $desc != $excerpt )
3020
+ $excerpt .= ' [&hellip;]';
3021
+
3022
+ $excerpt = esc_html( $excerpt );
3023
+
3024
+ if ( $show_summary ) {
3025
+ $summary = "<p>$excerpt</p>";
3026
+ } else {
3027
+ $summary = '';
3028
+ }
3029
+
3030
+ $date = '';
3031
+ if ( $show_date ) {
3032
+ $date = $item->get_date( 'U' );
3033
+
3034
+ if ( $date ) {
3035
+ $date = ' <span class="rss-date">' . date_i18n( get_option( 'date_format' ), $date ) . '</span>';
3036
+ }
3037
+ }
3038
+
3039
+ $author = '';
3040
+ if ( $show_author ) {
3041
+ $author = $item->get_author();
3042
+ if ( is_object($author) ) {
3043
+ $author = $author->get_name();
3044
+ $author = ' <cite>' . esc_html( strip_tags( $author ) ) . '</cite>';
3045
+ }
3046
+ }
3047
+
3048
+ if ( $link == '' ) {
3049
+ echo "<h3>$title</h3>{$summary}";
3050
+ } else {
3051
+ echo "<h3>$title</h3>{$summary}<p><a class='btn btn-large btn-warning' href='$link' target='_blank' rel='nofollow'>Read More</a></p>";
3052
+ }
3053
+ }
3054
+ $rss->__destruct();
3055
+ unset($rss);
3056
+ }
3057
+
3058
+ /**
3059
+ * @since 7.6.2
3060
+ */
3061
+ function promo_sdf_banners() {
3062
+
3063
+ if ($this->should_show_sdf_theme_promo()) {
3064
+ ?>
3065
+ <div id="sds_promo_blog_post" class="hide">
3066
+ <?php $this->promo_sdf_banners_rss_output( 'http://feeds.seodesignsolutions.com/SeoDesignSolutionsBlog', array('show_summary' => 1, 'show_date' => 0, 'items' => 1) ); ?>
3067
+ </div>
3068
+ <div id="sdf-promo-carousel"></div>
3069
+ <?php
3070
+ }
3071
+ }
3072
+ }
3073
  ?>
modules/files/files.php CHANGED
@@ -1,192 +1,192 @@
1
- <?php
2
- /**
3
- * File Editor Module
4
- *
5
- * @since 0.8
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_Files extends SU_Module {
11
-
12
- var $htaccess_recovery = null;
13
-
14
- static function get_module_title() { return __('File Editor', 'seo-ultimate'); }
15
- static function get_menu_title() { return __('File Editor', 'seo-ultimate'); }
16
-
17
- function init() {
18
-
19
- //If the custom robots.txt file is enabled...
20
- if ($this->get_setting('enable_custom_robotstxt')) {
21
-
22
- //...Remove WordPress's robots.txt handler and replace it with ours.
23
- remove_action('do_robots', 'do_robots');
24
- add_action('do_robots', array(&$this, 'do_robots'));
25
-
26
- //...And put a notice on the Privacy options page that the privacy settings won't take effect.
27
- add_action('admin_notices', array(&$this, 'privacy_options_notice'));
28
- }
29
-
30
- //We override the default behavior of saving the custom htaccess contents to the database and instead save the contents to the file
31
- add_filter('su_get_setting-files-htaccess', array(&$this, 'get_htaccess'));
32
- add_filter('su_custom_update_setting-files-htaccess', array(&$this, 'update_htaccess'), 10, 2);
33
- }
34
-
35
- function admin_page_contents() {
36
-
37
- global $is_apache;
38
-
39
- if ($this->should_show_sdf_theme_promo()) {
40
- echo "\n\n<div class='row'>\n";
41
- echo "\n\n<div class='col-sm-8 col-md-9'>\n";
42
- }
43
-
44
- //Initialize variables
45
- $exists = $writable = false;
46
- $is_super_admin = !function_exists('is_super_admin') || !function_exists('is_multisite') || !is_multisite() || is_super_admin();
47
-
48
- //Does the server run Apache?
49
- if ($is_apache) {
50
-
51
- //The get_home_path() function is what WordPress uses to locate the htaccess file
52
- $htaccess = get_home_path().'.htaccess';
53
-
54
- //Does htaccess exist? Is it writable?
55
- $exists = file_exists($htaccess);
56
- $writable = is_writable($htaccess);
57
-
58
- if ($is_super_admin && $exists && !$writable) $this->queue_message('warning',
59
- __('A .htaccess file exists, but it&#8217;s not writable. You can edit it here once the file permissions are corrected.', 'seo-ultimate'));
60
- }
61
-
62
- //WordPress's robots.txt file is dynamically generated, so we need URL rewriting for this to work
63
- //In the future, I'll likely add support for writing to a static robots.txt file
64
- if (!strlen(get_option('permalink_structure'))) $this->queue_message('error',
65
- __('WordPress won&#8217;t be able to display your robots.txt file because the default <a href="options-permalink.php" target="_blank">permalink structure</a> is in use.', 'seo-ultimate'));
66
-
67
- $this->print_messages();
68
-
69
- $this->admin_form_start();
70
-
71
- //Show robots.txt textarea
72
- $this->textarea('robotstxt', sprintf(__('robots.txt [<a href="%s" target="_blank">Open</a>]', 'seo-ultimate'), trailingslashit(get_bloginfo('url')).'robots.txt'));
73
-
74
- //Show robots.txt settings checkboxes
75
- $this->checkboxes(array(
76
- 'enable_custom_robotstxt' => __('Enable this custom robots.txt file and disable the default file', 'seo-ultimate')
77
- , 'enable_do_robotstxt_action' => __('Let other plugins add rules to my custom robots.txt file', 'seo-ultimate')
78
- ), __('robots.txt Settings', 'seo-ultimate'));
79
-
80
- $this->queue_message('warning',
81
- __('Please realize that incorrectly editing your robots.txt file could block search engines from your site.', 'seo-ultimate'));
82
-
83
- //Of course, only bother with htaccess if we're running Apache.
84
- if ($is_super_admin && $is_apache && ($writable || !$exists)) {
85
- $this->textarea('htaccess', __('.htaccess', 'seo-ultimate'));
86
-
87
- $this->queue_message('warning',
88
- __('Also, incorrectly editing your .htaccess file could disable your entire website. Edit with caution!', 'seo-ultimate'));
89
- }
90
-
91
- $this->admin_form_end();
92
-
93
- //Print the caution message(s) at the end
94
- $this->print_messages();
95
-
96
- if ($this->should_show_sdf_theme_promo()) {
97
- echo "\n\n</div>\n";
98
- echo "\n\n<div class='col-sm-4 col-md-3'>\n";
99
- $this->promo_sdf_banners();
100
- echo "\n\n</div>\n";
101
- echo "\n\n</div>\n";
102
- }
103
- }
104
-
105
- function do_robots() {
106
-
107
- //Announce that this is a text file
108
- header( 'Content-Type: text/plain; charset=utf-8' );
109
-
110
- //Should we allow plugins to add custom rules?
111
- if ($this->get_setting('enable_do_robotstxt_action'))
112
- do_action('do_robotstxt');
113
- else
114
- do_action('su_do_robotstxt');
115
-
116
- //Print the custom robots.txt file
117
- echo $this->get_setting('robotstxt');
118
- }
119
-
120
- function get_htaccess() {
121
- if ($this->htaccess_recovery) return $this->htaccess_recovery;
122
-
123
- $htaccess = get_home_path().'.htaccess';
124
- if (is_readable($htaccess))
125
- return file_get_contents($htaccess);
126
-
127
- return false;
128
- }
129
-
130
- function update_htaccess($unused, $value) {
131
-
132
- //If the write fails, we don't want the user to lose their changes; we save the user's data to a variable so it can be displayed in the textarea
133
- $this->htaccess_recovery = $value;
134
-
135
- //Overwrite the file
136
- $htaccess = get_home_path().'.htaccess';
137
- $fp = fopen($htaccess, 'w');
138
- fwrite($fp, $value);
139
- fclose($fp);
140
-
141
- return true;
142
- }
143
-
144
- function privacy_options_notice() {
145
- global $pagenow;
146
- if ($pagenow == 'options-reading.php') { //Shows on the "Settings > Reading" page
147
- $this->print_message('info', sprintf(
148
- __('Please note that the &#8220;discourage search engines&#8221; setting 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'),
149
- admin_url('admin.php?page='.$this->plugin->key_to_hook($this->get_module_key()))
150
- ));
151
- }
152
- }
153
-
154
- function add_help_tabs($screen) {
155
-
156
- $screen->add_help_tab(array(
157
- 'id' => 'su-files-overview'
158
- , 'title' => __('Overview', 'seo-ultimate')
159
- , 'content' => __("
160
- <ul>
161
- <li><strong>What it does:</strong> The File Editor module lets you edit two important SEO-related files: robots.txt and .htaccess.</li>
162
- <li><strong>Why it helps:</strong> You can use the <a href='http://www.robotstxt.org/robotstxt.html' target='_blank'>robots.txt file</a> to give instructions to search engine spiders. You can use the <a href='http://httpd.apache.org/docs/2.2/howto/htaccess.html' target='_blank'>.htaccess file</a> to implement advanced SEO strategies (URL rewriting, regex redirects, etc.). SEO Ultimate makes editing these files easier than ever.</li>
163
- <li><strong>How to use it:</strong> Edit the files as desired, then click Save Changes. If you create a custom robots.txt file, be sure to enable it with the checkbox.</li>
164
- </ul>
165
- ", 'seo-ultimate')));
166
-
167
- $screen->add_help_tab(array(
168
- 'id' => 'su-files-faq'
169
- , 'title' => __('FAQ', 'seo-ultimate')
170
- , 'content' => __("
171
- <ul>
172
- <li><strong>Will my robots.txt edits remain if I disable the File Editor?</strong><br />No. On a WordPress blog, the robots.txt file is dynamically generated just like your posts and Pages. If you disable the File Editor module or the entire SEO Ultimate plugin, the File Editor won&#8217;t be able to insert your custom code into the robots.txt file anymore.</li>
173
- <li><strong>Will my .htaccess edits remain if I disable the File Editor?</strong><br />Yes. The .htaccess file is static. Your edits will remain even if you disable SEO Ultimate or its File Editor module.</li>
174
- </ul>
175
- ", 'seo-ultimate')));
176
-
177
- $screen->add_help_tab(array(
178
- 'id' => 'su-files-troubleshooting'
179
- , 'title' => __('Troubleshooting', 'seo-ultimate')
180
- , 'content' => __("
181
- <ul>
182
- <li><strong>Why do I get a &#8220;500 Server Error&#8221; after using the File Editor?</strong><br />You may have inserted code into your .htaccess file that your web server can't understand. As the File Editor warns, incorrectly editing your .htaccess file can disable your entire website in this way. To restore your site, you'll need to use an FTP client (or your web host's File Manager) to edit or rename your .htaccess file. If you need help, please contact your web host.</li>
183
- <li><strong>Where did my .htaccess edits go?</strong><br />The .htaccess file is static, so SEO Ultimate doesn't have total control over it. It&#8217;s possible that WordPress, another plugin, or other software may overwrite your .htaccess file. If you have a backup of your blog&#8217;s files, you can try recovering your edits from there.</li>
184
- </ul>
185
- ", 'seo-ultimate')));
186
-
187
-
188
- }
189
- }
190
-
191
- }
192
  ?>
1
+ <?php
2
+ /**
3
+ * File Editor Module
4
+ *
5
+ * @since 0.8
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_Files extends SU_Module {
11
+
12
+ var $htaccess_recovery = null;
13
+
14
+ static function get_module_title() { return __('File Editor', 'seo-ultimate'); }
15
+ static function get_menu_title() { return __('File Editor', 'seo-ultimate'); }
16
+
17
+ function init() {
18
+
19
+ //If the custom robots.txt file is enabled...
20
+ if ($this->get_setting('enable_custom_robotstxt')) {
21
+
22
+ //...Remove WordPress's robots.txt handler and replace it with ours.
23
+ remove_action('do_robots', 'do_robots');
24
+ add_action('do_robots', array(&$this, 'do_robots'));
25
+
26
+ //...And put a notice on the Privacy options page that the privacy settings won't take effect.
27
+ add_action('admin_notices', array(&$this, 'privacy_options_notice'));
28
+ }
29
+
30
+ //We override the default behavior of saving the custom htaccess contents to the database and instead save the contents to the file
31
+ add_filter('su_get_setting-files-htaccess', array(&$this, 'get_htaccess'));
32
+ add_filter('su_custom_update_setting-files-htaccess', array(&$this, 'update_htaccess'), 10, 2);
33
+ }
34
+
35
+ function admin_page_contents() {
36
+
37
+ global $is_apache;
38
+
39
+ if ($this->should_show_sdf_theme_promo()) {
40
+ echo "\n\n<div class='row'>\n";
41
+ echo "\n\n<div class='col-sm-8 col-md-9'>\n";
42
+ }
43
+
44
+ //Initialize variables
45
+ $exists = $writable = false;
46
+ $is_super_admin = !function_exists('is_super_admin') || !function_exists('is_multisite') || !is_multisite() || is_super_admin();
47
+
48
+ //Does the server run Apache?
49
+ if ($is_apache) {
50
+
51
+ //The get_home_path() function is what WordPress uses to locate the htaccess file
52
+ $htaccess = get_home_path().'.htaccess';
53
+
54
+ //Does htaccess exist? Is it writable?
55
+ $exists = file_exists($htaccess);
56
+ $writable = is_writable($htaccess);
57
+
58
+ if ($is_super_admin && $exists && !$writable) $this->queue_message('warning',
59
+ __('A .htaccess file exists, but it&#8217;s not writable. You can edit it here once the file permissions are corrected.', 'seo-ultimate'));
60
+ }
61
+
62
+ //WordPress's robots.txt file is dynamically generated, so we need URL rewriting for this to work
63
+ //In the future, I'll likely add support for writing to a static robots.txt file
64
+ if (!strlen(get_option('permalink_structure'))) $this->queue_message('error',
65
+ __('WordPress won&#8217;t be able to display your robots.txt file because the default <a href="options-permalink.php" target="_blank">permalink structure</a> is in use.', 'seo-ultimate'));
66
+
67
+ $this->print_messages();
68
+
69
+ $this->admin_form_start();
70
+
71
+ //Show robots.txt textarea
72
+ $this->textarea('robotstxt', sprintf(__('robots.txt [<a href="%s" target="_blank">Open</a>]', 'seo-ultimate'), trailingslashit(get_bloginfo('url')).'robots.txt'));
73
+
74
+ //Show robots.txt settings checkboxes
75
+ $this->checkboxes(array(
76
+ 'enable_custom_robotstxt' => __('Enable this custom robots.txt file and disable the default file', 'seo-ultimate')
77
+ , 'enable_do_robotstxt_action' => __('Let other plugins add rules to my custom robots.txt file', 'seo-ultimate')
78
+ ), __('robots.txt Settings', 'seo-ultimate'));
79
+
80
+ $this->queue_message('warning',
81
+ __('Please realize that incorrectly editing your robots.txt file could block search engines from your site.', 'seo-ultimate'));
82
+
83
+ //Of course, only bother with htaccess if we're running Apache.
84
+ if ($is_super_admin && $is_apache && ($writable || !$exists)) {
85
+ $this->textarea('htaccess', __('.htaccess', 'seo-ultimate'));
86
+
87
+ $this->queue_message('warning',
88
+ __('Also, incorrectly editing your .htaccess file could disable your entire website. Edit with caution!', 'seo-ultimate'));
89
+ }
90
+
91
+ $this->admin_form_end();
92
+
93
+ //Print the caution message(s) at the end
94
+ $this->print_messages();
95
+
96
+ if ($this->should_show_sdf_theme_promo()) {
97
+ echo "\n\n</div>\n";
98
+ echo "\n\n<div class='col-sm-4 col-md-3'>\n";
99
+ $this->promo_sdf_banners();
100
+ echo "\n\n</div>\n";
101
+ echo "\n\n</div>\n";
102
+ }
103
+ }
104
+
105
+ function do_robots() {
106
+
107
+ //Announce that this is a text file
108
+ header( 'Content-Type: text/plain; charset=utf-8' );
109
+
110
+ //Should we allow plugins to add custom rules?
111
+ if ($this->get_setting('enable_do_robotstxt_action'))
112
+ do_action('do_robotstxt');
113
+ else
114
+ do_action('su_do_robotstxt');
115
+
116
+ //Print the custom robots.txt file
117
+ echo $this->get_setting('robotstxt');
118
+ }
119
+
120
+ function get_htaccess() {
121
+ if ($this->htaccess_recovery) return $this->htaccess_recovery;
122
+
123
+ $htaccess = get_home_path().'.htaccess';
124
+ if (is_readable($htaccess))
125
+ return file_get_contents($htaccess);
126
+
127
+ return false;
128
+ }
129
+
130
+ function update_htaccess($unused, $value) {
131
+
132
+ //If the write fails, we don't want the user to lose their changes; we save the user's data to a variable so it can be displayed in the textarea
133
+ $this->htaccess_recovery = $value;
134
+
135
+ //Overwrite the file
136
+ $htaccess = get_home_path().'.htaccess';
137
+ $fp = fopen($htaccess, 'w');
138
+ fwrite($fp, $value);
139
+ fclose($fp);
140
+
141
+ return true;
142
+ }
143
+
144
+ function privacy_options_notice() {
145
+ global $pagenow;
146
+ if ($pagenow == 'options-reading.php') { //Shows on the "Settings > Reading" page
147
+ $this->print_message('info', sprintf(
148
+ __('Please note that the &#8220;discourage search engines&#8221; setting 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'),
149
+ admin_url('admin.php?page='.$this->plugin->key_to_hook($this->get_module_key()))
150
+ ));
151
+ }
152
+ }
153
+
154
+ function add_help_tabs($screen) {
155
+
156
+ $screen->add_help_tab(array(
157
+ 'id' => 'su-files-overview'
158
+ , 'title' => __('Overview', 'seo-ultimate')
159
+ , 'content' => __("
160
+ <ul>
161
+ <li><strong>What it does:</strong> The File Editor module lets you edit two important SEO-related files: robots.txt and .htaccess.</li>
162
+ <li><strong>Why it helps:</strong> You can use the <a href='http://www.robotstxt.org/robotstxt.html' target='_blank'>robots.txt file</a> to give instructions to search engine spiders. You can use the <a href='http://httpd.apache.org/docs/2.2/howto/htaccess.html' target='_blank'>.htaccess file</a> to implement advanced SEO strategies (URL rewriting, regex redirects, etc.). SEO Ultimate makes editing these files easier than ever.</li>
163
+ <li><strong>How to use it:</strong> Edit the files as desired, then click Save Changes. If you create a custom robots.txt file, be sure to enable it with the checkbox.</li>
164
+ </ul>
165
+ ", 'seo-ultimate')));
166
+
167
+ $screen->add_help_tab(array(
168
+ 'id' => 'su-files-faq'
169
+ , 'title' => __('FAQ', 'seo-ultimate')
170
+ , 'content' => __("
171
+ <ul>
172
+ <li><strong>Will my robots.txt edits remain if I disable the File Editor?</strong><br />No. On a WordPress blog, the robots.txt file is dynamically generated just like your posts and Pages. If you disable the File Editor module or the entire SEO Ultimate plugin, the File Editor won&#8217;t be able to insert your custom code into the robots.txt file anymore.</li>
173
+ <li><strong>Will my .htaccess edits remain if I disable the File Editor?</strong><br />Yes. The .htaccess file is static. Your edits will remain even if you disable SEO Ultimate or its File Editor module.</li>
174
+ </ul>
175
+ ", 'seo-ultimate')));
176
+
177
+ $screen->add_help_tab(array(
178
+ 'id' => 'su-files-troubleshooting'
179
+ , 'title' => __('Troubleshooting', 'seo-ultimate')
180
+ , 'content' => __("
181
+ <ul>
182
+ <li><strong>Why do I get a &#8220;500 Server Error&#8221; after using the File Editor?</strong><br />You may have inserted code into your .htaccess file that your web server can't understand. As the File Editor warns, incorrectly editing your .htaccess file can disable your entire website in this way. To restore your site, you'll need to use an FTP client (or your web host's File Manager) to edit or rename your .htaccess file. If you need help, please contact your web host.</li>
183
+ <li><strong>Where did my .htaccess edits go?</strong><br />The .htaccess file is static, so SEO Ultimate doesn't have total control over it. It&#8217;s possible that WordPress, another plugin, or other software may overwrite your .htaccess file. If you have a backup of your blog&#8217;s files, you can try recovering your edits from there.</li>
184
+ </ul>
185
+ ", 'seo-ultimate')));
186
+
187
+
188
+ }
189
+ }
190
+
191
+ }
192
  ?>
modules/files/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/import-aiosp/import-aiosp.php CHANGED
@@ -1,42 +1,42 @@
1
- <?php
2
- /**
3
- * AISOP Import Module
4
- *
5
- * @since 1.6
6
- */
7
-
8
- if (class_exists('SU_ImportModule')) {
9
-
10
- class SU_ImportAIOSP extends SU_ImportModule {
11
-
12
- static function get_module_title() { return __('Import from All in One SEO Pack', 'seo-ultimate'); }
13
- static function get_menu_title() { return __('AIOSP Import', 'seo-ultimate'); }
14
-
15
- function get_op_title() { return __('All in One SEO Pack', 'seo-ultimate'); }
16
- function get_op_abbr() { return __('AIOSP', 'seo-ultimate'); }
17
- function get_import_desc() { return __('Import post data (custom title tags and meta tags).', 'seo-ultimate'); }
18
-
19
- function admin_page_contents() {
20
- echo "<p>";
21
- _e('Here you can move post fields from the All in One SEO Pack (AIOSP) plugin to SEO Ultimate. AIOSP&#8217;s data remains in your WordPress database after AIOSP is deactivated or even uninstalled. This means that as long as AIOSP was active on this blog sometime in the past, AIOSP does <em>not</em> need to be currently installed or activated for the import to take place.', 'seo-ultimate');
22
- echo "</p>\n<p>";
23
- _e('The import tool can only move over data from AIOSP version 1.6 or above. If you use an older version of AIOSP, you should update to the latest version first and run AIOSP&#8217;s upgrade process.', 'seo-ultimate');
24
- echo "</p>\n";
25
-
26
- $this->admin_form_start();
27
- $this->admin_page_postmeta();
28
- $this->admin_form_end();
29
- }
30
-
31
- function do_import() {
32
- $this->do_import_deactivate(SU_AIOSP_PATH);
33
-
34
- $this->do_import_postmeta(
35
- suarr::aprintf('_aioseop_%s', '_su_%s', array('title', 'description', 'keywords'))
36
- , '_aioseop_disable'
37
- );
38
- }
39
- }
40
-
41
- }
42
  ?>
1
+ <?php
2
+ /**
3
+ * AISOP Import Module
4
+ *
5
+ * @since 1.6
6
+ */
7
+
8
+ if (class_exists('SU_ImportModule')) {
9
+
10
+ class SU_ImportAIOSP extends SU_ImportModule {
11
+
12
+ static function get_module_title() { return __('Import from All in One SEO Pack', 'seo-ultimate'); }
13
+ static function get_menu_title() { return __('AIOSP Import', 'seo-ultimate'); }
14
+
15
+ function get_op_title() { return __('All in One SEO Pack', 'seo-ultimate'); }
16
+ function get_op_abbr() { return __('AIOSP', 'seo-ultimate'); }
17
+ function get_import_desc() { return __('Import post data (custom title tags and meta tags).', 'seo-ultimate'); }
18
+
19
+ function admin_page_contents() {
20
+ echo "<p>";
21
+ _e('Here you can move post fields from the All in One SEO Pack (AIOSP) plugin to SEO Ultimate. AIOSP&#8217;s data remains in your WordPress database after AIOSP is deactivated or even uninstalled. This means that as long as AIOSP was active on this blog sometime in the past, AIOSP does <em>not</em> need to be currently installed or activated for the import to take place.', 'seo-ultimate');
22
+ echo "</p>\n<p>";
23
+ _e('The import tool can only move over data from AIOSP version 1.6 or above. If you use an older version of AIOSP, you should update to the latest version first and run AIOSP&#8217;s upgrade process.', 'seo-ultimate');
24
+ echo "</p>\n";
25
+
26
+ $this->admin_form_start();
27
+ $this->admin_page_postmeta();
28
+ $this->admin_form_end();
29
+ }
30
+
31
+ function do_import() {
32
+ $this->do_import_deactivate(SU_AIOSP_PATH);
33
+
34
+ $this->do_import_postmeta(
35
+ suarr::aprintf('_aioseop_%s', '_su_%s', array('title', 'description', 'keywords'))
36
+ , '_aioseop_disable'
37
+ );
38
+ }
39
+ }
40
+
41
+ }
42
  ?>
modules/import-aiosp/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/internal-link-aliases/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/internal-link-aliases/internal-link-aliases.css CHANGED
@@ -1,35 +1,35 @@
1
- #su-internal-link-aliases table.widefat,
2
- #su-internal-link-aliases table.widefat input.textbox {
3
- width: 100%;
4
- }
5
-
6
- #su-internal-link-aliases table.widefat td {
7
- vertical-align: middle;
8
- }
9
-
10
- #su-internal-link-aliases table.widefat td.su-alias-to {
11
- width: 15em;
12
- }
13
-
14
- #su-internal-link-aliases table.widefat td.su-alias-to-test {
15
- font-size: 0.8em;
16
- }
17
-
18
- #su-internal-link-aliases table.widefat td.su-alias-delete {
19
- width: 3em;
20
- text-align: center;
21
- }
22
-
23
- #su-internal-link-aliases table.widefat td.su-alias-to table,
24
- #su-internal-link-aliases table.widefat td.su-alias-to table tr,
25
- #su-internal-link-aliases table.widefat td.su-alias-to table tr td {
26
- border-collapse: 0;
27
- padding: 0;
28
- margin: 0;
29
- border: 0 none;
30
- background: transparent;
31
- }
32
-
33
- #su-internal-link-aliases table.widefat td.su-alias-to table tr td input.textbox {
34
- width: 98%;
35
  }
1
+ #su-internal-link-aliases table.widefat,
2
+ #su-internal-link-aliases table.widefat input.textbox {
3
+ width: 100%;
4
+ }
5
+
6
+ #su-internal-link-aliases table.widefat td {
7
+ vertical-align: middle;
8
+ }
9
+
10
+ #su-internal-link-aliases table.widefat td.su-alias-to {
11
+ width: 15em;
12
+ }
13
+
14
+ #su-internal-link-aliases table.widefat td.su-alias-to-test {
15
+ font-size: 0.8em;
16
+ }
17
+
18
+ #su-internal-link-aliases table.widefat td.su-alias-delete {
19
+ width: 3em;
20
+ text-align: center;
21
+ }
22
+
23
+ #su-internal-link-aliases table.widefat td.su-alias-to table,
24
+ #su-internal-link-aliases table.widefat td.su-alias-to table tr,
25
+ #su-internal-link-aliases table.widefat td.su-alias-to table tr td {
26
+ border-collapse: 0;
27
+ padding: 0;
28
+ margin: 0;
29
+ border: 0 none;
30
+ background: transparent;
31
+ }
32
+
33
+ #su-internal-link-aliases table.widefat td.su-alias-to table tr td input.textbox {
34
+ width: 98%;
35
  }
modules/internal-link-aliases/internal-link-aliases.php CHANGED
@@ -1,374 +1,374 @@
1
- <?php
2
-
3
- class SU_InternalLinkAliases extends SU_Module {
4
-
5
- function get_default_settings() {
6
- return array(
7
- 'alias_dir' => 'go'
8
- );
9
- }
10
-
11
- function init() {
12
- add_filter('su_custom_update_postmeta-aliases', array(&$this, 'save_post_aliases'), 10, 4);
13
- add_filter('su_get_setting-internal-link-aliases-alias_dir', array(&$this, 'filter_alias_dir'));
14
-
15
- if (suwp::permalink_mode() == SUWP_PRETTY_PERMALINKS) {
16
- add_filter('the_content', array(&$this, 'apply_aliases'), 9); //Run before wp_texturize etc.
17
- add_action('template_redirect', array(&$this, 'redirect_aliases'), 0);
18
- add_action('do_robotstxt', array(&$this, 'block_aliases_dir'));
19
- add_action('su_do_robotstxt', array(&$this, 'block_aliases_dir'));
20
- }
21
- }
22
-
23
- function admin_page_init() {
24
- $this->jlsuggest_init();
25
- }
26
-
27
- static function get_module_title() { return __('Link Mask Generator', 'seo-ultimate'); }
28
- static function get_menu_title() { return __('Link Mask Generator', 'seo-ultimate'); }
29
-
30
- function get_settings_key() { return 'internal-link-aliases'; }
31
-
32
- function admin_page_contents() {
33
-
34
- if (suwp::permalink_mode() != SUWP_PRETTY_PERMALINKS)
35
- $this->print_message('error', sprintf(__('Link Mask Generator won&#8217;t work with default or &#8220;pathinfo&#8221; permalinks. Please change your <a href="%s">permalink structure</a> to enable this module&#8217;s functionality.', 'seo-ultimate'), 'options-permalink.php'));
36
-
37
- $this->children_admin_page_tabs_form();
38
- }
39
-
40
- function get_admin_page_tabs() {
41
- return array(
42
- array('id' => 'aliases', 'title' => __('Aliases', 'seo-ultimate'), 'callback' => 'editor_tab')
43
- , array('id' => 'settings', 'title' => __('Settings', 'seo-ultimate'), 'callback' => 'settings_tab')
44
- );
45
- }
46
-
47
- function remove_empty_aliases($alias) {
48
- return !empty($alias['to']);
49
- }
50
-
51
- function editor_tab() {
52
-
53
- $aliases = $this->get_setting('aliases', array());
54
- $aliases = array_map('unserialize', array_unique(array_map('serialize', $aliases)));
55
- $aliases = array_filter($aliases, array(&$this, 'remove_empty_aliases'));
56
- $num_aliases = count($aliases);
57
-
58
- if ($this->is_action('update')) {
59
-
60
- $aliases = array();
61
-
62
- for ($i=0; $i <= $num_aliases; $i++) {
63
-
64
- $id = stripslashes($_POST["alias_{$i}_id"]);
65
- $from = stripslashes($_POST["alias_{$i}_from"]);
66
- $to = stripslashes($_POST["alias_{$i}_to"]);
67
-
68
- $jls_post = stripslashes($_POST["alias_{$i}_posts"]);
69
- if ($jls_post) {
70
- $jls_post = $this->jlsuggest_value_explode($jls_post);
71
- $posts = array($jls_post[2]);
72
- } else {
73
- $posts = array();
74
- }
75
-
76
- $delete = isset($_POST["alias_{$i}_delete"]) ? (intval($_POST["alias_{$i}_delete"]) == 1) : false;
77
-
78
- if (!$delete && $from && $to)
79
- $aliases[$id] = compact('from', 'to', 'posts');
80
- }
81
- $this->update_setting('aliases', $aliases);
82
-
83
- $num_aliases = count($aliases);
84
- }
85
-
86
- if ($num_aliases > 0) {
87
- $this->admin_subheader(__('Edit Existing Aliases', 'seo-ultimate'));
88
- $this->aliases_form(0, $aliases);
89
- }
90
-
91
- $this->admin_subheader(__('Add a New Alias', 'seo-ultimate'));
92
- $this->aliases_form($num_aliases, array(array()), false);
93
- }
94
-
95
- function aliases_form($start_id = 0, $aliases, $existing_item = true) {
96
-
97
- //Set headers
98
- $headers = array(
99
- 'alias-from' => __('Actual URL', 'seo-ultimate')
100
- , 'alias-to' => __('Alias URL', 'seo-ultimate')
101
- , 'alias-posts' => __('Only on This Post&hellip; <em>(optional)</em>', 'seo-ultimate')
102
- );
103
- if ($existing_item) $headers['alias-delete'] = __('Delete', 'seo-ultimate');
104
-
105
- //Begin table; output headers
106
- $this->admin_wftable_start($headers);
107
-
108
- //Cycle through links
109
- $i = $start_id;
110
- foreach ($aliases as $id => $alias) {
111
-
112
- if (!is_string($id)) $id = uniqid($i, true);
113
-
114
- if (!isset($alias['from'])) $alias['from'] = '';
115
- if (!isset($alias['to'])) $alias['to'] = '';
116
- $u_alias_to = urlencode($alias['to']);
117
-
118
- if (isset($alias['posts'][0]))
119
- $jlsuggest_value = 'obj_posttype_' . get_post_type($alias['posts'][0]) . '/' . $alias['posts'][0];
120
- else
121
- $jlsuggest_value = '';
122
-
123
- $alias_dir = $this->get_setting('alias_dir', 'go', null, true);
124
- $alias_url = get_bloginfo('url') . "/$alias_dir/$u_alias_to/";
125
-
126
- $test_link = $existing_item ? "<td class='su-alias-to-test'>[<a href='$alias_url' target='_blank'>" . __('Test', 'seo-ultimate') . "</a>]</td>" : '';
127
-
128
- $cells = array(
129
- 'alias-from' =>
130
- $this->get_input_element('hidden', "alias_{$i}_id", $id)
131
- . $this->get_input_element('textbox', "alias_{$i}_from", $alias['from'])
132
- , 'alias-to' => "
133
- <table><tr>
134
- <td class='su-alias-to-dir'>/$alias_dir/</td>
135
- <td class='su-alias-to-slug'>" . $this->get_input_element('textbox', "alias_{$i}_to", $alias['to']) . "</td>
136
- $test_link
137
- </tr></table>"
138
- , 'alias-posts' => $this->get_jlsuggest_box("alias_{$i}_posts", $jlsuggest_value, 'types=posttype')
139
- );
140
- if ($existing_item)
141
- $cells['alias-delete'] = $this->get_input_element('checkbox', "alias_{$i}_delete");
142
-
143
- $this->table_row($cells, $i, 'alias');
144
-
145
- $i++;
146
- }
147
-
148
- $this->admin_wftable_end();
149
- }
150
-
151
- function settings_tab() {
152
- $this->admin_form_table_start();
153
- $this->textbox('alias_dir', __('Alias Directory', 'seo-ultimate'), $this->get_default_setting('alias_dir'));
154
- if ($this->plugin->module_exists('link-nofollow'))
155
- $this->checkbox('nofollow_aliased_links', __('Nofollow masked links', 'seo-ultimate'), __('Link Attributes', 'seo-ultimate'));
156
- $this->admin_form_table_end();
157
- }
158
-
159
- function filter_alias_dir($alias_dir) {
160
- return trim(sustr::preg_filter('a-zA-Z0-9_/', $alias_dir), '/');
161
- }
162
-
163
- function postmeta_fields($fields, $screen) {
164
-
165
- if (!current_user_can('manage_options'))
166
- return $fields;
167
-
168
- $post_id = suwp::get_post_id();
169
- $post = get_post($post_id);
170
- if (!$post) return $fields;
171
- $content = $post->post_content;
172
-
173
- $alias_dir = $this->get_setting('alias_dir', 'go');
174
-
175
- if ($content && preg_match_all('@ href=["\']([^#][^"\']+)["\']@', $content, $matches)) {
176
- $urls = array_unique($matches[1]);
177
-
178
- $html = "<tr valign='top'>\n<th scope='row' class='su'>".__('Link Masks:', 'seo-ultimate')."</th>\n<td>\n";
179
-
180
- $html .= "<table class='widefat'><thead>\n";
181
- $headers = array(__('URL', 'seo-ultimate'), '', __('Mask URL', 'seo-ultimate'));
182
- foreach ($headers as $header) $html .= "<th>$header</th>\n";
183
- $html .= "</thead>\n<tbody>";
184
-
185
- $aliases = $this->get_setting('aliases', array());
186
- $post_aliases = array();
187
- foreach ($aliases as $id => $alias) {
188
- if (empty($alias['posts']) || in_array($post->ID, $alias['posts']))
189
- $post_aliases[$alias['from']] = array('id' => $id, 'to' => $alias['to']);
190
- }
191
-
192
- foreach ($urls as $url) {
193
-
194
- $a_url = su_esc_attr($url);
195
- $un_h_url = htmlspecialchars_decode($url);
196
- $ht_url = esc_html(sustr::truncate($url, 30));
197
-
198
- if (isset($post_aliases[$url]))
199
- $url_key = $url;
200
- elseif (isset($post_aliases[$un_h_url]))
201
- $url_key = $un_h_url;
202
- else
203
- $url_key = false;
204
-
205
- $alias_to = '';
206
- $alias_id = uniqid('', true);
207
- if ($url_key) {
208
- if (isset($post_aliases[$url_key]['to'])) $alias_to = $post_aliases[$url_key]['to'];
209
- if (isset($post_aliases[$url_key]['id'])) $alias_id = $post_aliases[$url_key]['id'];
210
- }
211
-
212
- $a_alias_to = esc_attr($alias_to);
213
-
214
- $html .= "<tr><td><a href='$a_url' title='$a_url' target='_blank'>$ht_url</a><input type='hidden' name='_su_aliases[$alias_id][from]' value='$a_url' /></td>\n<td>&rArr;</td><td>/$alias_dir/<input type='text' name='_su_aliases[$alias_id][to]' value='$a_alias_to' /></td></tr>\n";
215
- }
216
-
217
- $html .= "</tbody>\n</table>\n";
218
-
219
- $html .= '<p><small>' . __('You can stop search engines from following a link by typing in a mask for its URL.', 'seo-ultimate') . "</small></p>\n";
220
-
221
- $html .= "</td>\n</tr>\n";
222
-
223
- $fields['links'][100]['aliases'] = $html;
224
- }
225
-
226
- return $fields;
227
- }
228
-
229
- function save_post_aliases($false, $saved_aliases, $metakey, $post) {
230
- if ($post->post_type == 'revision' || !is_array($saved_aliases)) return true;
231
-
232
- $aliases = $this->get_setting('aliases', array());
233
-
234
- foreach ($saved_aliases as $saved_id => $saved_data) {
235
-
236
- if (isset($aliases[$saved_id])) {
237
-
238
- if ($saved_data['to'])
239
- $aliases[$saved_id]['to'] = $saved_data['to'];
240
- else
241
- unset($aliases[$saved_id]);
242
-
243
- } elseif ($saved_data['to']) {
244
- $aliases[$saved_id]['from'] = $saved_data['from'];
245
- $aliases[$saved_id]['to'] = $saved_data['to'];
246
- $aliases[$saved_id]['posts'] = array($post->ID);
247
- }
248
- }
249
-
250
- $this->update_setting('aliases', $aliases);
251
-
252
- return true;
253
- }
254
-
255
- function apply_aliases($content) {
256
- return preg_replace_callback('@<a ([^>]*)href=(["\'])([^"\']+)(["\'])([^>]*)>@', array(&$this, 'apply_aliases_callback'), $content);
257
- }
258
-
259
- function apply_aliases_callback($matches) {
260
- $id = suwp::get_post_id();
261
-
262
- static $aliases = false;
263
- //Just in case we have duplicate aliases, make sure the most recent ones are applied first
264
- if ($aliases === false) $aliases = array_reverse($this->get_setting('aliases', array()), true);
265
-
266
- static $alias_dir = false;
267
- if ($alias_dir === false) $alias_dir = $this->get_setting('alias_dir', 'go');
268
-
269
- $new_url = $old_url = $matches[3];
270
-
271
- foreach ($aliases as $alias) {
272
- $to = urlencode($alias['to']);
273
-
274
- if ((empty($alias['posts']) || in_array($id, $alias['posts'])) && $to) {
275
- $from = $alias['from'];
276
- $h_from = esc_html($from);
277
- $to = get_bloginfo('url') . "/$alias_dir/$to/";
278
-
279
- if ($from == $old_url || $h_from == $old_url) {
280
- $new_url = $to;
281
- break;
282
- }
283
- }
284
- }
285
-
286
- $attrs = "{$matches[1]}href={$matches[2]}{$new_url}{$matches[4]}{$matches[5]}";
287
-
288
- if ($old_url != $new_url && $this->get_setting('nofollow_aliased_links', false) && $this->plugin->module_exists('link-nofollow'))
289
- $this->plugin->call_module_func('link-nofollow', 'nofollow_attributes_string', $attrs, $attrs);
290
-
291
- return "<a $attrs>";
292
- }
293
-
294
- function redirect_aliases() {
295
- $aliases = $this->get_setting('aliases', array());
296
- $alias_dir = $this->get_setting('alias_dir', 'go');
297
-
298
- foreach ($aliases as $alias)
299
- if ($to = $alias['to'])
300
- if (suurl::equal(suurl::current(), get_bloginfo('url') . "/$alias_dir/$to/"))
301
- wp_redirect($alias['from']);
302
- }
303
-
304
- function block_aliases_dir() {
305
- echo '# ';
306
- _e("Added by SEO Ultimate's Link Mask Generator module", 'seo-ultimate');
307
- echo "\n";
308
-
309
- $urlinfo = parse_url(get_bloginfo('url'));
310
- $path = $urlinfo['path'];
311
- echo "User-agent: *\n";
312
-
313
- $alias_dir = $this->get_setting('alias_dir', 'go');
314
- echo "Disallow: $path/$alias_dir/\n";
315
-
316
- echo '# ';
317
- _e('End Link Mask Generator output', 'seo-ultimate');
318
- echo "\n\n";
319
- }
320
-
321
-
322
- function add_help_tabs($screen) {
323
-
324
- $screen->add_help_tab(array(
325
- 'id' => 'su-internal-link-aliases-overview'
326
- , 'title' => __('Overview', 'seo-ultimate')
327
- , 'content' => __("
328
- <ul>
329
- <li><strong>What it does:</strong> Link Mask Generator lets you replace ugly affiliate links with clean-looking link aliases that redirect to the real URLs. Link Mask Generator will scan your posts for the links to the actual URLs and replace them with links to the alias URLs. When a visitor clicks on the link to the alias URL, Link Mask Generator will redirect the visitor to the actual URL.</li>
330
- <li><strong>Why it helps:</strong> This type of functionality is a staple in an affiliate marketer&#8217;s toolkit. Link Mask Generator helps you by doing it in an SEO-friendly way: by funneling your affiliate links through a directory (e.g. <code>/go/</code>) which is blocked with <code>robots.txt</code> rules, effectively sealing off link juice flow to your affiliate links.</li>
331
- <li><strong>How to use it:</strong> Type in the real URL, type in an alias URL, and click &#8220;Save Changes&#8221; &mdash; that&#8217;s it!</li>
332
- </ul>
333
- ", 'seo-ultimate')));
334
-
335
- $screen->add_help_tab(array(
336
- 'id' => 'su-internal-link-aliases-aliases'
337
- , 'title' => __('Aliases Tab', 'seo-ultimate')
338
- , 'content' => __("
339
- <p>To add a link alias, fill in the fields and then click &#8220;Save Changes.&#8221; Once you do so, you can edit your newly masked link or add another one.</p>
340
-
341
- <ul>
342
- <li><strong>Actual URL</strong> &mdash; This box is where you put your affiliate URL (or other URL that you want to mask).</li>
343
- <li><strong>Alias URL</strong> &mdash; This box is where you specify the new URL that will replace the actual one.</li>
344
- <li><strong>Only on This Post</strong> &mdash; If you want to mask the actual URL across your entire site, leave this box blank. If you only want to mask the actual URL within an individual post, then type its name into this box and select it from the dropdown.</li>
345
- <li><strong>Delete</strong> &mdash; To delete a link mask, tick its &#8220;Delete&#8221; checkbox and then click &#8220;Save Changes.&#8221;</li>
346
- </ul>
347
- ", 'seo-ultimate')));
348
-
349
- $screen->add_help_tab(array(
350
- 'id' => 'su-internal-link-aliases-settings'
351
- , 'title' => __('Settings Tab', 'seo-ultimate')
352
- , 'content' => __("
353
- <p>The following options are available on the Settings tab:</p>
354
-
355
- <ul>
356
- <li><strong>Alias Directory</strong> &mdash; If you&#8217;d like, you can change the name of the directory that contains all your alias URLs. (Don&#8217;t worry, you won&#8217;t break any links by changing this.)</li>
357
- <li><strong>Nofollow masked links</strong> &mdash; Checking this will add the <code>rel=&quot;nofollow&quot;</code> attribute to any masked links on your site. This makes it super-easy to nofollow all your affiliate links automatically.</li>
358
- </ul>
359
- ", 'seo-ultimate')));
360
-
361
- $screen->add_help_tab(array(
362
- 'id' => 'su-autolinks-faq'
363
- , 'title' => __('FAQ', 'seo-ultimate')
364
- , 'content' => __("
365
- <ul>
366
- <li><strong>Can I automatically link a phrase on my site to one of my alias URLs?</strong><br />Yes. Once you&#8217;ve created your link mask, go to Deeplink Juggernaut&#8217;s &#8220;Content Links&#8221; section, type the contents of your link mask&#8217;s &#8220;Alias URL&#8221; field into Deeplink Juggernaut&#8217;s &#8220;Destination&#8221; field, and select your link mask from the dropdown that appears.</li>
367
- <li><strong>Will Link Mask Generator still add the <code>robots.txt</code> rules if I&#8217;m using the File Editor module to create a custom <code>robots.txt</code>?</strong><br />Yes.</li>
368
- </ul>
369
- ", 'seo-ultimate')));
370
-
371
- }
372
-
373
- }
374
  ?>
1
+ <?php
2
+
3
+ class SU_InternalLinkAliases extends SU_Module {
4
+
5
+ function get_default_settings() {
6
+ return array(
7
+ 'alias_dir' => 'go'
8
+ );
9
+ }
10
+
11
+ function init() {
12
+ add_filter('su_custom_update_postmeta-aliases', array(&$this, 'save_post_aliases'), 10, 4);
13
+ add_filter('su_get_setting-internal-link-aliases-alias_dir', array(&$this, 'filter_alias_dir'));
14
+
15
+ if (suwp::permalink_mode() == SUWP_PRETTY_PERMALINKS) {
16
+ add_filter('the_content', array(&$this, 'apply_aliases'), 9); //Run before wp_texturize etc.
17
+ add_action('template_redirect', array(&$this, 'redirect_aliases'), 0);
18
+ add_action('do_robotstxt', array(&$this, 'block_aliases_dir'));
19
+ add_action('su_do_robotstxt', array(&$this, 'block_aliases_dir'));
20
+ }
21
+ }
22
+
23
+ function admin_page_init() {
24
+ $this->jlsuggest_init();
25
+ }
26
+
27
+ static function get_module_title() { return __('Link Mask Generator', 'seo-ultimate'); }
28
+ static function get_menu_title() { return __('Link Mask Generator', 'seo-ultimate'); }
29
+
30
+ function get_settings_key() { return 'internal-link-aliases'; }
31
+
32
+ function admin_page_contents() {
33
+
34
+ if (suwp::permalink_mode() != SUWP_PRETTY_PERMALINKS)
35
+ $this->print_message('error', sprintf(__('Link Mask Generator won&#8217;t work with default or &#8220;pathinfo&#8221; permalinks. Please change your <a href="%s">permalink structure</a> to enable this module&#8217;s functionality.', 'seo-ultimate'), 'options-permalink.php'));
36
+
37
+ $this->children_admin_page_tabs_form();
38
+ }
39
+
40
+ function get_admin_page_tabs() {
41
+ return array(
42
+ array('id' => 'aliases', 'title' => __('Aliases', 'seo-ultimate'), 'callback' => 'editor_tab')
43
+ , array('id' => 'settings', 'title' => __('Settings', 'seo-ultimate'), 'callback' => 'settings_tab')
44
+ );
45
+ }
46
+
47
+ function remove_empty_aliases($alias) {
48
+ return !empty($alias['to']);
49
+ }
50
+
51
+ function editor_tab() {
52
+
53
+ $aliases = $this->get_setting('aliases', array());
54
+ $aliases = array_map('unserialize', array_unique(array_map('serialize', $aliases)));
55
+ $aliases = array_filter($aliases, array(&$this, 'remove_empty_aliases'));
56
+ $num_aliases = count($aliases);
57
+
58
+ if ($this->is_action('update')) {
59
+
60
+ $aliases = array();
61
+
62
+ for ($i=0; $i <= $num_aliases; $i++) {
63
+
64
+ $id = stripslashes($_POST["alias_{$i}_id"]);
65
+ $from = stripslashes($_POST["alias_{$i}_from"]);
66
+ $to = stripslashes($_POST["alias_{$i}_to"]);
67
+
68
+ $jls_post = stripslashes($_POST["alias_{$i}_posts"]);
69
+ if ($jls_post) {
70
+ $jls_post = $this->jlsuggest_value_explode($jls_post);
71
+ $posts = array($jls_post[2]);
72
+ } else {
73
+ $posts = array();
74
+ }
75
+
76
+ $delete = isset($_POST["alias_{$i}_delete"]) ? (intval($_POST["alias_{$i}_delete"]) == 1) : false;
77
+
78
+ if (!$delete && $from && $to)
79
+ $aliases[$id] = compact('from', 'to', 'posts');
80
+ }
81
+ $this->update_setting('aliases', $aliases);
82
+
83
+ $num_aliases = count($aliases);
84
+ }
85
+
86
+ if ($num_aliases > 0) {
87
+ $this->admin_subheader(__('Edit Existing Aliases', 'seo-ultimate'));
88
+ $this->aliases_form(0, $aliases);
89
+ }
90
+
91
+ $this->admin_subheader(__('Add a New Alias', 'seo-ultimate'));
92
+ $this->aliases_form($num_aliases, array(array()), false);
93
+ }
94
+
95
+ function aliases_form($start_id = 0, $aliases, $existing_item = true) {
96
+
97
+ //Set headers
98
+ $headers = array(
99
+ 'alias-from' => __('Actual URL', 'seo-ultimate')
100
+ , 'alias-to' => __('Alias URL', 'seo-ultimate')
101
+ , 'alias-posts' => __('Only on This Post&hellip; <em>(optional)</em>', 'seo-ultimate')
102
+ );
103
+ if ($existing_item) $headers['alias-delete'] = __('Delete', 'seo-ultimate');
104
+
105
+ //Begin table; output headers
106
+ $this->admin_wftable_start($headers);
107
+
108
+ //Cycle through links
109
+ $i = $start_id;
110
+ foreach ($aliases as $id => $alias) {
111
+
112
+ if (!is_string($id)) $id = uniqid($i, true);
113
+
114
+ if (!isset($alias['from'])) $alias['from'] = '';
115
+ if (!isset($alias['to'])) $alias['to'] = '';
116
+ $u_alias_to = urlencode($alias['to']);
117
+
118
+ if (isset($alias['posts'][0]))
119
+ $jlsuggest_value = 'obj_posttype_' . get_post_type($alias['posts'][0]) . '/' . $alias['posts'][0];
120
+ else
121
+ $jlsuggest_value = '';
122
+
123
+ $alias_dir = $this->get_setting('alias_dir', 'go', null, true);
124
+ $alias_url = get_bloginfo('url') . "/$alias_dir/$u_alias_to/";
125
+
126
+ $test_link = $existing_item ? "<td class='su-alias-to-test'>[<a href='$alias_url' target='_blank'>" . __('Test', 'seo-ultimate') . "</a>]</td>" : '';
127
+
128
+ $cells = array(
129
+ 'alias-from' =>
130
+ $this->get_input_element('hidden', "alias_{$i}_id", $id)
131
+ . $this->get_input_element('textbox', "alias_{$i}_from", $alias['from'])
132
+ , 'alias-to' => "
133
+ <table><tr>
134
+ <td class='su-alias-to-dir'>/$alias_dir/</td>
135
+ <td class='su-alias-to-slug'>" . $this->get_input_element('textbox', "alias_{$i}_to", $alias['to']) . "</td>
136
+ $test_link
137
+ </tr></table>"
138
+ , 'alias-posts' => $this->get_jlsuggest_box("alias_{$i}_posts", $jlsuggest_value, 'types=posttype')
139
+ );
140
+ if ($existing_item)
141
+ $cells['alias-delete'] = $this->get_input_element('checkbox', "alias_{$i}_delete");
142
+
143
+ $this->table_row($cells, $i, 'alias');
144
+
145
+ $i++;
146
+ }
147
+
148
+ $this->admin_wftable_end();
149
+ }
150
+
151
+ function settings_tab() {
152
+ $this->admin_form_table_start();
153
+ $this->textbox('alias_dir', __('Alias Directory', 'seo-ultimate'), $this->get_default_setting('alias_dir'));
154
+ if ($this->plugin->module_exists('link-nofollow'))
155
+ $this->checkbox('nofollow_aliased_links', __('Nofollow masked links', 'seo-ultimate'), __('Link Attributes', 'seo-ultimate'));
156
+ $this->admin_form_table_end();
157
+ }
158
+
159
+ function filter_alias_dir($alias_dir) {
160
+ return trim(sustr::preg_filter('a-zA-Z0-9_/', $alias_dir), '/');
161
+ }
162
+
163
+ function postmeta_fields($fields, $screen) {
164
+
165
+ if (!current_user_can('manage_options'))
166
+ return $fields;
167
+
168
+ $post_id = suwp::get_post_id();
169
+ $post = get_post($post_id);
170
+ if (!$post) return $fields;
171
+ $content = $post->post_content;
172
+
173
+ $alias_dir = $this->get_setting('alias_dir', 'go');
174
+
175
+ if ($content && preg_match_all('@ href=["\']([^#][^"\']+)["\']@', $content, $matches)) {
176
+ $urls = array_unique($matches[1]);
177
+
178
+ $html = "<tr valign='top'>\n<th scope='row' class='su'>".__('Link Masks:', 'seo-ultimate')."</th>\n<td>\n";
179
+
180
+ $html .= "<table class='widefat'><thead>\n";
181
+ $headers = array(__('URL', 'seo-ultimate'), '', __('Mask URL', 'seo-ultimate'));
182
+ foreach ($headers as $header) $html .= "<th>$header</th>\n";
183
+ $html .= "</thead>\n<tbody>";
184
+
185
+ $aliases = $this->get_setting('aliases', array());
186
+ $post_aliases = array();
187
+ foreach ($aliases as $id => $alias) {
188
+ if (empty($alias['posts']) || in_array($post->ID, $alias['posts']))
189
+ $post_aliases[$alias['from']] = array('id' => $id, 'to' => $alias['to']);
190
+ }
191
+
192
+ foreach ($urls as $url) {
193
+
194
+ $a_url = su_esc_attr($url);
195
+ $un_h_url = htmlspecialchars_decode($url);
196
+ $ht_url = esc_html(sustr::truncate($url, 30));
197
+
198
+ if (isset($post_aliases[$url]))
199
+ $url_key = $url;
200
+ elseif (isset($post_aliases[$un_h_url]))
201
+ $url_key = $un_h_url;
202
+ else
203
+ $url_key = false;
204
+
205
+ $alias_to = '';
206
+ $alias_id = uniqid('', true);
207
+ if ($url_key) {
208
+ if (isset($post_aliases[$url_key]['to'])) $alias_to = $post_aliases[$url_key]['to'];
209
+ if (isset($post_aliases[$url_key]['id'])) $alias_id = $post_aliases[$url_key]['id'];
210
+ }
211
+
212
+ $a_alias_to = esc_attr($alias_to);
213
+
214
+ $html .= "<tr><td><a href='$a_url' title='$a_url' target='_blank'>$ht_url</a><input type='hidden' name='_su_aliases[$alias_id][from]' value='$a_url' /></td>\n<td>&rArr;</td><td>/$alias_dir/<input type='text' name='_su_aliases[$alias_id][to]' value='$a_alias_to' /></td></tr>\n";
215
+ }
216
+
217
+ $html .= "</tbody>\n</table>\n";
218
+
219
+ $html .= '<p><small>' . __('You can stop search engines from following a link by typing in a mask for its URL.', 'seo-ultimate') . "</small></p>\n";
220
+
221
+ $html .= "</td>\n</tr>\n";
222
+
223
+ $fields['links'][100]['aliases'] = $html;
224
+ }
225
+
226
+ return $fields;
227
+ }
228
+
229
+ function save_post_aliases($false, $saved_aliases, $metakey, $post) {
230
+ if ($post->post_type == 'revision' || !is_array($saved_aliases)) return true;
231
+
232
+ $aliases = $this->get_setting('aliases', array());
233
+
234
+ foreach ($saved_aliases as $saved_id => $saved_data) {
235
+
236
+ if (isset($aliases[$saved_id])) {
237
+
238
+ if ($saved_data['to'])
239
+ $aliases[$saved_id]['to'] = $saved_data['to'];
240
+ else
241
+ unset($aliases[$saved_id]);
242
+
243
+ } elseif ($saved_data['to']) {
244
+ $aliases[$saved_id]['from'] = $saved_data['from'];
245
+ $aliases[$saved_id]['to'] = $saved_data['to'];
246
+ $aliases[$saved_id]['posts'] = array($post->ID);
247
+ }
248
+ }
249
+
250
+ $this->update_setting('aliases', $aliases);
251
+
252
+ return true;
253
+ }
254
+
255
+ function apply_aliases($content) {
256
+ return preg_replace_callback('@<a ([^>]*)href=(["\'])([^"\']+)(["\'])([^>]*)>@', array(&$this, 'apply_aliases_callback'), $content);
257
+ }
258
+
259
+ function apply_aliases_callback($matches) {
260
+ $id = suwp::get_post_id();
261
+
262
+ static $aliases = false;
263
+ //Just in case we have duplicate aliases, make sure the most recent ones are applied first
264
+ if ($aliases === false) $aliases = array_reverse($this->get_setting('aliases', array()), true);
265
+
266
+ static $alias_dir = false;
267
+ if ($alias_dir === false) $alias_dir = $this->get_setting('alias_dir', 'go');
268
+
269
+ $new_url = $old_url = $matches[3];
270
+
271
+ foreach ($aliases as $alias) {
272
+ $to = urlencode($alias['to']);
273
+
274
+ if ((empty($alias['posts']) || in_array($id, $alias['posts'])) && $to) {
275
+ $from = $alias['from'];
276
+ $h_from = esc_html($from);
277
+ $to = get_bloginfo('url') . "/$alias_dir/$to/";
278
+
279
+ if ($from == $old_url || $h_from == $old_url) {
280
+ $new_url = $to;
281
+ break;
282
+ }
283
+ }
284
+ }
285
+
286
+ $attrs = "{$matches[1]}href={$matches[2]}{$new_url}{$matches[4]}{$matches[5]}";
287
+
288
+ if ($old_url != $new_url && $this->get_setting('nofollow_aliased_links', false) && $this->plugin->module_exists('link-nofollow'))
289
+ $this->plugin->call_module_func('link-nofollow', 'nofollow_attributes_string', $attrs, $attrs);
290
+
291
+ return "<a $attrs>";
292
+ }
293
+
294
+ function redirect_aliases() {
295
+ $aliases = $this->get_setting('aliases', array());
296
+ $alias_dir = $this->get_setting('alias_dir', 'go');
297
+
298
+ foreach ($aliases as $alias)
299
+ if ($to = $alias['to'])
300
+ if (suurl::equal(suurl::current(), get_bloginfo('url') . "/$alias_dir/$to/"))
301
+ wp_redirect($alias['from']);
302
+ }
303
+
304
+ function block_aliases_dir() {
305
+ echo '# ';
306
+ _e("Added by SEO Ultimate's Link Mask Generator module", 'seo-ultimate');
307
+ echo "\n";
308
+
309
+ $urlinfo = parse_url(get_bloginfo('url'));
310
+ $path = $urlinfo['path'];
311
+ echo "User-agent: *\n";
312
+
313
+ $alias_dir = $this->get_setting('alias_dir', 'go');
314
+ echo "Disallow: $path/$alias_dir/\n";
315
+
316
+ echo '# ';
317
+ _e('End Link Mask Generator output', 'seo-ultimate');
318
+ echo "\n\n";
319
+ }
320
+
321
+
322
+ function add_help_tabs($screen) {
323
+
324
+ $screen->add_help_tab(array(
325
+ 'id' => 'su-internal-link-aliases-overview'
326
+ , 'title' => __('Overview', 'seo-ultimate')
327
+ , 'content' => __("
328
+ <ul>
329
+ <li><strong>What it does:</strong> Link Mask Generator lets you replace ugly affiliate links with clean-looking link aliases that redirect to the real URLs. Link Mask Generator will scan your posts for the links to the actual URLs and replace them with links to the alias URLs. When a visitor clicks on the link to the alias URL, Link Mask Generator will redirect the visitor to the actual URL.</li>
330
+ <li><strong>Why it helps:</strong> This type of functionality is a staple in an affiliate marketer&#8217;s toolkit. Link Mask Generator helps you by doing it in an SEO-friendly way: by funneling your affiliate links through a directory (e.g. <code>/go/</code>) which is blocked with <code>robots.txt</code> rules, effectively sealing off link juice flow to your affiliate links.</li>
331
+ <li><strong>How to use it:</strong> Type in the real URL, type in an alias URL, and click &#8220;Save Changes&#8221; &mdash; that&#8217;s it!</li>
332
+ </ul>
333
+ ", 'seo-ultimate')));
334
+
335
+ $screen->add_help_tab(array(
336
+ 'id' => 'su-internal-link-aliases-aliases'
337
+ , 'title' => __('Aliases Tab', 'seo-ultimate')
338
+ , 'content' => __("
339
+ <p>To add a link alias, fill in the fields and then click &#8220;Save Changes.&#8221; Once you do so, you can edit your newly masked link or add another one.</p>
340
+
341
+ <ul>
342
+ <li><strong>Actual URL</strong> &mdash; This box is where you put your affiliate URL (or other URL that you want to mask).</li>
343
+ <li><strong>Alias URL</strong> &mdash; This box is where you specify the new URL that will replace the actual one.</li>
344
+ <li><strong>Only on This Post</strong> &mdash; If you want to mask the actual URL across your entire site, leave this box blank. If you only want to mask the actual URL within an individual post, then type its name into this box and select it from the dropdown.</li>
345
+ <li><strong>Delete</strong> &mdash; To delete a link mask, tick its &#8220;Delete&#8221; checkbox and then click &#8220;Save Changes.&#8221;</li>
346
+ </ul>
347
+ ", 'seo-ultimate')));
348
+
349
+ $screen->add_help_tab(array(
350
+ 'id' => 'su-internal-link-aliases-settings'
351
+ , 'title' => __('Settings Tab', 'seo-ultimate')
352
+ , 'content' => __("
353
+ <p>The following options are available on the Settings tab:</p>
354
+
355
+ <ul>
356
+ <li><strong>Alias Directory</strong> &mdash; If you&#8217;d like, you can change the name of the directory that contains all your alias URLs. (Don&#8217;t worry, you won&#8217;t break any links by changing this.)</li>
357
+ <li><strong>Nofollow masked links</strong> &mdash; Checking this will add the <code>rel=&quot;nofollow&quot;</code> attribute to any masked links on your site. This makes it super-easy to nofollow all your affiliate links automatically.</li>
358
+ </ul>
359
+ ", 'seo-ultimate')));
360
+
361
+ $screen->add_help_tab(array(
362
+ 'id' => 'su-autolinks-faq'
363
+ , 'title' => __('FAQ', 'seo-ultimate')
364
+ , 'content' => __("
365
+ <ul>
366
+ <li><strong>Can I automatically link a phrase on my site to one of my alias URLs?</strong><br />Yes. Once you&#8217;ve created your link mask, go to Deeplink Juggernaut&#8217;s &#8220;Content Links&#8221; section, type the contents of your link mask&#8217;s &#8220;Alias URL&#8221; field into Deeplink Juggernaut&#8217;s &#8220;Destination&#8221; field, and select your link mask from the dropdown that appears.</li>
367
+ <li><strong>Will Link Mask Generator still add the <code>robots.txt</code> rules if I&#8217;m using the File Editor module to create a custom <code>robots.txt</code>?</strong><br />Yes.</li>
368
+ </ul>
369
+ ", 'seo-ultimate')));
370
+
371
+ }
372
+
373
+ }
374
  ?>
modules/link-nofollow/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/link-nofollow/link-nofollow.php CHANGED
@@ -1,142 +1,142 @@
1
- <?php
2
- /**
3
- * Nofollow Manager Module
4
- *
5
- * @since 5.6
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_LinkNofollow extends SU_Module {
11
-
12
- static function get_module_title() { return __('Nofollow Manager', 'seo-ultimate'); }
13
- function get_default_status() { return SU_MODULE_DISABLED; }
14
-
15
- static function get_parent_module() { return 'misc'; }
16
- function get_settings_key() { return 'link-nofollow'; }
17
-
18
- function init() {
19
- $filterdata = array(
20
- 'nofollow_links' => array(
21
- 'nofollow_adjacent_post' => array('previous_post_link', 'next_post_link')
22
- , 'nofollow_category_loop' => 'the_category'
23
- , 'nofollow_category_list' => 'wp_list_categories'
24
- , 'nofollow_comment_feed' => 'post_comments_feed_link_html'
25
- , 'nofollow_date_archive' => 'get_archives_link'
26
- , 'nofollow_post_more' => 'the_content_more_link'
27
- , 'nofollow_register' => 'register'
28
- , 'nofollow_login' => 'loginout'
29
- , 'nofollow_tag_loop' => 'term_links-post_tag'
30
- , 'nofollow_tag_list' => 'wp_tag_cloud'
31
- )
32
- , 'nofollow_attributes_string' => array(
33
- 'nofollow_comment_popup' => 'comments_popup_link_attributes'
34
- , 'nofollow_paged' => array('previous_posts_link_attributes', 'next_posts_link_attributes')
35
- , 'nofollow_paged_home' => array('previous_posts_link_attributes', 'next_posts_link_attributes')
36
- )
37
- );
38
-
39
- if (!is_home()) unset($filterdata['nofollow_attributes_string']['nofollow_paged_home']);
40
-
41
- foreach ($filterdata as $callback => $filters) {
42
- foreach ($filters as $setting => $hooks) {
43
- if ($this->get_setting($setting)) {
44
- foreach ((array)$hooks as $hook) {
45
- add_filter($hook, array(&$this, $callback));
46
- }
47
- }
48
- }
49
- }
50
-
51
- add_filter('wp_list_pages', array(&$this, 'nofollow_page_links'));
52
- }
53
-
54
- function admin_page_contents() {
55
- $this->child_admin_form_start();
56
- $this->checkboxes(array(
57
- 'nofollow_adjacent_post' => __('Adjacent post links (next post / previous post)', 'seo-ultimate')
58
- , 'nofollow_category_loop' => __('Category links (after posts)', 'seo-ultimate')
59
- , 'nofollow_category_list' => __('Category links (in lists)', 'seo-ultimate')
60
- , 'nofollow_comment_popup' => __('Comment anchor links', 'seo-ultimate')
61
- , 'nofollow_comment_feed' => __('Comment feed links', 'seo-ultimate')
62
- , 'nofollow_date_archive' => __('Date-based archive links', 'seo-ultimate')
63
- , 'nofollow_paged' => __('Pagination navigation links (all)', 'seo-ultimate')
64
- , 'nofollow_paged_home' => __('Pagination navigation links (on blog home only)', 'seo-ultimate')
65
- , 'nofollow_post_more' => __('&#8220;Read more&#8221; links', 'seo-ultimate')
66
- , 'nofollow_register' => __('Registration link', 'seo-ultimate')
67
- , 'nofollow_login' => __('Login link', 'seo-ultimate')
68
- , 'nofollow_tag_loop' => __('Tag links (after posts)', 'seo-ultimate')
69
- , 'nofollow_tag_list' => __('Tag links (in lists and clouds)', 'seo-ultimate')
70
- ), __('Add the nofollow attribute to...', 'seo-ultimate'));
71
-
72
- $this->child_admin_form_end();
73
- }
74
-
75
- function postmeta_fields($fields, $screen) {
76
-
77
- if (strcmp($screen, 'page') == 0)
78
- $fields['links'][30]['nofollow'] = $this->get_postmeta_checkbox('nofollow', __('When displaying page lists, nofollow links to this page', 'seo-ultimate'), __('Nofollow:', 'seo-ultimate'));
79
-
80
- return $fields;
81
- }
82
-
83
- function nofollow_links($html) {
84
- return preg_replace_callback('|<a (.+?)>|i', array(&$this, 'nofollow_links_callback'), $html);
85
- }
86
-
87
- function nofollow_links_callback($matches) {
88
- $html = $this->nofollow_attributes_string($matches[1]);
89
- return "<a $html>";
90
- }
91
-
92
- function nofollow_attributes_string($html) {
93
- if (preg_match('|rel=[\'"]?[^>]+nofollow[^>]+[\'"]?|i', $html))
94
- return $html;
95
- elseif (preg_match('|rel=[\'"][^>]+[\'"]|i', $html))
96
- return preg_replace('|rel=([\'"])|i', 'rel=\\1nofollow ', $html);
97
- else {
98
- if (strlen($html)) $html = rtrim($html, ' ').' ';
99
- return $html.'rel="nofollow"';
100
- }
101
- }
102
-
103
- function nofollow_page_links($html) {
104
- return preg_replace_callback('|<a (.+?)>|i', array(&$this, 'nofollow_page_links_callback'), $html);
105
- }
106
-
107
- function nofollow_page_links_callback($matches) {
108
- $html = $matches[1];
109
-
110
- if (preg_match('|href=[\'"]([^\'"]+)[\'"]|i', $html, $pagematches)) {
111
- $pageurl = $pagematches[1];
112
- $pagepath = str_replace(array(untrailingslashit(get_bloginfo('url')), '/index.php/'), '', $pageurl);
113
-
114
- if (preg_match('|/?\\?page_id=([0-9]+)|i', $pagepath, $qsmatches))
115
- //We're using query string URLs
116
- $page = get_page(intval($qsmatches[1]));
117
- else
118
- //We're using pretty or pathinfo permalinks
119
- $page = get_page_by_path($pagepath);
120
-
121
- if ($this->get_postmeta('nofollow', $page->ID))
122
- $html = $this->nofollow_attributes_string($html);
123
- }
124
-
125
- return "<a $html>";
126
- }
127
-
128
- function add_help_tabs($screen) {
129
-
130
- $screen->add_help_tab(array(
131
- 'id' => 'su-link-nofollow-overview'
132
- , 'title' => $this->has_enabled_parent() ? __('Nofollow Manager', 'seo-ultimate') : __('Overview', 'seo-ultimate')
133
- , 'content' => __("
134
- <p>Nofollow Manager adds the <code>rel=&quot;nofollow&quot;</code> attribute to types of links that you specify. The <code>rel=&quot;nofollow&quot;</code> attribute prevents a link from passing PageRank.</p>
135
- <p>If you&#8217;re migrating to SEO Ultimate from another plugin, Nofollow Manager can help you maintain your existing settings (as part of an &#8220;if it ain&#8217;t broke don&#8217;t fix it&#8221; strategy). In other cases, however, we recommend not using the Nofollow Manager because in 2008 Google disabled the ability to use the <code>rel=&quot;nofollow&quot;</code> attribute for PageRank sculpting.</p>
136
- ", 'seo-ultimate')));
137
- }
138
-
139
- }
140
-
141
- }
142
  ?>
1
+ <?php
2
+ /**
3
+ * Nofollow Manager Module
4
+ *
5
+ * @since 5.6
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_LinkNofollow extends SU_Module {
11
+
12
+ static function get_module_title() { return __('Nofollow Manager', 'seo-ultimate'); }
13
+ function get_default_status() { return SU_MODULE_DISABLED; }
14
+
15
+ static function get_parent_module() { return 'misc'; }
16
+ function get_settings_key() { return 'link-nofollow'; }
17
+
18
+ function init() {
19
+ $filterdata = array(
20
+ 'nofollow_links' => array(
21
+ 'nofollow_adjacent_post' => array('previous_post_link', 'next_post_link')
22
+ , 'nofollow_category_loop' => 'the_category'
23
+ , 'nofollow_category_list' => 'wp_list_categories'
24
+ , 'nofollow_comment_feed' => 'post_comments_feed_link_html'
25
+ , 'nofollow_date_archive' => 'get_archives_link'
26
+ , 'nofollow_post_more' => 'the_content_more_link'
27
+ , 'nofollow_register' => 'register'
28
+ , 'nofollow_login' => 'loginout'
29
+ , 'nofollow_tag_loop' => 'term_links-post_tag'
30
+ , 'nofollow_tag_list' => 'wp_tag_cloud'
31
+ )
32
+ , 'nofollow_attributes_string' => array(
33
+ 'nofollow_comment_popup' => 'comments_popup_link_attributes'
34
+ , 'nofollow_paged' => array('previous_posts_link_attributes', 'next_posts_link_attributes')
35
+ , 'nofollow_paged_home' => array('previous_posts_link_attributes', 'next_posts_link_attributes')
36
+ )
37
+ );
38
+
39
+ if (!is_home()) unset($filterdata['nofollow_attributes_string']['nofollow_paged_home']);
40
+
41
+ foreach ($filterdata as $callback => $filters) {
42
+ foreach ($filters as $setting => $hooks) {
43
+ if ($this->get_setting($setting)) {
44
+ foreach ((array)$hooks as $hook) {
45
+ add_filter($hook, array(&$this, $callback));
46
+ }
47
+ }
48
+ }
49
+ }
50
+
51
+ add_filter('wp_list_pages', array(&$this, 'nofollow_page_links'));
52
+ }
53
+
54
+ function admin_page_contents() {
55
+ $this->child_admin_form_start();
56
+ $this->checkboxes(array(
57
+ 'nofollow_adjacent_post' => __('Adjacent post links (next post / previous post)', 'seo-ultimate')
58
+ , 'nofollow_category_loop' => __('Category links (after posts)', 'seo-ultimate')
59
+ , 'nofollow_category_list' => __('Category links (in lists)', 'seo-ultimate')
60
+ , 'nofollow_comment_popup' => __('Comment anchor links', 'seo-ultimate')
61
+ , 'nofollow_comment_feed' => __('Comment feed links', 'seo-ultimate')
62
+ , 'nofollow_date_archive' => __('Date-based archive links', 'seo-ultimate')
63
+ , 'nofollow_paged' => __('Pagination navigation links (all)', 'seo-ultimate')
64
+ , 'nofollow_paged_home' => __('Pagination navigation links (on blog home only)', 'seo-ultimate')
65
+ , 'nofollow_post_more' => __('&#8220;Read more&#8221; links', 'seo-ultimate')
66
+ , 'nofollow_register' => __('Registration link', 'seo-ultimate')
67
+ , 'nofollow_login' => __('Login link', 'seo-ultimate')
68
+ , 'nofollow_tag_loop' => __('Tag links (after posts)', 'seo-ultimate')
69
+ , 'nofollow_tag_list' => __('Tag links (in lists and clouds)', 'seo-ultimate')
70
+ ), __('Add the nofollow attribute to...', 'seo-ultimate'));
71
+
72
+ $this->child_admin_form_end();
73
+ }
74
+
75
+ function postmeta_fields($fields, $screen) {
76
+
77
+ if (strcmp($screen, 'page') == 0)
78
+ $fields['links'][30]['nofollow'] = $this->get_postmeta_checkbox('nofollow', __('When displaying page lists, nofollow links to this page', 'seo-ultimate'), __('Nofollow:', 'seo-ultimate'));
79
+
80
+ return $fields;
81
+ }
82
+
83
+ function nofollow_links($html) {
84
+ return preg_replace_callback('|<a (.+?)>|i', array(&$this, 'nofollow_links_callback'), $html);
85
+ }
86
+
87
+ function nofollow_links_callback($matches) {
88
+ $html = $this->nofollow_attributes_string($matches[1]);
89
+ return "<a $html>";
90
+ }
91
+
92
+ function nofollow_attributes_string($html) {
93
+ if (preg_match('|rel=[\'"]?[^>]+nofollow[^>]+[\'"]?|i', $html))
94
+ return $html;
95
+ elseif (preg_match('|rel=[\'"][^>]+[\'"]|i', $html))
96
+ return preg_replace('|rel=([\'"])|i', 'rel=\\1nofollow ', $html);
97
+ else {
98
+ if (strlen($html)) $html = rtrim($html, ' ').' ';
99
+ return $html.'rel="nofollow"';
100
+ }
101
+ }
102
+
103
+ function nofollow_page_links($html) {
104
+ return preg_replace_callback('|<a (.+?)>|i', array(&$this, 'nofollow_page_links_callback'), $html);
105
+ }
106
+
107
+ function nofollow_page_links_callback($matches) {
108
+ $html = $matches[1];
109
+
110
+ if (preg_match('|href=[\'"]([^\'"]+)[\'"]|i', $html, $pagematches)) {
111
+ $pageurl = $pagematches[1];
112
+ $pagepath = str_replace(array(untrailingslashit(get_bloginfo('url')), '/index.php/'), '', $pageurl);
113
+
114
+ if (preg_match('|/?\\?page_id=([0-9]+)|i', $pagepath, $qsmatches))
115
+ //We're using query string URLs
116
+ $page = get_page(intval($qsmatches[1]));
117
+ else
118
+ //We're using pretty or pathinfo permalinks
119
+ $page = get_page_by_path($pagepath);
120
+
121
+ if ($this->get_postmeta('nofollow', $page->ID))
122
+ $html = $this->nofollow_attributes_string($html);
123
+ }
124
+
125
+ return "<a $html>";
126
+ }
127
+
128
+ function add_help_tabs($screen) {
129
+
130
+ $screen->add_help_tab(array(
131
+ 'id' => 'su-link-nofollow-overview'
132
+ , 'title' => $this->has_enabled_parent() ? __('Nofollow Manager', 'seo-ultimate') : __('Overview', 'seo-ultimate')
133
+ , 'content' => __("
134
+ <p>Nofollow Manager adds the <code>rel=&quot;nofollow&quot;</code> attribute to types of links that you specify. The <code>rel=&quot;nofollow&quot;</code> attribute prevents a link from passing PageRank.</p>
135
+ <p>If you&#8217;re migrating to SEO Ultimate from another plugin, Nofollow Manager can help you maintain your existing settings (as part of an &#8220;if it ain&#8217;t broke don&#8217;t fix it&#8221; strategy). In other cases, however, we recommend not using the Nofollow Manager because in 2008 Google disabled the ability to use the <code>rel=&quot;nofollow&quot;</code> attribute for PageRank sculpting.</p>
136
+ ", 'seo-ultimate')));
137
+ }
138
+
139
+ }
140
+
141
+ }
142
  ?>
modules/linkbox/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/linkbox/linkbox.css CHANGED
@@ -1,4 +1,4 @@
1
-
2
- #su-linkbox textarea {
3
- width: 100%;
4
  }
1
+
2
+ #su-linkbox textarea {
3
+ width: 100%;
4
  }
modules/linkbox/linkbox.php CHANGED
@@ -1,147 +1,147 @@
1
- <?php
2
- /**
3
- * Linkbox Inserter Module
4
- *
5
- * @since 0.6
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_Linkbox extends SU_Module {
11
-
12
- static function get_module_title() { return __('Linkbox Inserter', 'seo-ultimate'); }
13
-
14
- static function get_parent_module() { return 'misc'; }
15
- function get_settings_key() { return 'linkbox'; }
16
-
17
- function get_default_settings() {
18
- //The default linkbox HTML
19
- return array(
20
- 'html' => '<div class="su-linkbox" id="post-{id}-linkbox"><div class="su-linkbox-label">' .
21
- __('Link to this post!', 'seo-ultimate') .
22
- '</div><div class="su-linkbox-field">' .
23
- '<input type="text" value="&lt;a href=&quot;{url}&quot;&gt;{title}&lt;/a&gt;" '.
24
- 'onclick="javascript:this.select()" readonly="readonly" style="width: 100%;" />' .
25
- '</div></div>'
26
- );
27
- }
28
-
29
- function init() {
30
- //We only want to filter post content when we're in the front-end, so we hook into template_redirect
31
- add_action('template_redirect', array(&$this, 'template_init'));
32
- }
33
-
34
- function template_init() {
35
- $enabled = false;
36
-
37
- if ($this->should_linkbox())
38
- //Add the linkbox to post/page content
39
- add_filter('the_content', array(&$this, 'linkbox_filter'));
40
-
41
- if ($this->get_setting('action_hook'))
42
- //Enable the action hook
43
- add_action('su_linkbox', array(&$this, 'linkbox_action'));
44
- }
45
-
46
- function admin_page_contents() {
47
- $this->child_admin_form_start();
48
- $this->checkboxes(array('filter_posts' => __('At the end of posts', 'seo-ultimate')
49
- , 'filter_pages' => __('At the end of pages', 'seo-ultimate')
50
- , 'action_hook' => __('When called by the su_linkbox hook', 'seo-ultimate')
51
- ), __('Display linkboxes...', 'seo-ultimate'));
52
- $this->textarea('html', __('Linkbox HTML', 'seo-ultimate'));
53
- $this->child_admin_form_end();
54
- }
55
-
56
- function should_linkbox() {
57
- return (!is_page() && $this->get_setting('filter_posts'))
58
- || ( is_page() && $this->get_setting('filter_pages'));
59
- }
60
-
61
- function linkbox_filter($content, $id = false) {
62
-
63
- //If no ID is provided, get the ID of the current post
64
- if (!$id) $id = suwp::get_post_id();
65
-
66
- if ($id) {
67
- //Don't add a linkbox if a "more" link is present (since a linkbox should go at the very bottom of a post)
68
- $morelink = '<a href="'.get_permalink($id).'#more-'.$id.'" class="more-link">';
69
- if (strpos($content, $morelink) !== false) return $content;
70
-
71
- //Load the HTML and replace the variables with the proper values
72
- $linkbox = $this->get_setting('html');
73
- $linkbox = str_replace(
74
- array('{id}', '{url}', '{title}'),
75
- array(intval($id), su_esc_attr(get_permalink($id)), su_esc_attr(get_the_title($id))),
76
- $linkbox
77
- );
78
-
79
- //Return the content with the linkbox added to the bottom
80
- return $content.$linkbox;
81
- }
82
-
83
- return $content;
84
- }
85
-
86
- function linkbox_action($id = false) {
87
- echo $this->linkbox_filter('', $id);
88
- }
89
-
90
- function add_help_tabs($screen) {
91
-
92
- $overview = __("
93
- <ul>
94
- <li><strong>What it does:</strong> Linkbox Inserter can add linkboxes to your posts/pages.</li>
95
- <li><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.</li>
96
- <li><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.</li>
97
- </ul>
98
- ", 'seo-ultimate');
99
-
100
- $settings = __("
101
- <p>Here&#8217;s information on the various settings:</p>
102
-
103
- <ul>
104
- <li>
105
- <strong>Display linkboxes...</strong>
106
- <ul>
107
- <li><strong>At the end of posts</strong> &mdash; Adds the linkbox HTML to the end of all posts (whether they're displayed on the blog homepage, in archives, or by themselves).</li>
108
- <li><strong>At the end of pages</strong> &mdash; Adds the linkbox HTML to the end of all Pages.</li>
109
- <li><strong>When called by the su_linkbox hook</strong> &mdash; For more fine-tuned control over where linkboxes appear, enable this option and add <code>&lt;?php do_action('su_linkbox'); ?&gt;</code> to your theme. You can also add an ID parameter to display the linkbox of a particular post/page; for example: <code>&lt;?php do_action('su_linkbox', 123); ?&gt;</code>.</li>
110
- </ul>
111
- </li>
112
- <li>
113
- <strong>HTML</strong> &mdash; The HTML that will be outputted to display the linkboxes. The HTML field supports these variables:
114
- <ul>
115
- <li>{id} &mdash; The ID of the current post/page, or the ID passed to the action hook call.</li>
116
- <li>{url} &mdash; The permalink URL of the post/page.</li>
117
- <li>{title} &mdash; The title of the post/page.</li>
118
- </ul>
119
- </li>
120
- </ul>
121
- ", 'seo-ultimate');
122
-
123
- if ($this->has_enabled_parent()) {
124
- $screen->add_help_tab(array(
125
- 'id' => 'su-linkbox-help'
126
- , 'title' => __('Linkbox Inserter', 'seo-ultimate')
127
- , 'content' =>
128
- '<h3>' . __('Overview', 'seo-ultimate') . '</h3>' . $overview .
129
- '<h3>' . __('Settings Help', 'seo-ultimate') . '</h3>' . $settings
130
- ));
131
- } else {
132
-
133
- $screen->add_help_tab(array(
134
- 'id' => 'su-linkbox-overview'
135
- , 'title' => __('Overview', 'seo-ultimate')
136
- , 'content' => $overview));
137
-
138
- $screen->add_help_tab(array(
139
- 'id' => 'su-linkbox-settings'
140
- , 'title' => __('Settings Help', 'seo-ultimate')
141
- , 'content' => $settings));
142
- }
143
- }
144
- }
145
-
146
- }
147
  ?>
1
+ <?php
2
+ /**
3
+ * Linkbox Inserter Module
4
+ *
5
+ * @since 0.6
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_Linkbox extends SU_Module {
11
+
12
+ static function get_module_title() { return __('Linkbox Inserter', 'seo-ultimate'); }
13
+
14
+ static function get_parent_module() { return 'misc'; }
15
+ function get_settings_key() { return 'linkbox'; }
16
+
17
+ function get_default_settings() {
18
+ //The default linkbox HTML
19
+ return array(
20
+ 'html' => '<div class="su-linkbox" id="post-{id}-linkbox"><div class="su-linkbox-label">' .
21
+ __('Link to this post!', 'seo-ultimate') .
22
+ '</div><div class="su-linkbox-field">' .
23
+ '<input type="text" value="&lt;a href=&quot;{url}&quot;&gt;{title}&lt;/a&gt;" '.
24
+ 'onclick="javascript:this.select()" readonly="readonly" style="width: 100%;" />' .
25
+ '</div></div>'
26
+ );
27
+ }
28
+
29
+ function init() {
30
+ //We only want to filter post content when we're in the front-end, so we hook into template_redirect
31
+ add_action('template_redirect', array(&$this, 'template_init'));
32
+ }
33
+
34
+ function template_init() {
35
+ $enabled = false;
36
+
37
+ if ($this->should_linkbox())
38
+ //Add the linkbox to post/page content
39
+ add_filter('the_content', array(&$this, 'linkbox_filter'));
40
+
41
+ if ($this->get_setting('action_hook'))
42
+ //Enable the action hook
43
+ add_action('su_linkbox', array(&$this, 'linkbox_action'));
44
+ }
45
+
46
+ function admin_page_contents() {
47
+ $this->child_admin_form_start();
48
+ $this->checkboxes(array('filter_posts' => __('At the end of posts', 'seo-ultimate')
49
+ , 'filter_pages' => __('At the end of pages', 'seo-ultimate')
50
+ , 'action_hook' => __('When called by the su_linkbox hook', 'seo-ultimate')
51
+ ), __('Display linkboxes...', 'seo-ultimate'));
52
+ $this->textarea('html', __('Linkbox HTML', 'seo-ultimate'));
53
+ $this->child_admin_form_end();
54
+ }
55
+
56
+ function should_linkbox() {
57
+ return (!is_page() && $this->get_setting('filter_posts'))
58
+ || ( is_page() && $this->get_setting('filter_pages'));
59
+ }
60
+
61
+ function linkbox_filter($content, $id = false) {
62
+
63
+ //If no ID is provided, get the ID of the current post
64
+ if (!$id) $id = suwp::get_post_id();
65
+
66
+ if ($id) {
67
+ //Don't add a linkbox if a "more" link is present (since a linkbox should go at the very bottom of a post)
68
+ $morelink = '<a href="'.get_permalink($id).'#more-'.$id.'" class="more-link">';
69
+ if (strpos($content, $morelink) !== false) return $content;
70
+
71
+ //Load the HTML and replace the variables with the proper values
72
+ $linkbox = $this->get_setting('html');
73
+ $linkbox = str_replace(
74
+ array('{id}', '{url}', '{title}'),
75
+ array(intval($id), su_esc_attr(get_permalink($id)), su_esc_attr(get_the_title($id))),
76
+ $linkbox
77
+ );
78
+
79
+ //Return the content with the linkbox added to the bottom
80
+ return $content.$linkbox;
81
+ }
82
+
83
+ return $content;
84
+ }
85
+
86
+ function linkbox_action($id = false) {
87
+ echo $this->linkbox_filter('', $id);
88
+ }
89
+
90
+ function add_help_tabs($screen) {
91
+
92
+ $overview = __("
93
+ <ul>
94
+ <li><strong>What it does:</strong> Linkbox Inserter can add linkboxes to your posts/pages.</li>
95
+ <li><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.</li>
96
+ <li><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.</li>
97
+ </ul>
98
+ ", 'seo-ultimate');
99
+
100
+ $settings = __("
101
+ <p>Here&#8217;s information on the various settings:</p>
102
+
103
+ <ul>
104
+ <li>
105
+ <strong>Display linkboxes...</strong>
106
+ <ul>
107
+ <li><strong>At the end of posts</strong> &mdash; Adds the linkbox HTML to the end of all posts (whether they're displayed on the blog homepage, in archives, or by themselves).</li>
108
+ <li><strong>At the end of pages</strong> &mdash; Adds the linkbox HTML to the end of all Pages.</li>
109
+ <li><strong>When called by the su_linkbox hook</strong> &mdash; For more fine-tuned control over where linkboxes appear, enable this option and add <code>&lt;?php do_action('su_linkbox'); ?&gt;</code> to your theme. You can also add an ID parameter to display the linkbox of a particular post/page; for example: <code>&lt;?php do_action('su_linkbox', 123); ?&gt;</code>.</li>
110
+ </ul>
111
+ </li>
112
+ <li>
113
+ <strong>HTML</strong> &mdash; The HTML that will be outputted to display the linkboxes. The HTML field supports these variables:
114
+ <ul>
115
+ <li>{id} &mdash; The ID of the current post/page, or the ID passed to the action hook call.</li>
116
+ <li>{url} &mdash; The permalink URL of the post/page.</li>
117
+ <li>{title} &mdash; The title of the post/page.</li>
118
+ </ul>
119
+ </li>
120
+ </ul>
121
+ ", 'seo-ultimate');
122
+
123
+ if ($this->has_enabled_parent()) {
124
+ $screen->add_help_tab(array(
125
+ 'id' => 'su-linkbox-help'
126
+ , 'title' => __('Linkbox Inserter', 'seo-ultimate')
127
+ , 'content' =>
128
+ '<h3>' . __('Overview', 'seo-ultimate') . '</h3>' . $overview .
129
+ '<h3>' . __('Settings Help', 'seo-ultimate') . '</h3>' . $settings
130
+ ));
131
+ } else {
132
+
133
+ $screen->add_help_tab(array(
134
+ 'id' => 'su-linkbox-overview'
135
+ , 'title' => __('Overview', 'seo-ultimate')
136
+ , 'content' => $overview));
137
+
138
+ $screen->add_help_tab(array(
139
+ 'id' => 'su-linkbox-settings'
140
+ , 'title' => __('Settings Help', 'seo-ultimate')
141
+ , 'content' => $settings));
142
+ }
143
+ }
144
+ }
145
+
146
+ }
147
  ?>
modules/meta/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/meta/meta-descriptions.css CHANGED
@@ -1,14 +1,14 @@
1
-
2
- #su-meta-descriptions .su-meta-edit-table .su-description textarea {
3
- height: 2.4em;
4
- resize: none;
5
-
6
- -moz-transition: height .2s; /* Firefox */
7
- -webkit-transition: height .2s; /* Safari and Chrome */
8
- -o-transition: height .2s; /* Opera */
9
- transition: height .2s;
10
- }
11
-
12
- #su-meta-descriptions .su-meta-edit-table .su-description textarea:focus {
13
- height: 10em;
14
  }
1
+
2
+ #su-meta-descriptions .su-meta-edit-table .su-description textarea {
3
+ height: 2.4em;
4
+ resize: none;
5
+
6
+ -moz-transition: height .2s; /* Firefox */
7
+ -webkit-transition: height .2s; /* Safari and Chrome */
8
+ -o-transition: height .2s; /* Opera */
9
+ transition: height .2s;
10
+ }
11
+
12
+ #su-meta-descriptions .su-meta-edit-table .su-description textarea:focus {
13
+ height: 10em;
14
  }
modules/meta/meta-descriptions.php CHANGED
@@ -1,240 +1,240 @@
1
- <?php
2
- /**
3
- * Meta Description Editor Module
4
- *
5
- * @since 4.0
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- function su_meta_descriptions_export_filter($all_settings) {
11
- unset($all_settings['meta']['taxonomy_descriptions']);
12
- return $all_settings;
13
- }
14
- add_filter('su_settings_export_array', 'su_meta_descriptions_export_filter');
15
-
16
- class SU_MetaDescriptions extends SU_Module {
17
-
18
- static function get_module_title() { return __('Meta Description Editor', 'seo-ultimate'); }
19
- static function get_menu_title() { return __('Meta Descriptions', 'seo-ultimate'); }
20
- function get_settings_key() { return 'meta'; }
21
-
22
- function init() {
23
- add_action('su_head', array(&$this, 'head_tag_output'));
24
- add_filter('su_postmeta_help', array(&$this, 'postmeta_help'), 20);
25
- }
26
-
27
- function get_admin_page_tabs() {
28
- return array_merge(
29
- array(
30
- array('title' => __('Default Formats', 'seo-ultimate'), 'id' => 'su-default-formats', 'callback' => 'formats_tab')
31
- , array('title' => __('Blog Homepage', 'seo-ultimate'), 'id' => 'su-blog-homepage', 'callback' => 'home_tab')
32
- )
33
- , $this->get_meta_edit_tabs(array(
34
- 'type' => 'textarea'
35
- , 'name' => 'description'
36
- , 'term_settings_key' => 'taxonomy_descriptions'
37
- , 'label' => __('Meta Description', 'seo-ultimate')
38
- ))
39
- );
40
- }
41
-
42
- function get_default_settings() {
43
- return array(
44
- 'home_description_tagline_default' => true
45
- , 'description_posttype_post' => '{excerpt}'
46
- , 'description_posttype_page' => ''
47
- , 'description_taxonomy_category' => '{description}'
48
- , 'description_taxonomy_post_tag' => '{description}'
49
- , 'description_paged' => '{meta_description} - Page {num}'
50
- );
51
- }
52
-
53
- function formats_tab() {
54
- $this->admin_form_table_start();
55
- $this->textboxes(array(
56
- 'description_posttype_post' => __('Post Description Format', 'seo-ultimate')
57
- , 'description_posttype_page' => __('Page Description Format', 'seo-ultimate')
58
- , 'description_taxonomy_category' => __('Category Description Format', 'seo-ultimate')
59
- , 'description_taxonomy_post_tag' => __('Post Tag Description Format', 'seo-ultimate')
60
- , 'description_paged' => __('Pagination Description Format', 'seo-ultimate')
61
- ), $this->get_default_settings());
62
-
63
- $this->admin_form_table_end();
64
- }
65
-
66
- function home_tab() {
67
- $this->admin_form_table_start();
68
- $this->textarea('home_description', __('Blog Homepage Meta Description', 'seo-ultimate'), 3);
69
- $this->checkboxes(array(
70
- 'home_description_tagline_default' => __('Use this blog&#8217s tagline as the default homepage description.', 'seo-ultimate')
71
- ), __('Default Value', 'seo-ultimate'));
72
- $this->admin_form_table_end();
73
- }
74
-
75
- function head_tag_output() {
76
-
77
- $desc = $this->get_meta_desc();
78
-
79
- //Do we have a description? If so, output it.
80
- if ($desc)
81
- echo "\t<meta name=\"description\" content=\"$desc\" />\n";
82
- }
83
-
84
- function get_meta_desc() {
85
-
86
- global $post;
87
-
88
- $desc = false;
89
-
90
- //If we're viewing the homepage, look for homepage meta data.
91
- if (is_home()) {
92
- $desc = $this->get_setting('home_description');
93
- if (!$desc && $this->get_setting('home_description_tagline_default')) $desc = get_bloginfo('description');
94
-
95
- //If we're viewing a post or page, look for its meta data.
96
- } elseif (is_singular()) {
97
- $desc = $this->get_postmeta('description');
98
-
99
- if (!trim($desc) && !post_password_required() && $format = $this->get_setting('description_posttype_'.get_post_type())) {
100
-
101
- $auto_excerpt = $post->post_content;
102
- $auto_excerpt = strip_shortcodes($auto_excerpt);
103
- $auto_excerpt = str_replace(']]>', ']]&gt;', $auto_excerpt);
104
- $auto_excerpt = strip_tags($auto_excerpt);
105
- $auto_excerpt = sustr::truncate($auto_excerpt, 150, '', true);
106
-
107
- $desc = str_replace(
108
- array('{excerpt::autogen}', '{excerpt}')
109
- , array($auto_excerpt, strip_tags($post->post_excerpt))
110
- , $format);
111
- }
112
-
113
- //If we're viewing a term, look for its meta data.
114
- } elseif (suwp::is_tax()) {
115
- global $wp_query;
116
- $tax_descriptions = $this->get_setting('taxonomy_descriptions');
117
- $term_id = $wp_query->get_queried_object_id();
118
- $term_obj = $wp_query->get_queried_object();
119
- $desc = isset($tax_descriptions[$term_id]) ? $tax_descriptions[$term_id] : '';
120
-
121
- if (!trim($desc) && $format = $this->get_setting('description_taxonomy_'.$term_obj->taxonomy)) {
122
-
123
- $desc = str_replace(
124
- array('{description}')
125
- , array($term_obj->description)
126
- , $format);
127
- }
128
- }
129
-
130
- $desc = trim($desc);
131
-
132
- if ($desc)
133
- $desc = $this->get_desc_paged($desc);
134
-
135
- $desc = trim($desc);
136
-
137
- $desc = su_esc_attr($desc);
138
-
139
- return $desc;
140
- }
141
-
142
- function get_desc_paged($desc) {
143
-
144
- global $wp_query, $numpages;
145
-
146
- if (is_paged() || get_query_var('page')) {
147
-
148
- if (is_paged()) {
149
- $num = absint(get_query_var('paged'));
150
- $max = absint($wp_query->max_num_pages);
151
- } else {
152
- $num = absint(get_query_var('page'));
153
-
154
- if (is_singular()) {
155
- $post = $wp_query->get_queried_object();
156
- $max = count(explode('<!--nextpage-->', $post->post_content));
157
- } else
158
- $max = '';
159
- }
160
-
161
- return str_replace(
162
- array('{meta_description}', '{num}', '{max}'),
163
- array( $desc, $num, $max ),
164
- $this->get_setting('description_paged'));
165
- } else
166
- return $desc;
167
- }
168
-
169
- function postmeta_fields($fields, $screen) {
170
- $id = '_su_description';
171
- $value = su_esc_attr($this->get_postmeta('description'));
172
-
173
- $fields['serp'][20]['description'] =
174
- "<div class='form-group su textarea'>\n<label class='col-sm-4 col-md-4 control-label' for='$id'>".__('Meta Description:', 'seo-ultimate')."</label>\n<div class='col-sm-4 col-md-4'>"
175
- . "<textarea name='$id' id='$id' class='form-control regular-text' cols='60' rows='3' tabindex='2'"
176
- . " onkeyup=\"javascript:document.getElementById('su_meta_description_charcount').innerHTML = document.getElementById('_su_description').value.length\">$value</textarea>"
177
- . "</div>\n<div class='col-sm-4 col-md-4 help-text'>".sprintf(__('You&#8217;ve entered %s characters. Most search engines use up to 140.', 'seo-ultimate'), "<strong id='su_meta_description_charcount'>".strlen($value)."</strong>")
178
- . "</div>\n</div>\n";
179
-
180
- return $fields;
181
- }
182
-
183
- function postmeta_help($help) {
184
- $help[] = __('<strong>Meta Description</strong> &mdash; The value of the meta description tag. The description will often appear underneath the title in search engine results. Writing an accurate, attention-grabbing description for every post is important to ensuring a good search results clickthrough rate.', 'seo-ultimate');
185
- return $help;
186
- }
187
-
188
- function add_help_tabs($screen) {
189
-
190
- $screen->add_help_tab(array(
191
- 'id' => 'su-meta-descriptions-overview'
192
- , 'title' => __('Overview', 'seo-ultimate')
193
- , 'content' => __("
194
- <ul>
195
- <li><strong>What it does:</strong> Meta Descriptions Editor lets you customize the text that you want to appear under your webpages&#8217; titles in search results.</li>
196
- <li><strong>Why it helps:</strong> Getting ranked isn&#8217;t enough; once you're ranked, you need visitors to click on your site in the results. That&#8217;s where meta descriptions can help. When you provide text that makes searchers want to visit your site, you can increase your SERP clickthrough rate and thus increase search traffic.</li>
197
- <li><strong>How to use it:</strong> Enter meta descriptions for your homepage, posts, pages, etc. as desired, and then click Save Changes. 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.</li>
198
- </ul>
199
- ", 'seo-ultimate')));
200
-
201
- $screen->add_help_tab(array(
202
- 'id' => 'su-meta-descriptions-blog-homepage'
203
- , 'title' => __('Blog Homepage Tab', 'seo-ultimate')
204
- , 'content' => __("
205
- <p>Here&#8217;s information on the various settings:</p>
206
-
207
- <ul>
208
- <li><strong>Blog Homepage Meta Description</strong> &mdash; When your blog homepage appears in search results, it&#8217;ll have a title and a description. When you type a description into this box, the Meta Editor will add code to your blog homepage (the <code>&lt;meta name=&quot;description&quot; /&gt;</code> tag) that asks search engines to use what you&#8217;ve entered as the homepage&#8217;s search results description.</li>
209
- <li><strong>Use this blog&#8217;s tagline as the default homepage description.</strong> &mdash; If this box is checked and if the Blog Homepage Meta Description field is empty, Meta Editor will use your blog&#8217;s tagline as the meta description. You can edit the blog&#8217;s tagline under <a href='options-general.php'>Settings &rArr; General</a>.</li>
210
- </ul>
211
- ", 'seo-ultimate')));
212
-
213
- $screen->add_help_tab(array(
214
- 'id' => 'su-meta-descriptions-faq'
215
- , 'title' => __('FAQ', 'seo-ultimate')
216
- , 'content' => __("
217
- <ul>
218
- <li><strong>How do I edit the meta description of my homepage?</strong><br />If you have configured your <a href='options-reading.php'>Settings &rArr; Reading</a> section to use a &#8220;front page&#8221; and/or a &#8220;posts page,&#8221; just edit those pages&#8217;s meta descriptions on the &#8220;Pages&#8221; tab. Otherwise, just use the Blog Homepage field.</li>
219
- </ul>
220
- ", 'seo-ultimate')));
221
-
222
- $screen->add_help_tab(array(
223
- 'id' => 'su-meta-descriptions-troubleshooting'
224
- , 'title' => __('Troubleshooting', 'seo-ultimate')
225
- , 'content' => __("
226
- <ul>
227
- <li>
228
- <p><strong>What do I do if my site has multiple meta tags?</strong><br />First, try removing your theme&#8217;s built-in meta tags if it has them. Go to <a href='theme-editor.php' target='_blank'>Appearance &rArr; Editor</a> and edit <code>header.php</code>. Delete or comment-out any <code>&lt;meta&gt;</code> tags.</p>
229
- <p>If the problem persists, try disabling other SEO plugins that may be generating meta tags.</p>
230
- <p>Troubleshooting tip: Go to <a href='options-general.php?page=seo-ultimate'>Settings &rArr; SEO Ultimate</a> and enable the &#8220;Identify the plugin&#8217;s HTML code insertions with HTML comment tags&#8221; option. This will mark SEO Ultimate&#8217;s meta tags with comments, allowing you to see which meta tags are generated by SEO Ultimate and which aren&#8217;t.</p>
231
- </li>
232
- </ul>
233
- ", 'seo-ultimate')));
234
-
235
- }
236
-
237
- }
238
-
239
- }
240
  ?>
1
+ <?php
2
+ /**
3
+ * Meta Description Editor Module
4
+ *
5
+ * @since 4.0
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ function su_meta_descriptions_export_filter($all_settings) {
11
+ unset($all_settings['meta']['taxonomy_descriptions']);
12
+ return $all_settings;
13
+ }
14
+ add_filter('su_settings_export_array', 'su_meta_descriptions_export_filter');
15
+
16
+ class SU_MetaDescriptions extends SU_Module {
17
+
18
+ static function get_module_title() { return __('Meta Description Editor', 'seo-ultimate'); }
19
+ static function get_menu_title() { return __('Meta Descriptions', 'seo-ultimate'); }
20
+ function get_settings_key() { return 'meta'; }
21
+
22
+ function init() {
23
+ add_action('su_head', array(&$this, 'head_tag_output'));
24
+ add_filter('su_postmeta_help', array(&$this, 'postmeta_help'), 20);
25
+ }
26
+
27
+ function get_admin_page_tabs() {
28
+ return array_merge(
29
+ array(
30
+ array('title' => __('Default Formats', 'seo-ultimate'), 'id' => 'su-default-formats', 'callback' => 'formats_tab')
31
+ , array('title' => __('Blog Homepage', 'seo-ultimate'), 'id' => 'su-blog-homepage', 'callback' => 'home_tab')
32
+ )
33
+ , $this->get_meta_edit_tabs(array(
34
+ 'type' => 'textarea'
35
+ , 'name' => 'description'
36
+ , 'term_settings_key' => 'taxonomy_descriptions'
37
+ , 'label' => __('Meta Description', 'seo-ultimate')
38
+ ))
39
+ );
40
+ }
41
+
42
+ function get_default_settings() {
43
+ return array(
44
+ 'home_description_tagline_default' => true
45
+ , 'description_posttype_post' => '{excerpt}'
46
+ , 'description_posttype_page' => ''
47
+ , 'description_taxonomy_category' => '{description}'
48
+ , 'description_taxonomy_post_tag' => '{description}'
49
+ , 'description_paged' => '{meta_description} - Page {num}'
50
+ );
51
+ }
52
+
53
+ function formats_tab() {
54
+ $this->admin_form_table_start();
55
+ $this->textboxes(array(
56
+ 'description_posttype_post' => __('Post Description Format', 'seo-ultimate')
57
+ , 'description_posttype_page' => __('Page Description Format', 'seo-ultimate')
58
+ , 'description_taxonomy_category' => __('Category Description Format', 'seo-ultimate')
59
+ , 'description_taxonomy_post_tag' => __('Post Tag Description Format', 'seo-ultimate')
60
+ , 'description_paged' => __('Pagination Description Format', 'seo-ultimate')
61
+ ), $this->get_default_settings());
62
+
63
+ $this->admin_form_table_end();
64
+ }
65
+
66
+ function home_tab() {
67
+ $this->admin_form_table_start();
68
+ $this->textarea('home_description', __('Blog Homepage Meta Description', 'seo-ultimate'), 3);
69
+ $this->checkboxes(array(
70
+ 'home_description_tagline_default' => __('Use this blog&#8217s tagline as the default homepage description.', 'seo-ultimate')
71
+ ), __('Default Value', 'seo-ultimate'));
72
+ $this->admin_form_table_end();
73
+ }
74
+
75
+ function head_tag_output() {
76
+
77
+ $desc = $this->get_meta_desc();
78
+
79
+ //Do we have a description? If so, output it.
80
+ if ($desc)
81
+ echo "\t<meta name=\"description\" content=\"$desc\" />\n";
82
+ }
83
+
84
+ function get_meta_desc() {
85
+
86
+ global $post;
87
+
88
+ $desc = false;
89
+
90
+ //If we're viewing the homepage, look for homepage meta data.
91
+ if (is_home()) {
92
+ $desc = $this->get_setting('home_description');
93
+ if (!$desc && $this->get_setting('home_description_tagline_default')) $desc = get_bloginfo('description');
94
+
95
+ //If we're viewing a post or page, look for its meta data.
96
+ } elseif (is_singular()) {
97
+ $desc = $this->get_postmeta('description');
98
+
99
+ if (!trim($desc) && !post_password_required() && $format = $this->get_setting('description_posttype_'.get_post_type())) {
100
+
101
+ $auto_excerpt = $post->post_content;
102
+ $auto_excerpt = strip_shortcodes($auto_excerpt);
103
+ $auto_excerpt = str_replace(']]>', ']]&gt;', $auto_excerpt);
104
+ $auto_excerpt = strip_tags($auto_excerpt);
105
+ $auto_excerpt = sustr::truncate($auto_excerpt, 150, '', true);
106
+
107
+ $desc = str_replace(
108
+ array('{excerpt::autogen}', '{excerpt}')
109
+ , array($auto_excerpt, strip_tags($post->post_excerpt))
110
+ , $format);
111
+ }
112
+
113
+ //If we're viewing a term, look for its meta data.
114
+ } elseif (suwp::is_tax()) {
115
+ global $wp_query;
116
+ $tax_descriptions = $this->get_setting('taxonomy_descriptions');
117
+ $term_id = $wp_query->get_queried_object_id();
118
+ $term_obj = $wp_query->get_queried_object();
119
+ $desc = isset($tax_descriptions[$term_id]) ? $tax_descriptions[$term_id] : '';
120
+
121
+ if (!trim($desc) && $format = $this->get_setting('description_taxonomy_'.$term_obj->taxonomy)) {
122
+
123
+ $desc = str_replace(
124
+ array('{description}')
125
+ , array($term_obj->description)
126
+ , $format);
127
+ }
128
+ }
129
+
130
+ $desc = trim($desc);
131
+
132
+ if ($desc)
133
+ $desc = $this->get_desc_paged($desc);
134
+
135
+ $desc = trim($desc);
136
+
137
+ $desc = su_esc_attr($desc);
138
+
139
+ return $desc;
140
+ }
141
+
142
+ function get_desc_paged($desc) {
143
+
144
+ global $wp_query, $numpages;
145
+
146
+ if (is_paged() || get_query_var('page')) {
147
+
148
+ if (is_paged()) {
149
+ $num = absint(get_query_var('paged'));
150
+ $max = absint($wp_query->max_num_pages);
151
+ } else {
152
+ $num = absint(get_query_var('page'));
153
+
154
+ if (is_singular()) {
155
+ $post = $wp_query->get_queried_object();
156
+ $max = count(explode('<!--nextpage-->', $post->post_content));
157
+ } else
158
+ $max = '';
159
+ }
160
+
161
+ return str_replace(
162
+ array('{meta_description}', '{num}', '{max}'),
163
+ array( $desc, $num, $max ),
164
+ $this->get_setting('description_paged'));
165
+ } else
166
+ return $desc;
167
+ }
168
+
169
+ function postmeta_fields($fields, $screen) {
170
+ $id = '_su_description';
171
+ $value = su_esc_attr($this->get_postmeta('description'));
172
+
173
+ $fields['serp'][20]['description'] =
174
+ "<div class='form-group su textarea'>\n<label class='col-sm-4 col-md-4 control-label' for='$id'>".__('Meta Description:', 'seo-ultimate')."</label>\n<div class='col-sm-4 col-md-4'>"
175
+ . "<textarea name='$id' id='$id' class='form-control regular-text' cols='60' rows='3' tabindex='2'"
176
+ . " onkeyup=\"javascript:document.getElementById('su_meta_description_charcount').innerHTML = document.getElementById('_su_description').value.length\">$value</textarea>"
177
+ . "</div>\n<div class='col-sm-4 col-md-4 help-text'>".sprintf(__('You&#8217;ve entered %s characters. Most search engines use up to 140.', 'seo-ultimate'), "<strong id='su_meta_description_charcount'>".strlen($value)."</strong>")
178
+ . "</div>\n</div>\n";
179
+
180
+ return $fields;
181
+ }
182
+
183
+ function postmeta_help($help) {
184
+ $help[] = __('<strong>Meta Description</strong> &mdash; The value of the meta description tag. The description will often appear underneath the title in search engine results. Writing an accurate, attention-grabbing description for every post is important to ensuring a good search results clickthrough rate.', 'seo-ultimate');
185
+ return $help;
186
+ }
187
+
188
+ function add_help_tabs($screen) {
189
+
190
+ $screen->add_help_tab(array(
191
+ 'id' => 'su-meta-descriptions-overview'
192
+ , 'title' => __('Overview', 'seo-ultimate')
193
+ , 'content' => __("
194
+ <ul>
195
+ <li><strong>What it does:</strong> Meta Descriptions Editor lets you customize the text that you want to appear under your webpages&#8217; titles in search results.</li>
196
+ <li><strong>Why it helps:</strong> Getting ranked isn&#8217;t enough; once you're ranked, you need visitors to click on your site in the results. That&#8217;s where meta descriptions can help. When you provide text that makes searchers want to visit your site, you can increase your SERP clickthrough rate and thus increase search traffic.</li>
197
+ <li><strong>How to use it:</strong> Enter meta descriptions for your homepage, posts, pages, etc. as desired, and then click Save Changes. 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.</li>
198
+ </ul>
199
+ ", 'seo-ultimate')));
200
+
201
+ $screen->add_help_tab(array(
202
+ 'id' => 'su-meta-descriptions-blog-homepage'
203
+ , 'title' => __('Blog Homepage Tab', 'seo-ultimate')
204
+ , 'content' => __("
205
+ <p>Here&#8217;s information on the various settings:</p>
206
+
207
+ <ul>
208
+ <li><strong>Blog Homepage Meta Description</strong> &mdash; When your blog homepage appears in search results, it&#8217;ll have a title and a description. When you type a description into this box, the Meta Editor will add code to your blog homepage (the <code>&lt;meta name=&quot;description&quot; /&gt;</code> tag) that asks search engines to use what you&#8217;ve entered as the homepage&#8217;s search results description.</li>
209
+ <li><strong>Use this blog&#8217;s tagline as the default homepage description.</strong> &mdash; If this box is checked and if the Blog Homepage Meta Description field is empty, Meta Editor will use your blog&#8217;s tagline as the meta description. You can edit the blog&#8217;s tagline under <a href='options-general.php'>Settings &rArr; General</a>.</li>
210
+ </ul>
211
+ ", 'seo-ultimate')));
212
+
213
+ $screen->add_help_tab(array(
214
+ 'id' => 'su-meta-descriptions-faq'
215
+ , 'title' => __('FAQ', 'seo-ultimate')
216
+ , 'content' => __("
217
+ <ul>
218
+ <li><strong>How do I edit the meta description of my homepage?</strong><br />If you have configured your <a href='options-reading.php'>Settings &rArr; Reading</a> section to use a &#8220;front page&#8221; and/or a &#8220;posts page,&#8221; just edit those pages&#8217;s meta descriptions on the &#8220;Pages&#8221; tab. Otherwise, just use the Blog Homepage field.</li>
219
+ </ul>
220
+ ", 'seo-ultimate')));
221
+
222
+ $screen->add_help_tab(array(
223
+ 'id' => 'su-meta-descriptions-troubleshooting'
224
+ , 'title' => __('Troubleshooting', 'seo-ultimate')
225
+ , 'content' => __("
226
+ <ul>
227
+ <li>
228
+ <p><strong>What do I do if my site has multiple meta tags?</strong><br />First, try removing your theme&#8217;s built-in meta tags if it has them. Go to <a href='theme-editor.php' target='_blank'>Appearance &rArr; Editor</a> and edit <code>header.php</code>. Delete or comment-out any <code>&lt;meta&gt;</code> tags.</p>
229
+ <p>If the problem persists, try disabling other SEO plugins that may be generating meta tags.</p>
230
+ <p>Troubleshooting tip: Go to <a href='options-general.php?page=seo-ultimate'>Settings &rArr; SEO Ultimate</a> and enable the &#8220;Identify the plugin&#8217;s HTML code insertions with HTML comment tags&#8221; option. This will mark SEO Ultimate&#8217;s meta tags with comments, allowing you to see which meta tags are generated by SEO Ultimate and which aren&#8217;t.</p>
231
+ </li>
232
+ </ul>
233
+ ", 'seo-ultimate')));
234
+
235
+ }
236
+
237
+ }
238
+
239
+ }
240
  ?>
modules/meta/meta-keywords.php CHANGED
@@ -1,227 +1,227 @@
1
- <?php
2
- /**
3
- * Meta Keywords Editor Module
4
- *
5
- * @since 4.0
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- function su_meta_keywords_export_filter($all_settings) {
11
- unset($all_settings['meta']['taxonomy_keywords']);
12
- return $all_settings;
13
- }
14
- add_filter('su_settings_export_array', 'su_meta_keywords_export_filter');
15
-
16
- class SU_MetaKeywords extends SU_Module {
17
-
18
- static function get_module_title() { return __('Meta Keywords Editor', 'seo-ultimate'); }
19
- static function get_menu_title() { return __('Meta Keywords', 'seo-ultimate'); }
20
- function get_settings_key() { return 'meta'; }
21
- function get_default_status() { return SU_MODULE_DISABLED; }
22
-
23
- function init() {
24
- add_action('su_head', array(&$this, 'head_tag_output'));
25
- }
26
-
27
- function get_default_settings() {
28
- return array(
29
- 'auto_keywords_posttype_post_words_value' => 3
30
- , 'auto_keywords_posttype_page_words_value' => 3
31
- , 'auto_keywords_posttype_attachment_words_value' => 3
32
- );
33
- }
34
-
35
- function get_admin_page_tabs() {
36
- return array_merge(
37
- array(
38
- array('title' => __('Sitewide Values', 'seo-ultimate'), 'id' => 'su-sitewide-values', 'callback' => 'global_tab')
39
- , array('title' => __('Default Values', 'seo-ultimate'), 'id' => 'su-default-values', 'callback' => 'defaults_tab')
40
- , array('title' => __('Blog Homepage', 'seo-ultimate'), 'id' => 'su-blog-homepage', 'callback' => 'home_tab')
41
- )
42
- , $this->get_meta_edit_tabs(array(
43
- 'type' => 'textbox'
44
- , 'name' => 'keywords'
45
- , 'term_settings_key' => 'taxonomy_keywords'
46
- , 'label' => __('Meta Keywords', 'seo-ultimate')
47
- ))
48
- );
49
- }
50
-
51
- function global_tab() {
52
- $this->admin_form_table_start();
53
- $this->textarea('global_keywords', __('Sitewide Keywords', 'seo-ultimate') . '<br /><small><em>' . __('(Separate with commas)', 'seo-ultimate') . '</em></small>');
54
- $this->admin_form_table_end();
55
- }
56
-
57
- function defaults_tab() {
58
- $this->admin_form_table_start();
59
-
60
- $posttypenames = get_post_types(array('public' => true), 'names');
61
- foreach ($posttypenames as $posttypename) {
62
- $posttype = get_post_type_object($posttypename);
63
- $posttypelabel = $posttype->labels->name;
64
-
65
- $checkboxes = array();
66
-
67
- if (post_type_supports($posttypename, 'editor'))
68
- $checkboxes["auto_keywords_posttype_{$posttypename}_words"] = __('The %d most commonly-used words', 'seo-ultimate');
69
-
70
- $taxnames = get_object_taxonomies($posttypename);
71
-
72
- foreach ($taxnames as $taxname) {
73
- $taxonomy = get_taxonomy($taxname);
74
- $checkboxes["auto_keywords_posttype_{$posttypename}_tax_{$taxname}"] = $taxonomy->labels->name;
75
- }
76
-
77
- if ($checkboxes)
78
- $this->checkboxes($checkboxes, $posttypelabel);
79
- }
80
-
81
- $this->admin_form_table_end();
82
- }
83
-
84
- function home_tab() {
85
- $this->admin_form_table_start();
86
- $this->textarea('home_keywords', __('Blog Homepage Meta Keywords', 'seo-ultimate'), 3);
87
- $this->admin_form_table_end();
88
- }
89
-
90
- function head_tag_output() {
91
- global $post;
92
-
93
- $kw = false;
94
-
95
- //If we're viewing the homepage, look for homepage meta data.
96
- if (is_home()) {
97
- $kw = $this->get_setting('home_keywords');
98
-
99
- //If we're viewing a post or page...
100
- } elseif (is_singular()) {
101
-
102
- //...look for its meta data
103
- $kw = $this->get_postmeta('keywords');
104
-
105
- //...and add default values
106
- if ($posttypename = get_post_type()) {
107
- $taxnames = get_object_taxonomies($posttypename);
108
-
109
- foreach ($taxnames as $taxname) {
110
- if ($this->get_setting("auto_keywords_posttype_{$posttypename}_tax_{$taxname}", false)) {
111
- $terms = get_the_terms(0, $taxname);
112
- $terms = suarr::flatten_values($terms, 'name');
113
- $terms = implode(',', $terms);
114
- $kw .= ',' . $terms;
115
- }
116
- }
117
-
118
- if ($this->get_setting("auto_keywords_posttype_{$posttypename}_words", false)) {
119
- $words = preg_split("/[\s+]/", strip_tags($post->post_content), null, PREG_SPLIT_NO_EMPTY);
120
- $words = array_count_values($words);
121
- arsort($words);
122
- $words = array_filter($words, array(&$this, 'filter_word_counts'));
123
- $words = array_keys($words);
124
- $stopwords = suarr::explode_lines($this->get_setting('words_to_remove', array(), 'slugs'));
125
- $stopwords = array_map(array('sustr', 'tolower'), $stopwords);
126
- $words = array_map(array('sustr', 'tolower'), $words);
127
- $words = array_diff($words, $stopwords);
128
- $words = array_slice($words, 0, $this->get_setting("auto_keywords_posttype_{$posttypename}_words_value"));
129
- $words = implode(',', $words);
130
- $kw .= ',' . $words;
131
- }
132
- }
133
-
134
- //If we're viewing a term, look for its meta data.
135
- } elseif (suwp::is_tax()) {
136
- global $wp_query;
137
- $tax_keywords = $this->get_setting('taxonomy_keywords');
138
-
139
- $term_id = $wp_query->get_queried_object_id();
140
- if (isset($tax_keywords[$term_id]))
141
- $kw = $tax_keywords[$term_id];
142
- else
143
- $kw = '';
144
- }
145
-
146
- if ($globals = $this->get_setting('global_keywords')) {
147
- if (strlen($kw)) $kw .= ',';
148
- $kw .= $globals;
149
- }
150
-
151
- $kw = str_replace(array("\r\n", "\n"), ',', $kw);
152
- $kw = explode(',', $kw);
153
- $kw = array_map('trim', $kw); //Remove extra spaces from beginning/end of keywords
154
- $kw = array_filter($kw); //Remove blank keywords
155
- $kw = suarr::array_unique_i($kw); //Remove duplicate keywords
156
- $kw = implode(',', $kw);
157
-
158
- //Do we have keywords? If so, output them.
159
- if ($kw) {
160
- $kw = su_esc_attr($kw);
161
- echo "\t<meta name=\"keywords\" content=\"$kw\" />\n";
162
- }
163
- }
164
-
165
- function filter_word_counts($count) {
166
- return $count > 1;
167
- }
168
-
169
- function postmeta_fields($fields, $screen) {
170
- $fields['25|keywords'] = $this->get_postmeta_textbox('keywords', __('Meta Keywords:<br /><em>(separate with commas)</em>', 'seo-ultimate'));
171
- return $fields;
172
- }
173
-
174
- function add_help_tabs($screen) {
175
-
176
- $screen->add_help_tab(array(
177
- 'id' => 'su-meta-keywords-overview'
178
- , 'title' => __('Overview', 'seo-ultimate')
179
- , 'content' => __("
180
- <p>Meta Keywords Editor lets you tell search engines what keywords are associated with the various pages on your site. Modern search engines don&#8217;t give meta keywords much weight, if any at all, but the option is there if you want to use it.</p>
181
- ", 'seo-ultimate')));
182
-
183
- $screen->add_help_tab(array(
184
- 'id' => 'su-meta-keywords-global'
185
- , 'title' => __('Sitewide Settings Tab', 'seo-ultimate')
186
- , 'content' => __("
187
- <ul>
188
- <li><strong>Sitewide Keywords</strong> &mdash; Here you can enter keywords that describe the overall subject matter of your entire blog. Use commas to separate keywords. These keywords will be put in the <code>&gt;meta name=&quot;keywords&quot; /&gt;</code> tags of all webpages on the site (homepage, posts, pages, archives, etc.).</li>
189
- </ul>
190
- ", 'seo-ultimate')));
191
-
192
- $screen->add_help_tab(array(
193
- 'id' => 'su-meta-keywords-home'
194
- , 'title' => __('Blog Homepage Tab', 'seo-ultimate')
195
- , 'content' => __("
196
- <ul>
197
- <li><strong>Blog Homepage Meta Keywords</strong> &mdash; These keywords will be applied only to the <em>blog</em> homepage. Note that if you&#8217;ve specified a &#8220;front page&#8221; under <a href='options-reading.php'>Settings &rArr; Reading</a>, you&#8217;ll need to edit your frontpage and set your frontpage keywords there.</li>
198
- </ul>
199
- ", 'seo-ultimate')));
200
-
201
- $screen->add_help_tab(array(
202
- 'id' => 'su-meta-keywords-faq'
203
- , 'title' => __('FAQ', 'seo-ultimate')
204
- , 'content' => __("
205
- <ul>
206
- <li><strong>How do I edit the meta keywords of my homepage?</strong><br />If you have configured your <a href='options-reading.php'>Settings &rArr; Reading</a> section to use a &#8220;front page&#8221; and/or a &#8220;posts page,&#8221; just edit those pages&#8217;s meta keywords on the &#8220;Pages&#8221; tab. Otherwise, just use the Blog Homepage field.</li>
207
- <li><strong>What happens if I add a global keyword that I previously assigned to individual posts or pages?</strong><br />Don&#8217;t worry; Meta Keywords Editor will remove duplicate keywords automatically.</li>
208
- </ul>
209
- ", 'seo-ultimate')));
210
-
211
- $screen->add_help_tab(array(
212
- 'id' => 'su-meta-keywords-troubleshooting'
213
- , 'title' => __('Troubleshooting', 'seo-ultimate')
214
- , 'content' => __("
215
- <ul>
216
- <li>
217
- <p><strong>What do I do if my site has multiple meta tags?</strong><br />First, try removing your theme&#8217;s built-in meta tags if it has them. Go to <a href='theme-editor.php' target='_blank'>Appearance &rArr; Editor</a> and edit <code>header.php</code>. Delete or comment-out any <code>&lt;meta&gt;</code> tags.</p>
218
- <p>If the problem persists, try disabling other SEO plugins that may be generating meta tags.</p>
219
- <p>Troubleshooting tip: Go to <a href='options-general.php?page=seo-ultimate'>Settings &rArr; SEO Ultimate</a> and enable the &#8220;Insert comments around HTML code insertions&#8221; option. This will mark SEO Ultimate&#8217;s meta tags with comments, allowing you to see which meta tags are generated by SEO Ultimate and which aren&#8217;t.</p>
220
- </li>
221
- </ul>
222
- ", 'seo-ultimate')));
223
- }
224
- }
225
-
226
- }
227
  ?>
1
+ <?php
2
+ /**
3
+ * Meta Keywords Editor Module
4
+ *
5
+ * @since 4.0
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ function su_meta_keywords_export_filter($all_settings) {
11
+ unset($all_settings['meta']['taxonomy_keywords']);
12
+ return $all_settings;
13
+ }
14
+ add_filter('su_settings_export_array', 'su_meta_keywords_export_filter');
15
+
16
+ class SU_MetaKeywords extends SU_Module {
17
+
18
+ static function get_module_title() { return __('Meta Keywords Editor', 'seo-ultimate'); }
19
+ static function get_menu_title() { return __('Meta Keywords', 'seo-ultimate'); }
20
+ function get_settings_key() { return 'meta'; }
21
+ function get_default_status() { return SU_MODULE_DISABLED; }
22
+
23
+ function init() {
24
+ add_action('su_head', array(&$this, 'head_tag_output'));
25
+ }
26
+
27
+ function get_default_settings() {
28
+ return array(
29
+ 'auto_keywords_posttype_post_words_value' => 3
30
+ , 'auto_keywords_posttype_page_words_value' => 3
31
+ , 'auto_keywords_posttype_attachment_words_value' => 3
32
+ );
33
+ }
34
+
35
+ function get_admin_page_tabs() {
36
+ return array_merge(
37
+ array(
38
+ array('title' => __('Sitewide Values', 'seo-ultimate'), 'id' => 'su-sitewide-values', 'callback' => 'global_tab')
39
+ , array('title' => __('Default Values', 'seo-ultimate'), 'id' => 'su-default-values', 'callback' => 'defaults_tab')
40
+ , array('title' => __('Blog Homepage', 'seo-ultimate'), 'id' => 'su-blog-homepage', 'callback' => 'home_tab')
41
+ )
42
+ , $this->get_meta_edit_tabs(array(
43
+ 'type' => 'textbox'
44
+ , 'name' => 'keywords'
45
+ , 'term_settings_key' => 'taxonomy_keywords'
46
+ , 'label' => __('Meta Keywords', 'seo-ultimate')
47
+ ))
48
+ );
49
+ }
50
+
51
+ function global_tab() {
52
+ $this->admin_form_table_start();
53
+ $this->textarea('global_keywords', __('Sitewide Keywords', 'seo-ultimate') . '<br /><small><em>' . __('(Separate with commas)', 'seo-ultimate') . '</em></small>');
54
+ $this->admin_form_table_end();
55
+ }
56
+
57
+ function defaults_tab() {
58
+ $this->admin_form_table_start();
59
+
60
+ $posttypenames = get_post_types(array('public' => true), 'names');
61
+ foreach ($posttypenames as $posttypename) {
62
+ $posttype = get_post_type_object($posttypename);
63
+ $posttypelabel = $posttype->labels->name;
64
+
65
+ $checkboxes = array();
66
+
67
+ if (post_type_supports($posttypename, 'editor'))
68
+ $checkboxes["auto_keywords_posttype_{$posttypename}_words"] = __('The %d most commonly-used words', 'seo-ultimate');
69
+
70
+ $taxnames = get_object_taxonomies($posttypename);
71
+
72
+ foreach ($taxnames as $taxname) {
73
+ $taxonomy = get_taxonomy($taxname);
74
+ $checkboxes["auto_keywords_posttype_{$posttypename}_tax_{$taxname}"] = $taxonomy->labels->name;
75
+ }
76
+
77
+ if ($checkboxes)
78
+ $this->checkboxes($checkboxes, $posttypelabel);
79
+ }
80
+
81
+ $this->admin_form_table_end();
82
+ }
83
+
84
+ function home_tab() {
85
+ $this->admin_form_table_start();
86
+ $this->textarea('home_keywords', __('Blog Homepage Meta Keywords', 'seo-ultimate'), 3);
87
+ $this->admin_form_table_end();
88
+ }
89
+
90
+ function head_tag_output() {
91
+ global $post;
92
+
93
+ $kw = false;
94
+
95
+ //If we're viewing the homepage, look for homepage meta data.
96
+ if (is_home()) {
97
+ $kw = $this->get_setting('home_keywords');
98
+
99
+ //If we're viewing a post or page...
100
+ } elseif (is_singular()) {
101
+
102
+ //...look for its meta data
103
+ $kw = $this->get_postmeta('keywords');
104
+
105
+ //...and add default values
106
+ if ($posttypename = get_post_type()) {
107
+ $taxnames = get_object_taxonomies($posttypename);
108
+
109
+ foreach ($taxnames as $taxname) {
110
+ if ($this->get_setting("auto_keywords_posttype_{$posttypename}_tax_{$taxname}", false)) {
111
+ $terms = get_the_terms(0, $taxname);
112
+ $terms = suarr::flatten_values($terms, 'name');
113
+ $terms = implode(',', $terms);
114
+ $kw .= ',' . $terms;
115
+ }
116
+ }
117
+
118
+ if ($this->get_setting("auto_keywords_posttype_{$posttypename}_words", false)) {
119
+ $words = preg_split("/[\s+]/", strip_tags($post->post_content), null, PREG_SPLIT_NO_EMPTY);
120
+ $words = array_count_values($words);
121
+ arsort($words);
122
+ $words = array_filter($words, array(&$this, 'filter_word_counts'));
123
+ $words = array_keys($words);
124
+ $stopwords = suarr::explode_lines($this->get_setting('words_to_remove', array(), 'slugs'));
125
+ $stopwords = array_map(array('sustr', 'tolower'), $stopwords);
126
+ $words = array_map(array('sustr', 'tolower'), $words);
127
+ $words = array_diff($words, $stopwords);
128
+ $words = array_slice($words, 0, $this->get_setting("auto_keywords_posttype_{$posttypename}_words_value"));
129
+ $words = implode(',', $words);
130
+ $kw .= ',' . $words;
131
+ }
132
+ }
133
+
134
+ //If we're viewing a term, look for its meta data.
135
+ } elseif (suwp::is_tax()) {
136
+ global $wp_query;
137
+ $tax_keywords = $this->get_setting('taxonomy_keywords');
138
+
139
+ $term_id = $wp_query->get_queried_object_id();
140
+ if (isset($tax_keywords[$term_id]))
141
+ $kw = $tax_keywords[$term_id];
142
+ else
143
+ $kw = '';
144
+ }
145
+
146
+ if ($globals = $this->get_setting('global_keywords')) {
147
+ if (strlen($kw)) $kw .= ',';
148
+ $kw .= $globals;
149
+ }
150
+
151
+ $kw = str_replace(array("\r\n", "\n"), ',', $kw);
152
+ $kw = explode(',', $kw);
153
+ $kw = array_map('trim', $kw); //Remove extra spaces from beginning/end of keywords
154
+ $kw = array_filter($kw); //Remove blank keywords
155
+ $kw = suarr::array_unique_i($kw); //Remove duplicate keywords
156
+ $kw = implode(',', $kw);
157
+
158
+ //Do we have keywords? If so, output them.
159
+ if ($kw) {
160
+ $kw = su_esc_attr($kw);
161
+ echo "\t<meta name=\"keywords\" content=\"$kw\" />\n";
162
+ }
163
+ }
164
+
165
+ function filter_word_counts($count) {
166
+ return $count > 1;
167
+ }
168
+
169
+ function postmeta_fields($fields, $screen) {
170
+ $fields['25|keywords'] = $this->get_postmeta_textbox('keywords', __('Meta Keywords:<br /><em>(separate with commas)</em>', 'seo-ultimate'));
171
+ return $fields;
172
+ }
173
+
174
+ function add_help_tabs($screen) {
175
+
176
+ $screen->add_help_tab(array(
177
+ 'id' => 'su-meta-keywords-overview'
178
+ , 'title' => __('Overview', 'seo-ultimate')
179
+ , 'content' => __("
180
+ <p>Meta Keywords Editor lets you tell search engines what keywords are associated with the various pages on your site. Modern search engines don&#8217;t give meta keywords much weight, if any at all, but the option is there if you want to use it.</p>
181
+ ", 'seo-ultimate')));
182
+
183
+ $screen->add_help_tab(array(
184
+ 'id' => 'su-meta-keywords-global'
185
+ , 'title' => __('Sitewide Settings Tab', 'seo-ultimate')
186
+ , 'content' => __("
187
+ <ul>
188
+ <li><strong>Sitewide Keywords</strong> &mdash; Here you can enter keywords that describe the overall subject matter of your entire blog. Use commas to separate keywords. These keywords will be put in the <code>&gt;meta name=&quot;keywords&quot; /&gt;</code> tags of all webpages on the site (homepage, posts, pages, archives, etc.).</li>
189
+ </ul>
190
+ ", 'seo-ultimate')));
191
+
192
+ $screen->add_help_tab(array(
193
+ 'id' => 'su-meta-keywords-home'
194
+ , 'title' => __('Blog Homepage Tab', 'seo-ultimate')
195
+ , 'content' => __("
196
+ <ul>
197
+ <li><strong>Blog Homepage Meta Keywords</strong> &mdash; These keywords will be applied only to the <em>blog</em> homepage. Note that if you&#8217;ve specified a &#8220;front page&#8221; under <a href='options-reading.php'>Settings &rArr; Reading</a>, you&#8217;ll need to edit your frontpage and set your frontpage keywords there.</li>
198
+ </ul>
199
+ ", 'seo-ultimate')));
200
+
201
+ $screen->add_help_tab(array(
202
+ 'id' => 'su-meta-keywords-faq'
203
+ , 'title' => __('FAQ', 'seo-ultimate')
204
+ , 'content' => __("
205
+ <ul>
206
+ <li><strong>How do I edit the meta keywords of my homepage?</strong><br />If you have configured your <a href='options-reading.php'>Settings &rArr; Reading</a> section to use a &#8220;front page&#8221; and/or a &#8220;posts page,&#8221; just edit those pages&#8217;s meta keywords on the &#8220;Pages&#8221; tab. Otherwise, just use the Blog Homepage field.</li>
207
+ <li><strong>What happens if I add a global keyword that I previously assigned to individual posts or pages?</strong><br />Don&#8217;t worry; Meta Keywords Editor will remove duplicate keywords automatically.</li>
208
+ </ul>
209
+ ", 'seo-ultimate')));
210
+
211
+ $screen->add_help_tab(array(
212
+ 'id' => 'su-meta-keywords-troubleshooting'
213
+ , 'title' => __('Troubleshooting', 'seo-ultimate')
214
+ , 'content' => __("
215
+ <ul>
216
+ <li>
217
+ <p><strong>What do I do if my site has multiple meta tags?</strong><br />First, try removing your theme&#8217;s built-in meta tags if it has them. Go to <a href='theme-editor.php' target='_blank'>Appearance &rArr; Editor</a> and edit <code>header.php</code>. Delete or comment-out any <code>&lt;meta&gt;</code> tags.</p>
218
+ <p>If the problem persists, try disabling other SEO plugins that may be generating meta tags.</p>
219
+ <p>Troubleshooting tip: Go to <a href='options-general.php?page=seo-ultimate'>Settings &rArr; SEO Ultimate</a> and enable the &#8220;Insert comments around HTML code insertions&#8221; option. This will mark SEO Ultimate&#8217;s meta tags with comments, allowing you to see which meta tags are generated by SEO Ultimate and which aren&#8217;t.</p>
220
+ </li>
221
+ </ul>
222
+ ", 'seo-ultimate')));
223
+ }
224
+ }
225
+
226
+ }
227
  ?>
modules/meta/meta-robots.css CHANGED
@@ -1,8 +1,8 @@
1
- #su-meta-robots table.widefat {
2
- width: auto;
3
- }
4
-
5
- #su-meta-robots table.widefat td.su-meta_robots_noindex,
6
- #su-meta-robots table.widefat td.su-meta_robots_nofollow {
7
- text-align: center;
8
  }
1
+ #su-meta-robots table.widefat {
2
+ width: auto;
3
+ }
4
+
5
+ #su-meta-robots table.widefat td.su-meta_robots_noindex,
6
+ #su-meta-robots table.widefat td.su-meta_robots_nofollow {
7
+ text-align: center;
8
  }
modules/meta/meta-robots.php CHANGED
@@ -1,117 +1,117 @@
1
- <?php
2
- /**
3
- * Meta Robot Tags Editor Module
4
- *
5
- * @since 4.0
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_MetaRobots extends SU_Module {
11
-
12
- static function get_module_title() { return __('Meta Robot Tags Editor', 'seo-ultimate'); }
13
- static function get_menu_title() { return __('Meta Robot Tags', 'seo-ultimate'); }
14
- function get_settings_key() { return 'meta'; }
15
-
16
- function init() {
17
- add_filter('su_meta_robots', array(&$this, 'meta_robots'));
18
- }
19
-
20
- function get_admin_page_tabs() {
21
- return array(
22
- array('title' => __('Sitewide Values', 'seo-ultimate'), 'id' => 'su-sitewide-values', 'callback' => 'global_tab')
23
- );
24
- }
25
-
26
- function global_tab() {
27
- $this->admin_form_table_start();
28
- $this->checkboxes(array(
29
- 'noodp' => __('Don&#8217t use this site&#8217s Open Directory description in search results.', 'seo-ultimate')
30
- , 'noydir' => __('Don&#8217t use this site&#8217s Yahoo! Directory description in search results.', 'seo-ultimate')
31
- , 'noarchive' => __('Don&#8217t cache or archive this site.', 'seo-ultimate')
32
- ), __('Spider Instructions', 'seo-ultimate'));
33
- $this->admin_form_table_end();
34
- }
35
-
36
- //Add the appropriate commands to the meta robots array
37
- function meta_robots($commands) {
38
-
39
- $tags = array('noodp', 'noydir', 'noarchive');
40
-
41
- foreach ($tags as $tag) {
42
- if ($this->get_setting($tag)) $commands[] = $tag;
43
- }
44
-
45
- return $commands;
46
- }
47
-
48
- function add_help_tabs($screen) {
49
-
50
- $screen->add_help_tab(array(
51
- 'id' => 'su-meta-robots-overview'
52
- , 'title' => __('Overview', 'seo-ultimate')
53
- , 'content' => __("
54
- <ul>
55
- <li><strong>What it does:</strong> Meta Robot Tags Editor lets you convey instructions to search engine spiders, as well as prohibit the spiders from indexing certain webpages on your blog using the <code>&lt;meta name=&quot;robots&quot; content=&quot;noindex&quot; /&gt;</code> tag.</li>
56
- <li><strong>Why it helps:</strong> The &#8220;Global&#8221; tab lets you stop DMOZ or Yahoo! Directory from overriding your custom meta descriptions, as well as prevent spiders from caching your site if you so desire. The &#8220;Default Values&#8221; tab lets you deindex entire sections of your site that contain content unimportant to visitors (e.g. the administration section), or sections of your site that mostly contain duplicate content (e.g. date archives). The editor tabs can do something similar, but for individual content items. By removing webpages from search results that visitors find unhelpful, you can help increase the focus on your more useful content.</li>
57
- <li><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 use the editor tabs to deindex individual content items on your site as well as enable the &#8220;nofollow&#8221; meta parameter that will nullify all outgoing links on a specific webpage.</li>
58
- </ul>
59
- ", 'seo-ultimate')));
60
-
61
- $screen->add_help_tab(array(
62
- 'id' => 'su-meta-robots-global'
63
- , 'title' => __('Sitewide Settings Tab', 'seo-ultimate')
64
- , 'content' => __("
65
- <ul>
66
- <li><strong>Don&#8217;t use this site&#8217;s Open Directory / Yahoo! Directory description in search results</strong> &mdash; If your site is listed in the <a href='http://www.dmoz.org/' target='_blank'>Open Directory (DMOZ)</a> or the <a href='http://dir.yahoo.com/' target='_blank'>Yahoo! Directory</a>, some search engines may use your directory listing as the meta description. These boxes tell search engines not to do that and will give you full control over your meta descriptions. These settings have no effect if your site isn&#8217;t listed in the Open Directory or Yahoo! Directory respectively.</li>
67
- <li><strong>Don&#8217;t cache or archive this site</strong> &mdash; When you check this box, Meta Editor will ask search engines (Google, Yahoo!, Bing, etc.) and archivers (Archive.org, etc.) to <em>not</em> make cached or archived &#8220;copies&#8221; of your site.</li>
68
- </ul>
69
- ", 'seo-ultimate')));
70
-
71
- $screen->add_help_tab(array(
72
- 'id' => 'su-meta-robots-defaults'
73
- , 'title' => __('Default Values Tab', 'seo-ultimate')
74
- , 'content' => __("
75
- <p><strong>Prevent indexing of&hellip;</strong></p>
76
- <ul>
77
- <li><strong>Administration back-end pages</strong> &mdash; Tells spiders not to index the administration area (the part you&#8217;re in now), in the unlikely event a spider somehow gains access to the administration. Recommended.</li>
78
- <li><strong>Author archives</strong> &mdash; Tells spiders not to index author archives. Useful if your blog only has one author.</li>
79
- <li><strong>Blog search pages</strong> &mdash; Tells spiders not to index the result pages of WordPress's blog search function. Recommended.</li>
80
- <li><strong>Category archives</strong> &mdash; Tells spiders not to index category archives. Recommended only if you don't use categories.</li>
81
- <li><strong>Comment feeds</strong> &mdash; Tells spiders not to index the RSS feeds that exist for every post's comments. (These comment feeds are totally separate from your normal blog feeds.)</li>
82
- <li><strong>Comment subpages</strong> &mdash; Tells spiders not to index posts' comment subpages.</li>
83
- <li><strong>Date-based archives</strong> &mdash; Tells spiders not to index day/month/year archives. Recommended, since these pages have little keyword value.</li>
84
- <li><strong>Subpages of the homepage</strong> &mdash; Tells spiders not to index the homepage's subpages (page 2, page 3, etc). Recommended.</li>
85
- <li><strong>Tag archives</strong> &mdash; Tells spiders not to index tag archives. Recommended only if you don't use tags.</li>
86
- <li><strong>User login/registration pages</strong> &mdash; Tells spiders not to index WordPress's user login and registration pages. Recommended.</li>
87
- </ul>
88
- ", 'seo-ultimate')));
89
-
90
- $screen->add_help_tab(array(
91
- 'id' => 'su-meta-robots-metaedit'
92
- , 'title' => __('Bulk Editor Tabs', 'seo-ultimate')
93
- , 'content' => __("
94
- <ul>
95
- <li><strong>Noindex</strong> &mdash; Checking this for an item will ask search engines to remove that item&#8217;s webpage from their indices. Use this to remove pages that you don&#8217;t want showing up in search results (such as a Privacy Policy page, for example).</li>
96
- <li><strong>Nofollow</strong> &mdash; Checking this for an item will tell search engines to ignore the links to other webpages that are on that item&#8217;s webpage. Note: this is page-level &#8220;meta nofollow,&#8221; not to be confused with link-level &#8220;rel nofollow.&#8221;</li>
97
- </ul>
98
- ", 'seo-ultimate')));
99
-
100
- $screen->add_help_tab(array(
101
- 'id' => 'su-meta-robots-troubleshooting'
102
- , 'title' => __('Troubleshooting', 'seo-ultimate')
103
- , 'content' => __("
104
- <ul>
105
- <li>
106
- <p><strong>What do I do if my site has multiple meta tags?</strong><br />First, try removing your theme&#8217;s built-in meta tags if it has them. Go to <a href='theme-editor.php' target='_blank'>Appearance &rArr; Editor</a> and edit <code>header.php</code>. Delete or comment-out any <code>&lt;meta&gt;</code> tags.</p>
107
- <p>If the problem persists, try disabling other SEO plugins that may be generating meta tags.</p>
108
- <p>Troubleshooting tip: Go to <a href='options-general.php?page=seo-ultimate'>Settings &rArr; SEO Ultimate</a> and enable the &#8220;Insert comments around HTML code insertions&#8221; option. This will mark SEO Ultimate&#8217;s meta tags with comments, allowing you to see which meta tags are generated by SEO Ultimate and which aren&#8217;t.</p>
109
- </li>
110
- </ul>
111
- ", 'seo-ultimate')));
112
-
113
- }
114
- }
115
-
116
- }
117
  ?>
1
+ <?php
2
+ /**
3
+ * Meta Robot Tags Editor Module
4
+ *
5
+ * @since 4.0
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_MetaRobots extends SU_Module {
11
+
12
+ static function get_module_title() { return __('Meta Robot Tags Editor', 'seo-ultimate'); }
13
+ static function get_menu_title() { return __('Meta Robot Tags', 'seo-ultimate'); }
14
+ function get_settings_key() { return 'meta'; }
15
+
16
+ function init() {
17
+ add_filter('su_meta_robots', array(&$this, 'meta_robots'));
18
+ }
19
+
20
+ function get_admin_page_tabs() {
21
+ return array(
22
+ array('title' => __('Sitewide Values', 'seo-ultimate'), 'id' => 'su-sitewide-values', 'callback' => 'global_tab')
23
+ );
24
+ }
25
+
26
+ function global_tab() {
27
+ $this->admin_form_table_start();
28
+ $this->checkboxes(array(
29
+ 'noodp' => __('Don&#8217t use this site&#8217s Open Directory description in search results.', 'seo-ultimate')
30
+ , 'noydir' => __('Don&#8217t use this site&#8217s Yahoo! Directory description in search results.', 'seo-ultimate')
31
+ , 'noarchive' => __('Don&#8217t cache or archive this site.', 'seo-ultimate')
32
+ ), __('Spider Instructions', 'seo-ultimate'));
33
+ $this->admin_form_table_end();
34
+ }
35
+
36
+ //Add the appropriate commands to the meta robots array
37
+ function meta_robots($commands) {
38
+
39
+ $tags = array('noodp', 'noydir', 'noarchive');
40
+
41
+ foreach ($tags as $tag) {
42
+ if ($this->get_setting($tag)) $commands[] = $tag;
43
+ }
44
+
45
+ return $commands;
46
+ }
47
+
48
+ function add_help_tabs($screen) {
49
+
50
+ $screen->add_help_tab(array(
51
+ 'id' => 'su-meta-robots-overview'
52
+ , 'title' => __('Overview', 'seo-ultimate')
53
+ , 'content' => __("
54
+ <ul>
55
+ <li><strong>What it does:</strong> Meta Robot Tags Editor lets you convey instructions to search engine spiders, as well as prohibit the spiders from indexing certain webpages on your blog using the <code>&lt;meta name=&quot;robots&quot; content=&quot;noindex&quot; /&gt;</code> tag.</li>
56
+ <li><strong>Why it helps:</strong> The &#8220;Global&#8221; tab lets you stop DMOZ or Yahoo! Directory from overriding your custom meta descriptions, as well as prevent spiders from caching your site if you so desire. The &#8220;Default Values&#8221; tab lets you deindex entire sections of your site that contain content unimportant to visitors (e.g. the administration section), or sections of your site that mostly contain duplicate content (e.g. date archives). The editor tabs can do something similar, but for individual content items. By removing webpages from search results that visitors find unhelpful, you can help increase the focus on your more useful content.</li>
57
+ <li><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 use the editor tabs to deindex individual content items on your site as well as enable the &#8220;nofollow&#8221; meta parameter that will nullify all outgoing links on a specific webpage.</li>
58
+ </ul>
59
+ ", 'seo-ultimate')));
60
+
61
+ $screen->add_help_tab(array(
62
+ 'id' => 'su-meta-robots-global'
63
+ , 'title' => __('Sitewide Settings Tab', 'seo-ultimate')
64
+ , 'content' => __("
65
+ <ul>
66
+ <li><strong>Don&#8217;t use this site&#8217;s Open Directory / Yahoo! Directory description in search results</strong> &mdash; If your site is listed in the <a href='http://www.dmoz.org/' target='_blank'>Open Directory (DMOZ)</a> or the <a href='http://dir.yahoo.com/' target='_blank'>Yahoo! Directory</a>, some search engines may use your directory listing as the meta description. These boxes tell search engines not to do that and will give you full control over your meta descriptions. These settings have no effect if your site isn&#8217;t listed in the Open Directory or Yahoo! Directory respectively.</li>
67
+ <li><strong>Don&#8217;t cache or archive this site</strong> &mdash; When you check this box, Meta Editor will ask search engines (Google, Yahoo!, Bing, etc.) and archivers (Archive.org, etc.) to <em>not</em> make cached or archived &#8220;copies&#8221; of your site.</li>
68
+ </ul>
69
+ ", 'seo-ultimate')));
70
+
71
+ $screen->add_help_tab(array(
72
+ 'id' => 'su-meta-robots-defaults'
73
+ , 'title' => __('Default Values Tab', 'seo-ultimate')
74
+ , 'content' => __("
75
+ <p><strong>Prevent indexing of&hellip;</strong></p>
76
+ <ul>
77
+ <li><strong>Administration back-end pages</strong> &mdash; Tells spiders not to index the administration area (the part you&#8217;re in now), in the unlikely event a spider somehow gains access to the administration. Recommended.</li>
78
+ <li><strong>Author archives</strong> &mdash; Tells spiders not to index author archives. Useful if your blog only has one author.</li>
79
+ <li><strong>Blog search pages</strong> &mdash; Tells spiders not to index the result pages of WordPress's blog search function. Recommended.</li>
80
+ <li><strong>Category archives</strong> &mdash; Tells spiders not to index category archives. Recommended only if you don't use categories.</li>
81
+ <li><strong>Comment feeds</strong> &mdash; Tells spiders not to index the RSS feeds that exist for every post's comments. (These comment feeds are totally separate from your normal blog feeds.)</li>
82
+ <li><strong>Comment subpages</strong> &mdash; Tells spiders not to index posts' comment subpages.</li>
83
+ <li><strong>Date-based archives</strong> &mdash; Tells spiders not to index day/month/year archives. Recommended, since these pages have little keyword value.</li>
84
+ <li><strong>Subpages of the homepage</strong> &mdash; Tells spiders not to index the homepage's subpages (page 2, page 3, etc). Recommended.</li>
85
+ <li><strong>Tag archives</strong> &mdash; Tells spiders not to index tag archives. Recommended only if you don't use tags.</li>
86
+ <li><strong>User login/registration pages</strong> &mdash; Tells spiders not to index WordPress's user login and registration pages. Recommended.</li>
87
+ </ul>
88
+ ", 'seo-ultimate')));
89
+
90
+ $screen->add_help_tab(array(
91
+ 'id' => 'su-meta-robots-metaedit'
92
+ , 'title' => __('Bulk Editor Tabs', 'seo-ultimate')
93
+ , 'content' => __("
94
+ <ul>
95
+ <li><strong>Noindex</strong> &mdash; Checking this for an item will ask search engines to remove that item&#8217;s webpage from their indices. Use this to remove pages that you don&#8217;t want showing up in search results (such as a Privacy Policy page, for example).</li>
96
+ <li><strong>Nofollow</strong> &mdash; Checking this for an item will tell search engines to ignore the links to other webpages that are on that item&#8217;s webpage. Note: this is page-level &#8220;meta nofollow,&#8221; not to be confused with link-level &#8220;rel nofollow.&#8221;</li>
97
+ </ul>
98
+ ", 'seo-ultimate')));
99
+
100
+ $screen->add_help_tab(array(
101
+ 'id' => 'su-meta-robots-troubleshooting'
102
+ , 'title' => __('Troubleshooting', 'seo-ultimate')
103
+ , 'content' => __("
104
+ <ul>
105
+ <li>
106
+ <p><strong>What do I do if my site has multiple meta tags?</strong><br />First, try removing your theme&#8217;s built-in meta tags if it has them. Go to <a href='theme-editor.php' target='_blank'>Appearance &rArr; Editor</a> and edit <code>header.php</code>. Delete or comment-out any <code>&lt;meta&gt;</code> tags.</p>
107
+ <p>If the problem persists, try disabling other SEO plugins that may be generating meta tags.</p>
108
+ <p>Troubleshooting tip: Go to <a href='options-general.php?page=seo-ultimate'>Settings &rArr; SEO Ultimate</a> and enable the &#8220;Insert comments around HTML code insertions&#8221; option. This will mark SEO Ultimate&#8217;s meta tags with comments, allowing you to see which meta tags are generated by SEO Ultimate and which aren&#8217;t.</p>
109
+ </li>
110
+ </ul>
111
+ ", 'seo-ultimate')));
112
+
113
+ }
114
+ }
115
+
116
+ }
117
  ?>
modules/meta/webmaster-verify.css CHANGED
@@ -1,21 +1,21 @@
1
-
2
- #su-webmaster-verify td {
3
- vertical-align: middle;
4
- }
5
-
6
- #su-webmaster-verify .su-webmaster-verify-meta_tag_before {
7
- padding-right: 0;
8
- }
9
-
10
- #su-webmaster-verify td.su-webmaster-verify-meta_tag_before {
11
- text-align: right;
12
- }
13
-
14
- #su-webmaster-verify .su-webmaster-verify-meta_tag {
15
- padding-left: 0;
16
- padding-right: 0;
17
- }
18
-
19
- #su-webmaster-verify .su-webmaster-verify-meta_tag_after {
20
- padding-left: 0;
21
  }
1
+
2
+ #su-webmaster-verify td {
3
+ vertical-align: middle;
4
+ }
5
+
6
+ #su-webmaster-verify .su-webmaster-verify-meta_tag_before {
7
+ padding-right: 0;
8
+ }
9
+
10
+ #su-webmaster-verify td.su-webmaster-verify-meta_tag_before {
11
+ text-align: right;
12
+ }
13
+
14
+ #su-webmaster-verify .su-webmaster-verify-meta_tag {
15
+ padding-left: 0;
16
+ padding-right: 0;
17
+ }
18
+
19
+ #su-webmaster-verify .su-webmaster-verify-meta_tag_after {
20
+ padding-left: 0;
21
  }
modules/meta/webmaster-verify.php CHANGED
@@ -1,110 +1,110 @@
1
- <?php
2
- /**
3
- * Webmaster Verification Assistant Module
4
- *
5
- * @since 4.0
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_WebmasterVerify extends SU_Module {
11
-
12
- static function get_module_title() { return __('Webmaster Verification Assistant', 'seo-ultimate'); }
13
- static function get_menu_title() { return __('W.M. Verification', 'seo-ultimate'); }
14
-
15
- static function get_parent_module() { return 'misc'; }
16
- function get_settings_key() { return 'meta'; }
17
-
18
- function init() {
19
- add_action('su_head', array(&$this, 'head_tag_output'));
20
- }
21
-
22
- function get_supported_search_engines() {
23
- return array(
24
- 'google' => array(
25
- 'title' => __('Google Webmaster Tools', 'seo-ultimate')
26
- , 'meta_name' => 'google-site-verification'
27
- ), 'microsoft' => array(
28
- 'title' => __('Bing Webmaster Center', 'seo-ultimate')
29
- , 'meta_name' => 'msvalidate.01'
30
- )
31
- );
32
- }
33
-
34
- function head_tag_output() {
35
- $verify = $this->get_supported_search_engines();
36
- foreach ($verify as $site => $site_data) {
37
- $name = $site_data['meta_name'];
38
- //Do we have verification tags? If so, output them.
39
- if ($value = $this->get_setting($site.'_verify')) {
40
- if (current_user_can('unfiltered_html') && sustr::startswith(trim($value), '<meta ') && sustr::endswith(trim($value), '/>'))
41
- echo "\t".trim($value)."\n";
42
- else {
43
- $value = su_esc_attr($value);
44
- echo "\t<meta name=\"$name\" content=\"$value\" />\n";
45
- }
46
- }
47
- }
48
- }
49
-
50
- function admin_page_contents() {
51
-
52
- $this->child_admin_form_start(false);
53
-
54
- $this->admin_wftable_start(array(
55
- 'portal' => __('Webmaster Portal', 'seo-ultimate')
56
- , 'meta_tag_before' => __('Meta Tag', 'seo-ultimate')
57
- , 'meta_tag' => ' '
58
- , 'meta_tag_after' => ' '
59
- ));
60
-
61
- $sites = $this->get_supported_search_engines();
62
-
63
- foreach ($sites as $site => $site_data) {
64
- echo "<tr>\n";
65
- echo "<td class='su-webmaster-verify-portal'>" . esc_html($site_data['title']) . "</td>\n";
66
- echo "<td class='su-webmaster-verify-meta_tag_before'>&lt;meta name=&quot;"
67
- . esc_html($site_data['meta_name']) . "&quot; content=&quot;</td>\n";
68
- echo "<td class='su-webmaster-verify-meta_tag'>";
69
- $this->textbox("{$site}_verify", '', false, false, array('in_table' => false));
70
- echo "</td>\n";
71
- echo "<td class='su-webmaster-verify-meta_tag_after'>&quot; /&gt;</td>\n";
72
- echo "</tr>\n";
73
- }
74
-
75
- $this->admin_wftable_end();
76
-
77
- $this->child_admin_form_end(false);
78
- }
79
-
80
- function add_help_tabs($screen) {
81
-
82
- $overview = __("
83
- <ul>
84
- <li><strong>What it does:</strong> Webmaster Verification Assistant lets you enter in verification codes for the webmaster portals of leading search engines.</li>
85
- <li><strong>Why it helps:</strong> Webmaster Verification Assistant assists you in obtaining access to webmaster portals, which can provide you with valuable SEO tools.</li>
86
- <li><strong>How to use it:</strong> Use a search engine to locate the webmaster portal you&#8217;re interested in, sign up at the portal, and then obtain a verification code. Once you have the code, you can paste it in here, click Save Changes, then return to the portal to verify that you own the site. Once that&#8217;s done, you'll have access to the portal&#8217;s SEO tools.</li>
87
- </ul>
88
- ", 'seo-ultimate');
89
-
90
- if ($this->has_enabled_parent()) {
91
- $screen->add_help_tab(array(
92
- 'id' => 'su-webmaster-verify-help'
93
- , 'title' => __('Webmaster Verification Assistant', 'seo-ultimate')
94
- , 'content' =>
95
- '<h3>' . __('Overview', 'seo-ultimate') . '</h3>' . $overview
96
- ));
97
- } else {
98
-
99
- $screen->add_help_tab(array(
100
- 'id' => 'su-webmaster-verify-overview'
101
- , 'title' => __('Overview', 'seo-ultimate')
102
- , 'content' => $overview));
103
-
104
- }
105
- }
106
-
107
- }
108
-
109
- }
110
  ?>
1
+ <?php
2
+ /**
3
+ * Webmaster Verification Assistant Module
4
+ *
5
+ * @since 4.0
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_WebmasterVerify extends SU_Module {
11
+
12
+ static function get_module_title() { return __('Webmaster Verification Assistant', 'seo-ultimate'); }
13
+ static function get_menu_title() { return __('W.M. Verification', 'seo-ultimate'); }
14
+
15
+ static function get_parent_module() { return 'misc'; }
16
+ function get_settings_key() { return 'meta'; }
17
+
18
+ function init() {
19
+ add_action('su_head', array(&$this, 'head_tag_output'));
20
+ }
21
+
22
+ function get_supported_search_engines() {
23
+ return array(
24
+ 'google' => array(
25
+ 'title' => __('Google Webmaster Tools', 'seo-ultimate')
26
+ , 'meta_name' => 'google-site-verification'
27
+ ), 'microsoft' => array(
28
+ 'title' => __('Bing Webmaster Center', 'seo-ultimate')
29
+ , 'meta_name' => 'msvalidate.01'
30
+ )
31
+ );
32
+ }
33
+
34
+ function head_tag_output() {
35
+ $verify = $this->get_supported_search_engines();
36
+ foreach ($verify as $site => $site_data) {
37
+ $name = $site_data['meta_name'];
38
+ //Do we have verification tags? If so, output them.
39
+ if ($value = $this->get_setting($site.'_verify')) {
40
+ if (current_user_can('unfiltered_html') && sustr::startswith(trim($value), '<meta ') && sustr::endswith(trim($value), '/>'))
41
+ echo "\t".trim($value)."\n";
42
+ else {
43
+ $value = su_esc_attr($value);
44
+ echo "\t<meta name=\"$name\" content=\"$value\" />\n";
45
+ }
46
+ }
47
+ }
48
+ }
49
+
50
+ function admin_page_contents() {
51
+
52
+ $this->child_admin_form_start(false);
53
+
54
+ $this->admin_wftable_start(array(
55
+ 'portal' => __('Webmaster Portal', 'seo-ultimate')
56
+ , 'meta_tag_before' => __('Meta Tag', 'seo-ultimate')
57
+ , 'meta_tag' => ' '
58
+ , 'meta_tag_after' => ' '
59
+ ));
60
+
61
+ $sites = $this->get_supported_search_engines();
62
+
63
+ foreach ($sites as $site => $site_data) {
64
+ echo "<tr>\n";
65
+ echo "<td class='su-webmaster-verify-portal'>" . esc_html($site_data['title']) . "</td>\n";
66
+ echo "<td class='su-webmaster-verify-meta_tag_before'>&lt;meta name=&quot;"
67
+ . esc_html($site_data['meta_name']) . "&quot; content=&quot;</td>\n";
68
+ echo "<td class='su-webmaster-verify-meta_tag'>";
69
+ $this->textbox("{$site}_verify", '', false, false, array('in_table' => false));
70
+ echo "</td>\n";
71
+ echo "<td class='su-webmaster-verify-meta_tag_after'>&quot; /&gt;</td>\n";
72
+ echo "</tr>\n";
73
+ }
74
+
75
+ $this->admin_wftable_end();
76
+
77
+ $this->child_admin_form_end(false);
78
+ }
79
+
80
+ function add_help_tabs($screen) {
81
+
82
+ $overview = __("
83
+ <ul>
84
+ <li><strong>What it does:</strong> Webmaster Verification Assistant lets you enter in verification codes for the webmaster portals of leading search engines.</li>
85
+ <li><strong>Why it helps:</strong> Webmaster Verification Assistant assists you in obtaining access to webmaster portals, which can provide you with valuable SEO tools.</li>
86
+ <li><strong>How to use it:</strong> Use a search engine to locate the webmaster portal you&#8217;re interested in, sign up at the portal, and then obtain a verification code. Once you have the code, you can paste it in here, click Save Changes, then return to the portal to verify that you own the site. Once that&#8217;s done, you'll have access to the portal&#8217;s SEO tools.</li>
87
+ </ul>
88
+ ", 'seo-ultimate');
89
+
90
+ if ($this->has_enabled_parent()) {
91
+ $screen->add_help_tab(array(
92
+ 'id' => 'su-webmaster-verify-help'
93
+ , 'title' => __('Webmaster Verification Assistant', 'seo-ultimate')
94
+ , 'content' =>
95
+ '<h3>' . __('Overview', 'seo-ultimate') . '</h3>' . $overview
96
+ ));
97
+ } else {
98
+
99
+ $screen->add_help_tab(array(
100
+ 'id' => 'su-webmaster-verify-overview'
101
+ , 'title' => __('Overview', 'seo-ultimate')
102
+ , 'content' => $overview));
103
+
104
+ }
105
+ }
106
+
107
+ }
108
+
109
+ }
110
  ?>
modules/misc/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/misc/misc.php CHANGED
@@ -1,42 +1,42 @@
1
- <?php
2
- /**
3
- * Miscellaneous Module
4
- *
5
- * @since 5.8
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_Misc extends SU_Module {
11
- static function get_module_title() { return __('Miscellaneous', 'seo-ultimate'); }
12
- static function get_menu_title() { return __('Miscellaneous', 'seo-ultimate'); }
13
- static function get_menu_pos() { return 30; }
14
- function admin_page_contents() {
15
-
16
- echo "\n\n<div class='row'>\n";
17
-
18
- if ($this->should_show_sdf_theme_promo()) {
19
- echo "\n\n<div class='col-sm-8 col-md-9'>\n";
20
- }
21
- else {
22
- echo "\n\n<div class='col-md-12'>\n";
23
- }
24
-
25
- echo '<p>' . __('The Miscellaneous page contains modules that don&#8217;t have enough settings to warrant their own separate admin pages.', 'seo-ultimate') . '</p>';
26
- $this->children_admin_pages_form();
27
-
28
- echo "\n\n</div>\n";
29
-
30
- if ($this->should_show_sdf_theme_promo()) {
31
- echo "\n\n<div class='col-sm-4 col-md-3'>\n";
32
- $this->promo_sdf_banners();
33
- echo "\n\n</div>\n";
34
- }
35
-
36
- echo "\n\n</div>\n";
37
-
38
- }
39
- }
40
-
41
- }
42
  ?>
1
+ <?php
2
+ /**
3
+ * Miscellaneous Module
4
+ *
5
+ * @since 5.8
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_Misc extends SU_Module {
11
+ static function get_module_title() { return __('Miscellaneous', 'seo-ultimate'); }
12
+ static function get_menu_title() { return __('Miscellaneous', 'seo-ultimate'); }
13
+ static function get_menu_pos() { return 30; }
14
+ function admin_page_contents() {
15
+
16
+ echo "\n\n<div class='row'>\n";
17
+
18
+ if ($this->should_show_sdf_theme_promo()) {
19
+ echo "\n\n<div class='col-sm-8 col-md-9'>\n";
20
+ }
21
+ else {
22
+ echo "\n\n<div class='col-md-12'>\n";
23
+ }
24
+
25
+ echo '<p>' . __('The Miscellaneous page contains modules that don&#8217;t have enough settings to warrant their own separate admin pages.', 'seo-ultimate') . '</p>';
26
+ $this->children_admin_pages_form();
27
+
28
+ echo "\n\n</div>\n";
29
+
30
+ if ($this->should_show_sdf_theme_promo()) {
31
+ echo "\n\n<div class='col-sm-4 col-md-3'>\n";
32
+ $this->promo_sdf_banners();
33
+ echo "\n\n</div>\n";
34
+ }
35
+
36
+ echo "\n\n</div>\n";
37
+
38
+ }
39
+ }
40
+
41
+ }
42
  ?>
modules/modules.css CHANGED
@@ -1,167 +1,167 @@
1
- /* ADMIN PAGES */
2
-
3
- div.sdf-admin {
4
- padding-bottom: 1em;
5
- }
6
-
7
- div.sdf-admin h2 {
8
- margin-bottom: 0.5em;
9
- }
10
-
11
- div.sdf-admin h4.su-subheader {
12
- font-size: 1.17em;
13
- margin: 3em 0 1em;
14
- padding-top: 1em;
15
- border-top: 3px solid #ccc;
16
- }
17
-
18
- div.sdf-admin table.widefat {
19
- width: auto;
20
- }
21
-
22
- div.sdf-admin table.fullwidth,
23
- div.sdf-admin table.fullwidth input.regular-text {
24
- width: 100%;
25
- }
26
-
27
- div.sdf-admin table.widefat td {
28
- padding-right: 2em;
29
- }
30
-
31
- div.sdf-admin table.widefat td ul {
32
- list-style-type: disc;
33
- margin-left: 1em;
34
- padding-left: 1em;
35
- }
36
-
37
- div.sdf-admin .form-table .regular-text,
38
- div.sdf-admin .form-table .jls_text_dest {
39
- width: 325px;
40
- }
41
-
42
- div.sdf-admin .form-table .subfield {
43
- width: auto;
44
- }
45
-
46
- div.sdf-admin .form-table div div.field {
47
- padding-bottom: 1em;
48
- }
49
-
50
- div.sdf-admin .form-table label.su-indent {
51
- padding-left: 3em;
52
- }
53
-
54
-
55
- div.sdf-admin table.report {
56
- border-collapse: collapse;
57
- border-top: 1px solid #ccc;
58
- }
59
-
60
- div.sdf-admin table.report th {
61
- font-weight: normal;
62
- }
63
-
64
- div.sdf-admin table.report th, div.sdf-admin table.report td {
65
- padding: 1em 3em 1em 0;
66
- border-bottom: 1px solid #ccc;
67
- text-align: left;
68
- }
69
-
70
- div.sdf-admin table.su-indent {
71
- padding-left: 30px;
72
- }
73
-
74
- div.sdf-admin table.su-indent th {
75
- font-weight: normal;
76
- }
77
-
78
- div.sdf-admin table.form-table table.su-indent th {
79
- font-size: 1.1em;
80
- }
81
-
82
- div.sdf-admin table.su-indent th:after { content: ":"; }
83
-
84
- div.sdf-admin table tr.su-indent-level-1 .su-field-label { padding-left: 1em; }
85
- div.sdf-admin table tr.su-indent-level-2 .su-field-label { padding-left: 3em; }
86
- div.sdf-admin table tr.su-indent-level-3 .su-field-label { padding-left: 5em; }
87
- div.sdf-admin table tr.su-indent-level-4 .su-field-label { padding-left: 7em; }
88
-
89
- div.sdf-admin table tr.su-indent .su-field-label {
90
- line-height: 1em;
91
- }
92
-
93
- div.sdf-admin table tr.su-indent .su-child-fields-toggle,
94
- div.sdf-admin table tr.su-indent .su-child-fields-toggle-filler {
95
- display: block;
96
- float: left;
97
- width: 1em;
98
- }
99
-
100
- div.sdf-admin table tr.su-indent .su-child-fields-toggle {
101
- text-align: center;
102
- cursor: pointer;
103
- border: 1px solid #666;
104
- border-radius: 2px;
105
- background-color: #eee;
106
- }
107
-
108
- div.sdf-admin table tr.su-indent .su-field-label-text {
109
- display: block;
110
- padding-left: 2em;
111
- }
112
-
113
- div.su-importmodule div.su-status {
114
- padding-top: 0.5em;
115
- padding-bottom: 0.5em;
116
- }
117
-
118
- div.su-importmodule #import-status {
119
- padding: 1em 0;
120
- }
121
-
122
- div.sdf-admin textarea[disabled] {
123
- background-color: #eee;
124
- }
125
-
126
- /* META EDIT TABLE */
127
-
128
- div.sdf-admin .su-meta-edit-table table.widefat,
129
- div.sdf-admin .su-meta-edit-table table.widefat .regular-text { width: 100%; }
130
- div.sdf-admin .su-meta-edit-table table.widefat td.su-actions { width: 8em; }
131
- div.sdf-admin .su-meta-edit-table table.widefat td.su-id { width: 2em; }
132
- div.sdf-admin .su-meta-edit-table table.widefat td.su-name { width: 20em; }
133
- div.sdf-admin .su-meta-edit-table table.widefat td { vertical-align: middle; }
134
-
135
- div.sdf-admin .su-meta-edit-table .su-meta-table-post-status {
136
- font-style: italic;
137
- color: #999;
138
- }
139
-
140
- /* IMPORT MODULES */
141
-
142
- .sdf-admin table#import-status {
143
- border: 0;
144
- width: auto;
145
- margin: 2em 0;
146
- }
147
-
148
- .sdf-admin table#import-status td {
149
- padding: 0 0.5em 1em 0;
150
- }
151
-
152
- .su-importmodule tr.su-admin-form-checkbox td,
153
- .su-importmodule tr.su-admin-form-textblock td {
154
- border-top: 3px solid #ccc;
155
- padding-top: 1em;
156
- }
157
-
158
- .su-importmodule table.form-table {
159
- border-bottom: 3px solid #ccc;
160
- }
161
-
162
- .su-importmodule td table tr.su-admin-form-checkbox td,
163
- .su-importmodule td table tr.su-admin-form-textblock td {
164
- border-top: 0 none;
165
- padding-top: 0;
166
- padding-bottom: 0;
167
  }
1
+ /* ADMIN PAGES */
2
+
3
+ div.sdf-admin {
4
+ padding-bottom: 1em;
5
+ }
6
+
7
+ div.sdf-admin h2 {
8
+ margin-bottom: 0.5em;
9
+ }
10
+
11
+ div.sdf-admin h4.su-subheader {
12
+ font-size: 1.17em;
13
+ margin: 3em 0 1em;
14
+ padding-top: 1em;
15
+ border-top: 3px solid #ccc;
16
+ }
17
+
18
+ div.sdf-admin table.widefat {
19
+ width: auto;
20
+ }
21
+
22
+ div.sdf-admin table.fullwidth,
23
+ div.sdf-admin table.fullwidth input.regular-text {
24
+ width: 100%;
25
+ }
26
+
27
+ div.sdf-admin table.widefat td {
28
+ padding-right: 2em;
29
+ }
30
+
31
+ div.sdf-admin table.widefat td ul {
32
+ list-style-type: disc;
33
+ margin-left: 1em;
34
+ padding-left: 1em;
35
+ }
36
+
37
+ div.sdf-admin .form-table .regular-text,
38
+ div.sdf-admin .form-table .jls_text_dest {
39
+ width: 325px;
40
+ }
41
+
42
+ div.sdf-admin .form-table .subfield {
43
+ width: auto;
44
+ }
45
+
46
+ div.sdf-admin .form-table div div.field {
47
+ padding-bottom: 1em;
48
+ }
49
+
50
+ div.sdf-admin .form-table label.su-indent {
51
+ padding-left: 3em;
52
+ }
53
+
54
+
55
+ div.sdf-admin table.report {
56
+ border-collapse: collapse;
57
+ border-top: 1px solid #ccc;
58
+ }
59
+
60
+ div.sdf-admin table.report th {
61
+ font-weight: normal;
62
+ }
63
+
64
+ div.sdf-admin table.report th, div.sdf-admin table.report td {
65
+ padding: 1em 3em 1em 0;
66
+ border-bottom: 1px solid #ccc;
67
+ text-align: left;
68
+ }
69
+
70
+ div.sdf-admin table.su-indent {
71
+ padding-left: 30px;
72
+ }
73
+
74
+ div.sdf-admin table.su-indent th {
75
+ font-weight: normal;
76
+ }
77
+
78
+ div.sdf-admin table.form-table table.su-indent th {
79
+ font-size: 1.1em;
80
+ }
81
+
82
+ div.sdf-admin table.su-indent th:after { content: ":"; }
83
+
84
+ div.sdf-admin table tr.su-indent-level-1 .su-field-label { padding-left: 1em; }
85
+ div.sdf-admin table tr.su-indent-level-2 .su-field-label { padding-left: 3em; }
86
+ div.sdf-admin table tr.su-indent-level-3 .su-field-label { padding-left: 5em; }
87
+ div.sdf-admin table tr.su-indent-level-4 .su-field-label { padding-left: 7em; }
88
+
89
+ div.sdf-admin table tr.su-indent .su-field-label {
90
+ line-height: 1em;
91
+ }
92
+
93
+ div.sdf-admin table tr.su-indent .su-child-fields-toggle,
94
+ div.sdf-admin table tr.su-indent .su-child-fields-toggle-filler {
95
+ display: block;
96
+ float: left;
97
+ width: 1em;
98
+ }
99
+
100
+ div.sdf-admin table tr.su-indent .su-child-fields-toggle {
101
+ text-align: center;
102
+ cursor: pointer;
103
+ border: 1px solid #666;
104
+ border-radius: 2px;
105
+ background-color: #eee;
106
+ }
107
+
108
+ div.sdf-admin table tr.su-indent .su-field-label-text {
109
+ display: block;
110
+ padding-left: 2em;
111
+ }
112
+
113
+ div.su-importmodule div.su-status {
114
+ padding-top: 0.5em;
115
+ padding-bottom: 0.5em;
116
+ }
117
+
118
+ div.su-importmodule #import-status {
119
+ padding: 1em 0;
120
+ }
121
+
122
+ div.sdf-admin textarea[disabled] {
123
+ background-color: #eee;
124
+ }
125
+
126
+ /* META EDIT TABLE */
127
+
128
+ div.sdf-admin .su-meta-edit-table table.widefat,
129
+ div.sdf-admin .su-meta-edit-table table.widefat .regular-text { width: 100%; }
130
+ div.sdf-admin .su-meta-edit-table table.widefat td.su-actions { width: 8em; }
131
+ div.sdf-admin .su-meta-edit-table table.widefat td.su-id { width: 2em; }
132
+ div.sdf-admin .su-meta-edit-table table.widefat td.su-name { width: 20em; }
133
+ div.sdf-admin .su-meta-edit-table table.widefat td { vertical-align: middle; }
134
+
135
+ div.sdf-admin .su-meta-edit-table .su-meta-table-post-status {
136
+ font-style: italic;
137
+ color: #999;
138
+ }
139
+
140
+ /* IMPORT MODULES */
141
+
142
+ .sdf-admin table#import-status {
143
+ border: 0;
144
+ width: auto;
145
+ margin: 2em 0;
146
+ }
147
+
148
+ .sdf-admin table#import-status td {
149
+ padding: 0 0.5em 1em 0;
150
+ }
151
+
152
+ .su-importmodule tr.su-admin-form-checkbox td,
153
+ .su-importmodule tr.su-admin-form-textblock td {
154
+ border-top: 3px solid #ccc;
155
+ padding-top: 1em;
156
+ }
157
+
158
+ .su-importmodule table.form-table {
159
+ border-bottom: 3px solid #ccc;
160
+ }
161
+
162
+ .su-importmodule td table tr.su-admin-form-checkbox td,
163
+ .su-importmodule td table tr.su-admin-form-textblock td {
164
+ border-top: 0 none;
165
+ padding-top: 0;
166
+ padding-bottom: 0;
167
  }
modules/modules.js CHANGED
@@ -1,48 +1,48 @@
1
- /*global jQuery:false, alert */
2
- (function($) {
3
- "use strict";
4
- jQuery(document).ready(function($) {
5
- $('input, textarea, select', 'div.sdf-admin').change(su_enable_unload_confirm);
6
- $('form', 'div.sdf-admin').submit(su_disable_unload_confirm);
7
-
8
- $('#wpbody').on('click', '.su_toggle_hide', function(e) {
9
- e.preventDefault();
10
- var selector = $(this).data('toggle'),
11
- to_toggle = $('#'+selector);
12
- to_toggle.slideToggle();
13
- });
14
- $('#wpbody').on('click', '.su_toggle_up', function(e) {
15
- e.preventDefault();
16
- var selector = $(this).data('toggle'),
17
- to_toggle = $('#'+selector);
18
- to_toggle.slideToggle();
19
- });
20
- });
21
- })(jQuery);
22
-
23
- function su_reset_textbox(id, d, m, e) {
24
- if (confirm(m+"\n\n"+d)) {
25
- document.getElementById(id).value=d;
26
- e.className='hidden';
27
- su_enable_unload_confirm();
28
- }
29
- }
30
-
31
- function su_textbox_value_changed(e, d, l) {
32
- if (e.value==d)
33
- document.getElementById(l).className='hidden';
34
- else
35
- document.getElementById(l).className='';
36
- }
37
-
38
- function su_enable_unload_confirm() {
39
- window.onbeforeunload = su_confirm_unload_message;
40
- }
41
-
42
- function su_disable_unload_confirm() {
43
- window.onbeforeunload = null;
44
- }
45
-
46
- function su_confirm_unload_message() {
47
- return suModulesModulesL10n.unloadConfirmMessage;
48
- }
1
+ /*global jQuery:false, alert */
2
+ (function($) {
3
+ "use strict";
4
+ jQuery(document).ready(function($) {
5
+ $('input, textarea, select', 'div.sdf-admin').change(su_enable_unload_confirm);
6
+ $('form', 'div.sdf-admin').submit(su_disable_unload_confirm);
7
+
8
+ $('#wpbody').on('click', '.su_toggle_hide', function(e) {
9
+ e.preventDefault();
10
+ var selector = $(this).data('toggle'),
11
+ to_toggle = $('#'+selector);
12
+ to_toggle.slideToggle();
13
+ });
14
+ $('#wpbody').on('click', '.su_toggle_up', function(e) {
15
+ e.preventDefault();
16
+ var selector = $(this).data('toggle'),
17
+ to_toggle = $('#'+selector);
18
+ to_toggle.slideToggle();
19
+ });
20
+ });
21
+ })(jQuery);
22
+
23
+ function su_reset_textbox(id, d, m, e) {
24
+ if (confirm(m+"\n\n"+d)) {
25
+ document.getElementById(id).value=d;
26
+ e.className='hidden';
27
+ su_enable_unload_confirm();
28
+ }
29
+ }
30
+
31
+ function su_textbox_value_changed(e, d, l) {
32
+ if (e.value==d)
33
+ document.getElementById(l).className='hidden';
34
+ else
35
+ document.getElementById(l).className='';
36
+ }
37
+
38
+ function su_enable_unload_confirm() {
39
+ window.onbeforeunload = su_confirm_unload_message;
40
+ }
41
+
42
+ function su_disable_unload_confirm() {
43
+ window.onbeforeunload = null;
44
+ }
45
+
46
+ function su_confirm_unload_message() {
47
+ return suModulesModulesL10n.unloadConfirmMessage;
48
+ }
modules/modules/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/modules/modules.css CHANGED
@@ -1,11 +1,11 @@
1
- #su-modules table.widefat {
2
- clear: left;
3
- }
4
-
5
- #su-modules .module-status a.status-10.active { color: green; }
6
- #su-modules .module-status a.status-5.active { color: black; }
7
- #su-modules .module-status a.status-0.active { color: darkorange; }
8
- #su-modules .module-status a.status-n10.active { color: red; }
9
- #su-modules .module-name { color: #767676; }
10
- #su-modules .module-name a.module-link { color: #0074A2; }
11
  #su-modules .module-name a.module-link:hover { color: #0074A2; }
1
+ #su-modules table.widefat {
2
+ clear: left;
3
+ }
4
+
5
+ #su-modules .module-status a.status-10.active { color: green; }
6
+ #su-modules .module-status a.status-5.active { color: black; }
7
+ #su-modules .module-status a.status-0.active { color: darkorange; }
8
+ #su-modules .module-status a.status-n10.active { color: red; }
9
+ #su-modules .module-name { color: #767676; }
10
+ #su-modules .module-name a.module-link { color: #0074A2; }
11
  #su-modules .module-name a.module-link:hover { color: #0074A2; }
modules/modules/modules.js CHANGED
@@ -1,9 +1,9 @@
1
-
2
- function set_module_status(key, input_value, a_obj) {
3
- var td_id = "module-status-"+key;
4
- var input_id = "su-"+key+"-module-status";
5
-
6
- jQuery("div#"+td_id+" a").removeClass("active");
7
- document.getElementById(input_id).value = input_value;
8
- a_obj.className += " active";
9
  }
1
+
2
+ function set_module_status(key, input_value, a_obj) {
3
+ var td_id = "module-status-"+key;
4
+ var input_id = "su-"+key+"-module-status";
5
+
6
+ jQuery("div#"+td_id+" a").removeClass("active");
7
+ document.getElementById(input_id).value = input_value;
8
+ a_obj.className += " active";
9
  }
modules/modules/modules.php CHANGED
@@ -1,236 +1,236 @@
1
- <?php
2
- /**
3
- * Module Manager Module
4
- *
5
- * @since 0.7
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_Modules extends SU_Module {
11
-
12
- static function get_module_title() { return __('Module Manager', 'seo-ultimate'); }
13
- static function get_menu_title() { return __('Modules', 'seo-ultimate'); }
14
- static function get_menu_pos() { return 0; }
15
- function is_menu_default(){ return true; }
16
-
17
- function init() {
18
-
19
- if ($this->is_action('update')) {
20
-
21
- $psdata = (array)get_option('seo_ultimate', array());
22
-
23
- foreach ($_POST as $key => $newvalue) {
24
- if (substr($key, 0, 3) == 'su-') {
25
- $key = str_replace(array('su-', '-module-status'), '', $key);
26
-
27
- $newvalue = intval($newvalue);
28
- $oldvalue = $psdata['modules'][$key];
29
-
30
- if ($oldvalue != $newvalue) {
31
- if ($oldvalue == SU_MODULE_DISABLED)
32
- $this->plugin->call_module_func($key, 'activate');
33
- if ($newvalue == SU_MODULE_DISABLED)
34
- $this->plugin->call_module_func($key, 'deactivate');
35
- }
36
-
37
- $psdata['modules'][$key] = $newvalue;
38
- }
39
- }
40
-
41
- update_option('seo_ultimate', $psdata);
42
-
43
- wp_redirect(add_query_arg('su-modules-updated', '1', suurl::current()), 301);
44
- exit;
45
- }
46
- }
47
-
48
- function admin_page_contents() {
49
-
50
- echo '<div class="row">';
51
- echo '<div class="col-sm-8 col-md-9">';
52
- echo '<div class="bs-callout bs-callout-grey"><p>';
53
- _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');
54
- echo "</p>\n<p>";
55
- _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');
56
- echo "</p></div>\n";
57
-
58
- if (!empty($_GET['su-modules-updated']))
59
- $this->print_message('success', __('Modules updated.', 'seo-ultimate'));
60
-
61
- $this->admin_form_start(false, false);
62
-
63
- $headers = array(
64
- __('Status', 'seo-ultimate')
65
- , __('Module', 'seo-ultimate')
66
- );
67
-
68
- echo <<<STR
69
- <div class="panel panel-default">
70
- <div class="panel-heading">
71
- <div class="row">
72
- <div class="col-sm-4 col-md-4">
73
- <h3 class="panel-title step-title module-status">{$headers[0]}</h3>
74
- </div>
75
- <div class="col-sm-4 col-md-4">
76
- <h3 class="panel-title step-title module-name">{$headers[1]}</h3>
77
- </div>
78
- </div>
79
- </div>
80
- <div class="panel-body">
81
-
82
- STR;
83
-
84
- $statuses = array(
85
- SU_MODULE_ENABLED => __('Enabled', 'seo-ultimate')
86
- , SU_MODULE_SILENCED => __('Silenced', 'seo-ultimate')
87
- , SU_MODULE_HIDDEN => __('Hidden', 'seo-ultimate')
88
- , SU_MODULE_DISABLED => __('Disabled', 'seo-ultimate')
89
- );
90
- $buttons = array(
91
- SU_MODULE_ENABLED => 'btn-success'
92
- , SU_MODULE_SILENCED => 'btn-default'
93
- , SU_MODULE_HIDDEN => 'btn-warning'
94
- , SU_MODULE_DISABLED => 'btn-danger'
95
- );
96
-
97
- $modules = array();
98
-
99
- foreach ($this->plugin->modules as $key => $x_module) {
100
- $module =& $this->plugin->modules[$key];
101
-
102
- //On some setups, get_parent_class() returns the class name in lowercase
103
- if (strcasecmp(get_parent_class($module), 'SU_Module') == 0 && !in_array($key, $this->plugin->get_invincible_modules()) && $module->is_independent_module())
104
- $modules[$key] = $module->get_module_title();
105
- }
106
-
107
- foreach ($this->plugin->disabled_modules as $key => $class) {
108
-
109
- if (call_user_func(array($class, 'is_independent_module')))
110
- $modules[$key] = call_user_func(array($class, 'get_module_title'));
111
- }
112
-
113
- asort($modules);
114
-
115
- //Do we have any modules requiring the "Silenced" column? Store that boolean in $any_hmc
116
- $any_hmc = false;
117
- foreach ($modules as $key => $name) {
118
- if ($this->plugin->call_module_func($key, 'has_menu_count', $hmc) && $hmc) {
119
- $any_hmc = true;
120
- break;
121
- }
122
- }
123
-
124
- $psdata = (array)get_option('seo_ultimate', array());
125
-
126
- foreach ($modules as $key => $name) {
127
-
128
- $currentstatus = $psdata['modules'][$key];
129
-
130
- echo "\t\t<div class='form-group'>\n\t\t\t<div class='col-sm-4 col-md-4'>\n";
131
- echo "\t\t\t<div class='btn-group sdf_toggle module-status' id='module-status-$key'>\n";
132
-
133
- $hidden_is_hidden = ($this->plugin->call_module_func($key, 'get_menu_title', $module_menu_title) && $module_menu_title === false)
134
- || ($this->plugin->call_module_func($key, 'is_independent_module', $is_independent_module) && $is_independent_module &&
135
- $this->plugin->call_module_func($key, 'get_parent_module', $parent_module) && $parent_module &&
136
- $this->plugin->module_exists($parent_module));
137
-
138
- foreach ($statuses as $statuscode => $statuslabel) {
139
-
140
- $hmc = ($this->plugin->call_module_func($key, 'has_menu_count', $_hmc) && $_hmc);
141
-
142
- $is_current = false;
143
- $style = '';
144
- switch ($statuscode) {
145
- case SU_MODULE_ENABLED:
146
- if (($currentstatus == SU_MODULE_SILENCED && !$hmc) ||
147
- ($currentstatus == SU_MODULE_HIDDEN && $hidden_is_hidden))
148
- $is_current = true;
149
- break;
150
- case SU_MODULE_SILENCED:
151
- if (!$any_hmc) continue 2; //break out of switch and foreach
152
- if (!$hmc) $style = " style='visibility: hidden;'";
153
- break;
154
- case SU_MODULE_HIDDEN:
155
- if ($hidden_is_hidden)
156
- $style = " style='visibility: hidden;'";
157
- break;
158
- }
159
-
160
- if ($is_current || $currentstatus == $statuscode) {
161
- $current = ' active';
162
- }
163
- else {
164
- $current = '';
165
- }
166
- $codeclass = str_replace('-', 'n', strval($statuscode));
167
- echo "\t\t\t\t\t";
168
- echo "<a href='javascript:void(0)' onclick=\"javascript:set_module_status('$key', $statuscode, this)\" type='button' class='status-$codeclass btn btn-sm btn-default$current'$style>$statuslabel</a>\n";
169
- }
170
-
171
- if (!$this->plugin->module_exists($key) || !$this->plugin->call_module_func($key, 'get_admin_url', $admin_url)) {
172
- $admin_url = false;
173
- }
174
-
175
- if ($currentstatus > SU_MODULE_DISABLED && $admin_url) {
176
- $cellcontent = "<a class='module-link' href='{$admin_url}'>$name</a>";
177
- } else
178
- $cellcontent = $name;
179
-
180
- echo "\t\t\t</div>\n";
181
- echo "\t\t\t\t<input type='hidden' name='su-$key-module-status' id='su-$key-module-status' value='$currentstatus' />\n";
182
- echo <<<STR
183
- </div>
184
- <div class='col-sm-4 col-md-4 module-name'>
185
- $cellcontent
186
- </div>
187
- </div>
188
-
189
- STR;
190
- }
191
-
192
- echo "\t</div>\n</div>\n";
193
-
194
- echo '</div>';
195
- echo '<div class="col-sm-4 col-md-3">';
196
-
197
- if ($this->should_show_sdf_theme_promo()) {
198
- $this->promo_sdf_banners();
199
- }
200
- echo '</div>';
201
- echo '</div>';
202
-
203
- $this->admin_form_end(null, false);
204
- }
205
-
206
- function add_help_tabs($screen) {
207
-
208
- $screen->add_help_tab(array(
209
- 'id' => 'su-modules-options'
210
- , 'title' => __('Options Help', 'seo-ultimate')
211
- , 'content' => __("
212
- <p>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.</p>
213
- <p>The Module Manager lets you customize the visibility and accessibility of each module; here are the options available:</p>
214
- <ul>
215
- <li><strong>Enabled</strong> &mdash; The default option. The module will be fully enabled and accessible.</li>
216
- <li><strong>Silenced</strong> &mdash; The module will be enabled and accessible, but it won't be allowed to display numeric bubble alerts on the menu.</li>
217
- <li><strong>Hidden</strong> &mdash; The module's functionality will be enabled, but the module won't be visible on the SEO menu. You will still be able to access the module's admin page by clicking on its title in the Module Manager table.</li>
218
- <li><strong>Disabled</strong> &mdash; The module will be completely disabled and inaccessible.</li>
219
- </ul>
220
- ", 'seo-ultimate')));
221
-
222
- $screen->add_help_tab(array(
223
- 'id' => 'su-modules-faq'
224
- , 'title' => __('FAQ', 'seo-ultimate')
225
- , 'content' => __("
226
- <ul>
227
- <li><strong>What are modules?</strong><br />SEO Ultimate&#8217;s features are divided into groups called &#8220;modules.&#8221; SEO Ultimate&#8217;s &#8220;Module Manager&#8221; lets you enable or disable each of these groups of features. This way, you can pick-and-choose which SEO Ultimate features you want.</li>
228
- <li><strong>Can I access a module again after I&#8217;ve hidden it?</strong><br />Yes. Just go to the Module Manager and click the module&#8217;s title to open its admin page. If you&#8217;d like to put the module back in the &#8220;SEO&#8221; menu, just re-enable the module in the Module Manager and click &#8220;Save Changes.&#8221;</li>
229
- <li><strong>How do I disable the number bubbles on the &#8220;SEO&#8221; menu?</strong><br />Just go to the Module Manager and select the &#8220;Silenced&#8221; option for any modules generating number bubbles. Then click &#8220;Save Changes.&#8221;</li>
230
- </ul>
231
- ", 'seo-ultimate')));
232
- }
233
- }
234
-
235
- }
236
  ?>
1
+ <?php
2
+ /**
3
+ * Module Manager Module
4
+ *
5
+ * @since 0.7
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_Modules extends SU_Module {
11
+
12
+ static function get_module_title() { return __('Module Manager', 'seo-ultimate'); }
13
+ static function get_menu_title() { return __('Modules', 'seo-ultimate'); }
14
+ static function get_menu_pos() { return 0; }
15
+ function is_menu_default(){ return true; }
16
+
17
+ function init() {
18
+
19
+ if ($this->is_action('update')) {
20
+
21
+ $psdata = (array)get_option('seo_ultimate', array());
22
+
23
+ foreach ($_POST as $key => $newvalue) {
24
+ if (substr($key, 0, 3) == 'su-') {
25
+ $key = str_replace(array('su-', '-module-status'), '', $key);
26
+
27
+ $newvalue = intval($newvalue);
28
+ $oldvalue = $psdata['modules'][$key];
29
+
30
+ if ($oldvalue != $newvalue) {
31
+ if ($oldvalue == SU_MODULE_DISABLED)
32
+ $this->plugin->call_module_func($key, 'activate');
33
+ if ($newvalue == SU_MODULE_DISABLED)
34
+ $this->plugin->call_module_func($key, 'deactivate');
35
+ }
36
+
37
+ $psdata['modules'][$key] = $newvalue;
38
+ }
39
+ }
40
+
41
+ update_option('seo_ultimate', $psdata);
42
+
43
+ wp_redirect(add_query_arg('su-modules-updated', '1', suurl::current()), 301);
44
+ exit;
45
+ }
46
+ }
47
+
48
+ function admin_page_contents() {
49
+
50
+ echo '<div class="row">';
51
+ echo '<div class="col-sm-8 col-md-9">';
52
+ echo '<div class="bs-callout bs-callout-grey"><p>';
53
+ _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');
54
+ echo "</p>\n<p>";
55
+ _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');
56
+ echo "</p></div>\n";
57
+
58
+ if (!empty($_GET['su-modules-updated']))
59
+ $this->print_message('success', __('Modules updated.', 'seo-ultimate'));
60
+
61
+ $this->admin_form_start(false, false);
62
+
63
+ $headers = array(
64
+ __('Status', 'seo-ultimate')
65
+ , __('Module', 'seo-ultimate')
66
+ );
67
+
68
+ echo <<<STR
69
+ <div class="panel panel-default">
70
+ <div class="panel-heading">
71
+ <div class="row">
72
+ <div class="col-sm-4 col-md-4">
73
+ <h3 class="panel-title step-title module-status">{$headers[0]}</h3>
74
+ </div>
75
+ <div class="col-sm-4 col-md-4">
76
+ <h3 class="panel-title step-title module-name">{$headers[1]}</h3>
77
+ </div>
78
+ </div>
79
+ </div>
80
+ <div class="panel-body">
81
+
82
+ STR;
83
+
84
+ $statuses = array(
85
+ SU_MODULE_ENABLED => __('Enabled', 'seo-ultimate')
86
+ , SU_MODULE_SILENCED => __('Silenced', 'seo-ultimate')
87
+ , SU_MODULE_HIDDEN => __('Hidden', 'seo-ultimate')
88
+ , SU_MODULE_DISABLED => __('Disabled', 'seo-ultimate')
89
+ );
90
+ $buttons = array(
91
+ SU_MODULE_ENABLED => 'btn-success'
92
+ , SU_MODULE_SILENCED => 'btn-default'
93
+ , SU_MODULE_HIDDEN => 'btn-warning'
94
+ , SU_MODULE_DISABLED => 'btn-danger'
95
+ );
96
+
97
+ $modules = array();
98
+
99
+ foreach ($this->plugin->modules as $key => $x_module) {
100
+ $module =& $this->plugin->modules[$key];
101
+
102
+ //On some setups, get_parent_class() returns the class name in lowercase
103
+ if (strcasecmp(get_parent_class($module), 'SU_Module') == 0 && !in_array($key, $this->plugin->get_invincible_modules()) && $module->is_independent_module())
104
+ $modules[$key] = $module->get_module_title();
105
+ }
106
+
107
+ foreach ($this->plugin->disabled_modules as $key => $class) {
108
+
109
+ if (call_user_func(array($class, 'is_independent_module')))
110
+ $modules[$key] = call_user_func(array($class, 'get_module_title'));
111
+ }
112
+
113
+ asort($modules);
114
+
115
+ //Do we have any modules requiring the "Silenced" column? Store that boolean in $any_hmc
116
+ $any_hmc = false;
117
+ foreach ($modules as $key => $name) {
118
+ if ($this->plugin->call_module_func($key, 'has_menu_count', $hmc) && $hmc) {
119
+ $any_hmc = true;
120
+ break;
121
+ }
122
+ }
123
+
124
+ $psdata = (array)get_option('seo_ultimate', array());
125
+
126
+ foreach ($modules as $key => $name) {
127
+
128
+ $currentstatus = $psdata['modules'][$key];
129
+
130
+ echo "\t\t<div class='form-group'>\n\t\t\t<div class='col-sm-4 col-md-4'>\n";
131
+ echo "\t\t\t<div class='btn-group sdf_toggle module-status' id='module-status-$key'>\n";
132
+
133
+ $hidden_is_hidden = ($this->plugin->call_module_func($key, 'get_menu_title', $module_menu_title) && $module_menu_title === false)
134
+ || ($this->plugin->call_module_func($key, 'is_independent_module', $is_independent_module) && $is_independent_module &&
135
+ $this->plugin->call_module_func($key, 'get_parent_module', $parent_module) && $parent_module &&
136
+ $this->plugin->module_exists($parent_module));
137
+
138
+ foreach ($statuses as $statuscode => $statuslabel) {
139
+
140
+ $hmc = ($this->plugin->call_module_func($key, 'has_menu_count', $_hmc) && $_hmc);
141
+
142
+ $is_current = false;
143
+ $style = '';
144
+ switch ($statuscode) {
145
+ case SU_MODULE_ENABLED:
146
+ if (($currentstatus == SU_MODULE_SILENCED && !$hmc) ||
147
+ ($currentstatus == SU_MODULE_HIDDEN && $hidden_is_hidden))
148
+ $is_current = true;
149
+ break;
150
+ case SU_MODULE_SILENCED:
151
+ if (!$any_hmc) continue 2; //break out of switch and foreach
152
+ if (!$hmc) $style = " style='visibility: hidden;'";
153
+ break;
154
+ case SU_MODULE_HIDDEN:
155
+ if ($hidden_is_hidden)
156
+ $style = " style='visibility: hidden;'";
157
+ break;
158
+ }
159
+
160
+ if ($is_current || $currentstatus == $statuscode) {
161
+ $current = ' active';
162
+ }
163
+ else {
164
+ $current = '';
165
+ }
166
+ $codeclass = str_replace('-', 'n', strval($statuscode));
167
+ echo "\t\t\t\t\t";
168
+ echo "<a href='javascript:void(0)' onclick=\"javascript:set_module_status('$key', $statuscode, this)\" type='button' class='status-$codeclass btn btn-sm btn-default$current'$style>$statuslabel</a>\n";
169
+ }
170
+
171
+ if (!$this->plugin->module_exists($key) || !$this->plugin->call_module_func($key, 'get_admin_url', $admin_url)) {
172
+ $admin_url = false;
173
+ }
174
+
175
+ if ($currentstatus > SU_MODULE_DISABLED && $admin_url) {
176
+ $cellcontent = "<a class='module-link' href='{$admin_url}'>$name</a>";
177
+ } else
178
+ $cellcontent = $name;
179
+
180
+ echo "\t\t\t</div>\n";
181
+ echo "\t\t\t\t<input type='hidden' name='su-$key-module-status' id='su-$key-module-status' value='$currentstatus' />\n";
182
+ echo <<<STR
183
+ </div>
184
+ <div class='col-sm-4 col-md-4 module-name'>
185
+ $cellcontent
186
+ </div>
187
+ </div>
188
+
189
+ STR;
190
+ }
191
+
192
+ echo "\t</div>\n</div>\n";
193
+
194
+ echo '</div>';
195
+ echo '<div class="col-sm-4 col-md-3">';
196
+
197
+ if ($this->should_show_sdf_theme_promo()) {
198
+ $this->promo_sdf_banners();
199
+ }
200
+ echo '</div>';
201
+ echo '</div>';
202
+
203
+ $this->admin_form_end(null, false);
204
+ }
205
+
206
+ function add_help_tabs($screen) {
207
+
208
+ $screen->add_help_tab(array(
209
+ 'id' => 'su-modules-options'
210
+ , 'title' => __('Options Help', 'seo-ultimate')
211
+ , 'content' => __("
212
+ <p>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.</p>
213
+ <p>The Module Manager lets you customize the visibility and accessibility of each module; here are the options available:</p>
214
+ <ul>
215
+ <li><strong>Enabled</strong> &mdash; The default option. The module will be fully enabled and accessible.</li>
216
+ <li><strong>Silenced</strong> &mdash; The module will be enabled and accessible, but it won't be allowed to display numeric bubble alerts on the menu.</li>
217
+ <li><strong>Hidden</strong> &mdash; The module's functionality will be enabled, but the module won't be visible on the SEO menu. You will still be able to access the module's admin page by clicking on its title in the Module Manager table.</li>
218
+ <li><strong>Disabled</strong> &mdash; The module will be completely disabled and inaccessible.</li>
219
+ </ul>
220
+ ", 'seo-ultimate')));
221
+
222
+ $screen->add_help_tab(array(
223
+ 'id' => 'su-modules-faq'
224
+ , 'title' => __('FAQ', 'seo-ultimate')
225
+ , 'content' => __("
226
+ <ul>
227
+ <li><strong>What are modules?</strong><br />SEO Ultimate&#8217;s features are divided into groups called &#8220;modules.&#8221; SEO Ultimate&#8217;s &#8220;Module Manager&#8221; lets you enable or disable each of these groups of features. This way, you can pick-and-choose which SEO Ultimate features you want.</li>
228
+ <li><strong>Can I access a module again after I&#8217;ve hidden it?</strong><br />Yes. Just go to the Module Manager and click the module&#8217;s title to open its admin page. If you&#8217;d like to put the module back in the &#8220;SEO&#8221; menu, just re-enable the module in the Module Manager and click &#8220;Save Changes.&#8221;</li>
229
+ <li><strong>How do I disable the number bubbles on the &#8220;SEO&#8221; menu?</strong><br />Just go to the Module Manager and select the &#8220;Silenced&#8221; option for any modules generating number bubbles. Then click &#8220;Save Changes.&#8221;</li>
230
+ </ul>
231
+ ", 'seo-ultimate')));
232
+ }
233
+ }
234
+
235
+ }
236
  ?>
modules/more-links/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/more-links/more-links.php CHANGED
@@ -1,123 +1,123 @@
1
- <?php
2
- /**
3
- * More Link Customizer Module
4
- *
5
- * @since 1.3
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_MoreLinks extends SU_Module {
11
-
12
- static function get_module_title() { return __('More Link Customizer', 'seo-ultimate'); }
13
-
14
- static function get_parent_module() { return 'misc'; }
15
- function get_settings_key() { return 'more-links'; }
16
-
17
- function get_default_settings() {
18
- return array(
19
- 'default' => 'Continue reading &#8220;{post}&#8221; &raquo;'
20
- );
21
- }
22
-
23
- function init() {
24
- add_filter('the_content_more_link', array(&$this, 'more_link_filter'), 10, 2);
25
- add_filter('su_get_postmeta-morelinktext', array(&$this, 'get_morelinktext_postmeta'), 10, 3);
26
- }
27
-
28
- function admin_page_contents() {
29
- $this->child_admin_form_start();
30
- $this->textbox('default', __('Default More Link Text', 'seo-ultimate'), $this->get_default_setting('default'));
31
- $this->child_admin_form_end();
32
- }
33
-
34
- function more_link_filter($link, $text=false) {
35
-
36
- if ($text === false) return $link; //Can't do it without $text parameter
37
-
38
- $default = $this->get_setting('default');
39
-
40
- if (strlen($newtext = trim($this->get_postmeta('morelinktext'))) || strlen(trim($newtext = $default))) {
41
- $newtext = str_replace('{post}', su_esc_html(get_the_title()), $newtext);
42
- $link = str_replace("$text</a>", "$newtext</a>", $link);
43
- }
44
-
45
- return $link;
46
- }
47
-
48
- function postmeta_fields($fields, $screen) {
49
-
50
- if (strcmp($screen, 'post') == 0)
51
- $fields['links'][20]['morelinktext'] = $this->get_postmeta_textbox('morelinktext', __('Anchor Text of &#8220;More&#8221; Link:', 'seo-ultimate'));
52
-
53
- return $fields;
54
- }
55
-
56
- function get_morelinktext_postmeta($value, $key, $post) {
57
-
58
- if (!strlen($value)) {
59
-
60
- //Import any custom anchors from the post itself
61
- $content = $post->post_content;
62
- $matches = array();
63
- if ( preg_match('/<!--more(.*?)?-->/', $content, $matches) ) {
64
- $content = explode($matches[0], $content, 2);
65
- if ( !empty($matches[1]) )
66
- return strip_tags(wp_kses_no_null(trim($matches[1])));
67
- }
68
- }
69
-
70
- return $value;
71
- }
72
-
73
- function add_help_tabs($screen) {
74
-
75
- $overview = __("
76
- <ul>
77
- <li><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>.</li>
78
- <li><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&#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).</li>
79
- <li><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 overridden 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.</li>
80
- </ul>
81
- ", 'seo-ultimate');
82
-
83
- $faq = __("
84
- <ul>
85
- <li>
86
- <p><strong>Why is the More Link Customizer an improvement over WordPress&#8217;s built-in functionality?</strong><br />Although WordPress does allow basic <a href='http://codex.wordpress.org/Customizing_the_Read_More#Having_a_custom_text_for_each_post' target='_blank'>custom &#8220;more&#8221; anchors</a>, the SEO Ultimate approach has several benefits:</p>
87
- <ul>
88
- <li>More Link Customizer (MLC) lets you set a custom default anchor text. WordPress, on the other hand, leaves this up to the currently-active theme.</li>
89
- <li>MLC lets you dynamically incorporate the post&#8217;s title into the anchor text.</li>
90
- <li>MLC lets you include HTML tags in your anchor, whereas WordPress strips these out.</li>
91
- <li>MLC&#8217;s functionality is much more prominent than WordPress&#8217;s unintuitive, barely-documented approach.</li>
92
- <li>Unlike WordPress's method, MLC doesn't require you to utilize the HTML editor.</li>
93
- </ul>
94
- <p>If you&#8217;ve already specified custom anchors via WordPress&#8217;s method, SEO Ultimate will import those anchors automatically into the More Link Customizer.</p>
95
- </li>
96
- </ul>
97
- ", 'seo-ultimate');
98
-
99
- if ($this->has_enabled_parent()) {
100
- $screen->add_help_tab(array(
101
- 'id' => 'su-more-links-help'
102
- , 'title' => __('More Link Customizer', 'seo-ultimate')
103
- , 'content' =>
104
- '<h3>' . __('Overview', 'seo-ultimate') . '</h3>' . $overview .
105
- '<h3>' . __('FAQ', 'seo-ultimate') . '</h3>' . $faq
106
- ));
107
- } else {
108
-
109
- $screen->add_help_tab(array(
110
- 'id' => 'su-more-links-overview'
111
- , 'title' => __('Overview', 'seo-ultimate')
112
- , 'content' => $overview));
113
-
114
- $screen->add_help_tab(array(
115
- 'id' => 'su-more-links-faq'
116
- , 'title' => __('FAQ', 'seo-ultimate')
117
- , 'content' => $faq));
118
- }
119
- }
120
- }
121
-
122
- }
123
  ?>
1
+ <?php
2
+ /**
3
+ * More Link Customizer Module
4
+ *
5
+ * @since 1.3
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_MoreLinks extends SU_Module {
11
+
12
+ static function get_module_title() { return __('More Link Customizer', 'seo-ultimate'); }
13
+
14
+ static function get_parent_module() { return 'misc'; }
15
+ function get_settings_key() { return 'more-links'; }
16
+
17
+ function get_default_settings() {
18
+ return array(
19
+ 'default' => 'Continue reading &#8220;{post}&#8221; &raquo;'
20
+ );
21
+ }
22
+
23
+ function init() {
24
+ add_filter('the_content_more_link', array(&$this, 'more_link_filter'), 10, 2);
25
+ add_filter('su_get_postmeta-morelinktext', array(&$this, 'get_morelinktext_postmeta'), 10, 3);
26
+ }
27
+
28
+ function admin_page_contents() {
29
+ $this->child_admin_form_start();
30
+ $this->textbox('default', __('Default More Link Text', 'seo-ultimate'), $this->get_default_setting('default'));
31
+ $this->child_admin_form_end();
32
+ }
33
+
34
+ function more_link_filter($link, $text=false) {
35
+
36
+ if ($text === false) return $link; //Can't do it without $text parameter
37
+
38
+ $default = $this->get_setting('default');
39
+
40
+ if (strlen($newtext = trim($this->get_postmeta('morelinktext'))) || strlen(trim($newtext = $default))) {
41
+ $newtext = str_replace('{post}', su_esc_html(get_the_title()), $newtext);
42
+ $link = str_replace("$text</a>", "$newtext</a>", $link);
43
+ }
44
+
45
+ return $link;
46
+ }
47
+
48
+ function postmeta_fields($fields, $screen) {
49
+
50
+ if (strcmp($screen, 'post') == 0)
51
+ $fields['links'][20]['morelinktext'] = $this->get_postmeta_textbox('morelinktext', __('Anchor Text of &#8220;More&#8221; Link:', 'seo-ultimate'));
52
+
53
+ return $fields;
54
+ }
55
+
56
+ function get_morelinktext_postmeta($value, $key, $post) {
57
+
58
+ if (!strlen($value)) {
59
+
60
+ //Import any custom anchors from the post itself
61
+ $content = $post->post_content;
62
+ $matches = array();
63
+ if ( preg_match('/<!--more(.*?)?-->/', $content, $matches) ) {
64
+ $content = explode($matches[0], $content, 2);
65
+ if ( !empty($matches[1]) )
66
+ return strip_tags(wp_kses_no_null(trim($matches[1])));
67
+ }
68
+ }
69
+
70
+ return $value;
71
+ }
72
+
73
+ function add_help_tabs($screen) {
74
+
75
+ $overview = __("
76
+ <ul>
77
+ <li><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>.</li>
78
+ <li><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&#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).</li>
79
+ <li><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 overridden 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.</li>
80
+ </ul>
81
+ ", 'seo-ultimate');
82
+
83
+ $faq = __("
84
+ <ul>
85
+ <li>
86
+ <p><strong>Why is the More Link Customizer an improvement over WordPress&#8217;s built-in functionality?</strong><br />Although WordPress does allow basic <a href='http://codex.wordpress.org/Customizing_the_Read_More#Having_a_custom_text_for_each_post' target='_blank'>custom &#8220;more&#8221; anchors</a>, the SEO Ultimate approach has several benefits:</p>
87
+ <ul>
88
+ <li>More Link Customizer (MLC) lets you set a custom default anchor text. WordPress, on the other hand, leaves this up to the currently-active theme.</li>
89
+ <li>MLC lets you dynamically incorporate the post&#8217;s title into the anchor text.</li>
90
+ <li>MLC lets you include HTML tags in your anchor, whereas WordPress strips these out.</li>
91
+ <li>MLC&#8217;s functionality is much more prominent than WordPress&#8217;s unintuitive, barely-documented approach.</li>
92
+ <li>Unlike WordPress's method, MLC doesn't require you to utilize the HTML editor.</li>
93
+ </ul>
94
+ <p>If you&#8217;ve already specified custom anchors via WordPress&#8217;s method, SEO Ultimate will import those anchors automatically into the More Link Customizer.</p>
95
+ </li>
96
+ </ul>
97
+ ", 'seo-ultimate');
98
+
99
+ if ($this->has_enabled_parent()) {
100
+ $screen->add_help_tab(array(
101
+ 'id' => 'su-more-links-help'
102
+ , 'title' => __('More Link Customizer', 'seo-ultimate')
103
+ , 'content' =>
104
+ '<h3>' . __('Overview', 'seo-ultimate') . '</h3>' . $overview .
105
+ '<h3>' . __('FAQ', 'seo-ultimate') . '</h3>' . $faq
106
+ ));
107
+ } else {
108
+
109
+ $screen->add_help_tab(array(
110
+ 'id' => 'su-more-links-overview'
111
+ , 'title' => __('Overview', 'seo-ultimate')
112
+ , 'content' => $overview));
113
+
114
+ $screen->add_help_tab(array(
115
+ 'id' => 'su-more-links-faq'
116
+ , 'title' => __('FAQ', 'seo-ultimate')
117
+ , 'content' => $faq));
118
+ }
119
+ }
120
+ }
121
+
122
+ }
123
  ?>
modules/noindex/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/noindex/noindex.php CHANGED
@@ -1,181 +1,181 @@
1
- <?php
2
- /**
3
- * Noindex Manager Module
4
- *
5
- * @since 0.1
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- function su_noindex_export_filter($all_settings) {
11
- unset($all_settings['meta']['taxonomy_meta_robots_noindex']);
12
- unset($all_settings['meta']['taxonomy_meta_robots_nofollow']);
13
- return $all_settings;
14
- }
15
- add_filter('su_settings_export_array', 'su_noindex_export_filter');
16
-
17
- class SU_Noindex extends SU_Module {
18
-
19
- static function get_module_title() { return __('Noindex Manager', 'seo-ultimate'); }
20
- function get_module_subtitle() { return __('Noindex', 'seo-ultimate'); }
21
-
22
- static function get_parent_module() { return 'meta-robots'; }
23
- function get_settings_key() { return 'noindex'; }
24
- static function is_independent_module() { return false; }
25
-
26
- function init() {
27
-
28
- //Hook into our wp_head() action
29
- add_action('su_meta_robots', array(&$this, 'wphead_meta_robots'), 1);
30
-
31
- //Now we'll hook into places where wp_head() is not called
32
-
33
- //Hook into comment feed headers
34
- if ($this->get_setting('noindex_comments_feed'))
35
- add_action('commentsrss2_head', array(&$this, 'rss2_noindex_tag'));
36
-
37
- //Hook into the admin header
38
- if ($this->get_setting('noindex_admin'))
39
- add_action('admin_head', array(&$this, 'xhtml_noindex_tag'));
40
-
41
- //Hook into the login header
42
- if ($this->get_setting('noindex_login'))
43
- add_action('login_head', array(&$this, 'xhtml_noindex_tag'));
44
- }
45
-
46
- function get_admin_page_tabs() {
47
-
48
- return array_merge(
49
- array(
50
- array('title' => __('Default Values', 'seo-ultimate'), 'id' => 'su-default-values', 'callback' => 'defaults_tab')
51
- )
52
- , $this->get_postmeta_edit_tabs(array(
53
- array(
54
- 'type' => 'checkbox'
55
- , 'name' => 'meta_robots_noindex'
56
- , 'label' => __('Noindex', 'seo-ultimate')
57
- )
58
- , array(
59
- 'type' => 'checkbox'
60
- , 'name' => 'meta_robots_nofollow'
61
- , 'label' => __('Nofollow', 'seo-ultimate')
62
- )
63
- ))
64
- , $this->get_taxmeta_edit_tabs(array(
65
- array(
66
- 'type' => 'dropdown'
67
- , 'name' => 'meta_robots_noindex'
68
- , 'options' => array(
69
- 0 => __('Use default', 'seo-ultimate')
70
- , 1 => __('noindex', 'seo-ultimate')
71
- , -1 => __('index', 'seo-ultimate')
72
- )
73
- , 'term_settings_key' => 'taxonomy_meta_robots_noindex'
74
- , 'label' => __('Noindex', 'seo-ultimate')
75
- )
76
- , array(
77
- 'type' => 'dropdown'
78
- , 'name' => 'meta_robots_nofollow'
79
- , 'options' => array(
80
- 0 => __('Use default', 'seo-ultimate')
81
- , 1 => __('nofollow', 'seo-ultimate')
82
- , -1 => __('follow', 'seo-ultimate')
83
- )
84
- , 'term_settings_key' => 'taxonomy_meta_robots_nofollow'
85
- , 'label' => __('Nofollow', 'seo-ultimate')
86
- )
87
- ))
88
- );
89
- }
90
-
91
- function defaults_tab() {
92
-
93
- //If global noindex tags are enabled, these settings will be moot, so notify the user.
94
- if (!get_option('blog_public'))
95
- $this->queue_message('error',
96
- __('Note: The <a href="options-reading.php">&#8220;discourage search engines&#8221; checkbox</a> will block indexing of the entire site, regardless of which options are set below.', 'seo-ultimate') );
97
-
98
- $this->admin_form_table_start();
99
- $this->admin_form_subheader(__('Prevent indexing of...', 'seo-ultimate'));
100
- $this->checkboxes(array('noindex_admin' => __('Administration back-end pages', 'seo-ultimate')
101
- , 'noindex_author' => __('Author archives', 'seo-ultimate')
102
- , 'noindex_search' => __('Blog search pages', 'seo-ultimate')
103
- , 'noindex_category' => __('Category archives', 'seo-ultimate')
104
- , 'noindex_comments_feed' => __('Comment feeds', 'seo-ultimate')
105
- , 'noindex_cpage' => __('Comment subpages', 'seo-ultimate')
106
- , 'noindex_date' => __('Date-based archives', 'seo-ultimate')
107
- , 'noindex_home_paged' => __('Subpages of the homepage', 'seo-ultimate')
108
- , 'noindex_tag' => __('Tag archives', 'seo-ultimate')
109
- , 'noindex_login' => __('User login/registration pages', 'seo-ultimate')
110
- ));
111
- $this->admin_form_table_end();
112
- }
113
-
114
- function wphead_meta_robots($commands) {
115
-
116
- $new = array(
117
- $this->should_noindex() ? 'noindex' : 'index'
118
- , $this->should_nofollow() ? 'nofollow' : 'follow'
119
- );
120
-
121
- if ($new != array('index', 'follow'))
122
- $commands = array_merge($commands, $new);
123
-
124
- return $commands;
125
- }
126
-
127
- function should_noindex() {
128
- if ($this->get_postmeta('meta_robots_noindex')) return true;
129
-
130
- switch ($this->get_termmeta('meta_robots_noindex', false, 'meta')) {
131
- case 1: return true; break;
132
- case -1: return false; break;
133
- }
134
-
135
- $checks = array('author', 'search', 'category', 'date', 'tag');
136
-
137
- foreach ($checks as $setting) {
138
- if (call_user_func("is_$setting")) return $this->get_setting("noindex_$setting");
139
- }
140
-
141
- //Homepage subpages
142
- if ($this->get_setting('noindex_home_paged') && is_home() && is_paged()) return true;
143
-
144
- //Comment subpages
145
- global $wp_query;
146
- if ($this->get_setting('noindex_cpage') && isset($wp_query->query_vars['cpage'])) return true;
147
-
148
- return false;
149
- }
150
-
151
- function should_nofollow() {
152
- if ($this->get_postmeta('meta_robots_nofollow')) return true;
153
-
154
- switch ($this->get_termmeta('meta_robots_nofollow', false, 'meta')) {
155
- case 1: return true; break;
156
- case 0: case -1: return false; break;
157
- }
158
-
159
- return false;
160
- }
161
-
162
- function rss2_noindex_tag() {
163
- echo "<xhtml:meta xmlns:xhtml=\"http://www.w3.org/1999/xhtml\" name=\"robots\" content=\"noindex\" />\n";
164
- }
165
-
166
- function xhtml_noindex_tag() {
167
- echo "\t<meta name=\"robots\" content=\"noindex\" />\n";
168
- }
169
-
170
- function postmeta_fields($fields, $screen) {
171
- $fields['30|meta_robots_noindex|meta_robots_nofollow'] = $this->get_postmeta_checkboxes(array(
172
- 'meta_robots_noindex' => __('Noindex: Tell search engines not to index this webpage.', 'seo-ultimate')
173
- , 'meta_robots_nofollow' => __('Nofollow: Tell search engines not to spider links on this webpage.', 'seo-ultimate')
174
- ), __('Meta Robots Tag:', 'seo-ultimate'));
175
-
176
- return $fields;
177
- }
178
- }
179
-
180
- }
181
  ?>
1
+ <?php
2
+ /**
3
+ * Noindex Manager Module
4
+ *
5
+ * @since 0.1
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ function su_noindex_export_filter($all_settings) {
11
+ unset($all_settings['meta']['taxonomy_meta_robots_noindex']);
12
+ unset($all_settings['meta']['taxonomy_meta_robots_nofollow']);
13
+ return $all_settings;
14
+ }
15
+ add_filter('su_settings_export_array', 'su_noindex_export_filter');
16
+
17
+ class SU_Noindex extends SU_Module {
18
+
19
+ static function get_module_title() { return __('Noindex Manager', 'seo-ultimate'); }
20
+ function get_module_subtitle() { return __('Noindex', 'seo-ultimate'); }
21
+
22
+ static function get_parent_module() { return 'meta-robots'; }
23
+ function get_settings_key() { return 'noindex'; }
24
+ static function is_independent_module() { return false; }
25
+
26
+ function init() {
27
+
28
+ //Hook into our wp_head() action
29
+ add_action('su_meta_robots', array(&$this, 'wphead_meta_robots'), 1);
30
+
31
+ //Now we'll hook into places where wp_head() is not called
32
+
33
+ //Hook into comment feed headers
34
+ if ($this->get_setting('noindex_comments_feed'))
35
+ add_action('commentsrss2_head', array(&$this, 'rss2_noindex_tag'));
36
+
37
+ //Hook into the admin header
38
+ if ($this->get_setting('noindex_admin'))
39
+ add_action('admin_head', array(&$this, 'xhtml_noindex_tag'));
40
+
41
+ //Hook into the login header
42
+ if ($this->get_setting('noindex_login'))
43
+ add_action('login_head', array(&$this, 'xhtml_noindex_tag'));
44
+ }
45
+
46
+ function get_admin_page_tabs() {
47
+
48
+ return array_merge(
49
+ array(
50
+ array('title' => __('Default Values', 'seo-ultimate'), 'id' => 'su-default-values', 'callback' => 'defaults_tab')
51
+ )
52
+ , $this->get_postmeta_edit_tabs(array(
53
+ array(
54
+ 'type' => 'checkbox'
55
+ , 'name' => 'meta_robots_noindex'
56
+ , 'label' => __('Noindex', 'seo-ultimate')
57
+ )
58
+ , array(
59
+ 'type' => 'checkbox'
60
+ , 'name' => 'meta_robots_nofollow'
61
+ , 'label' => __('Nofollow', 'seo-ultimate')
62
+ )
63
+ ))
64
+ , $this->get_taxmeta_edit_tabs(array(
65
+ array(
66
+ 'type' => 'dropdown'
67
+ , 'name' => 'meta_robots_noindex'
68
+ , 'options' => array(
69
+ 0 => __('Use default', 'seo-ultimate')
70
+ , 1 => __('noindex', 'seo-ultimate')
71
+ , -1 => __('index', 'seo-ultimate')
72
+ )
73
+ , 'term_settings_key' => 'taxonomy_meta_robots_noindex'
74
+ , 'label' => __('Noindex', 'seo-ultimate')
75
+ )
76
+ , array(
77
+ 'type' => 'dropdown'
78
+ , 'name' => 'meta_robots_nofollow'
79
+ , 'options' => array(
80
+ 0 => __('Use default', 'seo-ultimate')
81
+ , 1 => __('nofollow', 'seo-ultimate')
82
+ , -1 => __('follow', 'seo-ultimate')
83
+ )
84
+ , 'term_settings_key' => 'taxonomy_meta_robots_nofollow'
85
+ , 'label' => __('Nofollow', 'seo-ultimate')
86
+ )
87
+ ))
88
+ );
89
+ }
90
+
91
+ function defaults_tab() {
92
+
93
+ //If global noindex tags are enabled, these settings will be moot, so notify the user.
94
+ if (!get_option('blog_public'))
95
+ $this->queue_message('error',
96
+ __('Note: The <a href="options-reading.php">&#8220;discourage search engines&#8221; checkbox</a> will block indexing of the entire site, regardless of which options are set below.', 'seo-ultimate') );
97
+
98
+ $this->admin_form_table_start();
99
+ $this->admin_form_subheader(__('Prevent indexing of...', 'seo-ultimate'));
100
+ $this->checkboxes(array('noindex_admin' => __('Administration back-end pages', 'seo-ultimate')
101
+ , 'noindex_author' => __('Author archives', 'seo-ultimate')
102
+ , 'noindex_search' => __('Blog search pages', 'seo-ultimate')
103
+ , 'noindex_category' => __('Category archives', 'seo-ultimate')
104
+ , 'noindex_comments_feed' => __('Comment feeds', 'seo-ultimate')
105
+ , 'noindex_cpage' => __('Comment subpages', 'seo-ultimate')
106
+ , 'noindex_date' => __('Date-based archives', 'seo-ultimate')
107
+ , 'noindex_home_paged' => __('Subpages of the homepage', 'seo-ultimate')
108
+ , 'noindex_tag' => __('Tag archives', 'seo-ultimate')
109
+ , 'noindex_login' => __('User login/registration pages', 'seo-ultimate')
110
+ ));
111
+ $this->admin_form_table_end();
112
+ }
113
+
114
+ function wphead_meta_robots($commands) {
115
+
116
+ $new = array(
117
+ $this->should_noindex() ? 'noindex' : 'index'
118
+ , $this->should_nofollow() ? 'nofollow' : 'follow'
119
+ );
120
+
121
+ if ($new != array('index', 'follow'))
122
+ $commands = array_merge($commands, $new);
123
+
124
+ return $commands;
125
+ }
126
+
127
+ function should_noindex() {
128
+ if ($this->get_postmeta('meta_robots_noindex')) return true;
129
+
130
+ switch ($this->get_termmeta('meta_robots_noindex', false, 'meta')) {
131
+ case 1: return true; break;
132
+ case -1: return false; break;
133
+ }
134
+
135
+ $checks = array('author', 'search', 'category', 'date', 'tag');
136
+
137
+ foreach ($checks as $setting) {
138
+ if (call_user_func("is_$setting")) return $this->get_setting("noindex_$setting");
139
+ }
140
+
141
+ //Homepage subpages
142
+ if ($this->get_setting('noindex_home_paged') && is_home() && is_paged()) return true;
143
+
144
+ //Comment subpages
145
+ global $wp_query;
146
+ if ($this->get_setting('noindex_cpage') && isset($wp_query->query_vars['cpage'])) return true;
147
+
148
+ return false;
149
+ }
150
+
151
+ function should_nofollow() {
152
+ if ($this->get_postmeta('meta_robots_nofollow')) return true;
153
+
154
+ switch ($this->get_termmeta('meta_robots_nofollow', false, 'meta')) {
155
+ case 1: return true; break;
156
+ case 0: case -1: return false; break;
157
+ }
158
+
159
+ return false;
160
+ }
161
+
162
+ function rss2_noindex_tag() {
163
+ echo "<xhtml:meta xmlns:xhtml=\"http://www.w3.org/1999/xhtml\" name=\"robots\" content=\"noindex\" />\n";
164
+ }
165
+
166
+ function xhtml_noindex_tag() {
167
+ echo "\t<meta name=\"robots\" content=\"noindex\" />\n";
168
+ }
169
+
170
+ function postmeta_fields($fields, $screen) {
171
+ $fields['30|meta_robots_noindex|meta_robots_nofollow'] = $this->get_postmeta_checkboxes(array(
172
+ 'meta_robots_noindex' => __('Noindex: Tell search engines not to index this webpage.', 'seo-ultimate')
173
+ , 'meta_robots_nofollow' => __('Nofollow: Tell search engines not to spider links on this webpage.', 'seo-ultimate')
174
+ ), __('Meta Robots Tag:', 'seo-ultimate'));
175
+
176
+ return $fields;
177
+ }
178
+ }
179
+
180
+ }
181
  ?>
modules/opengraph/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/opengraph/opengraph.css CHANGED
@@ -1,13 +1,13 @@
1
-
2
- #su-opengraph .form-table tr th {
3
- width: 150px;
4
- }
5
-
6
- #su-opengraph table.widefat .su-og_type {
7
- width: 100px;
8
- }
9
-
10
- #su-opengraph #su-default-values table.widefat td,
11
- #su-opengraph #su-default-values table.widefat th {
12
- padding-right: 3em;
13
  }
1
+
2
+ #su-opengraph .form-table tr th {
3
+ width: 150px;
4
+ }
5
+
6
+ #su-opengraph table.widefat .su-og_type {
7
+ width: 100px;
8
+ }
9
+
10
+ #su-opengraph #su-default-values table.widefat td,
11
+ #su-opengraph #su-default-values table.widefat th {
12
+ padding-right: 3em;
13
  }
modules/opengraph/opengraph.php CHANGED
@@ -1,558 +1,558 @@
1
- <?php
2
- /**
3
- * Open Graph Integrator Module
4
- *
5
- * @since 7.3
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_OpenGraph extends SU_Module {
11
-
12
- var $namespaces_declared = false;
13
- var $jlsuggest_box_post_id = false;
14
-
15
- static function get_module_title() { return __('Open Graph Integrator', 'seo-ultimate'); }
16
- static function get_menu_title() { return __('Open Graph', 'seo-ultimate'); }
17
-
18
- function get_default_settings() {
19
- return array(
20
- 'default_post_og_type' => 'article'
21
- , 'default_page_og_type' => 'article'
22
- , 'default_post_twitter_card' => 'summary'
23
- , 'default_page_twitter_card' => 'summary'
24
- , 'default_attachment_twitter_card' => 'photo'
25
- , 'enable_og_article_author' => true
26
- );
27
- }
28
-
29
- function init() {
30
- add_filter('language_attributes', array(&$this, 'html_tag_attrs'), 1000);
31
- add_action('su_head', array(&$this, 'head_tag_output'));
32
- add_filter('su_get_setting-opengraph-twitter_site_handle', array(&$this, 'sanitize_twitter_handle'));
33
- add_filter('user_contactmethods', array(&$this, 'add_twitter_field'));
34
- add_filter('su_get_setting-opengraph-twitter_creator_handle', array(&$this, 'sanitize_twitter_handle'));
35
- }
36
-
37
- function html_tag_attrs($attrs) {
38
- $this->namespaces_declared = true;
39
- $namespace_urls = $this->get_namespace_urls();
40
-
41
- $doctype = $this->get_setting('doctype', '');
42
- switch ($doctype) {
43
- case 'xhtml':
44
- foreach ($namespace_urls as $namespace => $url) {
45
- $namespace = su_esc_attr($namespace);
46
- $url = su_esc_attr($url);
47
- $attrs .= " xmlns:$namespace=\"$url\"";
48
- }
49
- break;
50
- case 'html5':
51
- default:
52
- $attrs .= ' prefix="';
53
- $whitespace = '';
54
- foreach ($namespace_urls as $namespace => $url) {
55
- $namespace = su_esc_attr($namespace);
56
- $url = su_esc_attr($url);
57
- $attrs .= "$whitespace$namespace: $url";
58
- $whitespace = ' ';
59
- }
60
- $attrs .= '"';
61
- break;
62
- }
63
-
64
- return $attrs;
65
- }
66
-
67
- function get_namespace_urls() {
68
- return array(
69
- 'og' => 'http://ogp.me/ns#'
70
- , 'fb' => 'http://ogp.me/ns/fb#'
71
- );
72
- }
73
-
74
- function head_tag_output() {
75
- global $wp_query;
76
-
77
- $tags = $twitter_tags = array();
78
-
79
- if (is_home()) {
80
-
81
- //Type
82
- $tags['og:type'] = 'blog';
83
-
84
- //Twitter Type
85
- $twitter_tags['twitter:card'] = 'summary';
86
-
87
- //Title
88
- if (!($tags['og:title'] = $this->get_setting('home_og_title')))
89
- $tags['og:title'] = get_bloginfo('name');
90
-
91
- //Description
92
- if (!($tags['og:description'] = $this->get_setting('home_og_description')))
93
- $tags['og:description'] = get_bloginfo('description');
94
-
95
- //URL
96
- $tags['og:url'] = suwp::get_blog_home_url();
97
-
98
- //Image
99
- $tags['og:image'] = $this->get_setting('home_og_image');
100
-
101
- } elseif (is_singular()) {
102
-
103
- $post = $wp_query->get_queried_object();
104
-
105
- if (is_object($post)) {
106
- //Type
107
- if (!($tags['og:type'] = $this->get_postmeta('og_type')))
108
- $tags['og:type'] = $this->get_setting("default_{$post->post_type}_og_type");
109
-
110
- //Twitter Type
111
- if (!($twitter_tags['twitter:card'] = $this->get_postmeta('twitter_card')))
112
- $twitter_tags['twitter:card'] = $this->get_setting("default_{$post->post_type}_twitter_card");
113
-
114
- //Title
115
- if (!($tags['og:title'] = $this->get_postmeta('og_title')))
116
- $tags['og:title'] = strip_tags( apply_filters( 'single_post_title', $post->post_title ) );
117
-
118
- //Description
119
- if (!($tags['og:description'] = $this->get_postmeta('og_description')))
120
- if ($this->plugin->call_module_func('meta-descriptions', 'get_meta_desc', $meta_desc, false) && $meta_desc)
121
- $tags['og:description'] = $meta_desc;
122
-
123
- //URL
124
- $tags['og:url'] = get_permalink($post->ID);
125
-
126
- //Image
127
- $tags['og:image'] = $this->jlsuggest_value_to_url($this->get_postmeta('og_image'), true);
128
- if (!$tags['og:image']) {
129
- if ('attachment' == $post->post_type) {
130
- $tags['og:image'] = wp_get_attachment_url();
131
- } elseif (current_theme_supports('post-thumbnails') && $thumbnail_id = get_post_thumbnail_id($post->ID)) {
132
- $tags['og:image'] = wp_get_attachment_url($thumbnail_id);
133
- }
134
- }
135
-
136
- //Additional fields
137
- switch ($tags['og:type']) {
138
- case 'article':
139
-
140
- $tags['article:published_time'] = get_the_date('Y-m-d');
141
- $tags['article:modified_time'] = get_the_modified_date('Y-m-d');
142
-
143
- //Authorship generally doesn't apply to pages
144
- if (!is_page() && $this->get_setting('enable_og_article_author', true))
145
- $tags['article:author'] = get_author_posts_url($post->post_author);
146
-
147
- $single_category = (count(get_the_category()) == 1);
148
-
149
- $taxonomy_names = suwp::get_taxonomy_names();
150
- foreach ($taxonomy_names as $taxonomy_name) {
151
- if ($terms = get_the_terms(get_the_ID(), $taxonomy_name)) {
152
-
153
- if ($single_category && 'category' == $taxonomy_name)
154
- $meta_property = 'article:section';
155
- else
156
- $meta_property = 'article:tag';
157
-
158
- foreach ($terms as $term) {
159
- $tags[$meta_property][] = $term->name;
160
- }
161
- }
162
- }
163
-
164
- break;
165
- }
166
-
167
- //Author's Twitter Handle
168
- $handle = get_user_meta($post->post_author, 'twitter', true);
169
- $handle = $this->sanitize_twitter_handle($handle);
170
- $twitter_tags['twitter:creator'] = $handle;
171
- }
172
- } elseif (is_author()) {
173
-
174
- $author = $wp_query->get_queried_object();
175
-
176
- if (is_object($author)) {
177
- //Type
178
- $tags['og:type'] = 'profile';
179
-
180
- //Title
181
- $tags['og:title'] = $author->display_name;
182
-
183
- //Description
184
- $tags['og:title'] = get_the_author_meta('description', $author->ID);
185
-
186
- //Image
187
- $tags['og:image'] = false;
188
-
189
- //URL
190
- $tags['og:url'] = get_author_posts_url($author->ID, $author->user_nicename);
191
-
192
- //First Name
193
- $tags['profile:first_name'] = get_the_author_meta('first_name', $author->ID);
194
-
195
- //Last Name
196
- $tags['profile:last_name'] = get_the_author_meta('last_name', $author->ID);
197
-
198
- //Username
199
- $tags['profile:username'] = $author->user_login;
200
-
201
- //Twitter Handle
202
- $handle = get_user_meta($author->ID, 'twitter', true);
203
- $handle = $this->sanitize_twitter_handle($handle);
204
- $twitter_tags['twitter:creator'] = $handle;
205
- }
206
- } else
207
- return;
208
-
209
- if ($tags['og:type'] == 'none')
210
- $tags['og:type'] = '';
211
-
212
- if ((!isset($tags['og:image']) || !$tags['og:image']) && $tags['og:image'] !== false)
213
- $tags['og:image'] = $this->jlsuggest_value_to_url($this->get_setting('default_og_image'), true);
214
-
215
- //Site Name
216
- if (!($tags['og:site_name'] = $this->get_setting('og_site_name')))
217
- $tags['og:site_name'] = get_bloginfo('name');
218
-
219
- //FB App ID
220
- $tags['fb:app_id'] = $this->get_setting('default_fb_app_id');
221
-
222
- //Twitter Site Handle
223
- $twitter_tags['twitter:site'] = $this->get_setting('twitter_site_handle');
224
- $twitter_tags['twitter:site:id'] = $this->get_setting('twitter_site_id_handle');
225
- $twitter_tags['twitter:creator'] = $this->get_setting('twitter_creator_handle');
226
- $twitter_tags['twitter:creator:id'] = $this->get_setting('twitter_creator_id_handle');
227
- $twitter_tags['twitter:description'] = $this->get_setting('twitter_description_handle');
228
- $twitter_tags['twitter:title'] = $this->get_setting('twitter_title_handle');
229
- $twitter_tags['twitter:image:src'] = $this->get_setting('twitter_image_src_handle');
230
- $twitter_tags['twitter:image:width'] = $this->get_setting('twitter_image_width_handle');
231
- $twitter_tags['twitter:image:height'] = $this->get_setting('twitter_image_height_handle');
232
- $twitter_tags['twitter:data1'] = $this->get_setting('twitter_data1_handle');
233
- $twitter_tags['twitter:label1'] = $this->get_setting('twitter_label1_handle');
234
- $twitter_tags['twitter:data2'] = $this->get_setting('twitter_data2_handle');
235
- $twitter_tags['twitter:label2'] = $this->get_setting('twitter_label2_handle');
236
- $twitter_tags['twitter:image0:src'] = $this->get_setting('twitter_image0_src_handle');
237
- $twitter_tags['twitter:image1:src'] = $this->get_setting('twitter_image1_src_handle');
238
- $twitter_tags['twitter:image2:src'] = $this->get_setting('twitter_image2_src_handle');
239
- $twitter_tags['twitter:image3:src'] = $this->get_setting('twitter_image3_src_handle');
240
- $twitter_tags['twitter:player'] = $this->get_setting('twitter_player_handle');
241
- $twitter_tags['twitter:player:width'] = $this->get_setting('twitter_player_width_handle');
242
- $twitter_tags['twitter:player:height'] = $this->get_setting('twitter_player_height_handle');
243
- $twitter_tags['twitter:player:stream'] = $this->get_setting('twitter_player_stream_handle');
244
- $twitter_tags['twitter:app:name:iphone'] = $this->get_setting('twitter_app_name_iphone_handle');
245
- $twitter_tags['twitter:app:id:iphone'] = $this->get_setting('twitter_app_id_iphone_handle');
246
- $twitter_tags['twitter:app:url:iphone'] = $this->get_setting('twitter_app_url_iphone_handle');
247
- $twitter_tags['twitter:app:name:iphone'] = $this->get_setting('twitter_app_name_ipad_handle');
248
- $twitter_tags['twitter:app:id:iphone'] = $this->get_setting('twitter_app_id_ipad_handle');
249
- $twitter_tags['twitter:app:url:iphone'] = $this->get_setting('twitter_app_url_ipad_handle');
250
- $twitter_tags['twitter:app:name:googleplay'] = $this->get_setting('twitter_app_name_googleplay_handle');
251
- $twitter_tags['twitter:app:id:googleplay'] = $this->get_setting('twitter_app_id_googleplay_handle');
252
- $twitter_tags['twitter:app:url:googleplay'] = $this->get_setting('twitter_app_url_googleplay_handle');
253
-
254
-
255
- //Output meta tags
256
- $namespace_urls = $this->namespaces_declared ? array() : $this->get_namespace_urls();
257
- $doctype = $this->get_setting('doctype', '');
258
-
259
- switch ($doctype) {
260
- case 'xhtml':
261
- $output_formats = array('<meta%3$s name="%1$s" content="%2$s" />' => array_merge($tags, $twitter_tags));
262
- break;
263
- case 'html5':
264
- $output_formats = array('<meta%3$s property="%1$s" content="%2$s">' => array_merge($tags, $twitter_tags));
265
- break;
266
- default:
267
- $output_formats = array(
268
- '<meta%3$s property="%1$s" content="%2$s" />' => $tags
269
- , '<meta%3$s name="%1$s" content="%2$s" />' => $twitter_tags
270
- );
271
- break;
272
- }
273
-
274
- foreach ($output_formats as $html_format => $format_tags) {
275
- foreach ($format_tags as $property => $values) {
276
- foreach ((array)$values as $value) {
277
- $property = su_esc_attr($property);
278
- $value = su_esc_attr($value);
279
- if (strlen(trim($property)) && strlen(trim($value))) {
280
-
281
- $namespace_attr = '';
282
- $namespace = sustr::upto($property, ':');
283
- if (!empty($namespace_urls[$namespace])) {
284
- $a_namespace = su_esc_attr($namespace);
285
- $a_namespace_url = su_esc_attr($namespace_urls[$namespace]);
286
-
287
- switch ($doctype) {
288
- case 'xhtml':
289
- $namespace_attr = " xmlns:$a_namespace=\"$a_namespace_url\"";
290
- break;
291
- case 'html5':
292
- default:
293
- $namespace_attr = " prefix=\"$a_namespace: $a_namespace_url\"";
294
- break;
295
- }
296
- }
297
-
298
- echo "\t";
299
- printf($html_format, $property, $value, $namespace_attr);
300
- echo "\n";
301
- }
302
- }
303
- }
304
- }
305
- }
306
-
307
- function admin_page_init() {
308
- $this->jlsuggest_init();
309
- }
310
-
311
- function editor_init() {
312
- $this->jlsuggest_init();
313
- }
314
-
315
- function get_admin_page_tabs() {
316
-
317
- $postmeta_edit_tabs = $this->get_postmeta_edit_tabs(array(
318
- array(
319
- 'type' => 'dropdown'
320
- , 'options' => array_merge(array('' => __('Use default', 'seo-ultimate')), $this->get_type_options())
321
- , 'name' => 'og_type'
322
- , 'label' => __('Type', 'seo-ultimate')
323
- )
324
- , array(
325
- 'type' => 'textbox'
326
- , 'name' => 'og_title'
327
- , 'label' => __('Title', 'seo-ultimate')
328
- )
329
- , array(
330
- 'type' => 'textbox'
331
- , 'name' => 'og_description'
332
- , 'label' => __('Description', 'seo-ultimate')
333
- )
334
- , array(
335
- 'type' => 'jlsuggest'
336
- , 'name' => 'og_image'
337
- , 'label' => __('Image', 'seo-ultimate')
338
- , 'options' => array(
339
- 'params' => 'types=posttype_attachment&post_mime_type=image/*'
340
- ))
341
- ));
342
-
343
- //Remove the Image boxes from the Media tab
344
- //(it's obvious what the og:image of an attachment should be...)
345
- unset($postmeta_edit_tabs['attachment']['callback'][5][3]);
346
-
347
- return array_merge(
348
- array(
349
- array('title' => __('Sitewide Values', 'seo-ultimate'), 'id' => 'su-sitewide-values', 'callback' => 'global_tab')
350
- , array('title' => __('Default Values', 'seo-ultimate'), 'id' => 'su-default-values', 'callback' => 'defaults_tab')
351
- , array('title' => __('Settings', 'seo-ultimate'), 'id' => 'su-settings', 'callback' => 'settings_tab')
352
- , array('title' => __('Blog Homepage', 'seo-ultimate'), 'id' => 'su-homepage', 'callback' => 'home_tab')
353
- )
354
- , $postmeta_edit_tabs
355
- );
356
- }
357
-
358
- function global_tab() {
359
- $this->admin_form_table_start();
360
- $this->textbox('og_site_name', __('Site Name', 'seo-ultimate'), false, false, array(), array('placeholder' => get_bloginfo('name')));
361
- $this->textbox('default_fb_app_id', __('Facebook App ID', 'seo-ultimate'));
362
- $this->textbox('twitter_site_handle', __('@username of website', 'seo-ultimate'), false, false, array('help_text' => 'twitter:site', 'callout' => 'Twitter Card Tags'));
363
- $this->textbox('twitter_site_id_handle', __('Same as twitter:site, but the user&#8217;s Twitter ID', 'seo-ultimate'), false, false, array('help_text' => 'twitter:site:id'));
364
- $this->textbox('twitter_creator_handle', __('@username of content creator', 'seo-ultimate'), false, false, array('help_text' => 'twitter:creator'));
365
- $this->textbox('twitter_creator_id_handle', __('Twitter user ID of content creator', 'seo-ultimate'), false, false, array('help_text' => 'twitter:creator:id'));
366
- $this->textbox('twitter_description_handle', __('Description of content (maximum 200 characters)', 'seo-ultimate'), false, false, array('help_text' => 'twitter:description'));
367
- $this->textbox('twitter_title_handle', __('Title of content (maximum 70 characters)', 'seo-ultimate'), false, false, array('help_text' => 'twitter:title'));
368
- $this->textbox('twitter_image_src_handle', __('URL of image to use in the card. Image must be less than 1MB in size.', 'seo-ultimate'), false, false, array('help_text' => 'twitter:image:src'));
369
- $this->textbox('twitter_image_width_handle', __('Width of image in pixels', 'seo-ultimate'), false, false, array('help_text' => 'twitter:image:width'));
370
- $this->textbox('twitter_image_height_handle', __('Height of image in pixels', 'seo-ultimate'), false, false, array('help_text' => 'twitter:image:height'));
371
- $this->textbox('twitter_data1_handle', __('Top customizable data field, can be a relatively short string (ie "$3.99")', 'seo-ultimate'), false, false, array('help_text' => 'twitter:data1'));
372
- $this->textbox('twitter_label1_handle', __('Customizable label or units for the information in twitter:data1 (best practice: use all caps)', 'seo-ultimate'), false, false, array('help_text' => 'twitter:label1'));
373
- $this->textbox('twitter_data2_handle', __('Bottom customizable data field, can be a relatively short string (ie "Seattle, WA")', 'seo-ultimate'), false, false, array('help_text' => 'twitter:data2'));
374
- $this->textbox('twitter_label2_handle', __('Customizable label or units for the information in twitter:data1 (best practice: use all caps)', 'seo-ultimate'), false, false, array('help_text' => 'twitter:label2'));
375
- $this->textbox('twitter_image0_src_handle', __('1st image in the gallery. Images must be less than 1MB in size.', 'seo-ultimate'), false, false, array('help_text' => 'twitter:image0:src'));
376
- $this->textbox('twitter_image1_src_handle', __('2nd image in the gallery. Images must be less than 1MB in size.', 'seo-ultimate'), false, false, array('help_text' => 'twitter:image1:src'));
377
- $this->textbox('twitter_image2_src_handle', __('3rd image in the gallery. Images must be less than 1MB in size.', 'seo-ultimate'), false, false, array('help_text' => 'twitter:image2:src'));
378
- $this->textbox('twitter_image3_src_handle', __('4th image in the gallery. Images must be less than 1MB in size.', 'seo-ultimate'), false, false, array('help_text' => 'twitter:image3:src'));
379
- $this->textbox('twitter_player_handle', __(' HTTPS URL of player iframe', 'seo-ultimate'), false, false, array('help_text' => 'twitter:player'));
380
- $this->textbox('twitter_player_width_handle', __('Width of iframe in pixels', 'seo-ultimate'), false, false, array('help_text' => 'twitter:player:width'));
381
- $this->textbox('twitter_player_height_handle', __('Height of iframe in pixels', 'seo-ultimate'), false, false, array('help_text' => 'twitter:player:height'));
382
- $this->textbox('twitter_player_stream_handle', __('URL to raw video or audio stream', 'seo-ultimate'), false, false, array('help_text' => 'twitter:player:stream'));
383
- $this->textbox('twitter_app_name_iphone_handle', __('Name of your iPhone app', 'seo-ultimate'), false, false, array('help_text' => 'twitter:app:name:iphone'));
384
- $this->textbox('twitter_app_id_iphone_handle', __('Your app ID in the iTunes App Store (Note: NOT your bundle ID)', 'seo-ultimate'), false, false, array('help_text' => 'twitter:app:id:iphone'));
385
- $this->textbox('twitter_app_url_iphone_handle', __('Your app&#8217;s custom URL scheme (you must include "://" after your scheme name)', 'seo-ultimate'), false, false, array('help_text' => 'twitter:app:url:iphone'));
386
- $this->textbox('twitter_app_name_ipad_handle', __('Name of your iPad optimized app', 'seo-ultimate'), false, false, array('help_text' => 'twitter:app:name:ipad'));
387
- $this->textbox('twitter_app_id_ipad_handle', __('Your app ID in the iTunes App Store', 'seo-ultimate'), false, false, array('help_text' => 'twitter:app:id:ipad'));
388
- $this->textbox('twitter_app_url_ipad_handle', __('Your app&#8217;s custom URL scheme', 'seo-ultimate'), false, false, array('help_text' => 'twitter:app:url:ipad'));
389
- $this->textbox('twitter_app_name_googleplay_handle', __('Name of your Android app', 'seo-ultimate'), false, false, array('help_text' => 'twitter:app:name:googleplay'));
390
- $this->textbox('twitter_app_id_googleplay_handle', __('Your app ID in the Google Play Store', 'seo-ultimate'), false, false, array('help_text' => 'twitter:app:id:googleplay'));
391
- $this->textbox('twitter_app_url_googleplay_handle', __('Your app#8217;s custom URL scheme', 'seo-ultimate'), false, false, array('help_text' => 'twitter:app:url:googleplay'));
392
- $this->admin_form_table_end();
393
- }
394
-
395
- function defaults_tab() {
396
- $posttypes = get_post_types(array('public' => true), 'objects');
397
-
398
- $this->admin_subheader(__('Default Types', 'seo-ultimate'));
399
- $this->admin_wftable_start(array(
400
- 'posttype' => __('Post Type', 'seo-ultimate')
401
- , 'og' => __('Open Graph Type', 'seo-ultimate')
402
- , 'twitter' => __('Twitter Type', 'seo-ultimate')
403
- ));
404
- foreach ($posttypes as $posttype) {
405
- echo "<tr valign='middle'>\n";
406
- echo "\t<th class='su-opengraph-posttype' scope='row'>" . esc_html($posttype->labels->name) . "</th>\n";
407
- echo "\t<td class='su-opengraph-og'>";
408
- $this->dropdown("default_{$posttype->name}_og_type", $this->get_type_options(), false, '%s', array('in_table' => false));
409
- echo "</td>\n";
410
- echo "\t<td class='su-opengraph-twitter'>";
411
- $this->dropdown("default_{$posttype->name}_twitter_card", $this->get_twitter_type_options(), false, '%s', array('in_table' => false));
412
- echo "</td>\n";
413
- echo "</tr>\n";
414
- }
415
- $this->admin_wftable_end();
416
-
417
- $this->admin_subheader(__('Default Image', 'seo-ultimate'));
418
- $this->admin_form_table_start();
419
-
420
- $this->textblock(__('In the box below, you can specify an image URL or an image from your media library to use as a default image in the event that there is no image otherwise specified for a given webpage on your site.', 'seo-ultimate'));
421
-
422
- $this->medialib_box('default_og_image', __('Default Image', 'seo-ultimate'), 'types=posttype_attachment&post_mime_type=image/*');
423
-
424
- $this->admin_form_table_end();
425
- }
426
-
427
- function settings_tab() {
428
- $this->admin_form_table_start();
429
- $this->checkbox('enable_og_article_author', __('Include author data for posts', 'seo-ultimate'), __('Open Graph Data', 'seo-ultimate'));
430
- $this->radiobuttons('doctype', array(
431
- '' => __('Use the non-validating code prescribed by Open Graph and Twitter', 'seo-ultimate')
432
- , 'xhtml' => __('Alter the code to validate as XHTML', 'seo-ultimate')
433
- , 'html5' => __('Alter the code to validate as HTML5', 'seo-ultimate')
434
- ), __('HTML Validation', 'seo-ultimate'));
435
- $this->admin_form_table_end();
436
- }
437
-
438
- function home_tab() {
439
- $this->admin_form_table_start();
440
- $this->textbox('home_og_title', __('Blog Homepage Title', 'seo-ultimate'), false, false, array(), array('placeholder' => get_bloginfo('name')));
441
- $this->textbox('home_og_description', __('Blog Homepage Description', 'seo-ultimate'), false, false, array(), array('placeholder' => get_bloginfo('description')));
442
- $this->medialib_box('home_og_image', __('Blog Homepage Image', 'seo-ultimate'), 'types=posttype_attachment&post_mime_type=image/*');
443
- $this->admin_form_table_end();
444
- }
445
-
446
- function postmeta_fields($fields, $screen) {
447
-
448
- $fields['opengraph'][10]['og_title'] = $this->get_postmeta_textbox('og_title', __('Title:', 'seo-ultimate'));
449
- $fields['opengraph'][20]['og_description'] = $this->get_postmeta_textarea('og_description', __('Description:', 'seo-ultimate'));
450
- $fields['opengraph'][30]['og_image'] = $this->get_postmeta_medialib_box('og_image', __('Image:', 'seo-ultimate'));
451
- $fields['opengraph'][40]['og_type'] = $this->get_postmeta_dropdown('og_type', array_merge(array('' => __('Use default', 'seo-ultimate')), $this->get_type_options()), __('Open Graph Type:', 'seo-ultimate'));
452
- $fields['opengraph'][50]['twitter_card'] = $this->get_postmeta_dropdown('twitter_card', array_merge(array('' => __('Use default', 'seo-ultimate')), $this->get_twitter_type_options()), __('Twitter Type:', 'seo-ultimate'));
453
-
454
- return $fields;
455
- }
456
-
457
- function get_postmeta_jlsuggest_boxes($jls_boxes) {
458
- $this->jlsuggest_box_post_id = suwp::get_post_id();
459
- return parent::get_postmeta_jlsuggest_boxes($jls_boxes);
460
- }
461
-
462
- function get_input_element($type, $name, $value=null, $extra=false, $inputid=true) {
463
-
464
- $name_parts = explode('_', $name);
465
- if (isset($name_parts[1]) && is_numeric($post_id = $name_parts[1]))
466
- $this->jlsuggest_box_post_id = $post_id;
467
- else
468
- $this->jlsuggest_box_post_id = false;
469
-
470
- return parent::get_input_element($type, $name, $value, $extra, $inputid);
471
- }
472
-
473
- function get_jlsuggest_box($name, $value, $params='', $placeholder='') {
474
-
475
- if (empty($value) && $this->jlsuggest_box_post_id && current_theme_supports('post-thumbnails') && $thumbnail_id = get_post_thumbnail_id($this->jlsuggest_box_post_id)) {
476
- $selected_post = get_post($thumbnail_id);
477
- $placeholder = sprintf(__('Featured Image: %s', 'seo-ultimate'), $selected_post->post_title);
478
- }
479
-
480
- return parent::get_jlsuggest_box($name, $value, $params, $placeholder);
481
- }
482
-
483
- function get_type_options() {
484
- return array(
485
- 'none' => __('None', 'seo-ultimate')
486
- , __('Internet', 'seo-ultimate') => array(
487
- 'article' => __('Article', 'seo-ultimate')
488
- , 'blog' => __('Blog', 'seo-ultimate')
489
- , 'profile' => __('Profile', 'seo-ultimate')
490
- , 'website' => __('Website', 'seo-ultimate')
491
- ),__('Products', 'seo-ultimate') => array(
492
- 'book' => __('Book', 'seo-ultimate')
493
- ),__('Music', 'seo-ultimate') => array(
494
- 'music.album' => __('Album', 'seo-ultimate')
495
- , 'music.playlist' => __('Playlist', 'seo-ultimate')
496
- , 'music.radio_station' => __('Radio Station', 'seo-ultimate')
497
- , 'music.song' => __('Song', 'seo-ultimate')
498
- ),__('Videos', 'seo-ultimate') => array(
499
- 'video.movie' => __('Movie', 'seo-ultimate')
500
- , 'video.episode' => __('TV Episode', 'seo-ultimate')
501
- , 'video.tv_show' => __('TV Show', 'seo-ultimate')
502
- , 'video.other' => __('Video', 'seo-ultimate')
503
- )
504
- );
505
- }
506
-
507
- function get_twitter_type_options() {
508
- return array(
509
- 'summary' => __('Summary', 'seo-ultimate')
510
- , 'product' => __('Product', 'seo-ultimate')
511
- , 'photo' => __('Photo', 'seo-ultimate')
512
- , 'summary_large_image' => __('Summary Large Image', 'seo-ultimate')
513
- , 'gallery' => __('Gallery', 'seo-ultimate')
514
- , 'player' => __('Player', 'seo-ultimate')
515
- , 'app' => __('App', 'seo-ultimate')
516
- );
517
- }
518
-
519
- function sanitize_twitter_handle($value) {
520
- if (strpos($value, '/') === false) {
521
- $handle = ltrim($value, '@');
522
- } else {
523
- $url_parts = explode('/', $value);
524
- $handle = array_pop($url_parts);
525
- }
526
-
527
- $handle = sustr::preg_filter('a-zA-Z0-9_', $handle);
528
- $handle = trim($handle);
529
-
530
- if ($handle)
531
- $handle = "@$handle";
532
-
533
- return $handle;
534
- }
535
-
536
- function add_twitter_field( $contactmethods ) {
537
- $contactmethods['twitter'] = __('Twitter Handle', 'seo-ultimate');
538
- return $contactmethods;
539
- }
540
-
541
- function add_help_tabs($screen) {
542
-
543
- $screen->add_help_tab(array(
544
- 'id' => 'su-opengraph-overview'
545
- , 'title' => __('Overview', 'seo-ultimate')
546
- , 'content' => __("
547
- <ul>
548
- <li><strong>What it does:</strong> Open Graph Integrator makes it easy for you to convey information about your site to social networks like Facebook, Twitter, and Google+.</li>
549
- <li><strong>Why it helps:</strong> By providing this Open Graph data, you can customize how these social networks will present your site when people share it with their followers.</li>
550
- <li><strong>How to use it:</strong> The &#8220;Sitewide Values&#8221; tab lets you specify data that applies to your entire site. The &#8220;Default Values&#8221; tab lets you specify default data for your posts, pages, etc. The bulk editor tabs let you override those defaults on individual posts and pages. If the authors on your site fill in the &#8220;Twitter Handle&#8221; field which Open Graph Integrator adds to the <a href='profile.php'>profile editor</a>, Open Graph Integrator will communicate that information to Twitter as well.</li>
551
- </ul>
552
- ", 'seo-ultimate')));
553
-
554
- }
555
- }
556
-
557
- }
558
  ?>
1
+ <?php
2
+ /**
3
+ * Open Graph Integrator Module
4
+ *
5
+ * @since 7.3
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_OpenGraph extends SU_Module {
11
+
12
+ var $namespaces_declared = false;
13
+ var $jlsuggest_box_post_id = false;
14
+
15
+ static function get_module_title() { return __('Open Graph Integrator', 'seo-ultimate'); }
16
+ static function get_menu_title() { return __('Open Graph', 'seo-ultimate'); }
17
+
18
+ function get_default_settings() {
19
+ return array(
20
+ 'default_post_og_type' => 'article'
21
+ , 'default_page_og_type' => 'article'
22
+ , 'default_post_twitter_card' => 'summary'
23
+ , 'default_page_twitter_card' => 'summary'
24
+ , 'default_attachment_twitter_card' => 'photo'
25
+ , 'enable_og_article_author' => true
26
+ );
27
+ }
28
+
29
+ function init() {
30
+ add_filter('language_attributes', array(&$this, 'html_tag_attrs'), 1000);
31
+ add_action('su_head', array(&$this, 'head_tag_output'));
32
+ add_filter('su_get_setting-opengraph-twitter_site_handle', array(&$this, 'sanitize_twitter_handle'));
33
+ add_filter('user_contactmethods', array(&$this, 'add_twitter_field'));
34
+ add_filter('su_get_setting-opengraph-twitter_creator_handle', array(&$this, 'sanitize_twitter_handle'));
35
+ }
36
+
37
+ function html_tag_attrs($attrs) {
38
+ $this->namespaces_declared = true;
39
+ $namespace_urls = $this->get_namespace_urls();
40
+
41
+ $doctype = $this->get_setting('doctype', '');
42
+ switch ($doctype) {
43
+ case 'xhtml':
44
+ foreach ($namespace_urls as $namespace => $url) {
45
+ $namespace = su_esc_attr($namespace);
46
+ $url = su_esc_attr($url);
47
+ $attrs .= " xmlns:$namespace=\"$url\"";
48
+ }
49
+ break;
50
+ case 'html5':
51
+ default:
52
+ $attrs .= ' prefix="';
53
+ $whitespace = '';
54
+ foreach ($namespace_urls as $namespace => $url) {
55
+ $namespace = su_esc_attr($namespace);
56
+ $url = su_esc_attr($url);
57
+ $attrs .= "$whitespace$namespace: $url";
58
+ $whitespace = ' ';
59
+ }
60
+ $attrs .= '"';
61
+ break;
62
+ }
63
+
64
+ return $attrs;
65
+ }
66
+
67
+ function get_namespace_urls() {
68
+ return array(
69
+ 'og' => 'http://ogp.me/ns#'
70
+ , 'fb' => 'http://ogp.me/ns/fb#'
71
+ );
72
+ }
73
+
74
+ function head_tag_output() {
75
+ global $wp_query;
76
+
77
+ $tags = $twitter_tags = array();
78
+
79
+ if (is_home()) {
80
+
81
+ //Type
82
+ $tags['og:type'] = 'blog';
83
+
84
+ //Twitter Type
85
+ $twitter_tags['twitter:card'] = 'summary';
86
+
87
+ //Title
88
+ if (!($tags['og:title'] = $this->get_setting('home_og_title')))
89
+ $tags['og:title'] = get_bloginfo('name');
90
+
91
+ //Description
92
+ if (!($tags['og:description'] = $this->get_setting('home_og_description')))
93
+ $tags['og:description'] = get_bloginfo('description');
94
+
95
+ //URL
96
+ $tags['og:url'] = suwp::get_blog_home_url();
97
+
98
+ //Image
99
+ $tags['og:image'] = $this->get_setting('home_og_image');
100
+
101
+ } elseif (is_singular()) {
102
+
103
+ $post = $wp_query->get_queried_object();
104
+
105
+ if (is_object($post)) {
106
+ //Type
107
+ if (!($tags['og:type'] = $this->get_postmeta('og_type')))
108
+ $tags['og:type'] = $this->get_setting("default_{$post->post_type}_og_type");
109
+
110
+ //Twitter Type
111
+ if (!($twitter_tags['twitter:card'] = $this->get_postmeta('twitter_card')))
112
+ $twitter_tags['twitter:card'] = $this->get_setting("default_{$post->post_type}_twitter_card");
113
+
114
+ //Title
115
+ if (!($tags['og:title'] = $this->get_postmeta('og_title')))
116
+ $tags['og:title'] = strip_tags( apply_filters( 'single_post_title', $post->post_title ) );
117
+
118
+ //Description
119
+ if (!($tags['og:description'] = $this->get_postmeta('og_description')))
120
+ if ($this->plugin->call_module_func('meta-descriptions', 'get_meta_desc', $meta_desc, false) && $meta_desc)
121
+ $tags['og:description'] = $meta_desc;
122
+
123
+ //URL
124
+ $tags['og:url'] = get_permalink($post->ID);
125
+
126
+ //Image
127
+ $tags['og:image'] = $this->jlsuggest_value_to_url($this->get_postmeta('og_image'), true);
128
+ if (!$tags['og:image']) {
129
+ if ('attachment' == $post->post_type) {
130
+ $tags['og:image'] = wp_get_attachment_url();
131
+ } elseif (current_theme_supports('post-thumbnails') && $thumbnail_id = get_post_thumbnail_id($post->ID)) {
132
+ $tags['og:image'] = wp_get_attachment_url($thumbnail_id);
133
+ }
134
+ }
135
+
136
+ //Additional fields
137
+ switch ($tags['og:type']) {
138
+ case 'article':
139
+
140
+ $tags['article:published_time'] = get_the_date('Y-m-d');
141
+ $tags['article:modified_time'] = get_the_modified_date('Y-m-d');
142
+
143
+ //Authorship generally doesn't apply to pages
144
+ if (!is_page() && $this->get_setting('enable_og_article_author', true))
145
+ $tags['article:author'] = get_author_posts_url($post->post_author);
146
+
147
+ $single_category = (count(get_the_category()) == 1);
148
+
149
+ $taxonomy_names = suwp::get_taxonomy_names();
150
+ foreach ($taxonomy_names as $taxonomy_name) {
151
+ if ($terms = get_the_terms(get_the_ID(), $taxonomy_name)) {
152
+
153
+ if ($single_category && 'category' == $taxonomy_name)
154
+ $meta_property = 'article:section';
155
+ else
156
+ $meta_property = 'article:tag';
157
+
158
+ foreach ($terms as $term) {
159
+ $tags[$meta_property][] = $term->name;
160
+ }
161
+ }
162
+ }
163
+
164
+ break;
165
+ }
166
+
167
+ //Author's Twitter Handle
168
+ $handle = get_user_meta($post->post_author, 'twitter', true);
169
+ $handle = $this->sanitize_twitter_handle($handle);
170
+ $twitter_tags['twitter:creator'] = $handle;
171
+ }
172
+ } elseif (is_author()) {
173
+
174
+ $author = $wp_query->get_queried_object();
175
+
176
+ if (is_object($author)) {
177
+ //Type
178
+ $tags['og:type'] = 'profile';
179
+
180
+ //Title
181
+ $tags['og:title'] = $author->display_name;
182
+
183
+ //Description
184
+ $tags['og:title'] = get_the_author_meta('description', $author->ID);
185
+
186
+ //Image
187
+ $tags['og:image'] = false;
188
+
189
+ //URL
190
+ $tags['og:url'] = get_author_posts_url($author->ID, $author->user_nicename);
191
+
192
+ //First Name
193
+ $tags['profile:first_name'] = get_the_author_meta('first_name', $author->ID);
194
+
195
+ //Last Name
196
+ $tags['profile:last_name'] = get_the_author_meta('last_name', $author->ID);
197
+
198
+ //Username
199
+ $tags['profile:username'] = $author->user_login;
200
+
201
+ //Twitter Handle
202
+ $handle = get_user_meta($author->ID, 'twitter', true);
203
+ $handle = $this->sanitize_twitter_handle($handle);
204
+ $twitter_tags['twitter:creator'] = $handle;
205
+ }
206
+ } else
207
+ return;
208
+
209
+ if ($tags['og:type'] == 'none')
210
+ $tags['og:type'] = '';
211
+
212
+ if ((!isset($tags['og:image']) || !$tags['og:image']) && $tags['og:image'] !== false)
213
+ $tags['og:image'] = $this->jlsuggest_value_to_url($this->get_setting('default_og_image'), true);
214
+
215
+ //Site Name
216
+ if (!($tags['og:site_name'] = $this->get_setting('og_site_name')))
217
+ $tags['og:site_name'] = get_bloginfo('name');
218
+
219
+ //FB App ID
220
+ $tags['fb:app_id'] = $this->get_setting('default_fb_app_id');
221
+
222
+ //Twitter Site Handle
223
+ $twitter_tags['twitter:site'] = $this->get_setting('twitter_site_handle');
224
+ $twitter_tags['twitter:site:id'] = $this->get_setting('twitter_site_id_handle');
225
+ $twitter_tags['twitter:creator'] = $this->get_setting('twitter_creator_handle');
226
+ $twitter_tags['twitter:creator:id'] = $this->get_setting('twitter_creator_id_handle');
227
+ $twitter_tags['twitter:description'] = $this->get_setting('twitter_description_handle');
228
+ $twitter_tags['twitter:title'] = $this->get_setting('twitter_title_handle');
229
+ $twitter_tags['twitter:image:src'] = $this->get_setting('twitter_image_src_handle');
230
+ $twitter_tags['twitter:image:width'] = $this->get_setting('twitter_image_width_handle');
231
+ $twitter_tags['twitter:image:height'] = $this->get_setting('twitter_image_height_handle');
232
+ $twitter_tags['twitter:data1'] = $this->get_setting('twitter_data1_handle');
233
+ $twitter_tags['twitter:label1'] = $this->get_setting('twitter_label1_handle');
234
+ $twitter_tags['twitter:data2'] = $this->get_setting('twitter_data2_handle');
235
+ $twitter_tags['twitter:label2'] = $this->get_setting('twitter_label2_handle');
236
+ $twitter_tags['twitter:image0:src'] = $this->get_setting('twitter_image0_src_handle');
237
+ $twitter_tags['twitter:image1:src'] = $this->get_setting('twitter_image1_src_handle');
238
+ $twitter_tags['twitter:image2:src'] = $this->get_setting('twitter_image2_src_handle');
239
+ $twitter_tags['twitter:image3:src'] = $this->get_setting('twitter_image3_src_handle');
240
+ $twitter_tags['twitter:player'] = $this->get_setting('twitter_player_handle');
241
+ $twitter_tags['twitter:player:width'] = $this->get_setting('twitter_player_width_handle');
242
+ $twitter_tags['twitter:player:height'] = $this->get_setting('twitter_player_height_handle');
243
+ $twitter_tags['twitter:player:stream'] = $this->get_setting('twitter_player_stream_handle');
244
+ $twitter_tags['twitter:app:name:iphone'] = $this->get_setting('twitter_app_name_iphone_handle');
245
+ $twitter_tags['twitter:app:id:iphone'] = $this->get_setting('twitter_app_id_iphone_handle');
246
+ $twitter_tags['twitter:app:url:iphone'] = $this->get_setting('twitter_app_url_iphone_handle');
247
+ $twitter_tags['twitter:app:name:iphone'] = $this->get_setting('twitter_app_name_ipad_handle');
248
+ $twitter_tags['twitter:app:id:iphone'] = $this->get_setting('twitter_app_id_ipad_handle');
249
+ $twitter_tags['twitter:app:url:iphone'] = $this->get_setting('twitter_app_url_ipad_handle');
250
+ $twitter_tags['twitter:app:name:googleplay'] = $this->get_setting('twitter_app_name_googleplay_handle');
251
+ $twitter_tags['twitter:app:id:googleplay'] = $this->get_setting('twitter_app_id_googleplay_handle');
252
+ $twitter_tags['twitter:app:url:googleplay'] = $this->get_setting('twitter_app_url_googleplay_handle');
253
+
254
+
255
+ //Output meta tags
256
+ $namespace_urls = $this->namespaces_declared ? array() : $this->get_namespace_urls();
257
+ $doctype = $this->get_setting('doctype', '');
258
+
259
+ switch ($doctype) {
260
+ case 'xhtml':
261
+ $output_formats = array('<meta%3$s name="%1$s" content="%2$s" />' => array_merge($tags, $twitter_tags));
262
+ break;
263
+ case 'html5':
264
+ $output_formats = array('<meta%3$s property="%1$s" content="%2$s">' => array_merge($tags, $twitter_tags));
265
+ break;
266
+ default:
267
+ $output_formats = array(
268
+ '<meta%3$s property="%1$s" content="%2$s" />' => $tags
269
+ , '<meta%3$s name="%1$s" content="%2$s" />' => $twitter_tags
270
+ );
271
+ break;
272
+ }
273
+
274
+ foreach ($output_formats as $html_format => $format_tags) {
275
+ foreach ($format_tags as $property => $values) {
276
+ foreach ((array)$values as $value) {
277
+ $property = su_esc_attr($property);
278
+ $value = su_esc_attr($value);
279
+ if (strlen(trim($property)) && strlen(trim($value))) {
280
+
281
+ $namespace_attr = '';
282
+ $namespace = sustr::upto($property, ':');
283
+ if (!empty($namespace_urls[$namespace])) {
284
+ $a_namespace = su_esc_attr($namespace);
285
+ $a_namespace_url = su_esc_attr($namespace_urls[$namespace]);
286
+
287
+ switch ($doctype) {
288
+ case 'xhtml':
289
+ $namespace_attr = " xmlns:$a_namespace=\"$a_namespace_url\"";
290
+ break;
291
+ case 'html5':
292
+ default:
293
+ $namespace_attr = " prefix=\"$a_namespace: $a_namespace_url\"";
294
+ break;
295
+ }
296
+ }
297
+
298
+ echo "\t";
299
+ printf($html_format, $property, $value, $namespace_attr);
300
+ echo "\n";
301
+ }
302
+ }
303
+ }
304
+ }
305
+ }
306
+
307
+ function admin_page_init() {
308
+ $this->jlsuggest_init();
309
+ }
310
+
311
+ function editor_init() {
312
+ $this->jlsuggest_init();
313
+ }
314
+
315
+ function get_admin_page_tabs() {
316
+
317
+ $postmeta_edit_tabs = $this->get_postmeta_edit_tabs(array(
318
+ array(
319
+ 'type' => 'dropdown'
320
+ , 'options' => array_merge(array('' => __('Use default', 'seo-ultimate')), $this->get_type_options())
321
+ , 'name' => 'og_type'
322
+ , 'label' => __('Type', 'seo-ultimate')
323
+ )
324
+ , array(
325
+ 'type' => 'textbox'
326
+ , 'name' => 'og_title'
327
+ , 'label' => __('Title', 'seo-ultimate')
328
+ )
329
+ , array(
330
+ 'type' => 'textbox'
331
+ , 'name' => 'og_description'
332
+ , 'label' => __('Description', 'seo-ultimate')
333
+ )
334
+ , array(
335
+ 'type' => 'jlsuggest'
336
+ , 'name' => 'og_image'
337
+ , 'label' => __('Image', 'seo-ultimate')
338
+ , 'options' => array(
339
+ 'params' => 'types=posttype_attachment&post_mime_type=image/*'
340
+ ))
341
+ ));
342
+
343
+ //Remove the Image boxes from the Media tab
344
+ //(it's obvious what the og:image of an attachment should be...)
345
+ unset($postmeta_edit_tabs['attachment']['callback'][5][3]);
346
+
347
+ return array_merge(
348
+ array(
349
+ array('title' => __('Sitewide Values', 'seo-ultimate'), 'id' => 'su-sitewide-values', 'callback' => 'global_tab')
350
+ , array('title' => __('Default Values', 'seo-ultimate'), 'id' => 'su-default-values', 'callback' => 'defaults_tab')
351
+ , array('title' => __('Settings', 'seo-ultimate'), 'id' => 'su-settings', 'callback' => 'settings_tab')
352
+ , array('title' => __('Blog Homepage', 'seo-ultimate'), 'id' => 'su-homepage', 'callback' => 'home_tab')
353
+ )
354
+ , $postmeta_edit_tabs
355
+ );
356
+ }
357
+
358
+ function global_tab() {
359
+ $this->admin_form_table_start();
360
+ $this->textbox('og_site_name', __('Site Name', 'seo-ultimate'), false, false, array(), array('placeholder' => get_bloginfo('name')));
361
+ $this->textbox('default_fb_app_id', __('Facebook App ID', 'seo-ultimate'));
362
+ $this->textbox('twitter_site_handle', __('@username of website', 'seo-ultimate'), false, false, array('help_text' => 'twitter:site', 'callout' => 'Twitter Card Tags'));
363
+ $this->textbox('twitter_site_id_handle', __('Same as twitter:site, but the user&#8217;s Twitter ID', 'seo-ultimate'), false, false, array('help_text' => 'twitter:site:id'));
364
+ $this->textbox('twitter_creator_handle', __('@username of content creator', 'seo-ultimate'), false, false, array('help_text' => 'twitter:creator'));
365
+ $this->textbox('twitter_creator_id_handle', __('Twitter user ID of content creator', 'seo-ultimate'), false, false, array('help_text' => 'twitter:creator:id'));
366
+ $this->textbox('twitter_description_handle', __('Description of content (maximum 200 characters)', 'seo-ultimate'), false, false, array('help_text' => 'twitter:description'));
367
+ $this->textbox('twitter_title_handle', __('Title of content (maximum 70 characters)', 'seo-ultimate'), false, false, array('help_text' => 'twitter:title'));
368
+ $this->textbox('twitter_image_src_handle', __('URL of image to use in the card. Image must be less than 1MB in size.', 'seo-ultimate'), false, false, array('help_text' => 'twitter:image:src'));
369
+ $this->textbox('twitter_image_width_handle', __('Width of image in pixels', 'seo-ultimate'), false, false, array('help_text' => 'twitter:image:width'));
370
+ $this->textbox('twitter_image_height_handle', __('Height of image in pixels', 'seo-ultimate'), false, false, array('help_text' => 'twitter:image:height'));
371
+ $this->textbox('twitter_data1_handle', __('Top customizable data field, can be a relatively short string (ie "$3.99")', 'seo-ultimate'), false, false, array('help_text' => 'twitter:data1'));
372
+ $this->textbox('twitter_label1_handle', __('Customizable label or units for the information in twitter:data1 (best practice: use all caps)', 'seo-ultimate'), false, false, array('help_text' => 'twitter:label1'));
373
+ $this->textbox('twitter_data2_handle', __('Bottom customizable data field, can be a relatively short string (ie "Seattle, WA")', 'seo-ultimate'), false, false, array('help_text' => 'twitter:data2'));
374
+ $this->textbox('twitter_label2_handle', __('Customizable label or units for the information in twitter:data1 (best practice: use all caps)', 'seo-ultimate'), false, false, array('help_text' => 'twitter:label2'));
375
+ $this->textbox('twitter_image0_src_handle', __('1st image in the gallery. Images must be less than 1MB in size.', 'seo-ultimate'), false, false, array('help_text' => 'twitter:image0:src'));
376
+ $this->textbox('twitter_image1_src_handle', __('2nd image in the gallery. Images must be less than 1MB in size.', 'seo-ultimate'), false, false, array('help_text' => 'twitter:image1:src'));
377
+ $this->textbox('twitter_image2_src_handle', __('3rd image in the gallery. Images must be less than 1MB in size.', 'seo-ultimate'), false, false, array('help_text' => 'twitter:image2:src'));
378
+ $this->textbox('twitter_image3_src_handle', __('4th image in the gallery. Images must be less than 1MB in size.', 'seo-ultimate'), false, false, array('help_text' => 'twitter:image3:src'));
379
+ $this->textbox('twitter_player_handle', __(' HTTPS URL of player iframe', 'seo-ultimate'), false, false, array('help_text' => 'twitter:player'));
380
+ $this->textbox('twitter_player_width_handle', __('Width of iframe in pixels', 'seo-ultimate'), false, false, array('help_text' => 'twitter:player:width'));
381
+ $this->textbox('twitter_player_height_handle', __('Height of iframe in pixels', 'seo-ultimate'), false, false, array('help_text' => 'twitter:player:height'));
382
+ $this->textbox('twitter_player_stream_handle', __('URL to raw video or audio stream', 'seo-ultimate'), false, false, array('help_text' => 'twitter:player:stream'));
383
+ $this->textbox('twitter_app_name_iphone_handle', __('Name of your iPhone app', 'seo-ultimate'), false, false, array('help_text' => 'twitter:app:name:iphone'));
384
+ $this->textbox('twitter_app_id_iphone_handle', __('Your app ID in the iTunes App Store (Note: NOT your bundle ID)', 'seo-ultimate'), false, false, array('help_text' => 'twitter:app:id:iphone'));
385
+ $this->textbox('twitter_app_url_iphone_handle', __('Your app&#8217;s custom URL scheme (you must include "://" after your scheme name)', 'seo-ultimate'), false, false, array('help_text' => 'twitter:app:url:iphone'));
386
+ $this->textbox('twitter_app_name_ipad_handle', __('Name of your iPad optimized app', 'seo-ultimate'), false, false, array('help_text' => 'twitter:app:name:ipad'));
387
+ $this->textbox('twitter_app_id_ipad_handle', __('Your app ID in the iTunes App Store', 'seo-ultimate'), false, false, array('help_text' => 'twitter:app:id:ipad'));
388
+ $this->textbox('twitter_app_url_ipad_handle', __('Your app&#8217;s custom URL scheme', 'seo-ultimate'), false, false, array('help_text' => 'twitter:app:url:ipad'));
389
+ $this->textbox('twitter_app_name_googleplay_handle', __('Name of your Android app', 'seo-ultimate'), false, false, array('help_text' => 'twitter:app:name:googleplay'));
390
+ $this->textbox('twitter_app_id_googleplay_handle', __('Your app ID in the Google Play Store', 'seo-ultimate'), false, false, array('help_text' => 'twitter:app:id:googleplay'));
391
+ $this->textbox('twitter_app_url_googleplay_handle', __('Your app#8217;s custom URL scheme', 'seo-ultimate'), false, false, array('help_text' => 'twitter:app:url:googleplay'));
392
+ $this->admin_form_table_end();
393
+ }
394
+
395
+ function defaults_tab() {
396
+ $posttypes = get_post_types(array('public' => true), 'objects');
397
+
398
+ $this->admin_subheader(__('Default Types', 'seo-ultimate'));
399
+ $this->admin_wftable_start(array(
400
+ 'posttype' => __('Post Type', 'seo-ultimate')
401
+ , 'og' => __('Open Graph Type', 'seo-ultimate')
402
+ , 'twitter' => __('Twitter Type', 'seo-ultimate')
403
+ ));
404
+ foreach ($posttypes as $posttype) {
405
+ echo "<tr valign='middle'>\n";
406
+ echo "\t<th class='su-opengraph-posttype' scope='row'>" . esc_html($posttype->labels->name) . "</th>\n";
407
+ echo "\t<td class='su-opengraph-og'>";
408
+ $this->dropdown("default_{$posttype->name}_og_type", $this->get_type_options(), false, '%s', array('in_table' => false));
409
+ echo "</td>\n";
410
+ echo "\t<td class='su-opengraph-twitter'>";
411
+ $this->dropdown("default_{$posttype->name}_twitter_card", $this->get_twitter_type_options(), false, '%s', array('in_table' => false));
412
+ echo "</td>\n";
413
+ echo "</tr>\n";
414
+ }
415
+ $this->admin_wftable_end();
416
+
417
+ $this->admin_subheader(__('Default Image', 'seo-ultimate'));
418
+ $this->admin_form_table_start();
419
+
420
+ $this->textblock(__('In the box below, you can specify an image URL or an image from your media library to use as a default image in the event that there is no image otherwise specified for a given webpage on your site.', 'seo-ultimate'));
421
+
422
+ $this->medialib_box('default_og_image', __('Default Image', 'seo-ultimate'), 'types=posttype_attachment&post_mime_type=image/*');
423
+
424
+ $this->admin_form_table_end();
425
+ }
426
+
427
+ function settings_tab() {
428
+ $this->admin_form_table_start();
429
+ $this->checkbox('enable_og_article_author', __('Include author data for posts', 'seo-ultimate'), __('Open Graph Data', 'seo-ultimate'));
430
+ $this->radiobuttons('doctype', array(
431
+ '' => __('Use the non-validating code prescribed by Open Graph and Twitter', 'seo-ultimate')
432
+ , 'xhtml' => __('Alter the code to validate as XHTML', 'seo-ultimate')
433
+ , 'html5' => __('Alter the code to validate as HTML5', 'seo-ultimate')
434
+ ), __('HTML Validation', 'seo-ultimate'));
435
+ $this->admin_form_table_end();
436
+ }
437
+
438
+ function home_tab() {
439
+ $this->admin_form_table_start();
440
+ $this->textbox('home_og_title', __('Blog Homepage Title', 'seo-ultimate'), false, false, array(), array('placeholder' => get_bloginfo('name')));
441
+ $this->textbox('home_og_description', __('Blog Homepage Description', 'seo-ultimate'), false, false, array(), array('placeholder' => get_bloginfo('description')));
442
+ $this->medialib_box('home_og_image', __('Blog Homepage Image', 'seo-ultimate'), 'types=posttype_attachment&post_mime_type=image/*');
443
+ $this->admin_form_table_end();
444
+ }
445
+
446
+ function postmeta_fields($fields, $screen) {
447
+
448
+ $fields['opengraph'][10]['og_title'] = $this->get_postmeta_textbox('og_title', __('Title:', 'seo-ultimate'));
449
+ $fields['opengraph'][20]['og_description'] = $this->get_postmeta_textarea('og_description', __('Description:', 'seo-ultimate'));
450
+ $fields['opengraph'][30]['og_image'] = $this->get_postmeta_medialib_box('og_image', __('Image:', 'seo-ultimate'));
451
+ $fields['opengraph'][40]['og_type'] = $this->get_postmeta_dropdown('og_type', array_merge(array('' => __('Use default', 'seo-ultimate')), $this->get_type_options()), __('Open Graph Type:', 'seo-ultimate'));
452
+ $fields['opengraph'][50]['twitter_card'] = $this->get_postmeta_dropdown('twitter_card', array_merge(array('' => __('Use default', 'seo-ultimate')), $this->get_twitter_type_options()), __('Twitter Type:', 'seo-ultimate'));
453
+
454
+ return $fields;
455
+ }
456
+
457
+ function get_postmeta_jlsuggest_boxes($jls_boxes) {
458
+ $this->jlsuggest_box_post_id = suwp::get_post_id();
459
+ return parent::get_postmeta_jlsuggest_boxes($jls_boxes);
460
+ }
461
+
462
+ function get_input_element($type, $name, $value=null, $extra=false, $inputid=true) {
463
+
464
+ $name_parts = explode('_', $name);
465
+ if (isset($name_parts[1]) && is_numeric($post_id = $name_parts[1]))
466
+ $this->jlsuggest_box_post_id = $post_id;
467
+ else
468
+ $this->jlsuggest_box_post_id = false;
469
+
470
+ return parent::get_input_element($type, $name, $value, $extra, $inputid);
471
+ }
472
+
473
+ function get_jlsuggest_box($name, $value, $params='', $placeholder='') {
474
+
475
+ if (empty($value) && $this->jlsuggest_box_post_id && current_theme_supports('post-thumbnails') && $thumbnail_id = get_post_thumbnail_id($this->jlsuggest_box_post_id)) {
476
+ $selected_post = get_post($thumbnail_id);
477
+ $placeholder = sprintf(__('Featured Image: %s', 'seo-ultimate'), $selected_post->post_title);
478
+ }
479
+
480
+ return parent::get_jlsuggest_box($name, $value, $params, $placeholder);
481
+ }
482
+
483
+ function get_type_options() {
484
+ return array(
485
+ 'none' => __('None', 'seo-ultimate')
486
+ , __('Internet', 'seo-ultimate') => array(
487
+ 'article' => __('Article', 'seo-ultimate')
488
+ , 'blog' => __('Blog', 'seo-ultimate')
489
+ , 'profile' => __('Profile', 'seo-ultimate')
490
+ , 'website' => __('Website', 'seo-ultimate')
491
+ ),__('Products', 'seo-ultimate') => array(
492
+ 'book' => __('Book', 'seo-ultimate')
493
+ ),__('Music', 'seo-ultimate') => array(
494
+ 'music.album' => __('Album', 'seo-ultimate')
495
+ , 'music.playlist' => __('Playlist', 'seo-ultimate')
496
+ , 'music.radio_station' => __('Radio Station', 'seo-ultimate')
497
+ , 'music.song' => __('Song', 'seo-ultimate')
498
+ ),__('Videos', 'seo-ultimate') => array(
499
+ 'video.movie' => __('Movie', 'seo-ultimate')
500
+ , 'video.episode' => __('TV Episode', 'seo-ultimate')
501
+ , 'video.tv_show' => __('TV Show', 'seo-ultimate')
502
+ , 'video.other' => __('Video', 'seo-ultimate')
503
+ )
504
+ );
505
+ }
506
+
507
+ function get_twitter_type_options() {
508
+ return array(
509
+ 'summary' => __('Summary', 'seo-ultimate')
510
+ , 'product' => __('Product', 'seo-ultimate')
511
+ , 'photo' => __('Photo', 'seo-ultimate')
512
+ , 'summary_large_image' => __('Summary Large Image', 'seo-ultimate')
513
+ , 'gallery' => __('Gallery', 'seo-ultimate')
514
+ , 'player' => __('Player', 'seo-ultimate')
515
+ , 'app' => __('App', 'seo-ultimate')
516
+ );
517
+ }
518
+
519
+ function sanitize_twitter_handle($value) {
520
+ if (strpos($value, '/') === false) {
521
+ $handle = ltrim($value, '@');
522
+ } else {
523
+ $url_parts = explode('/', $value);
524
+ $handle = array_pop($url_parts);
525
+ }
526
+
527
+ $handle = sustr::preg_filter('a-zA-Z0-9_', $handle);
528
+ $handle = trim($handle);
529
+
530
+ if ($handle)
531
+ $handle = "@$handle";
532
+
533
+ return $handle;
534
+ }
535
+
536
+ function add_twitter_field( $contactmethods ) {
537
+ $contactmethods['twitter'] = __('Twitter Handle', 'seo-ultimate');
538
+ return $contactmethods;
539
+ }
540
+
541
+ function add_help_tabs($screen) {
542
+
543
+ $screen->add_help_tab(array(
544
+ 'id' => 'su-opengraph-overview'
545
+ , 'title' => __('Overview', 'seo-ultimate')
546
+ , 'content' => __("
547
+ <ul>
548
+ <li><strong>What it does:</strong> Open Graph Integrator makes it easy for you to convey information about your site to social networks like Facebook, Twitter, and Google+.</li>
549
+ <li><strong>Why it helps:</strong> By providing this Open Graph data, you can customize how these social networks will present your site when people share it with their followers.</li>
550
+ <li><strong>How to use it:</strong> The &#8220;Sitewide Values&#8221; tab lets you specify data that applies to your entire site. The &#8220;Default Values&#8221; tab lets you specify default data for your posts, pages, etc. The bulk editor tabs let you override those defaults on individual posts and pages. If the authors on your site fill in the &#8220;Twitter Handle&#8221; field which Open Graph Integrator adds to the <a href='profile.php'>profile editor</a>, Open Graph Integrator will communicate that information to Twitter as well.</li>
551
+ </ul>
552
+ ", 'seo-ultimate')));
553
+
554
+ }
555
+ }
556
+
557
+ }
558
  ?>
modules/permalinks/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/permalinks/permalinks.css CHANGED
@@ -1,19 +1,19 @@
1
- #su-permalinks table.widefat {
2
- width: 100%;
3
- }
4
-
5
- #su-permalinks table.widefat th,
6
- #su-permalinks table.widefat td {
7
- vertical-align: middle;
8
- padding: 5px;
9
- }
10
-
11
- #su-permalinks table.widefat .su-permalinks-taxonomy {
12
- width: 10em;
13
- }
14
-
15
- #su-permalinks table.widefat .su-permalinks-arrow {
16
- width: 2em;
17
- padding: 0;
18
- text-align: center;
19
  }
1
+ #su-permalinks table.widefat {
2
+ width: 100%;
3
+ }
4
+
5
+ #su-permalinks table.widefat th,
6
+ #su-permalinks table.widefat td {
7
+ vertical-align: middle;
8
+ padding: 5px;
9
+ }
10
+
11
+ #su-permalinks table.widefat .su-permalinks-taxonomy {
12
+ width: 10em;
13
+ }
14
+
15
+ #su-permalinks table.widefat .su-permalinks-arrow {
16
+ width: 2em;
17
+ padding: 0;
18
+ text-align: center;
19
  }
modules/permalinks/permalinks.php CHANGED
@@ -1,209 +1,209 @@
1
- <?php
2
- /**
3
- * Permalink Tweaker Module
4
- *
5
- * @since 5.8
6
- */
7
-
8
- //Permalink base removal code based on code from WP No Category Base plugin
9
- //http://wordpress.org/extend/plugins/wp-no-category-base/
10
-
11
- if (class_exists('SU_Module')) {
12
-
13
- class SU_Permalinks extends SU_Module {
14
-
15
- static function get_module_title() { return __('Permalink Tweaker', 'seo-ultimate'); }
16
- static function get_parent_module() { return 'misc'; }
17
- function get_settings_key() { return 'permalinks'; }
18
-
19
- function get_default_settings() {
20
- return array(
21
- 'add_rule_if_conflict' => true
22
- );
23
- }
24
-
25
- function init() {
26
- if (suwp::permalink_mode()) {
27
- $nobase_enabled = false;
28
- $taxonomies = suwp::get_taxonomy_names();
29
- foreach ($taxonomies as $taxonomy) {
30
- if ($this->get_setting("nobase_$taxonomy", false)) {
31
- add_action("created_$taxonomy", array(&$this, 'flush_rewrite_rules'));
32
- add_action("edited_$taxonomy", array(&$this, 'flush_rewrite_rules'));
33
- add_action("delete_$taxonomy", array(&$this, 'flush_rewrite_rules'));
34
- add_filter("{$taxonomy}_rewrite_rules", array(&$this, 'nobase_rewrite_rules'));
35
- $nobase_enabled = true;
36
- }
37
- }
38
- if ($nobase_enabled) {
39
- add_action('wp_insert_post', array(&$this, 'flush_rewrite_rules'));
40
- add_filter('term_link', array(&$this, 'nobase_term_link'), 1000, 2);
41
- add_filter('query_vars', array(&$this, 'nobase_query_vars'));
42
- add_filter('request', array(&$this, 'nobase_old_base_redirect'));
43
- }
44
- }
45
- }
46
-
47
- function deactivate() {
48
- if (suwp::permalink_mode()) {
49
- $nobase_enabled = false;
50
- $taxonomies = suwp::get_taxonomy_names();
51
- foreach ($taxonomies as $taxonomy) {
52
- if ($this->get_setting("nobase_$taxonomy", false)) {
53
- remove_action("created_$taxonomy", array(&$this, 'flush_rewrite_rules'));
54
- remove_action("edited_$taxonomy", array(&$this, 'flush_rewrite_rules'));
55
- remove_action("delete_$taxonomy", array(&$this, 'flush_rewrite_rules'));
56
- remove_filter("{$taxonomy}_rewrite_rules", array(&$this, 'nobase_rewrite_rules'));
57
- $nobase_enabled = true;
58
- }
59
- }
60
- if ($nobase_enabled) {
61
- remove_action('wp_insert_post', array(&$this, 'flush_rewrite_rules'));
62
- remove_filter('term_link', array(&$this, 'nobase_term_link'), 1000, 2);
63
- remove_filter('query_vars', array(&$this, 'nobase_query_vars'));
64
- remove_filter('request', array(&$this, 'nobase_old_base_redirect'));
65
- }
66
- }
67
-
68
- $this->flush_rewrite_rules();
69
- }
70
-
71
- function admin_page_contents() {
72
-
73
- if (!suwp::permalink_mode()) {
74
- $this->print_message('warning', __('To use the Permalinks Tweaker, you must disable default (query-string) permalinks in your <a href="options-permalink.php">Permalink Settings</a>.', 'seo-ultimate'));
75
- return;
76
- }
77
-
78
- $this->child_admin_form_start();
79
-
80
- $nobase_checkboxes = array();
81
- $taxonomies = suwp::get_taxonomies();
82
- foreach ($taxonomies as $taxonomy) {
83
-
84
- global $wp_rewrite;
85
- $before_url = $wp_rewrite->get_extra_permastruct($taxonomy->name);
86
- $before_url = str_replace("%{$taxonomy->name}%", 'example', $before_url);
87
- $before_url = home_url( user_trailingslashit($before_url, 'category') );
88
-
89
- $after_url = home_url( user_trailingslashit('/example', 'category') );
90
-
91
- $nobase_checkboxes[] = array(
92
- 'setting_id' => 'nobase_' . $taxonomy->name
93
- , 'taxonomy_label' => $taxonomy->labels->name
94
- , 'example_before' => $before_url
95
- , 'example_after' => $after_url
96
- );
97
- }
98
-
99
- $this->admin_form_group_start(__('Remove the URL bases of...', 'seo-ultimate'));
100
-
101
- echo "<tr><td>\n";
102
- $this->admin_wftable_start(array(
103
- 'taxonomy' => ' '
104
- , 'before' => __('Before', 'seo-ultimate')
105
- , 'arrow' => ' '
106
- , 'after' => __('After', 'seo-ultimate')
107
- ));
108
-
109
- foreach ($nobase_checkboxes as $nobase_checkbox) {
110
- echo "<tr>\n";
111
- echo "<td class='su-permalinks-taxonomy'>";
112
- $this->checkbox($nobase_checkbox['setting_id'], $nobase_checkbox['taxonomy_label'], false, array('output_tr' => false));
113
- echo "</td>\n";
114
- echo "<td class='su-permalinks-before'>" . esc_html($nobase_checkbox['example_before']) . "</td>\n";
115
- echo "<td class='su-permalinks-arrow'>&rArr;</td>\n";
116
- echo "<td class='su-permalinks-after'>" . esc_html($nobase_checkbox['example_after']) . "</td>\n";
117
- echo "</tr>\n";
118
- }
119
-
120
- $this->admin_wftable_end();
121
- echo "</td></tr>\n";
122
-
123
- $this->admin_form_group_end();
124
-
125
- $this->dropdown('add_rule_if_conflict', array(
126
- '1' => __('term archive', 'seo-ultimate')
127
- , '0' => __('page', 'seo-ultimate')
128
- ), __('URL Conflict Resolution', 'seo-ultimate'), __('If a term archive and a Page with the same slug end up having the same URL because of the term&#8217;s base being removed, the URL should be given to the %s.', 'seo-ultimate'));
129
-
130
- $this->child_admin_form_end();
131
-
132
- $this->update_rewrite_filters();
133
- $this->flush_rewrite_rules();
134
- }
135
-
136
- function flush_rewrite_rules() {
137
- global $wp_rewrite;
138
- $wp_rewrite->flush_rules();
139
- }
140
-
141
- function update_rewrite_filters() {
142
- if (suwp::permalink_mode()) {
143
- $taxonomies = suwp::get_taxonomy_names();
144
- foreach ($taxonomies as $taxonomy) {
145
- if ($this->get_setting("nobase_$taxonomy", false))
146
- add_filter("{$taxonomy}_rewrite_rules", array(&$this, 'nobase_rewrite_rules'));
147
- else
148
- remove_filter("{$taxonomy}_rewrite_rules", array(&$this, 'nobase_rewrite_rules'));
149
- }
150
- }
151
- }
152
-
153
- function nobase_term_link($url, $term_obj) {
154
- if ($this->get_setting('nobase_' . $term_obj->taxonomy, false))
155
- return home_url( user_trailingslashit('/' . suwp::get_term_slug($term_obj), 'category') );
156
-
157
- return $url;
158
- }
159
-
160
- function nobase_rewrite_rules($rules) {
161
- $rules=array();
162
-
163
- $tax_name = sustr::rtrim_str(current_filter(), '_rewrite_rules');
164
- $tax_obj = get_taxonomy($tax_name);
165
-
166
- wp_cache_flush(); //Otherwise get_terms() won't include the term just added
167
- $terms = get_terms($tax_name);
168
- if ($terms && !is_wp_error($terms)) {
169
- foreach ($terms as $term_obj) {
170
- $term_slug = suwp::get_term_slug($term_obj);
171
-
172
- if ($tax_obj->query_var && is_string($tax_obj->query_var))
173
- $url_start = "index.php?{$tax_obj->query_var}=";
174
- else
175
- $url_start = "index.php?taxonomy={$tax_name}&term=";
176
-
177
- if ($this->get_setting('add_rule_if_conflict', true) || get_page_by_path($term_slug) === null) {
178
- $rules['('.$term_slug.')/(?:feed/)?(feed|rdf|rss|rss2|atom)/?$'] = $url_start . '$matches[1]&feed=$matches[2]';
179
- $rules['('.$term_slug.')/page/?([0-9]{1,})/?$'] = $url_start . '$matches[1]&paged=$matches[2]';
180
- $rules['('.$term_slug.')/?$'] = $url_start . '$matches[1]';
181
- }
182
- }
183
- }
184
-
185
- global $wp_rewrite;
186
- $old_base = $wp_rewrite->get_extra_permastruct($tax_name);
187
- $old_base = str_replace( "%{$tax_name}%", '(.+)', $old_base );
188
- $old_base = trim($old_base, '/');
189
- $rules[$old_base.'$'] = 'index.php?su_term_redirect=$matches[1]';
190
-
191
- return $rules;
192
- }
193
-
194
- function nobase_query_vars($query_vars) {
195
- $query_vars[] = 'su_term_redirect';
196
- return $query_vars;
197
- }
198
-
199
- function nobase_old_base_redirect($query_vars) {
200
- if (isset($query_vars['su_term_redirect'])) {
201
- wp_redirect(home_url(user_trailingslashit($query_vars['su_term_redirect'], 'category')));
202
- exit;
203
- }
204
- return $query_vars;
205
- }
206
- }
207
-
208
- }
209
  ?>
1
+ <?php
2
+ /**
3
+ * Permalink Tweaker Module
4
+ *
5
+ * @since 5.8
6
+ */
7
+
8
+ //Permalink base removal code based on code from WP No Category Base plugin
9
+ //http://wordpress.org/extend/plugins/wp-no-category-base/
10
+
11
+ if (class_exists('SU_Module')) {
12
+
13
+ class SU_Permalinks extends SU_Module {
14
+
15
+ static function get_module_title() { return __('Permalink Tweaker', 'seo-ultimate'); }
16
+ static function get_parent_module() { return 'misc'; }
17
+ function get_settings_key() { return 'permalinks'; }
18
+
19
+ function get_default_settings() {
20
+ return array(
21
+ 'add_rule_if_conflict' => true
22
+ );
23
+ }
24
+
25
+ function init() {
26
+ if (suwp::permalink_mode()) {
27
+ $nobase_enabled = false;
28
+ $taxonomies = suwp::get_taxonomy_names();
29
+ foreach ($taxonomies as $taxonomy) {
30
+ if ($this->get_setting("nobase_$taxonomy", false)) {
31
+ add_action("created_$taxonomy", array(&$this, 'flush_rewrite_rules'));
32
+ add_action("edited_$taxonomy", array(&$this, 'flush_rewrite_rules'));
33
+ add_action("delete_$taxonomy", array(&$this, 'flush_rewrite_rules'));
34
+ add_filter("{$taxonomy}_rewrite_rules", array(&$this, 'nobase_rewrite_rules'));
35
+ $nobase_enabled = true;
36
+ }
37
+ }
38
+ if ($nobase_enabled) {
39
+ add_action('wp_insert_post', array(&$this, 'flush_rewrite_rules'));
40
+ add_filter('term_link', array(&$this, 'nobase_term_link'), 1000, 2);
41
+ add_filter('query_vars', array(&$this, 'nobase_query_vars'));
42
+ add_filter('request', array(&$this, 'nobase_old_base_redirect'));
43
+ }
44
+ }
45
+ }
46
+
47
+ function deactivate() {
48
+ if (suwp::permalink_mode()) {
49
+ $nobase_enabled = false;
50
+ $taxonomies = suwp::get_taxonomy_names();
51
+ foreach ($taxonomies as $taxonomy) {
52
+ if ($this->get_setting("nobase_$taxonomy", false)) {
53
+ remove_action("created_$taxonomy", array(&$this, 'flush_rewrite_rules'));
54
+ remove_action("edited_$taxonomy", array(&$this, 'flush_rewrite_rules'));
55
+ remove_action("delete_$taxonomy", array(&$this, 'flush_rewrite_rules'));
56
+ remove_filter("{$taxonomy}_rewrite_rules", array(&$this, 'nobase_rewrite_rules'));
57
+ $nobase_enabled = true;
58
+ }
59
+ }
60
+ if ($nobase_enabled) {
61
+ remove_action('wp_insert_post', array(&$this, 'flush_rewrite_rules'));
62
+ remove_filter('term_link', array(&$this, 'nobase_term_link'), 1000, 2);
63
+ remove_filter('query_vars', array(&$this, 'nobase_query_vars'));
64
+ remove_filter('request', array(&$this, 'nobase_old_base_redirect'));
65
+ }
66
+ }
67
+
68
+ $this->flush_rewrite_rules();
69
+ }
70
+
71
+ function admin_page_contents() {
72
+
73
+ if (!suwp::permalink_mode()) {
74
+ $this->print_message('warning', __('To use the Permalinks Tweaker, you must disable default (query-string) permalinks in your <a href="options-permalink.php">Permalink Settings</a>.', 'seo-ultimate'));
75
+ return;
76
+ }
77
+
78
+ $this->child_admin_form_start();
79
+
80
+ $nobase_checkboxes = array();
81
+ $taxonomies = suwp::get_taxonomies();
82
+ foreach ($taxonomies as $taxonomy) {
83
+
84
+ global $wp_rewrite;
85
+ $before_url = $wp_rewrite->get_extra_permastruct($taxonomy->name);
86
+ $before_url = str_replace("%{$taxonomy->name}%", 'example', $before_url);
87
+ $before_url = home_url( user_trailingslashit($before_url, 'category') );
88
+
89
+ $after_url = home_url( user_trailingslashit('/example', 'category') );
90
+
91
+ $nobase_checkboxes[] = array(
92
+ 'setting_id' => 'nobase_' . $taxonomy->name
93
+ , 'taxonomy_label' => $taxonomy->labels->name
94
+ , 'example_before' => $before_url
95
+ , 'example_after' => $after_url
96
+ );
97
+ }
98
+
99
+ $this->admin_form_group_start(__('Remove the URL bases of...', 'seo-ultimate'));
100
+
101
+ echo "<tr><td>\n";
102
+ $this->admin_wftable_start(array(
103
+ 'taxonomy' => ' '
104
+ , 'before' => __('Before', 'seo-ultimate')
105
+ , 'arrow' => ' '
106
+ , 'after' => __('After', 'seo-ultimate')
107
+ ));
108
+
109
+ foreach ($nobase_checkboxes as $nobase_checkbox) {
110
+ echo "<tr>\n";
111
+ echo "<td class='su-permalinks-taxonomy'>";
112
+ $this->checkbox($nobase_checkbox['setting_id'], $nobase_checkbox['taxonomy_label'], false, array('output_tr' => false));
113
+ echo "</td>\n";
114
+ echo "<td class='su-permalinks-before'>" . esc_html($nobase_checkbox['example_before']) . "</td>\n";
115
+ echo "<td class='su-permalinks-arrow'>&rArr;</td>\n";
116
+ echo "<td class='su-permalinks-after'>" . esc_html($nobase_checkbox['example_after']) . "</td>\n";
117
+ echo "</tr>\n";
118
+ }
119
+
120
+ $this->admin_wftable_end();
121
+ echo "</td></tr>\n";
122
+
123
+ $this->admin_form_group_end();
124
+
125
+ $this->dropdown('add_rule_if_conflict', array(
126
+ '1' => __('term archive', 'seo-ultimate')
127
+ , '0' => __('page', 'seo-ultimate')
128
+ ), __('URL Conflict Resolution', 'seo-ultimate'), __('If a term archive and a Page with the same slug end up having the same URL because of the term&#8217;s base being removed, the URL should be given to the %s.', 'seo-ultimate'));
129
+
130
+ $this->child_admin_form_end();
131
+
132
+ $this->update_rewrite_filters();
133
+ $this->flush_rewrite_rules();
134
+ }
135
+
136
+ function flush_rewrite_rules() {
137
+ global $wp_rewrite;
138
+ $wp_rewrite->flush_rules();
139
+ }
140
+
141
+ function update_rewrite_filters() {
142
+ if (suwp::permalink_mode()) {
143
+ $taxonomies = suwp::get_taxonomy_names();
144
+ foreach ($taxonomies as $taxonomy) {
145
+ if ($this->get_setting("nobase_$taxonomy", false))
146
+ add_filter("{$taxonomy}_rewrite_rules", array(&$this, 'nobase_rewrite_rules'));
147
+ else
148
+ remove_filter("{$taxonomy}_rewrite_rules", array(&$this, 'nobase_rewrite_rules'));
149
+ }
150
+ }
151
+ }
152
+
153
+ function nobase_term_link($url, $term_obj) {
154
+ if ($this->get_setting('nobase_' . $term_obj->taxonomy, false))
155
+ return home_url( user_trailingslashit('/' . suwp::get_term_slug($term_obj), 'category') );
156
+
157
+ return $url;
158
+ }
159
+
160
+ function nobase_rewrite_rules($rules) {
161
+ $rules=array();
162
+
163
+ $tax_name = sustr::rtrim_str(current_filter(), '_rewrite_rules');
164
+ $tax_obj = get_taxonomy($tax_name);
165
+
166
+ wp_cache_flush(); //Otherwise get_terms() won't include the term just added
167
+ $terms = get_terms($tax_name);
168
+ if ($terms && !is_wp_error($terms)) {
169
+ foreach ($terms as $term_obj) {
170
+ $term_slug = suwp::get_term_slug($term_obj);
171
+
172
+ if ($tax_obj->query_var && is_string($tax_obj->query_var))
173
+ $url_start = "index.php?{$tax_obj->query_var}=";
174
+ else
175
+ $url_start = "index.php?taxonomy={$tax_name}&term=";
176
+
177
+ if ($this->get_setting('add_rule_if_conflict', true) || get_page_by_path($term_slug) === null) {
178
+ $rules['('.$term_slug.')/(?:feed/)?(feed|rdf|rss|rss2|atom)/?$'] = $url_start . '$matches[1]&feed=$matches[2]';
179
+ $rules['('.$term_slug.')/page/?([0-9]{1,})/?$'] = $url_start . '$matches[1]&paged=$matches[2]';
180
+ $rules['('.$term_slug.')/?$'] = $url_start . '$matches[1]';
181
+ }
182
+ }
183
+ }
184
+
185
+ global $wp_rewrite;
186
+ $old_base = $wp_rewrite->get_extra_permastruct($tax_name);
187
+ $old_base = str_replace( "%{$tax_name}%", '(.+)', $old_base );
188
+ $old_base = trim($old_base, '/');
189
+ $rules[$old_base.'$'] = 'index.php?su_term_redirect=$matches[1]';
190
+
191
+ return $rules;
192
+ }
193
+
194
+ function nobase_query_vars($query_vars) {
195
+ $query_vars[] = 'su_term_redirect';
196
+ return $query_vars;
197
+ }
198
+
199
+ function nobase_old_base_redirect($query_vars) {
200
+ if (isset($query_vars['su_term_redirect'])) {
201
+ wp_redirect(home_url(user_trailingslashit($query_vars['su_term_redirect'], 'category')));
202
+ exit;
203
+ }
204
+ return $query_vars;
205
+ }
206
+ }
207
+
208
+ }
209
  ?>
modules/rich-snippets/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/rich-snippets/rich-snippets.php CHANGED
@@ -1,430 +1,430 @@
1
- <?php
2
- /**
3
- * Rich Snippet Creator Module
4
- *
5
- * @since 3.0
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_RichSnippets extends SU_Module {
11
-
12
- var $apply_subproperty_markup_args = array();
13
-
14
- static function get_module_title() { return __('Rich Snippet Creator', 'seo-ultimate'); }
15
-
16
- static function get_parent_module() { return 'misc'; }
17
- function get_settings_key() { return 'rich-snippets'; }
18
-
19
- function init() {
20
- add_filter('the_content', array(&$this, 'apply_markup'));
21
- }
22
-
23
- function admin_page_contents() {
24
- $this->child_admin_form_start();
25
- $this->textblock(__('Rich Snippet Creator adds a &#8220;Search Result Type&#8221; dropdown to the WordPress content editor screen. To add rich snippet data to a post, select &#8220;Review&#8221; or &#8220;Place&#8221; from a post&#8217;s &#8220;Search Result Type&#8221; dropdown and fill in the fields that appear.', 'seo-ultimate'));
26
- $this->child_admin_form_end();
27
- }
28
-
29
- function get_supported_snippet_formats() {
30
-
31
- return array(
32
- 'so' => array(
33
- 'label' => __('Schema.org Microdata', 'seo-ultimate')
34
- , 'item_tags_template' => '<div itemscope itemtype="http://schema.org/%1$s">%2$s</div>'
35
- , 'property_tags_template' => '<span itemprop="%1$s">%2$s</span>'
36
- , 'hidden_property_tags_template' => '<meta itemprop="%1$s" content="%2$s" />'
37
- )
38
- );
39
- }
40
-
41
- function get_supported_snippet_types() {
42
-
43
- return array(
44
- 'review' => array(
45
- 'label' => __('Review', 'seo-ultimate')
46
- , 'tags' => 'Review'
47
- , 'content_tags' => '<div itemprop="reviewBody">%s</div>'
48
- , 'properties' => array(
49
- 'item' => array(
50
- 'label' => __('Name of Reviewed Item', 'seo-ultimate')
51
- , 'tags' => 'itemReviewed'
52
- ),'rating' => array(
53
- 'label' => __('Star Rating', 'seo-ultimate')
54
- , 'value_format' => array('%s star', '%s stars', '%s-star', '%s-stars')
55
- , 'tags' => '<span itemprop="reviewRating" itemscope itemtype="http://schema.org/Rating">'
56
- . '<meta itemprop="worstRating" content="0" />'
57
- . '<span itemprop="ratingValue">%s</span>'
58
- . '<meta itemprop="bestRating" content="5" />'
59
- . '</span>'
60
- , 'hidden_tags'=> '<span itemprop="reviewRating" itemscope itemtype="http://schema.org/Rating">'
61
- . '<meta itemprop="worstRating" content="0" />'
62
- . '<meta itemprop="ratingValue" content="%s" />'
63
- . '<meta itemprop="bestRating" content="5" />'
64
- . '</span>'
65
- ),'image' => array(
66
- 'label' => __('Image of Reviewed Item', 'seo-ultimate')
67
- , 'tags' => '<a itemprop="image" href="%1$s">%1$s</a>'
68
- , 'hidden_tags'=> '<link itemprop="image" href="%s" />'
69
- , 'jlsuggest' => true
70
- ),'reviewer' => array(
71
- 'label' => __('Review Author', 'seo-ultimate')
72
- , 'editable' => false
73
- , 'value_function' => 'get_the_author'
74
- , 'tags' => 'author'
75
- ),'date_reviewed' => array(
76
- 'label' => __('Date Reviewed', 'seo-ultimate')
77
- , 'editable' => false
78
- , 'value_function' => array('get_the_time', 'Y-m-d')
79
- , 'tags' => '<time itemprop="datePublished">%s</time>'
80
- , 'hidden_tags' => '<meta itemprop="datePublished" content="%s" />'
81
- )
82
- )
83
- ),'place' => array(
84
- 'label' => __('Place', 'seo-ultimate')
85
- , 'tags' => 'Place'
86
- , 'properties' => array(
87
- 'address' => array(
88
- 'label' => __('Address', 'seo-ultimate')
89
- , 'tags' => '<span itemprop="address" itemscope itemtype="http://schema.org/PostalAddress">%s</span>'
90
- , 'properties' => array(
91
- 'street' => array(
92
- 'label' => __('Street Address', 'seo-ultimate')
93
- , 'tags' => 'streetAddress'
94
- ),'po_box' => array(
95
- 'label' => __('PO Box', 'seo-ultimate')
96
- , 'tags' => 'postOfficeBoxNumber'
97
- ),'city' => array(
98
- 'label' => __('City', 'seo-ultimate')
99
- , 'tags' => 'addressLocality'
100
- ),'state' => array(
101
- 'label' => __('City', 'seo-ultimate')
102
- , 'tags' => 'addressRegion'
103
- ),'country' => array(
104
- 'label' => __('Country', 'seo-ultimate')
105
- , 'tags' => 'addressCountry'
106
- ),'postal_code' => array(
107
- 'label' => __('Postal Code', 'seo-ultimate')
108
- , 'tags' => 'postalCode'
109
- )
110
- )
111
- ),'fax_number' => array(
112
- 'label' => __('Fax Number', 'seo-ultimate')
113
- , 'tags' => 'faxNumber'
114
- ),'map_url' => array(
115
- 'label' => __('Map URL', 'seo-ultimate')
116
- , 'tags' => '<a itemprop="map" href="%1$s">%1$s</a>'
117
- , 'hidden_tags' => '<link itemprop="map" href="%s" />'
118
- , 'jlsuggest' => true
119
- ),'photo' => array(
120
- 'label' => __('Photo', 'seo-ultimate')
121
- , 'tags'=>'<span itemprop="photo" itemscope itemtype="http://schema.org/Photograph">'
122
- . '<a itemprop="url" href="%1$s">%1$s</a>'
123
- . '</span>'
124
- , 'hidden_tags'=> '<span itemprop="photo" itemscope itemtype="http://schema.org/Photograph">'
125
- . '<link itemprop="url" href="%s" />'
126
- . '</span>'
127
- , 'jlsuggest' => true
128
- ),'tel_number' => array(
129
- 'label' => __('Phone Number', 'seo-ultimate')
130
- , 'tags' => 'telephone'
131
- )
132
- )
133
- )
134
- );
135
- }
136
-
137
- function add_tags($content, $tags, $template, $escape=true) {
138
- if ($escape) $content = su_esc_attr($content);
139
- $tags = array_reverse((array)$tags);
140
- foreach ($tags as $tag) {
141
- if (sustr::startswith($tag, '<'))
142
- $content = sprintf($tag, $content);
143
- else
144
- $content = sprintf($template, $tag, $content);
145
- }
146
- return $content;
147
- }
148
-
149
- function apply_markup($content) {
150
-
151
- //Single items only
152
- if (!is_singular() || !in_the_loop()) return $content;
153
-
154
- //Get the current type
155
- $type = $this->get_postmeta('rich_snippet_type');
156
- if (!strlen($type) || $type == 'none') return $content;
157
-
158
- //Get the current format
159
- $format = 'so';
160
-
161
- //Get tag templates for the current format
162
- $formats = $this->get_supported_snippet_formats();
163
-
164
- //Get data for the current type
165
- $types = $this->get_supported_snippet_types();
166
- $type_data = $types[$type];
167
-
168
- //Cycle through the current type's properties
169
- $append = '';
170
- $num_properties = 0;
171
- $supervalue_regex = '';
172
- foreach ($type_data['properties'] as $property => $property_data) {
173
-
174
- //Get the property tags
175
- $tag = is_array($property_data['tags']) ?
176
- $property_data['tags'][$format] :
177
- $property_data['tags'];
178
-
179
- if (isset($property_data['hidden_tags'])) {
180
- $hidden_tag = is_array($property_data['hidden_tags']) ?
181
- $property_data['hidden_tags'][$format] :
182
- $property_data['hidden_tags'];
183
- } else
184
- $hidden_tag = $tag;
185
-
186
-
187
- if (isset($property_data['properties']) && is_array($property_data['properties']) && count($property_data['properties'])) {
188
-
189
- $subproperty_regex_pieces = array();
190
- $subproperty_hidden_markedup_values = array();
191
- foreach ($property_data['properties'] as $subproperty => $subproperty_data) {
192
-
193
- //Get the subproperty tags
194
- $subproperty_tag = is_array($subproperty_data['tags']) ?
195
- $subproperty_data['tags'][$format] :
196
- $subproperty_data['tags'];
197
-
198
- if (isset($subproperty_data['hidden_tags'])) {
199
- $subproperty_hidden_tag = is_array($subproperty_data['hidden_tags']) ?
200
- $subproperty_data['hidden_tags'][$format] :
201
- $subproperty_data['hidden_tags'];
202
- } else
203
- $subproperty_hidden_tag = $subproperty_tag;
204
-
205
- $subproperty_value = strval($this->get_postmeta("rich_snippet_{$type}_{$property}_{$subproperty}"));
206
- if ($subproperty_value) {
207
- $subproperty_hidden_markedup_values[] = $this->add_tags($subproperty_value, $subproperty_hidden_tag, $formats[$format]['hidden_property_tags_template']);
208
- $subproperty_regex_pieces[] = sustr::preg_escape($subproperty_value);
209
- }
210
- }
211
- /*$supervalue_regex = implode('(<br ?/?>|\s|,)*?', $subproperty_regex_pieces);*/
212
- $supervalue_regex = implode('|', $subproperty_regex_pieces);
213
- $supervalue_regex = "($supervalue_regex)";
214
- $supervalue_regex = array_fill(0, count($subproperty_regex_pieces), $supervalue_regex);
215
- $supervalue_regex = implode('(<br ?/?>|\s|.){0,20}', $supervalue_regex);
216
-
217
- $this->apply_subproperty_markup_args = array(
218
- 'format' => $format
219
- , 'type' => $type
220
- , 'property' => $property
221
- , 'property_tag' => $tag
222
- , 'property_tag_template' => $formats[$format]['property_tags_template']
223
- , 'subproperties' => $property_data['properties']
224
- );
225
- $count = 0;
226
- $content = preg_replace_callback("%({$supervalue_regex})%", array(&$this, 'apply_subproperty_markup'), $content, 1, $count);
227
-
228
- if ($count == 0) {
229
- if (count($subproperty_hidden_markedup_values)) {
230
- $append .= $this->add_tags(implode($subproperty_hidden_markedup_values), $tag, $formats[$format]['property_tags_template'], false);
231
- $num_properties++;
232
- }
233
- } else {
234
- $num_properties++;
235
- }
236
-
237
- } else {
238
-
239
- //Get the current value for this property
240
- $value = strval($this->get_postmeta("rich_snippet_{$type}_{$property}"));
241
-
242
- if (strlen($value)) {
243
-
244
- if (sustr::startswith($value, 'obj_') && isset($property_data['jlsuggest']) && $property_data['jlsuggest'])
245
- $value = $this->jlsuggest_value_to_url($value, true);
246
-
247
- } else {
248
-
249
- //If a value is not set, look for a value-generating function
250
- if (isset($property_data['value_function'])) {
251
- $valfunc = (array)$property_data['value_function'];
252
- if (is_callable($valfunc[0])) {
253
- $valfunc_args = isset($valfunc[1]) ? (array)$valfunc[1] : array();
254
- $value = call_user_func_array($valfunc[0], $valfunc_args);
255
- }
256
- }
257
- }
258
-
259
- //If still no value, skip this property
260
- if (!strlen($value)) continue;
261
-
262
- //Add property tags to the value
263
- $markedup_value = $this->add_tags($value, $tag, $formats[$format]['property_tags_template']);
264
- $hidden_markedup_value = $this->add_tags($value, $hidden_tag, $formats[$format]['hidden_property_tags_template']);
265
-
266
- //Apply a value format to visible values if provided
267
- if (isset($property_data['value_format'])) {
268
- $values = array_values(sustr::batch_replace('%s', $value, $property_data['value_format']));
269
- $markedup_values = array_values(sustr::batch_replace('%s', $markedup_value, $property_data['value_format']));
270
- } else {
271
- $values = array($value);
272
- $markedup_values = array($markedup_value);
273
- }
274
-
275
- //Is the value in the content, and are we allowed to search/replace the content for this value?
276
- $count = 0;
277
- if (empty($property_data['always_hidden'])) {
278
- for ($i=0; $i<count($values); $i++) {
279
- $content = sustr::htmlsafe_str_replace($values[$i], $markedup_values[$i], $content, 1, $count);
280
- if ($count > 0) break;
281
- }
282
- }
283
-
284
- if ($count == 0)
285
- $append .= $hidden_markedup_value;
286
-
287
- $num_properties++;
288
- }
289
- }
290
-
291
- if (isset($type_data['content_tags'])) {
292
- $content_tag = is_array($type_data['content_tags']) ?
293
- $type_data['content_tags'][$format] :
294
- $type_data['content_tags'];
295
-
296
- $content = $this->add_tags($content, $content_tag, $formats[$format]['property_tags_template'], false);
297
- }
298
-
299
- if ($num_properties) {
300
- $type_tag = is_array($type_data['tags']) ?
301
- $type_data['tags'][$format] :
302
- $type_data['tags'];
303
- $content = $this->add_tags("$content<div>$append</div>", $type_tag, $formats[$format]['item_tags_template'], false);
304
-
305
- if ($this->get_setting('mark_code', true, 'settings'))
306
- $content .= "\n\n<!-- " . sprintf(__('Schema.org markup generated by %1$s (%2$s)', 'seo-ultimate'), SU_PLUGIN_NAME, SU_PLUGIN_URI) . " -->\n\n";
307
- }
308
-
309
- //Return filtered content
310
- return $content;
311
- }
312
-
313
- function apply_subproperty_markup($matches) {
314
-
315
- if (empty($matches[1]))
316
- return '';
317
-
318
- $content = $matches[1];
319
-
320
- extract($this->apply_subproperty_markup_args, EXTR_SKIP);
321
-
322
- foreach ($subproperties as $subproperty => $subproperty_data) {
323
-
324
- //Get the subproperty tags
325
- $subproperty_tag = is_array($subproperty_data['tags']) ?
326
- $subproperty_data['tags'][$format] :
327
- $subproperty_data['tags'];
328
-
329
- $subproperty_value = strval($this->get_postmeta("rich_snippet_{$type}_{$property}_{$subproperty}"));
330
-
331
- if ($subproperty_value) {
332
- $subproperty_markedup_value = $this->add_tags($subproperty_value, $subproperty_tag, $property_tag_template);
333
- $content = sustr::htmlsafe_str_replace($subproperty_value, $subproperty_markedup_value, $content, 1, $count);
334
- }
335
- }
336
-
337
- $content = $this->add_tags($content, $property_tag, $property_tag_format, false);
338
-
339
- return $content;
340
- }
341
-
342
- function postmeta_fields($fields, $screen) {
343
- $fields['serp'][40]['rich_snippet_type'] = $this->get_postmeta_dropdown('rich_snippet_type', array(
344
- 'none' => __('Standard', 'seo-ultimate')
345
- , 'review' => __('Review', 'seo-ultimate')
346
- , 'place' => __('Place', 'seo-ultimate')
347
- ), __('Search Result Type:', 'seo-ultimate'));
348
-
349
- $fields['serp'][45]['rich_snippet_review_item|rich_snippet_review_image|rich_snippet_review_rating'] =
350
- $this->get_postmeta_subsection('rich_snippet_type', 'review',
351
-
352
- $this->get_postmeta_textbox('rich_snippet_review_item', __('Name of Reviewed Item:', 'seo-ultimate'))
353
-
354
- . $this->get_postmeta_jlsuggest_box('rich_snippet_review_image', __('Image of Reviewed Item:', 'seo-ultimate'), 'types=posttype_attachment&post_mime_type=image/*')
355
-
356
- . $this->get_postmeta_dropdown('rich_snippet_review_rating', array(
357
- '0' => __('None', 'seo-ultimate')
358
- , '0.5' => __('0.5 stars', 'seo-ultimate')
359
- , '1' => __('1 star', 'seo-ultimate')
360
- , '1.5' => __('1.5 stars', 'seo-ultimate')
361
- , '2' => __('2 stars', 'seo-ultimate')
362
- , '2.5' => __('2.5 stars', 'seo-ultimate')
363
- , '3' => __('3 stars', 'seo-ultimate')
364
- , '3.5' => __('3.5 stars', 'seo-ultimate')
365
- , '4' => __('4 stars', 'seo-ultimate')
366
- , '4.5' => __('4.5 stars', 'seo-ultimate')
367
- , '5' => __('5 stars', 'seo-ultimate')
368
- ), __('Star Rating for Reviewed Item:', 'seo-ultimate'))
369
- );
370
-
371
- $fields['serp'][46]['rich_snippet_place_address_street|rich_snippet_place_address_po_box|rich_snippet_place_address_city|rich_snippet_place_address_state|rich_snippet_place_address_country|rich_snippet_place_address_postal_code|rich_snippet_place_map_url|rich_snippet_place_tel_number|rich_snippet_place_fax_number|rich_snippet_place_photo'] =
372
- $this->get_postmeta_subsection('rich_snippet_type', 'place',
373
- $this->get_postmeta_textbox('rich_snippet_place_address_street', __('Street Address:', 'seo-ultimate'), array('type' => 'text'))
374
- . $this->get_postmeta_textbox('rich_snippet_place_address_po_box', __('Post Office Box Number:', 'seo-ultimate'), array('type' => 'text'))
375
- . $this->get_postmeta_textbox('rich_snippet_place_address_city', __('City:', 'seo-ultimate'), array('type' => 'text'))
376
- . $this->get_postmeta_textbox('rich_snippet_place_address_state', __('State or Region:', 'seo-ultimate'), array('type' => 'text'))
377
- . $this->get_postmeta_textbox('rich_snippet_place_address_country', __('Country:', 'seo-ultimate'), array('type' => 'text'))
378
- . $this->get_postmeta_textbox('rich_snippet_place_address_postal_code', __('Postal Code:', 'seo-ultimate'), array('type' => 'text'))
379
- . $this->get_postmeta_jlsuggest_box('rich_snippet_place_map_url', __('Map Page:', 'seo-ultimate'), 'types=posttype')
380
- . $this->get_postmeta_textbox('rich_snippet_place_tel_number', __('Phone Number:', 'seo-ultimate'), array('type' => 'tel'))
381
- . $this->get_postmeta_textbox('rich_snippet_place_fax_number', __('Fax Number:', 'seo-ultimate'), array('type' => 'tel'))
382
- . $this->get_postmeta_jlsuggest_box('rich_snippet_place_photo', __('Photo:', 'seo-ultimate'), 'types=posttype_attachment&post_mime_type=image/*')
383
- );
384
-
385
- return $fields;
386
- }
387
-
388
-
389
- function add_help_tabs($screen) {
390
-
391
- $overview = __("
392
- <ul>
393
- <li><strong>What it does:</strong> Rich Snippet Creator adds special code (called Schema.org data) to your posts that asks Google and other major search engines to display special pertinent information (known as Rich Snippets) in search results for certain types of content. For example, if you&#8217;ve written a product review, you can use Rich Snippet Creator to ask Google to display the star rating that you gave the product in your review next to your review webpage when it appears in search results.</li>
394
- <li><strong>Why it helps:</strong> Rich Snippet Creator enhances the search engine results for your content by asking Google to add extra, eye-catching info that could help draw in more search engine visitors.</li>
395
- <li><strong>How it works:</strong> When editing one of your posts or pages, see if your content fits one of the available rich snippet types (for example, a review). If so, select that type from the &#8220;Search Result Type&#8221; dropdown box. Once you select the applicable type, additional options will appear that vary based on the type selected. For example, a &#8220;Star Rating for Reviewed Item&#8221; field will appear if you select the &#8220;Review&#8221; type. Once you save the post/page, Rich Snippet Creator will add the special code to it. You can remove this code at any time by selecting &#8220;Standard&#8221; from the &#8220;Search Result Type&#8221; dropdown and resaving the post/page.</li>
396
- </ul>
397
- ", 'seo-ultimate');
398
-
399
- $troubleshooting = __("
400
- <ul>
401
- <li><p><strong>Why aren&#8217;t rich snippets showing up in Google search results for my site?</strong><br />Enter the URL of your post/page into <a href='http://www.google.com/webmasters/tools/richsnippets' target='_blank'>Google&#8217;s testing tool</a> to make sure Google can find the rich snippet code on your site. If no code is found, check and make sure you&#8217;ve enabled rich snippets for that particular post/page.</p><p>Note that having the code on a post/page doesn&#8217;t guarantee that Google will actually use it to create a rich snippet. If Google is able to read your code but isn&#8217;t using it to generate rich snippets, you can ask Google to do so using <a href='http://www.google.com/support/webmasters/bin/request.py?contact_type=rich_snippets_feedback' target='_blank'>this form</a>.</p></li>
402
- </ul>
403
- ", 'seo-ultimate');
404
-
405
- if ($this->has_enabled_parent()) {
406
- $screen->add_help_tab(array(
407
- 'id' => 'su-rich-snippets-help'
408
- , 'title' => __('Rich Snippet Creator', 'seo-ultimate')
409
- , 'content' =>
410
- '<h3>' . __('Overview', 'seo-ultimate') . '</h3>' . $overview .
411
- '<h3>' . __('Troubleshooting', 'seo-ultimate') . '</h3>' . $troubleshooting
412
- ));
413
- } else {
414
-
415
- $screen->add_help_tab(array(
416
- 'id' => 'su-rich-snippets-overview'
417
- , 'title' => __('Overview', 'seo-ultimate')
418
- , 'content' => $overview));
419
-
420
- $screen->add_help_tab(array(
421
- 'id' => 'su-rich-snippets-troubleshooting'
422
- , 'title' => __('Troubleshooting', 'seo-ultimate')
423
- , 'content' => $troubleshooting));
424
- }
425
-
426
- }
427
- }
428
-
429
- }
430
  ?>
1
+ <?php
2
+ /**
3
+ * Rich Snippet Creator Module
4
+ *
5
+ * @since 3.0
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_RichSnippets extends SU_Module {
11
+
12
+ var $apply_subproperty_markup_args = array();
13
+
14
+ static function get_module_title() { return __('Rich Snippet Creator', 'seo-ultimate'); }
15
+
16
+ static function get_parent_module() { return 'misc'; }
17
+ function get_settings_key() { return 'rich-snippets'; }
18
+
19
+ function init() {
20
+ add_filter('the_content', array(&$this, 'apply_markup'));
21
+ }
22
+
23
+ function admin_page_contents() {
24
+ $this->child_admin_form_start();
25
+ $this->textblock(__('Rich Snippet Creator adds a &#8220;Search Result Type&#8221; dropdown to the WordPress content editor screen. To add rich snippet data to a post, select &#8220;Review&#8221; or &#8220;Place&#8221; from a post&#8217;s &#8220;Search Result Type&#8221; dropdown and fill in the fields that appear.', 'seo-ultimate'));
26
+ $this->child_admin_form_end();
27
+ }
28
+
29
+ function get_supported_snippet_formats() {
30
+
31
+ return array(
32
+ 'so' => array(
33
+ 'label' => __('Schema.org Microdata', 'seo-ultimate')
34
+ , 'item_tags_template' => '<div itemscope itemtype="http://schema.org/%1$s">%2$s</div>'
35
+ , 'property_tags_template' => '<span itemprop="%1$s">%2$s</span>'
36
+ , 'hidden_property_tags_template' => '<meta itemprop="%1$s" content="%2$s" />'
37
+ )
38
+ );
39
+ }
40
+
41
+ function get_supported_snippet_types() {
42
+
43
+ return array(
44
+ 'review' => array(
45
+ 'label' => __('Review', 'seo-ultimate')
46
+ , 'tags' => 'Review'
47
+ , 'content_tags' => '<div itemprop="reviewBody">%s</div>'
48
+ , 'properties' => array(
49
+ 'item' => array(
50
+ 'label' => __('Name of Reviewed Item', 'seo-ultimate')
51
+ , 'tags' => 'itemReviewed'
52
+ ),'rating' => array(
53
+ 'label' => __('Star Rating', 'seo-ultimate')
54
+ , 'value_format' => array('%s star', '%s stars', '%s-star', '%s-stars')
55
+ , 'tags' => '<span itemprop="reviewRating" itemscope itemtype="http://schema.org/Rating">'
56
+ . '<meta itemprop="worstRating" content="0" />'
57
+ . '<span itemprop="ratingValue">%s</span>'
58
+ . '<meta itemprop="bestRating" content="5" />'
59
+ . '</span>'
60
+ , 'hidden_tags'=> '<span itemprop="reviewRating" itemscope itemtype="http://schema.org/Rating">'
61
+ . '<meta itemprop="worstRating" content="0" />'
62
+ . '<meta itemprop="ratingValue" content="%s" />'
63
+ . '<meta itemprop="bestRating" content="5" />'
64
+ . '</span>'
65
+ ),'image' => array(
66
+ 'label' => __('Image of Reviewed Item', 'seo-ultimate')
67
+ , 'tags' => '<a itemprop="image" href="%1$s">%1$s</a>'
68
+ , 'hidden_tags'=> '<link itemprop="image" href="%s" />'
69
+ , 'jlsuggest' => true
70
+ ),'reviewer' => array(
71
+ 'label' => __('Review Author', 'seo-ultimate')
72
+ , 'editable' => false
73
+ , 'value_function' => 'get_the_author'
74
+ , 'tags' => 'author'
75
+ ),'date_reviewed' => array(
76
+ 'label' => __('Date Reviewed', 'seo-ultimate')
77
+ , 'editable' => false
78
+ , 'value_function' => array('get_the_time', 'Y-m-d')
79
+ , 'tags' => '<time itemprop="datePublished">%s</time>'
80
+ , 'hidden_tags' => '<meta itemprop="datePublished" content="%s" />'
81
+ )
82
+ )
83
+ ),'place' => array(
84
+ 'label' => __('Place', 'seo-ultimate')
85
+ , 'tags' => 'Place'
86
+ , 'properties' => array(
87
+ 'address' => array(
88
+ 'label' => __('Address', 'seo-ultimate')
89
+ , 'tags' => '<span itemprop="address" itemscope itemtype="http://schema.org/PostalAddress">%s</span>'
90
+ , 'properties' => array(
91
+ 'street' => array(
92
+ 'label' => __('Street Address', 'seo-ultimate')
93
+ , 'tags' => 'streetAddress'
94
+ ),'po_box' => array(
95
+ 'label' => __('PO Box', 'seo-ultimate')
96
+ , 'tags' => 'postOfficeBoxNumber'
97
+ ),'city' => array(
98
+ 'label' => __('City', 'seo-ultimate')
99
+ , 'tags' => 'addressLocality'
100
+ ),'state' => array(
101
+ 'label' => __('City', 'seo-ultimate')
102
+ , 'tags' => 'addressRegion'
103
+ ),'country' => array(
104
+ 'label' => __('Country', 'seo-ultimate')
105
+ , 'tags' => 'addressCountry'
106
+ ),'postal_code' => array(
107
+ 'label' => __('Postal Code', 'seo-ultimate')
108
+ , 'tags' => 'postalCode'
109
+ )
110
+ )
111
+ ),'fax_number' => array(
112
+ 'label' => __('Fax Number', 'seo-ultimate')
113
+ , 'tags' => 'faxNumber'
114
+ ),'map_url' => array(
115
+ 'label' => __('Map URL', 'seo-ultimate')
116
+ , 'tags' => '<a itemprop="map" href="%1$s">%1$s</a>'
117
+ , 'hidden_tags' => '<link itemprop="map" href="%s" />'
118
+ , 'jlsuggest' => true
119
+ ),'photo' => array(
120
+ 'label' => __('Photo', 'seo-ultimate')
121
+ , 'tags'=>'<span itemprop="photo" itemscope itemtype="http://schema.org/Photograph">'
122
+ . '<a itemprop="url" href="%1$s">%1$s</a>'
123
+ . '</span>'
124
+ , 'hidden_tags'=> '<span itemprop="photo" itemscope itemtype="http://schema.org/Photograph">'
125
+ . '<link itemprop="url" href="%s" />'
126
+ . '</span>'
127
+ , 'jlsuggest' => true
128
+ ),'tel_number' => array(
129
+ 'label' => __('Phone Number', 'seo-ultimate')
130
+ , 'tags' => 'telephone'
131
+ )
132
+ )
133
+ )
134
+ );
135
+ }
136
+
137
+ function add_tags($content, $tags, $template, $escape=true) {
138
+ if ($escape) $content = su_esc_attr($content);
139
+ $tags = array_reverse((array)$tags);
140
+ foreach ($tags as $tag) {
141
+ if (sustr::startswith($tag, '<'))
142
+ $content = sprintf($tag, $content);
143
+ else
144
+ $content = sprintf($template, $tag, $content);
145
+ }
146
+ return $content;
147
+ }
148
+
149
+ function apply_markup($content) {
150
+
151
+ //Single items only
152
+ if (!is_singular() || !in_the_loop()) return $content;
153
+
154
+ //Get the current type
155
+ $type = $this->get_postmeta('rich_snippet_type');
156
+ if (!strlen($type) || $type == 'none') return $content;
157
+
158
+ //Get the current format
159
+ $format = 'so';
160
+
161
+ //Get tag templates for the current format
162
+ $formats = $this->get_supported_snippet_formats();
163
+
164
+ //Get data for the current type
165
+ $types = $this->get_supported_snippet_types();
166
+ $type_data = $types[$type];
167
+
168
+ //Cycle through the current type's properties
169
+ $append = '';
170
+ $num_properties = 0;
171
+ $supervalue_regex = '';
172
+ foreach ($type_data['properties'] as $property => $property_data) {
173
+
174
+ //Get the property tags
175
+ $tag = is_array($property_data['tags']) ?
176
+ $property_data['tags'][$format] :
177
+ $property_data['tags'];
178
+
179
+ if (isset($property_data['hidden_tags'])) {
180
+ $hidden_tag = is_array($property_data['hidden_tags']) ?
181
+ $property_data['hidden_tags'][$format] :
182
+ $property_data['hidden_tags'];
183
+ } else
184
+ $hidden_tag = $tag;
185
+
186
+
187
+ if (isset($property_data['properties']) && is_array($property_data['properties']) && count($property_data['properties'])) {
188
+
189
+ $subproperty_regex_pieces = array();
190
+ $subproperty_hidden_markedup_values = array();
191
+ foreach ($property_data['properties'] as $subproperty => $subproperty_data) {
192
+
193
+ //Get the subproperty tags
194
+ $subproperty_tag = is_array($subproperty_data['tags']) ?
195
+ $subproperty_data['tags'][$format] :
196
+ $subproperty_data['tags'];
197
+
198
+ if (isset($subproperty_data['hidden_tags'])) {
199
+ $subproperty_hidden_tag = is_array($subproperty_data['hidden_tags']) ?
200
+ $subproperty_data['hidden_tags'][$format] :
201
+ $subproperty_data['hidden_tags'];
202
+ } else
203
+ $subproperty_hidden_tag = $subproperty_tag;
204
+
205
+ $subproperty_value = strval($this->get_postmeta("rich_snippet_{$type}_{$property}_{$subproperty}"));
206
+ if ($subproperty_value) {
207
+ $subproperty_hidden_markedup_values[] = $this->add_tags($subproperty_value, $subproperty_hidden_tag, $formats[$format]['hidden_property_tags_template']);
208
+ $subproperty_regex_pieces[] = sustr::preg_escape($subproperty_value);
209
+ }
210
+ }
211
+ /*$supervalue_regex = implode('(<br ?/?>|\s|,)*?', $subproperty_regex_pieces);*/
212
+ $supervalue_regex = implode('|', $subproperty_regex_pieces);
213
+ $supervalue_regex = "($supervalue_regex)";
214
+ $supervalue_regex = array_fill(0, count($subproperty_regex_pieces), $supervalue_regex);
215
+ $supervalue_regex = implode('(<br ?/?>|\s|.){0,20}', $supervalue_regex);
216
+
217
+ $this->apply_subproperty_markup_args = array(
218
+ 'format' => $format
219
+ , 'type' => $type
220
+ , 'property' => $property
221
+ , 'property_tag' => $tag
222
+ , 'property_tag_template' => $formats[$format]['property_tags_template']
223
+ , 'subproperties' => $property_data['properties']
224
+ );
225
+ $count = 0;
226
+ $content = preg_replace_callback("%({$supervalue_regex})%", array(&$this, 'apply_subproperty_markup'), $content, 1, $count);
227
+
228
+ if ($count == 0) {
229
+ if (count($subproperty_hidden_markedup_values)) {
230
+ $append .= $this->add_tags(implode($subproperty_hidden_markedup_values), $tag, $formats[$format]['property_tags_template'], false);
231
+ $num_properties++;
232
+ }
233
+ } else {
234
+ $num_properties++;
235
+ }
236
+
237
+ } else {
238
+
239
+ //Get the current value for this property
240
+ $value = strval($this->get_postmeta("rich_snippet_{$type}_{$property}"));
241
+
242
+ if (strlen($value)) {
243
+
244
+ if (sustr::startswith($value, 'obj_') && isset($property_data['jlsuggest']) && $property_data['jlsuggest'])
245
+ $value = $this->jlsuggest_value_to_url($value, true);
246
+
247
+ } else {
248
+
249
+ //If a value is not set, look for a value-generating function
250
+ if (isset($property_data['value_function'])) {
251
+ $valfunc = (array)$property_data['value_function'];
252
+ if (is_callable($valfunc[0])) {
253
+ $valfunc_args = isset($valfunc[1]) ? (array)$valfunc[1] : array();
254
+ $value = call_user_func_array($valfunc[0], $valfunc_args);
255
+ }
256
+ }
257
+ }
258
+
259
+ //If still no value, skip this property
260
+ if (!strlen($value)) continue;
261
+
262
+ //Add property tags to the value
263
+ $markedup_value = $this->add_tags($value, $tag, $formats[$format]['property_tags_template']);
264
+ $hidden_markedup_value = $this->add_tags($value, $hidden_tag, $formats[$format]['hidden_property_tags_template']);
265
+
266
+ //Apply a value format to visible values if provided
267
+ if (isset($property_data['value_format'])) {
268
+ $values = array_values(sustr::batch_replace('%s', $value, $property_data['value_format']));
269
+ $markedup_values = array_values(sustr::batch_replace('%s', $markedup_value, $property_data['value_format']));
270
+ } else {
271
+ $values = array($value);
272
+ $markedup_values = array($markedup_value);
273
+ }
274
+
275
+ //Is the value in the content, and are we allowed to search/replace the content for this value?
276
+ $count = 0;
277
+ if (empty($property_data['always_hidden'])) {
278
+ for ($i=0; $i<count($values); $i++) {
279
+ $content = sustr::htmlsafe_str_replace($values[$i], $markedup_values[$i], $content, 1, $count);
280
+ if ($count > 0) break;
281
+ }
282
+ }
283
+
284
+ if ($count == 0)
285
+ $append .= $hidden_markedup_value;
286
+
287
+ $num_properties++;
288
+ }
289
+ }
290
+
291
+ if (isset($type_data['content_tags'])) {
292
+ $content_tag = is_array($type_data['content_tags']) ?
293
+ $type_data['content_tags'][$format] :
294
+ $type_data['content_tags'];
295
+
296
+ $content = $this->add_tags($content, $content_tag, $formats[$format]['property_tags_template'], false);
297
+ }
298
+
299
+ if ($num_properties) {
300
+ $type_tag = is_array($type_data['tags']) ?
301
+ $type_data['tags'][$format] :
302
+ $type_data['tags'];
303
+ $content = $this->add_tags("$content<div>$append</div>", $type_tag, $formats[$format]['item_tags_template'], false);
304
+
305
+ if ($this->get_setting('mark_code', true, 'settings'))
306
+ $content .= "\n\n<!-- " . sprintf(__('Schema.org markup generated by %1$s (%2$s)', 'seo-ultimate'), SU_PLUGIN_NAME, SU_PLUGIN_URI) . " -->\n\n";
307
+ }
308
+
309
+ //Return filtered content
310
+ return $content;
311
+ }
312
+
313
+ function apply_subproperty_markup($matches) {
314
+
315
+ if (empty($matches[1]))
316
+ return '';
317
+
318
+ $content = $matches[1];
319
+
320
+ extract($this->apply_subproperty_markup_args, EXTR_SKIP);
321
+
322
+ foreach ($subproperties as $subproperty => $subproperty_data) {
323
+
324
+ //Get the subproperty tags
325
+ $subproperty_tag = is_array($subproperty_data['tags']) ?
326
+ $subproperty_data['tags'][$format] :
327
+ $subproperty_data['tags'];
328
+
329
+ $subproperty_value = strval($this->get_postmeta("rich_snippet_{$type}_{$property}_{$subproperty}"));
330
+
331
+ if ($subproperty_value) {
332
+ $subproperty_markedup_value = $this->add_tags($subproperty_value, $subproperty_tag, $property_tag_template);
333
+ $content = sustr::htmlsafe_str_replace($subproperty_value, $subproperty_markedup_value, $content, 1, $count);
334
+ }
335
+ }
336
+
337
+ $content = $this->add_tags($content, $property_tag, $property_tag_format, false);
338
+
339
+ return $content;
340
+ }
341
+
342
+ function postmeta_fields($fields, $screen) {
343
+ $fields['serp'][40]['rich_snippet_type'] = $this->get_postmeta_dropdown('rich_snippet_type', array(
344
+ 'none' => __('Standard', 'seo-ultimate')
345
+ , 'review' => __('Review', 'seo-ultimate')
346
+ , 'place' => __('Place', 'seo-ultimate')
347
+ ), __('Search Result Type:', 'seo-ultimate'));
348
+
349
+ $fields['serp'][45]['rich_snippet_review_item|rich_snippet_review_image|rich_snippet_review_rating'] =
350
+ $this->get_postmeta_subsection('rich_snippet_type', 'review',
351
+
352
+ $this->get_postmeta_textbox('rich_snippet_review_item', __('Name of Reviewed Item:', 'seo-ultimate'))
353
+
354
+ . $this->get_postmeta_jlsuggest_box('rich_snippet_review_image', __('Image of Reviewed Item:', 'seo-ultimate'), 'types=posttype_attachment&post_mime_type=image/*')
355
+
356
+ . $this->get_postmeta_dropdown('rich_snippet_review_rating', array(
357
+ '0' => __('None', 'seo-ultimate')
358
+ , '0.5' => __('0.5 stars', 'seo-ultimate')
359
+ , '1' => __('1 star', 'seo-ultimate')
360
+ , '1.5' => __('1.5 stars', 'seo-ultimate')
361
+ , '2' => __('2 stars', 'seo-ultimate')
362
+ , '2.5' => __('2.5 stars', 'seo-ultimate')
363
+ , '3' => __('3 stars', 'seo-ultimate')
364
+ , '3.5' => __('3.5 stars', 'seo-ultimate')
365
+ , '4' => __('4 stars', 'seo-ultimate')
366
+ , '4.5' => __('4.5 stars', 'seo-ultimate')
367
+ , '5' => __('5 stars', 'seo-ultimate')
368
+ ), __('Star Rating for Reviewed Item:', 'seo-ultimate'))
369
+ );
370
+
371
+ $fields['serp'][46]['rich_snippet_place_address_street|rich_snippet_place_address_po_box|rich_snippet_place_address_city|rich_snippet_place_address_state|rich_snippet_place_address_country|rich_snippet_place_address_postal_code|rich_snippet_place_map_url|rich_snippet_place_tel_number|rich_snippet_place_fax_number|rich_snippet_place_photo'] =
372
+ $this->get_postmeta_subsection('rich_snippet_type', 'place',
373
+ $this->get_postmeta_textbox('rich_snippet_place_address_street', __('Street Address:', 'seo-ultimate'), array('type' => 'text'))
374
+ . $this->get_postmeta_textbox('rich_snippet_place_address_po_box', __('Post Office Box Number:', 'seo-ultimate'), array('type' => 'text'))
375
+ . $this->get_postmeta_textbox('rich_snippet_place_address_city', __('City:', 'seo-ultimate'), array('type' => 'text'))
376
+ . $this->get_postmeta_textbox('rich_snippet_place_address_state', __('State or Region:', 'seo-ultimate'), array('type' => 'text'))
377
+ . $this->get_postmeta_textbox('rich_snippet_place_address_country', __('Country:', 'seo-ultimate'), array('type' => 'text'))
378
+ . $this->get_postmeta_textbox('rich_snippet_place_address_postal_code', __('Postal Code:', 'seo-ultimate'), array('type' => 'text'))
379
+ . $this->get_postmeta_jlsuggest_box('rich_snippet_place_map_url', __('Map Page:', 'seo-ultimate'), 'types=posttype')
380
+ . $this->get_postmeta_textbox('rich_snippet_place_tel_number', __('Phone Number:', 'seo-ultimate'), array('type' => 'tel'))
381
+ . $this->get_postmeta_textbox('rich_snippet_place_fax_number', __('Fax Number:', 'seo-ultimate'), array('type' => 'tel'))
382
+ . $this->get_postmeta_jlsuggest_box('rich_snippet_place_photo', __('Photo:', 'seo-ultimate'), 'types=posttype_attachment&post_mime_type=image/*')
383
+ );
384
+
385
+ return $fields;
386
+ }
387
+
388
+
389
+ function add_help_tabs($screen) {
390
+
391
+ $overview = __("
392
+ <ul>
393
+ <li><strong>What it does:</strong> Rich Snippet Creator adds special code (called Schema.org data) to your posts that asks Google and other major search engines to display special pertinent information (known as Rich Snippets) in search results for certain types of content. For example, if you&#8217;ve written a product review, you can use Rich Snippet Creator to ask Google to display the star rating that you gave the product in your review next to your review webpage when it appears in search results.</li>
394
+ <li><strong>Why it helps:</strong> Rich Snippet Creator enhances the search engine results for your content by asking Google to add extra, eye-catching info that could help draw in more search engine visitors.</li>
395
+ <li><strong>How it works:</strong> When editing one of your posts or pages, see if your content fits one of the available rich snippet types (for example, a review). If so, select that type from the &#8220;Search Result Type&#8221; dropdown box. Once you select the applicable type, additional options will appear that vary based on the type selected. For example, a &#8220;Star Rating for Reviewed Item&#8221; field will appear if you select the &#8220;Review&#8221; type. Once you save the post/page, Rich Snippet Creator will add the special code to it. You can remove this code at any time by selecting &#8220;Standard&#8221; from the &#8220;Search Result Type&#8221; dropdown and resaving the post/page.</li>
396
+ </ul>
397
+ ", 'seo-ultimate');
398
+
399
+ $troubleshooting = __("
400
+ <ul>
401
+ <li><p><strong>Why aren&#8217;t rich snippets showing up in Google search results for my site?</strong><br />Enter the URL of your post/page into <a href='http://www.google.com/webmasters/tools/richsnippets' target='_blank'>Google&#8217;s testing tool</a> to make sure Google can find the rich snippet code on your site. If no code is found, check and make sure you&#8217;ve enabled rich snippets for that particular post/page.</p><p>Note that having the code on a post/page doesn&#8217;t guarantee that Google will actually use it to create a rich snippet. If Google is able to read your code but isn&#8217;t using it to generate rich snippets, you can ask Google to do so using <a href='http://www.google.com/support/webmasters/bin/request.py?contact_type=rich_snippets_feedback' target='_blank'>this form</a>.</p></li>
402
+ </ul>
403
+ ", 'seo-ultimate');
404
+
405
+ if ($this->has_enabled_parent()) {
406
+ $screen->add_help_tab(array(
407
+ 'id' => 'su-rich-snippets-help'
408
+ , 'title' => __('Rich Snippet Creator', 'seo-ultimate')
409
+ , 'content' =>
410
+ '<h3>' . __('Overview', 'seo-ultimate') . '</h3>' . $overview .
411
+ '<h3>' . __('Troubleshooting', 'seo-ultimate') . '</h3>' . $troubleshooting
412
+ ));
413
+ } else {
414
+
415
+ $screen->add_help_tab(array(
416
+ 'id' => 'su-rich-snippets-overview'
417
+ , 'title' => __('Overview', 'seo-ultimate')
418
+ , 'content' => $overview));
419
+
420
+ $screen->add_help_tab(array(
421
+ 'id' => 'su-rich-snippets-troubleshooting'
422
+ , 'title' => __('Troubleshooting', 'seo-ultimate')
423
+ , 'content' => $troubleshooting));
424
+ }
425
+
426
+ }
427
+ }
428
+
429
+ }
430
  ?>
modules/sdf-ads/banners/01.png DELETED
Binary file
modules/sdf-ads/banners/02.png DELETED
Binary file
modules/sdf-ads/banners/06.png DELETED
Binary file
modules/sdf-ads/banners/07.png DELETED
Binary file
modules/sdf-ads/banners/InternalLinkBanner.jpg ADDED
Binary file
modules/sdf-ads/banners/MetaWritingBanner.jpg ADDED
Binary file
modules/sdf-ads/banners/SEO-VideoTraining-Banner-v3.jpg ADDED
Binary file
modules/sdf-ads/sdf-ads.css CHANGED
@@ -1,72 +1,72 @@
1
-
2
- /* CUSTOMIZE THE CAROUSEL/BANNERS
3
- -------------------------------------------------- */
4
- /* Carousel base class */
5
- #sdf-promo-carousel {
6
- max-width: 300px;
7
- }
8
- #sdf-promo-carousel .carousel {
9
- margin-bottom: 40px;
10
-
11
- /* Negative margin to pull up carousel. 90px is roughly margins and height of navbar. */
12
- margin-top: 0px;
13
- }
14
- /* Since positioning the image, we need to help out the caption */
15
- #sdf-promo-carousel .carousel-caption {
16
- z-index: 10;
17
- }
18
- #sdf-promo-carousel .carousel-caption h1,
19
- #sdf-promo-carousel .carousel-caption h1 a,#sdf-promo-carousel .carousel-caption h1 a:hover,#sdf-promo-carousel .carousel-caption h1 a:focus,
20
- #sdf-promo-carousel .carousel-caption h2,
21
- #sdf-promo-carousel .carousel-caption h2 a,#sdf-promo-carousel .carousel-caption h2 a:hover,#sdf-promo-carousel .carousel-caption h2 a:focus,
22
- #sdf-promo-carousel .carousel-caption h3,
23
- #sdf-promo-carousel .carousel-caption h3 a,#sdf-promo-carousel .carousel-caption h3 a:hover,#sdf-promo-carousel .carousel-caption h3 a:focus {
24
- color: #ffffff;
25
- }
26
-
27
- /* Declare heights because of positioning of img element */
28
- #sdf-promo-carousel .carousel .item {
29
- height: 330px;
30
- background-color: #868686;
31
- }
32
- #sdf-promo-carousel .carousel-inner > .item a img {
33
- position: absolute;
34
- top: 0;
35
- left: 0;
36
- min-width: 100%;
37
- }
38
- .sdf-admin #sdf-promo-carousel .carousel-control {
39
- opacity: 0.2;
40
- filter: alpha(opacity=20);
41
- }
42
- .sdf-admin #sdf-promo-carousel .carousel-control.left {
43
- background-image: -webkit-gradient(linear, 0 top, 100% top, from(rgba(0, 0, 0, 0.4)), to(rgba(0, 0, 0, 0.0001)));
44
- background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.4) 0), color-stop(rgba(0, 0, 0, 0.0001) 100%));
45
- background-image: -moz-linear-gradient(left, rgba(0, 0, 0, 0.4) 0, rgba(0, 0, 0, 0.0001) 100%);
46
- background-image: linear-gradient(to right, rgba(0, 0, 0, 0.4) 0, rgba(0, 0, 0, 0.0001) 100%);
47
- background-repeat: repeat-x;
48
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);
49
- }
50
- .sdf-admin #sdf-promo-carousel .carousel-control.right {
51
- right: 0;
52
- left: auto;
53
- background-image: -webkit-gradient(linear, 0 top, 100% top, from(rgba(0, 0, 0, 0.0001)), to(rgba(0, 0, 0, 0.4)));
54
- background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.0001) 0), color-stop(rgba(0, 0, 0, 0.4) 100%));
55
- background-image: -moz-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0, rgba(0, 0, 0, 0.4) 100%);
56
- background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0, rgba(0, 0, 0, 0.4) 100%);
57
- background-repeat: repeat-x;
58
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);
59
- }
60
- .sdf-admin #sdf-promo-carousel .carousel-control:hover,.sdf-admin .carousel-control:focus {
61
- color: #ffffff;
62
- text-decoration: none;
63
- opacity: 0.5;
64
- filter: alpha(opacity=50);
65
- }
66
- .sdf-admin #sdf-promo-carousel .carousel-control .icon-prev, .sdf-admin .carousel-control .icon-next, .sdf-admin .carousel-control .glyphicon-chevron-left, .sdf-admin .carousel-control .glyphicon-chevron-right {
67
- bottom: 140px !important;
68
- top: auto !important;
69
- }
70
- .sdf-admin #sdf-promo-carousel .carousel-control .icon-next, .sdf-admin .carousel-control .glyphicon-chevron-right {
71
- left: 0 !important;
72
  }
1
+
2
+ /* CUSTOMIZE THE CAROUSEL/BANNERS
3
+ -------------------------------------------------- */
4
+ /* Carousel base class */
5
+ #sdf-promo-carousel {
6
+ max-width: 300px;
7
+ }
8
+ #sdf-promo-carousel .carousel {
9
+ margin-bottom: 40px;
10
+
11
+ /* Negative margin to pull up carousel. 90px is roughly margins and height of navbar. */
12
+ margin-top: 0px;
13
+ }
14
+ /* Since positioning the image, we need to help out the caption */
15
+ #sdf-promo-carousel .carousel-caption {
16
+ z-index: 10;
17
+ }
18
+ #sdf-promo-carousel .carousel-caption h1,
19
+ #sdf-promo-carousel .carousel-caption h1 a,#sdf-promo-carousel .carousel-caption h1 a:hover,#sdf-promo-carousel .carousel-caption h1 a:focus,
20
+ #sdf-promo-carousel .carousel-caption h2,
21
+ #sdf-promo-carousel .carousel-caption h2 a,#sdf-promo-carousel .carousel-caption h2 a:hover,#sdf-promo-carousel .carousel-caption h2 a:focus,
22
+ #sdf-promo-carousel .carousel-caption h3,
23
+ #sdf-promo-carousel .carousel-caption h3 a,#sdf-promo-carousel .carousel-caption h3 a:hover,#sdf-promo-carousel .carousel-caption h3 a:focus {
24
+ color: #ffffff;
25
+ }
26
+
27
+ /* Declare heights because of positioning of img element */
28
+ #sdf-promo-carousel .carousel .item {
29
+ height: 330px;
30
+ background-color: #868686;
31
+ }
32
+ #sdf-promo-carousel .carousel-inner > .item a img {
33
+ position: absolute;
34
+ top: 0;
35
+ left: 0;
36
+ min-width: 100%;
37
+ }
38
+ .sdf-admin #sdf-promo-carousel .carousel-control {
39
+ opacity: 0.2;
40
+ filter: alpha(opacity=20);
41
+ }
42
+ .sdf-admin #sdf-promo-carousel .carousel-control.left {
43
+ background-image: -webkit-gradient(linear, 0 top, 100% top, from(rgba(0, 0, 0, 0.4)), to(rgba(0, 0, 0, 0.0001)));
44
+ background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.4) 0), color-stop(rgba(0, 0, 0, 0.0001) 100%));
45
+ background-image: -moz-linear-gradient(left, rgba(0, 0, 0, 0.4) 0, rgba(0, 0, 0, 0.0001) 100%);
46
+ background-image: linear-gradient(to right, rgba(0, 0, 0, 0.4) 0, rgba(0, 0, 0, 0.0001) 100%);
47
+ background-repeat: repeat-x;
48
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);
49
+ }
50
+ .sdf-admin #sdf-promo-carousel .carousel-control.right {
51
+ right: 0;
52
+ left: auto;
53
+ background-image: -webkit-gradient(linear, 0 top, 100% top, from(rgba(0, 0, 0, 0.0001)), to(rgba(0, 0, 0, 0.4)));
54
+ background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.0001) 0), color-stop(rgba(0, 0, 0, 0.4) 100%));
55
+ background-image: -moz-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0, rgba(0, 0, 0, 0.4) 100%);
56
+ background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0, rgba(0, 0, 0, 0.4) 100%);
57
+ background-repeat: repeat-x;
58
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);
59
+ }
60
+ .sdf-admin #sdf-promo-carousel .carousel-control:hover,.sdf-admin .carousel-control:focus {
61
+ color: #ffffff;
62
+ text-decoration: none;
63
+ opacity: 0.5;
64
+ filter: alpha(opacity=50);
65
+ }
66
+ .sdf-admin #sdf-promo-carousel .carousel-control .icon-prev, .sdf-admin .carousel-control .icon-next, .sdf-admin .carousel-control .glyphicon-chevron-left, .sdf-admin .carousel-control .glyphicon-chevron-right {
67
+ bottom: 140px !important;
68
+ top: auto !important;
69
+ }
70
+ .sdf-admin #sdf-promo-carousel .carousel-control .icon-next, .sdf-admin .carousel-control .glyphicon-chevron-right {
71
+ left: 0 !important;
72
  }
modules/sdf-ads/sdf-ads.js CHANGED
@@ -1,88 +1,80 @@
1
- /*global jQuery:false, alert */
2
- (function($) {
3
- "use strict";
4
- jQuery(document).ready(function($) {
5
-
6
- $('#sdf-promo-carousel').hide();
7
- $('#sdf_dashboard_widget .inside').hide();
8
- var sds_promo_blog_post = $('#sds_promo_blog_post').html();
9
- var banners_remote = 'https://s3.amazonaws.com/sdfimages/seoultimatebanner/seo_ultimate_banners_jsonp_764.json';
10
-
11
- $.ajax({
12
- url: banners_remote,
13
- dataType: 'jsonp',
14
- jsonp: false,
15
- jsonpCallback: 'sdfbanners'
16
- })
17
- .done(function (data) {
18
- var sdf_carousel = '';
19
- if (data.enabled === true) {
20
- var shuffled_banners = shuffleArray(data.banners);
21
- var shuffled_slides = shuffleArray(data.slides);
22
- // check if it's cloud hosted banner
23
- var banner_img = shuffled_banners[0].banner_img
24
- if(banner_img.indexOf('https://') == -1) banner_img = suModulesSdfAdsSdfAdsL10n.sdf_banners_url + banner_img;
25
- sdf_carousel = sdf_carousel + "<a href=\"" + shuffled_banners[0].banner_link + "\" rel=\"nofollow\" target=\"_blank\"><img src=\"" + banner_img + "\" alt=\"Slide "+ i +"\"></a>";
26
- sdf_carousel = sdf_carousel + "<div id=\"sdfCarousel\" class=\"carousel slide\"><ol class=\"carousel-indicators\">";
27
-
28
- var active_indicator = '';
29
- for ( var i = 0; i < shuffled_slides.length; i++ ) {
30
- if (i == 0) active_indicator = ' class=\"active\"';
31
- else active_indicator = '';
32
- sdf_carousel = sdf_carousel + "<li data-target=\"#sdfCarousel\" data-slide-to=\""+ i +"\""+ active_indicator +"></li>";
33
- };
34
- sdf_carousel = sdf_carousel + "<li data-target=\"#sdfCarousel\" data-slide-to=\""+ i +"\"></li>";
35
- sdf_carousel = sdf_carousel + "</ol><div class=\"carousel-inner\">";
36
-
37
-
38
- for ( var i = 0; i < shuffled_slides.length; i++ ) {
39
- if (i == 0) active_indicator = ' active';
40
- else active_indicator = '';
41
- sdf_carousel = sdf_carousel + "<div class=\"item"+ active_indicator +"\"><div class=\"container\"><div class=\"carousel-caption\">"+ shuffled_slides[i].slide_cap + "<p><a class=\"btn btn-large btn-warning\" href=\""+ shuffled_slides[i].slide_link + "\" rel=\"nofollow\" target=\"_blank\">Read More</a></p></div></div></div>";
42
- };
43
- sdf_carousel = sdf_carousel + "<div class=\"item\"><div class=\"container\"><div class=\"carousel-caption\">"+ sds_promo_blog_post + "</div></div></div>";
44
- sdf_carousel = sdf_carousel + "</div><a class=\"left carousel-control\" href=\"#sdfCarousel\" data-slide=\"prev\"><span class=\"glyphicon glyphicon-chevron-left\"></span></a><a class=\"right carousel-control\" href=\"#sdfCarousel\" data-slide=\"next\"><span class=\"glyphicon glyphicon-chevron-right\"></span></a></div>";
45
-
46
- $('#sdf-promo-carousel').html(sdf_carousel).delay(500).fadeIn(600).carousel({ interval:8000 });
47
-
48
- // dashboard widget
49
- $('#sdf_dashboard_widget h3.hndle span').html(data.dashboard_widget[0].title);
50
- $('#sdf_dashboard_widget .inside').html(data.dashboard_widget[0].content);
51
- setTimeout(function(){
52
- $('#sdf_dashboard_widget .inside').fadeIn(600);
53
- },800);
54
- }
55
- })
56
- .fail(function (data) {
57
- $('#sdf-promo-carousel').delay(500).fadeIn(600).carousel({ interval:8000 });
58
- });
59
-
60
- });
61
-
62
- $.fn.animate_show_el = function(anim_duration)
63
- {
64
- $(this).css( {overflow:"hidden"}).animate({height:"auto", opacity:1}, anim_duration,
65
- function(){ $(this).css({display:"inline-block", overflow:"visible", visibility:"visible", position:"relative", height:"auto"}); });
66
- };
67
-
68
- $.fn.animate_hide_el = function(anim_duration)
69
- {
70
- $(this).css({overflow:"hidden"}).animate({height:0, opacity:0}, anim_duration,
71
- function(){ $(this).css({display:"none", overflow:"visible", visibility:"hidden", position:"absolute"}); });
72
- };
73
-
74
- })(jQuery);
75
-
76
- /**
77
- * Randomize array element order in-place.
78
- * Using Fisher-Yates shuffle algorithm.
79
- */
80
- function shuffleArray(array) {
81
- for (var i = array.length - 1; i > 0; i--) {
82
- var j = Math.floor(Math.random() * (i + 1));
83
- var temp = array[i];
84
- array[i] = array[j];
85
- array[j] = temp;
86
- }
87
- return array;
88
  }
1
+ /*global jQuery:false, alert */
2
+ (function($) {
3
+ "use strict";
4
+ jQuery(document).ready(function($) {
5
+
6
+ $('#sdf-promo-carousel').hide();
7
+ $('#sdf_dashboard_widget .inside').hide();
8
+ var sds_promo_blog_post = $('#sds_promo_blog_post').html();
9
+ var banners_remote = ({
10
+ "enabled":true,
11
+ "banners": [
12
+ {"banner_img":"InternalLinkBanner.jpg", "banner_link":"https://seodesignframework.leadpages.net/internal-links/"},
13
+ {"banner_img":"MetaWritingBanner.jpg", "banner_link":"https://seodesignframework.leadpages.net/meta-titles-descriptions/"}
14
+ ],
15
+ "slides": [
16
+ {"slide_cap":"<h3>Download Jeffrey’s Brain</h3><p>Get Equipped for Success - Tips from Our Founder. Download: 20 SEO Tips, SEO for Large Websites and the Organic SEO EBook today.</p>", "slide_link":"http://www.seodesignframework.com/ebooks/"},
17
+ {"slide_cap":"<h3>Got Design?</h3><p>Unleash Your Best Design Concepts with Drag-n-Drop Controls that Give You the Power to Implement Complex Designs Quickly and Easily</p>", "slide_link":"http://www.seodesignframework.com/sdf-drag-and-drop-page-builder/"},
18
+ {"slide_cap":"<h3>Silos Made Easy</h3><p>Deploy Perfect Website Silo Architecture Quickly and Easily with the SEO Design Framework.</p>", "slide_link":"http://www.seodesignframework.com/website-silo-architecture/"},
19
+ {"slide_cap":"<h3>What, No Control?</h3><p>Become Master of your Blog with Page-Level Controls that Liberate Designs and Crush Limitations of other Themes and Frameworks.</p>", "slide_link":"http://www.seodesignframework.com/page-level-controls/"}
20
+ ],
21
+ "dashboard_widget": [
22
+ {"title":"Learn How to Use SEO Ultimate", "content":"<p>Get access to <a rel=\"nofollow\" target=\"_blank\" title=\"SEO Ultimate video training\" href=\"https://seodesignframework.leadpages.net/seo-ultimate-video-training/\">detailed video training</a> covering each module.</p><a rel=\"nofollow\" target=\"_blank\" title=\"SEO Ultimate video training\" href=\"https://seodesignframework.leadpages.net/seo-ultimate-video-training/\"><img src=\"" + suModulesSdfAdsSdfAdsL10n.sdf_banners_url + "SEO-VideoTraining-Banner-v3.jpg\" alt=\"SEO Ultimate video training\" /></a>"}
23
+ ]
24
+ })
25
+
26
+ var sdf_carousel = '';
27
+ if (banners_remote.enabled === true) {
28
+ var shuffled_banners = shuffleArray(banners_remote.banners);
29
+ var shuffled_slides = shuffleArray(banners_remote.slides);
30
+ // check if it's cloud hosted banner
31
+ var banner_img = shuffled_banners[0].banner_img
32
+ if(banner_img.indexOf('https://') == -1) banner_img = suModulesSdfAdsSdfAdsL10n.sdf_banners_url + banner_img;
33
+ sdf_carousel = sdf_carousel + "<a href=\"" + shuffled_banners[0].banner_link + "\" rel=\"nofollow\" target=\"_blank\"><img src=\"" + banner_img + "\" alt=\"Slide "+ i +"\"></a>";
34
+ sdf_carousel = sdf_carousel + "<div id=\"sdfCarousel\" class=\"carousel slide\"><ol class=\"carousel-indicators\">";
35
+
36
+ var active_indicator = '';
37
+ for ( var i = 0; i < shuffled_slides.length; i++ ) {
38
+ if (i == 0) active_indicator = ' class=\"active\"';
39
+ else active_indicator = '';
40
+ sdf_carousel = sdf_carousel + "<li data-target=\"#sdfCarousel\" data-slide-to=\""+ i +"\""+ active_indicator +"></li>";
41
+ };
42
+ sdf_carousel = sdf_carousel + "<li data-target=\"#sdfCarousel\" data-slide-to=\""+ i +"\"></li>";
43
+ sdf_carousel = sdf_carousel + "</ol><div class=\"carousel-inner\">";
44
+
45
+
46
+ for ( var i = 0; i < shuffled_slides.length; i++ ) {
47
+ if (i == 0) active_indicator = ' active';
48
+ else active_indicator = '';
49
+ sdf_carousel = sdf_carousel + "<div class=\"item"+ active_indicator +"\"><div class=\"container\"><div class=\"carousel-caption\">"+ shuffled_slides[i].slide_cap + "<p><a class=\"btn btn-large btn-warning\" href=\""+ shuffled_slides[i].slide_link + "\" rel=\"nofollow\" target=\"_blank\">Read More</a></p></div></div></div>";
50
+ };
51
+ sdf_carousel = sdf_carousel + "<div class=\"item\"><div class=\"container\"><div class=\"carousel-caption\">"+ sds_promo_blog_post + "</div></div></div>";
52
+ sdf_carousel = sdf_carousel + "</div><a class=\"left carousel-control\" href=\"#sdfCarousel\" data-slide=\"prev\"><span class=\"glyphicon glyphicon-chevron-left\"></span></a><a class=\"right carousel-control\" href=\"#sdfCarousel\" data-slide=\"next\"><span class=\"glyphicon glyphicon-chevron-right\"></span></a></div>";
53
+
54
+ $('#sdf-promo-carousel').html(sdf_carousel).delay(500).fadeIn(400).carousel({ interval:12000 });
55
+
56
+ // dashboard widget
57
+ $('#sdf_dashboard_widget h3.hndle span').html(banners_remote.dashboard_widget[0].title);
58
+ $('#sdf_dashboard_widget .inside').html(banners_remote.dashboard_widget[0].content);
59
+ setTimeout(function(){
60
+ $('#sdf_dashboard_widget .inside').fadeIn(400);
61
+ },800);
62
+ }
63
+
64
+ });
65
+
66
+ })(jQuery);
67
+
68
+ /**
69
+ * Randomize array element order in-place.
70
+ * Using Fisher-Yates shuffle algorithm.
71
+ */
72
+ function shuffleArray(array) {
73
+ for (var i = array.length - 1; i > 0; i--) {
74
+ var j = Math.floor(Math.random() * (i + 1));
75
+ var temp = array[i];
76
+ array[i] = array[j];
77
+ array[j] = temp;
78
+ }
79
+ return array;
 
 
 
 
 
 
 
 
80
  }
modules/sds-blog/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/sds-blog/sds-blog.css CHANGED
@@ -1,38 +1,38 @@
1
- #su-sds-blog .rss-widget {
2
- background-color: white;
3
- border: 1px solid black;
4
- padding: 2em;
5
- margin: 2em 0;
6
- border-radius: 10px;
7
- -moz-border-radius: 10px;
8
- -webkit-border-radius: 10px;
9
- }
10
-
11
- #su-sds-blog a.rsswidget {
12
- font-size: 13px;
13
- font-family: Georgia,"Times New Roman","Bitstream Charter",Times,serif;
14
- line-height: 1.7em;
15
- }
16
-
17
- #su-sds-blog li a:visited {
18
- color: purple;
19
- }
20
-
21
- #su-sds-blog span.rss-date {
22
- margin-left: 3px;
23
- }
24
-
25
- #su-sds-blog .rss-widget li {
26
- padding-bottom: 1em;
27
- }
28
-
29
- #su-sds-blog img#sds-logo {
30
- float: right;
31
- border: 1px solid black;
32
- padding: 1em;
33
- background-color: white;
34
- margin-left: 2em;
35
- border-radius: 10px;
36
- -moz-border-radius: 10px;
37
- -webkit-border-radius: 10px;
38
  }
1
+ #su-sds-blog .rss-widget {
2
+ background-color: white;
3
+ border: 1px solid black;
4
+ padding: 2em;
5
+ margin: 2em 0;
6
+ border-radius: 10px;
7
+ -moz-border-radius: 10px;
8
+ -webkit-border-radius: 10px;
9
+ }
10
+
11
+ #su-sds-blog a.rsswidget {
12
+ font-size: 13px;
13
+ font-family: Georgia,"Times New Roman","Bitstream Charter",Times,serif;
14
+ line-height: 1.7em;
15
+ }
16
+
17
+ #su-sds-blog li a:visited {
18
+ color: purple;
19
+ }
20
+
21
+ #su-sds-blog span.rss-date {
22
+ margin-left: 3px;
23
+ }
24
+
25
+ #su-sds-blog .rss-widget li {
26
+ padding-bottom: 1em;
27
+ }
28
+
29
+ #su-sds-blog img#sds-logo {
30
+ float: right;
31
+ border: 1px solid black;
32
+ padding: 1em;
33
+ background-color: white;
34
+ margin-left: 2em;
35
+ border-radius: 10px;
36
+ -moz-border-radius: 10px;
37
+ -webkit-border-radius: 10px;
38
  }
modules/sds-blog/sds-blog.php CHANGED
@@ -1,218 +1,218 @@
1
- <?php
2
- /**
3
- * SEO Design Solutions Whitepapers Module
4
- *
5
- * @since 0.1
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_SdsBlog extends SU_Module {
11
-
12
- static function get_module_title() { return __('Whitepapers', 'seo-ultimate'); }
13
- static function get_menu_title() { return __('Whitepapers', 'seo-ultimate'); }
14
- function get_page_title() { return __('SEO Design Solutions Whitepapers', 'seo-ultimate'); }
15
- static function has_menu_count() { return true; }
16
- function get_menu_count() { return $this->get_unread_count(); }
17
-
18
- function __construct() {
19
- add_filter('su_settings_export_array', array(&$this, 'filter_export_array'));
20
- }
21
-
22
- function init() {
23
- $this->cron('load_blog_rss', 'hourly');
24
- }
25
-
26
- function upgrade() {
27
- $this->delete_setting('rssitems');
28
- }
29
-
30
- function get_default_settings() {
31
- //Don't notify about new items when the plugin is just installed
32
- return array('lastread' => time());
33
- }
34
-
35
- function filter_export_array($settings) {
36
- unset($settings[$this->get_module_key()]['rss_item_times']);
37
- return $settings;
38
- }
39
-
40
- function load_blog_rss() {
41
- $rss = suwp::load_rss('http://feeds.seodesignsolutions.com/SeoDesignSolutionsBlog', SU_USER_AGENT);
42
- if ($rss && $rss->get_items()) {
43
- $times = array();
44
- foreach ($rss->get_items() as $item) $times[] = $this->get_feed_item_date($item);
45
- $this->update_setting('rss_item_times', $times);
46
- }
47
- }
48
-
49
- function admin_page_contents() {
50
-
51
- if ($this->should_show_sdf_theme_promo()) {
52
- echo "\n\n<div class='row'>\n";
53
- echo "\n\n<div class='col-sm-8 col-md-9'>\n";
54
- }
55
-
56
- echo "<a href='http://www.seodesignsolutions.com'><img src='{$this->plugin->plugin_dir_url}plugin/img/sds-logo.png' alt='".__('SEO Design Solutions', 'seo-ultimate')."' id='sds-logo' /></a>";
57
- echo "<p>".__('The search engine optimization articles below are loaded from the website of SEO Design Solutions, the company behind the SEO Ultimate plugin. Click on an article&#8217;s title to read it.', 'seo-ultimate')."</p>\n";
58
- echo "<div class='rss-widget'>\n";
59
-
60
- add_filter('http_headers_useragent', 'su_get_user_agent');
61
- add_filter('esc_html', array(&$this, 'truncate_at_ellipsis'));
62
- $this->sds_blog_rss_output( 'http://feeds.seodesignsolutions.com/SeoDesignSolutionsBlog', array('show_summary' => 1, 'show_date' => 1, 'items' => 10) );
63
- remove_filter('esc_html', array(&$this, 'truncate_at_ellipsis'));
64
- remove_filter('http_headers_useragent', 'su_get_user_agent');
65
-
66
- echo "</div>\n";
67
- $this->update_setting('lastread', time());
68
-
69
- if ($this->should_show_sdf_theme_promo()) {
70
- echo "\n\n</div>\n";
71
- echo "\n\n<div class='col-sm-4 col-md-3'>\n";
72
- $this->promo_sdf_banners();
73
- echo "\n\n</div>\n";
74
- echo "\n\n</div>\n";
75
- }
76
- }
77
-
78
- function truncate_at_ellipsis($content) {
79
- $end = '[...]';
80
- if (sustr::has($content, $end)) {
81
- $content = sustr::upto($content, $end);
82
- $content = sustr::rtrim_substr($content, $end);
83
- }
84
- return sustr::endwith($content, '[&hellip;]');
85
- }
86
-
87
- function get_unread_count() {
88
-
89
- if (count($times = $this->get_setting('rss_item_times', array()))) {
90
- $lastread = $this->get_setting('lastread');
91
- $new = 0; foreach ($times as $time) if ($time > $lastread) $new++;
92
- return $new;
93
- }
94
-
95
- return 0;
96
- }
97
-
98
- function get_feed_item_date($item) {
99
-
100
- //Is there an Atom date? If so, parse it.
101
- if (isset($item->issued) && $atom_date = $item->issued)
102
- $date = parse_w3cdtf($atom_date);
103
-
104
- //Or is there an RSS2 date? If so, parse it.
105
- elseif (isset($item->pubdate) && $rss_2_date = $item->pubdate)
106
- $date = strtotime($rss_2_date);
107
-
108
- //Or is there an RSS1 date? If so, parse it.
109
- elseif (isset($item->dc['date']) && $rss_1_date = $item->dc['date'])
110
- $date = parse_w3cdtf($rss_1_date);
111
-
112
- else $date = null;
113
-
114
- //Return a UNIX timestamp.
115
- if ($date) return $date; else return 0;
116
- }
117
-
118
- /**
119
- * Display the RSS entries in a list.
120
- *
121
- * @since 2.5.0
122
- *
123
- * @param string|array|object $rss RSS url.
124
- * @param array $args Widget arguments.
125
- */
126
- function sds_blog_rss_output( $rss, $args = array() ) {
127
- if ( is_string( $rss ) ) {
128
- $rss = fetch_feed($rss);
129
- } elseif ( is_array($rss) && isset($rss['url']) ) {
130
- $args = $rss;
131
- $rss = fetch_feed($rss['url']);
132
- } elseif ( !is_object($rss) ) {
133
- return;
134
- }
135
-
136
- if ( is_wp_error($rss) ) {
137
- if ( is_admin() || current_user_can('manage_options') )
138
- echo '<p>' . sprintf( __('<strong>RSS Error</strong>: %s'), $rss->get_error_message() ) . '</p>';
139
- return;
140
- }
141
-
142
- $default_args = array( 'show_author' => 0, 'show_date' => 0, 'show_summary' => 0 );
143
- $args = wp_parse_args( $args, $default_args );
144
- extract( $args, EXTR_SKIP );
145
-
146
- $items = (int) $items;
147
- if ( $items < 1 || 20 < $items )
148
- $items = 10;
149
- $show_summary = (int) $show_summary;
150
- $show_author = (int) $show_author;
151
- $show_date = (int) $show_date;
152
-
153
- if ( !$rss->get_item_quantity() ) {
154
- echo '<ul><li>' . __( 'An error has occurred, which probably means the feed is down. Try again later.' ) . '</li></ul>';
155
- $rss->__destruct();
156
- unset($rss);
157
- return;
158
- }
159
-
160
- echo '<ul>';
161
- foreach ( $rss->get_items(0, $items) as $item ) {
162
- $link = $item->get_link();
163
- while ( stristr($link, 'http') != $link )
164
- $link = substr($link, 1);
165
- $link = esc_url(strip_tags($link));
166
- $title = esc_attr(strip_tags($item->get_title()));
167
- if ( empty($title) )
168
- $title = __('Untitled');
169
-
170
- $desc = str_replace( array("\n", "\r"), ' ', esc_attr( strip_tags( @html_entity_decode( $item->get_description(), ENT_QUOTES, get_option('blog_charset') ) ) ) );
171
- $excerpt = wp_html_excerpt( $desc, 360 );
172
-
173
- // Append ellipsis. Change existing [...] to [&hellip;].
174
- if ( '[...]' == substr( $excerpt, -5 ) )
175
- $excerpt = substr( $excerpt, 0, -5 ) . '[&hellip;]';
176
- elseif ( '[&hellip;]' != substr( $excerpt, -10 ) && $desc != $excerpt )
177
- $excerpt .= ' [&hellip;]';
178
-
179
- $excerpt = esc_html( $excerpt );
180
-
181
- if ( $show_summary ) {
182
- $summary = "<div class='rssSummary'>$excerpt</div>";
183
- } else {
184
- $summary = '';
185
- }
186
-
187
- $date = '';
188
- if ( $show_date ) {
189
- $date = $item->get_date( 'U' );
190
-
191
- if ( $date ) {
192
- $date = ' <span class="rss-date">' . date_i18n( get_option( 'date_format' ), $date ) . '</span>';
193
- }
194
- }
195
-
196
- $author = '';
197
- if ( $show_author ) {
198
- $author = $item->get_author();
199
- if ( is_object($author) ) {
200
- $author = $author->get_name();
201
- $author = ' <cite>' . esc_html( strip_tags( $author ) ) . '</cite>';
202
- }
203
- }
204
-
205
- if ( $link == '' ) {
206
- echo "<li>$title{$date}{$summary}{$author}</li>";
207
- } else {
208
- echo "<li><a class='rsswidget' href='$link' title='$desc' target='_blank' rel='nofollow'>$title</a>{$date}{$summary}{$author}</li>";
209
- }
210
- }
211
- echo '</ul>';
212
- $rss->__destruct();
213
- unset($rss);
214
- }
215
- }
216
-
217
- }
218
  ?>
1
+ <?php
2
+ /**
3
+ * SEO Design Solutions Whitepapers Module
4
+ *
5
+ * @since 0.1
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_SdsBlog extends SU_Module {
11
+
12
+ static function get_module_title() { return __('Whitepapers', 'seo-ultimate'); }
13
+ static function get_menu_title() { return __('Whitepapers', 'seo-ultimate'); }
14
+ function get_page_title() { return __('SEO Design Solutions Whitepapers', 'seo-ultimate'); }
15
+ static function has_menu_count() { return true; }
16
+ function get_menu_count() { return $this->get_unread_count(); }
17
+
18
+ function __construct() {
19
+ add_filter('su_settings_export_array', array(&$this, 'filter_export_array'));
20
+ }
21
+
22
+ function init() {
23
+ $this->cron('load_blog_rss', 'hourly');
24
+ }
25
+
26
+ function upgrade() {
27
+ $this->delete_setting('rssitems');
28
+ }
29
+
30
+ function get_default_settings() {
31
+ //Don't notify about new items when the plugin is just installed
32
+ return array('lastread' => time());
33
+ }
34
+
35
+ function filter_export_array($settings) {
36
+ unset($settings[$this->get_module_key()]['rss_item_times']);
37
+ return $settings;
38
+ }
39
+
40
+ function load_blog_rss() {
41
+ $rss = suwp::load_rss('http://feeds.seodesignsolutions.com/SeoDesignSolutionsBlog', SU_USER_AGENT);
42
+ if ($rss && $rss->get_items()) {
43
+ $times = array();
44
+ foreach ($rss->get_items() as $item) $times[] = $this->get_feed_item_date($item);
45
+ $this->update_setting('rss_item_times', $times);
46
+ }
47
+ }
48
+
49
+ function admin_page_contents() {
50
+
51
+ if ($this->should_show_sdf_theme_promo()) {
52
+ echo "\n\n<div class='row'>\n";
53
+ echo "\n\n<div class='col-sm-8 col-md-9'>\n";
54
+ }
55
+
56
+ echo "<a href='http://www.seodesignsolutions.com'><img src='{$this->plugin->plugin_dir_url}plugin/img/sds-logo.png' alt='".__('SEO Design Solutions', 'seo-ultimate')."' id='sds-logo' /></a>";
57
+ echo "<p>".__('The search engine optimization articles below are loaded from the website of SEO Design Solutions, the company behind the SEO Ultimate plugin. Click on an article&#8217;s title to read it.', 'seo-ultimate')."</p>\n";
58
+ echo "<div class='rss-widget'>\n";
59
+
60
+ add_filter('http_headers_useragent', 'su_get_user_agent');
61
+ add_filter('esc_html', array(&$this, 'truncate_at_ellipsis'));
62
+ $this->sds_blog_rss_output( 'http://feeds.seodesignsolutions.com/SeoDesignSolutionsBlog', array('show_summary' => 1, 'show_date' => 1, 'items' => 10) );
63
+ remove_filter('esc_html', array(&$this, 'truncate_at_ellipsis'));
64
+ remove_filter('http_headers_useragent', 'su_get_user_agent');
65
+
66
+ echo "</div>\n";
67
+ $this->update_setting('lastread', time());
68
+
69
+ if ($this->should_show_sdf_theme_promo()) {
70
+ echo "\n\n</div>\n";
71
+ echo "\n\n<div class='col-sm-4 col-md-3'>\n";
72
+ $this->promo_sdf_banners();
73
+ echo "\n\n</div>\n";
74
+ echo "\n\n</div>\n";
75
+ }
76
+ }
77
+
78
+ function truncate_at_ellipsis($content) {
79
+ $end = '[...]';
80
+ if (sustr::has($content, $end)) {
81
+ $content = sustr::upto($content, $end);
82
+ $content = sustr::rtrim_substr($content, $end);
83
+ }
84
+ return sustr::endwith($content, '[&hellip;]');
85
+ }
86
+
87
+ function get_unread_count() {
88
+
89
+ if (count($times = $this->get_setting('rss_item_times', array()))) {
90
+ $lastread = $this->get_setting('lastread');
91
+ $new = 0; foreach ($times as $time) if ($time > $lastread) $new++;
92
+ return $new;
93
+ }
94
+
95
+ return 0;
96
+ }
97
+
98
+ function get_feed_item_date($item) {
99
+
100
+ //Is there an Atom date? If so, parse it.
101
+ if (isset($item->issued) && $atom_date = $item->issued)
102
+ $date = parse_w3cdtf($atom_date);
103
+
104
+ //Or is there an RSS2 date? If so, parse it.
105
+ elseif (isset($item->pubdate) && $rss_2_date = $item->pubdate)
106
+ $date = strtotime($rss_2_date);
107
+
108
+ //Or is there an RSS1 date? If so, parse it.
109
+ elseif (isset($item->dc['date']) && $rss_1_date = $item->dc['date'])
110
+ $date = parse_w3cdtf($rss_1_date);
111
+
112
+ else $date = null;
113
+
114
+ //Return a UNIX timestamp.
115
+ if ($date) return $date; else return 0;
116
+ }
117
+
118
+ /**
119
+ * Display the RSS entries in a list.
120
+ *
121
+ * @since 2.5.0
122
+ *
123
+ * @param string|array|object $rss RSS url.
124
+ * @param array $args Widget arguments.
125
+ */
126
+ function sds_blog_rss_output( $rss, $args = array() ) {
127
+ if ( is_string( $rss ) ) {
128
+ $rss = fetch_feed($rss);
129
+ } elseif ( is_array($rss) && isset($rss['url']) ) {
130
+ $args = $rss;
131
+ $rss = fetch_feed($rss['url']);
132
+ } elseif ( !is_object($rss) ) {
133
+ return;
134
+ }
135
+
136
+ if ( is_wp_error($rss) ) {
137
+ if ( is_admin() || current_user_can('manage_options') )
138
+ echo '<p>' . sprintf( __('<strong>RSS Error</strong>: %s'), $rss->get_error_message() ) . '</p>';
139
+ return;
140
+ }
141
+
142
+ $default_args = array( 'show_author' => 0, 'show_date' => 0, 'show_summary' => 0 );
143
+ $args = wp_parse_args( $args, $default_args );
144
+ extract( $args, EXTR_SKIP );
145
+
146
+ $items = (int) $items;
147
+ if ( $items < 1 || 20 < $items )
148
+ $items = 10;
149
+ $show_summary = (int) $show_summary;
150
+ $show_author = (int) $show_author;
151
+ $show_date = (int) $show_date;
152
+
153
+ if ( !$rss->get_item_quantity() ) {
154
+ echo '<ul><li>' . __( 'An error has occurred, which probably means the feed is down. Try again later.' ) . '</li></ul>';
155
+ $rss->__destruct();
156
+ unset($rss);
157
+ return;
158
+ }
159
+
160
+ echo '<ul>';
161
+ foreach ( $rss->get_items(0, $items) as $item ) {
162
+ $link = $item->get_link();
163
+ while ( stristr($link, 'http') != $link )
164
+ $link = substr($link, 1);
165
+ $link = esc_url(strip_tags($link));
166
+ $title = esc_attr(strip_tags($item->get_title()));
167
+ if ( empty($title) )
168
+ $title = __('Untitled');
169
+
170
+ $desc = str_replace( array("\n", "\r"), ' ', esc_attr( strip_tags( @html_entity_decode( $item->get_description(), ENT_QUOTES, get_option('blog_charset') ) ) ) );
171
+ $excerpt = wp_html_excerpt( $desc, 360 );
172
+
173
+ // Append ellipsis. Change existing [...] to [&hellip;].
174
+ if ( '[...]' == substr( $excerpt, -5 ) )
175
+ $excerpt = substr( $excerpt, 0, -5 ) . '[&hellip;]';
176
+ elseif ( '[&hellip;]' != substr( $excerpt, -10 ) && $desc != $excerpt )
177
+ $excerpt .= ' [&hellip;]';
178
+
179
+ $excerpt = esc_html( $excerpt );
180
+
181
+ if ( $show_summary ) {
182
+ $summary = "<div class='rssSummary'>$excerpt</div>";
183
+ } else {
184
+ $summary = '';
185
+ }
186
+
187
+ $date = '';
188
+ if ( $show_date ) {
189
+ $date = $item->get_date( 'U' );
190
+
191
+ if ( $date ) {
192
+ $date = ' <span class="rss-date">' . date_i18n( get_option( 'date_format' ), $date ) . '</span>';
193
+ }
194
+ }
195
+
196
+ $author = '';
197
+ if ( $show_author ) {
198
+ $author = $item->get_author();
199
+ if ( is_object($author) ) {
200
+ $author = $author->get_name();
201
+ $author = ' <cite>' . esc_html( strip_tags( $author ) ) . '</cite>';
202
+ }
203
+ }
204
+
205
+ if ( $link == '' ) {
206
+ echo "<li>$title{$date}{$summary}{$author}</li>";
207
+ } else {
208
+ echo "<li><a class='rsswidget' href='$link' title='$desc' target='_blank' rel='nofollow'>$title</a>{$date}{$summary}{$author}</li>";
209
+ }
210
+ }
211
+ echo '</ul>';
212
+ $rss->__destruct();
213
+ unset($rss);
214
+ }
215
+ }
216
+
217
+ }
218
  ?>
modules/settings/global-settings.php CHANGED
@@ -1,69 +1,69 @@
1
- <?php
2
- /**
3
- * Global Settings Module
4
- *
5
- * @since 2.1
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_GlobalSettings extends SU_Module {
11
-
12
- var $wp_meta_called = false;
13
-
14
- static function get_parent_module() { return 'settings'; }
15
- static function get_child_order() { return 10; }
16
- static function is_independent_module() { return false; }
17
-
18
- static function get_module_title() { return __('Global Settings', 'seo-ultimate'); }
19
-
20
- function get_default_settings() {
21
- return array(
22
- 'attribution_link' => false
23
- , 'mark_code' => true
24
- , 'sdf_theme' => true
25
- );
26
- }
27
-
28
- function init() {
29
- //Hook to add attribution link
30
- if ($this->get_setting('attribution_link')) {
31
- //add_action('wp_meta', array(&$this, 'meta_link'));
32
- //add_action('wp_footer', array(&$this, 'footer_link'));
33
- }
34
- }
35
-
36
- function admin_page_contents() {
37
-
38
- $this->admin_form_start();
39
-
40
- $checkboxes = array(
41
- 'mark_code' => __('Identify the plugin&#8217;s HTML code insertions with HTML comment tags', 'seo-ultimate')
42
- , 'sdf_theme' => __('Show the promo slider for SEO Design Framework on plugin pages', 'seo-ultimate')
43
- //, 'attribution_link' => __('Enable nofollow&#8217;d attribution link on my site', 'seo-ultimate')
44
- //, 'attribution_link_css' => array('description' => __('Add CSS styles to the attribution link', 'seo-ultimate'), 'indent' => true)
45
- );
46
-
47
- $this->checkboxes($checkboxes);
48
- $this->admin_form_end();
49
- }
50
-
51
- function meta_link() {
52
- echo "<li><a href='http://www.seodesignsolutions.com/' title='Search engine optimization technology by SEO Design Solutions' rel='nofollow'>SEO</a></li>\n";
53
- $this->wp_meta_called = true;
54
- }
55
-
56
- function footer_link() {
57
- if (!$this->wp_meta_called) {
58
- if ($this->get_setting('attribution_link_css')) {
59
- $pstyle = " style='text-align: center; font-size: smaller;'";
60
- $astyle = " style='color: inherit;'";
61
- } else $pstyle = $astyle = '';
62
-
63
- echo "\n<p id='suattr'$pstyle>Optimized by <a href='http://www.seodesignsolutions.com/' rel='nofollow'$astyle>SEO</a> Ultimate</p>\n";
64
- }
65
- }
66
- }
67
-
68
- }
69
  ?>
1
+ <?php
2
+ /**
3
+ * Global Settings Module
4
+ *
5
+ * @since 2.1
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_GlobalSettings extends SU_Module {
11
+
12
+ var $wp_meta_called = false;
13
+
14
+ static function get_parent_module() { return 'settings'; }
15
+ static function get_child_order() { return 10; }
16
+ static function is_independent_module() { return false; }
17
+
18
+ static function get_module_title() { return __('Global Settings', 'seo-ultimate'); }
19
+
20
+ function get_default_settings() {
21
+ return array(
22
+ 'attribution_link' => false
23
+ , 'mark_code' => true
24
+ , 'sdf_theme' => true
25
+ );
26
+ }
27
+
28
+ function init() {
29
+ //Hook to add attribution link
30
+ if ($this->get_setting('attribution_link')) {
31
+ //add_action('wp_meta', array(&$this, 'meta_link'));
32
+ //add_action('wp_footer', array(&$this, 'footer_link'));
33
+ }
34
+ }
35
+
36
+ function admin_page_contents() {
37
+
38
+ $this->admin_form_start();
39
+
40
+ $checkboxes = array(
41
+ 'mark_code' => __('Identify the plugin&#8217;s HTML code insertions with HTML comment tags', 'seo-ultimate')
42
+ , 'sdf_theme' => __('Show the promo slider for SEO Design Framework on plugin pages', 'seo-ultimate')
43
+ //, 'attribution_link' => __('Enable nofollow&#8217;d attribution link on my site', 'seo-ultimate')
44
+ //, 'attribution_link_css' => array('description' => __('Add CSS styles to the attribution link', 'seo-ultimate'), 'indent' => true)
45
+ );
46
+
47
+ $this->checkboxes($checkboxes);
48
+ $this->admin_form_end();
49
+ }
50
+
51
+ function meta_link() {
52
+ echo "<li><a href='http://www.seodesignsolutions.com/' title='Search engine optimization technology by SEO Design Solutions' rel='nofollow'>SEO</a></li>\n";
53
+ $this->wp_meta_called = true;
54
+ }
55
+
56
+ function footer_link() {
57
+ if (!$this->wp_meta_called) {
58
+ if ($this->get_setting('attribution_link_css')) {
59
+ $pstyle = " style='text-align: center; font-size: smaller;'";
60
+ $astyle = " style='color: inherit;'";
61
+ } else $pstyle = $astyle = '';
62
+
63
+ echo "\n<p id='suattr'$pstyle>Optimized by <a href='http://www.seodesignsolutions.com/' rel='nofollow'$astyle>SEO</a> Ultimate</p>\n";
64
+ }
65
+ }
66
+ }
67
+
68
+ }
69
  ?>
modules/settings/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/settings/install.css CHANGED
@@ -1,29 +1,29 @@
1
- .su-xgrade table.form-table ul {
2
- list-style-type: disc;
3
- padding: 0 0 0 2em;
4
- margin: 0 0 2em 2em;
5
- }
6
-
7
- .su-xgrade table.form-table li {
8
- padding-top: 0;
9
- padding-bottom: 0;
10
- margin-top: 0;
11
- margin-bottom: 0;
12
- }
13
-
14
- .su-xgrade label {
15
- padding: 0.5em 1em;
16
- }
17
-
18
- .su-xgrade label.first {
19
- background-color: #DFFFE3;
20
- }
21
-
22
- .su-xgrade label.current-setting {
23
- background-color: #FFFFE0;
24
- }
25
-
26
- #su-reinstall form, #su-reinstall form p.submit {
27
- padding: 0;
28
- margin: 0;
29
  }
1
+ .su-xgrade table.form-table ul {
2
+ list-style-type: disc;
3
+ padding: 0 0 0 2em;
4
+ margin: 0 0 2em 2em;
5
+ }
6
+
7
+ .su-xgrade table.form-table li {
8
+ padding-top: 0;
9
+ padding-bottom: 0;
10
+ margin-top: 0;
11
+ margin-bottom: 0;
12
+ }
13
+
14
+ .su-xgrade label {
15
+ padding: 0.5em 1em;
16
+ }
17
+
18
+ .su-xgrade label.first {
19
+ background-color: #DFFFE3;
20
+ }
21
+
22
+ .su-xgrade label.current-setting {
23
+ background-color: #FFFFE0;
24
+ }
25
+
26
+ #su-reinstall form, #su-reinstall form p.submit {
27
+ padding: 0;
28
+ margin: 0;
29
  }
modules/settings/install.php CHANGED
@@ -1,244 +1,244 @@
1
- <?php
2
- /**
3
- * Install Module
4
- *
5
- * @since 2.5
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- define('SU_DOWNGRADE_LIMIT', '5.0');
11
-
12
- class SU_Install extends SU_Module {
13
-
14
- static function get_parent_module() { return 'settings'; }
15
- static function get_child_order() { return 20; }
16
- static function is_independent_module() { return false; }
17
-
18
- static function get_module_title() { return __('Upgrade/Downgrade/Reinstall', 'seo-ultimate'); }
19
- static function get_menu_title() { return __('Installer', 'seo-ultimate'); }
20
-
21
- function get_admin_page_tabs() {
22
-
23
- $tabs = array();
24
-
25
- if ($this->current_user_can_upgrade())
26
- $tabs[] = array('title' => __('Upgrade', 'seo-ultimate'), 'id' => 'su-upgrade', 'callback' => 'upgrade_tab');
27
-
28
- if ($this->current_user_can_downgrade())
29
- $tabs[] = array('title' => __('Downgrade', 'seo-ultimate'), 'id' => 'su-downgrade', 'callback' => 'downgrade_tab');
30
-
31
- if ($this->current_user_can_reinstall())
32
- $tabs[] = array('title' => __('Reinstall', 'seo-ultimate'), 'id' => 'su-reinstall', 'callback' => 'reinstall_tab');
33
-
34
- if (count($tabs))
35
- return $tabs;
36
-
37
- return false;
38
- }
39
-
40
- function belongs_in_admin($admin_scope = null) {
41
-
42
- if ($admin_scope === null)
43
- $admin_scope = suwp::get_admin_scope();
44
-
45
- if ( ! function_exists( 'is_plugin_active_for_network' ) )
46
- require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
47
-
48
- switch ($admin_scope) {
49
- case 'blog':
50
- return !is_multisite() || !is_plugin_active_for_network($this->plugin->plugin_basename);
51
- break;
52
- case 'network':
53
- return is_plugin_active_for_network($this->plugin->plugin_basename);
54
- break;
55
- default:
56
- return false;
57
- break;
58
- }
59
- }
60
-
61
- function current_user_can_upgrade() {
62
- return current_user_can('update_plugins') && (!is_multisite() || is_super_admin());
63
- }
64
-
65
- function current_user_can_downgrade() {
66
- return current_user_can('install_plugins') && (!is_multisite() || is_super_admin());
67
- }
68
-
69
- function current_user_can_reinstall() {
70
- return current_user_can('install_plugins') && (!is_multisite() || is_super_admin());
71
- }
72
-
73
- function init() {
74
- if ($this->is_action('update')) {
75
- add_filter('su_custom_admin_page-settings', array(&$this, 'do_installation'));
76
- }
77
- }
78
-
79
- function upgrade_tab() {
80
-
81
- if (!$this->current_user_can_upgrade()) {
82
- $this->print_message('error', __('You do not have sufficient permissions to upgrade plugins on this site.', 'seo-ultimate'));
83
- return;
84
- }
85
-
86
- $radiobuttons = $this->get_version_radiobuttons(SU_VERSION, false);
87
- if (is_array($radiobuttons)) {
88
- if (count($radiobuttons) > 1) {
89
-
90
- echo "\n<p>";
91
- _e('From the list below, select the version to which you would like to upgrade. Then click the &#8220;Upgrade&#8221; button at the bottom of the screen.', 'seo-ultimate');
92
- echo "</p>\n";
93
-
94
- echo "<div class='su-xgrade'>\n";
95
- $this->admin_form_start();
96
- $this->radiobuttons('version', $radiobuttons);
97
- $this->admin_form_end(__('Upgrade', 'seo-ultimate'));
98
- echo "</div>\n";
99
- } else
100
- $this->print_message('success', __('You are already running the latest version.', 'seo-ultimate'));
101
- } else
102
- $this->print_message('error', __('There was an error retrieving the list of available versions. Please try again later. You can also upgrade to the latest version of SEO Ultimate using the WordPress plugin upgrader.', 'seo-ultimate'));
103
- }
104
-
105
- function downgrade_tab() {
106
-
107
- if (!$this->current_user_can_downgrade()) {
108
- $this->print_message('error', __('You do not have sufficient permissions to downgrade plugins on this site.', 'seo-ultimate'));
109
- return;
110
- }
111
-
112
- $radiobuttons = $this->get_version_radiobuttons(SU_DOWNGRADE_LIMIT, SU_VERSION, 5);
113
- if (is_array($radiobuttons)) {
114
- if (count($radiobuttons) > 1) {
115
-
116
- $this->print_message('warning', suwp::add_backup_url(__('Downgrading is provided as a convenience only and is not officially supported. Although unlikely, you may lose data in the downgrading process. It is your responsibility to backup your database before proceeding.', 'seo-ultimate')));
117
-
118
- echo "\n<p>";
119
- _e('From the list below, select the version to which you would like to downgrade. Then click the &#8220;Downgrade&#8221; button at the bottom of the screen.', 'seo-ultimate');
120
- echo "</p>\n";
121
-
122
- echo "<div class='su-xgrade'>\n";
123
- $this->admin_form_start();
124
- $this->radiobuttons('version', $radiobuttons);
125
- $this->admin_form_end(__('Downgrade', 'seo-ultimate'));
126
- echo "</div>\n";
127
- } else
128
- $this->print_message('warning', sprintf(__('Downgrading to versions earlier than %s is not supported because doing so will result the loss of some or all of your SEO Ultimate settings.', 'seo-ultimate'), SU_DOWNGRADE_LIMIT));
129
- } else
130
- $this->print_message('error', __('There was an error retrieving the list of available versions. Please try again later.', 'seo-ultimate'));
131
- }
132
-
133
- function reinstall_tab() {
134
-
135
- if (!$this->current_user_can_reinstall()) {
136
- $this->print_message('error', __('You do not have sufficient permissions to reinstall plugins on this site.', 'seo-ultimate'));
137
- return;
138
- }
139
-
140
- echo "\n<p>";
141
- _e('To download and install a fresh copy of the SEO Ultimate version you are currently using, click the &#8220;Reinstall&#8221; button below.', 'seo-ultimate');
142
- echo "</p>\n";
143
-
144
- $this->admin_form_start(false, false);
145
- echo "<input type='hidden' name='version' id='version' value='".su_esc_attr(SU_VERSION)."' />\n";
146
- $this->admin_form_end(__('Reinstall', 'seo-ultimate'), false);
147
- }
148
-
149
- function get_version_radiobuttons($min, $max, $limit=false) {
150
-
151
- $this->update_setting('version', SU_VERSION);
152
-
153
- $versions = $this->plugin->download_changelog();
154
-
155
- if (is_array($versions) && count($versions)) {
156
-
157
- $radiobuttons = array();
158
- $i = 0;
159
- foreach ($versions as $title => $changes) {
160
- if (preg_match('|Version ([0-9.]{3,9}) |', $title, $matches)) {
161
- $version = $matches[1];
162
-
163
- if ($max && version_compare($version, $max, '>')) continue;
164
- if ($min && version_compare($version, $min, '<')) break;
165
-
166
- $changes = wptexturize($changes);
167
- if ($version == SU_VERSION)
168
- $message = __('Your Current Version', 'seo-ultimate');
169
- elseif (0 == $i)
170
- $message = __('Latest Version', 'seo-ultimate');
171
- else
172
- $message = '';
173
- if ($message) $message = " &mdash; <em>$message</em>";
174
-
175
- $radiobuttons[$version] = "<strong>$title</strong>$message</label>\n$changes\n";
176
-
177
- if ($limit !== false && $limit > 0 && ++$i >= $limit) break;
178
- }
179
- }
180
-
181
- return $radiobuttons;
182
- }
183
-
184
- return false; //Error
185
- }
186
-
187
- function do_installation() {
188
-
189
- if (!isset($_POST['version'])) return false;
190
-
191
- $nv = sustr::preg_filter('0-9a-zA-Z .', $_POST['version']);
192
- if (!strlen($nv)) return false;
193
-
194
- //Don't allow downgrading to anything below the minimum limit
195
- if (version_compare(SU_DOWNGRADE_LIMIT, $nv, '>')) return;
196
-
197
- switch (version_compare($nv, SU_VERSION)) {
198
- case -1: //Downgrade
199
- $title = __('Downgrade to SEO Ultimate %s', 'seo-ultimate');
200
-
201
- if (!$this->current_user_can_downgrade()) {
202
- wp_die(__('You do not have sufficient permissions to downgrade plugins on this site.', 'seo-ultimate'));
203
- return;
204
- }
205
-
206
- break;
207
- case 0: //Reinstall
208
- $title = __('Reinstall SEO Ultimate %s', 'seo-ultimate');
209
-
210
- if (!$this->current_user_can_reinstall()) {
211
- wp_die(__('You do not have sufficient permissions to reinstall plugins on this site.', 'seo-ultimate'));
212
- return;
213
- }
214
-
215
- break;
216
- case 1: //Upgrade
217
- $title = __('Upgrade to SEO Ultimate %s', 'seo-ultimate');
218
-
219
- if (!$this->current_user_can_upgrade()) {
220
- wp_die(__('You do not have sufficient permissions to upgrade plugins on this site.', 'seo-ultimate'));
221
- return;
222
- }
223
-
224
- break;
225
- default:
226
- return;
227
- }
228
-
229
- $title = sprintf($title, $nv);
230
- $nonce = 'su-install-plugin';
231
- $plugin = 'seo-ultimate/seo-ultimate.php';
232
- $url = 'update.php?action=upgrade-plugin&plugin='.$plugin;
233
-
234
- include_once $this->plugin->plugin_dir_path.'plugin/class.su-installer.php';
235
-
236
- $upgrader = new SU_Installer( new SU_Installer_Skin( compact('title', 'nonce', 'url', 'plugin') ) );
237
- $upgrader->upgrade($plugin, SU_VERSION, $nv);
238
-
239
- return true;
240
- }
241
- }
242
-
243
- }
244
  ?>
1
+ <?php
2
+ /**
3
+ * Install Module
4
+ *
5
+ * @since 2.5
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ define('SU_DOWNGRADE_LIMIT', '5.0');
11
+
12
+ class SU_Install extends SU_Module {
13
+
14
+ static function get_parent_module() { return 'settings'; }
15
+ static function get_child_order() { return 20; }
16
+ static function is_independent_module() { return false; }
17
+
18
+ static function get_module_title() { return __('Upgrade/Downgrade/Reinstall', 'seo-ultimate'); }
19
+ static function get_menu_title() { return __('Installer', 'seo-ultimate'); }
20
+
21
+ function get_admin_page_tabs() {
22
+
23
+ $tabs = array();
24
+
25
+ if ($this->current_user_can_upgrade())
26
+ $tabs[] = array('title' => __('Upgrade', 'seo-ultimate'), 'id' => 'su-upgrade', 'callback' => 'upgrade_tab');
27
+
28
+ if ($this->current_user_can_downgrade())
29
+ $tabs[] = array('title' => __('Downgrade', 'seo-ultimate'), 'id' => 'su-downgrade', 'callback' => 'downgrade_tab');
30
+
31
+ if ($this->current_user_can_reinstall())
32
+ $tabs[] = array('title' => __('Reinstall', 'seo-ultimate'), 'id' => 'su-reinstall', 'callback' => 'reinstall_tab');
33
+
34
+ if (count($tabs))
35
+ return $tabs;
36
+
37
+ return false;
38
+ }
39
+
40
+ function belongs_in_admin($admin_scope = null) {
41
+
42
+ if ($admin_scope === null)
43
+ $admin_scope = suwp::get_admin_scope();
44
+
45
+ if ( ! function_exists( 'is_plugin_active_for_network' ) )
46
+ require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
47
+
48
+ switch ($admin_scope) {
49
+ case 'blog':
50
+ return !is_multisite() || !is_plugin_active_for_network($this->plugin->plugin_basename);
51
+ break;
52
+ case 'network':
53
+ return is_plugin_active_for_network($this->plugin->plugin_basename);
54
+ break;
55
+ default:
56
+ return false;
57
+ break;
58
+ }
59
+ }
60
+
61
+ function current_user_can_upgrade() {
62
+ return current_user_can('update_plugins') && (!is_multisite() || is_super_admin());
63
+ }
64
+
65
+ function current_user_can_downgrade() {
66
+ return current_user_can('install_plugins') && (!is_multisite() || is_super_admin());
67
+ }
68
+
69
+ function current_user_can_reinstall() {
70
+ return current_user_can('install_plugins') && (!is_multisite() || is_super_admin());
71
+ }
72
+
73
+ function init() {
74
+ if ($this->is_action('update')) {
75
+ add_filter('su_custom_admin_page-settings', array(&$this, 'do_installation'));
76
+ }
77
+ }
78
+
79
+ function upgrade_tab() {
80
+
81
+ if (!$this->current_user_can_upgrade()) {
82
+ $this->print_message('error', __('You do not have sufficient permissions to upgrade plugins on this site.', 'seo-ultimate'));
83
+ return;
84
+ }
85
+
86
+ $radiobuttons = $this->get_version_radiobuttons(SU_VERSION, false);
87
+ if (is_array($radiobuttons)) {
88
+ if (count($radiobuttons) > 1) {
89
+
90
+ echo "\n<p>";
91
+ _e('From the list below, select the version to which you would like to upgrade. Then click the &#8220;Upgrade&#8221; button at the bottom of the screen.', 'seo-ultimate');
92
+ echo "</p>\n";
93
+
94
+ echo "<div class='su-xgrade'>\n";
95
+ $this->admin_form_start();
96
+ $this->radiobuttons('version', $radiobuttons);
97
+ $this->admin_form_end(__('Upgrade', 'seo-ultimate'));
98
+ echo "</div>\n";
99
+ } else
100
+ $this->print_message('success', __('You are already running the latest version.', 'seo-ultimate'));
101
+ } else
102
+ $this->print_message('error', __('There was an error retrieving the list of available versions. Please try again later. You can also upgrade to the latest version of SEO Ultimate using the WordPress plugin upgrader.', 'seo-ultimate'));
103
+ }
104
+
105
+ function downgrade_tab() {
106
+
107
+ if (!$this->current_user_can_downgrade()) {
108
+ $this->print_message('error', __('You do not have sufficient permissions to downgrade plugins on this site.', 'seo-ultimate'));
109
+ return;
110
+ }
111
+
112
+ $radiobuttons = $this->get_version_radiobuttons(SU_DOWNGRADE_LIMIT, SU_VERSION, 5);
113
+ if (is_array($radiobuttons)) {
114
+ if (count($radiobuttons) > 1) {
115
+
116
+ $this->print_message('warning', suwp::add_backup_url(__('Downgrading is provided as a convenience only and is not officially supported. Although unlikely, you may lose data in the downgrading process. It is your responsibility to backup your database before proceeding.', 'seo-ultimate')));
117
+
118
+ echo "\n<p>";
119
+ _e('From the list below, select the version to which you would like to downgrade. Then click the &#8220;Downgrade&#8221; button at the bottom of the screen.', 'seo-ultimate');
120
+ echo "</p>\n";
121
+
122
+ echo "<div class='su-xgrade'>\n";
123
+ $this->admin_form_start();
124
+ $this->radiobuttons('version', $radiobuttons);
125
+ $this->admin_form_end(__('Downgrade', 'seo-ultimate'));
126
+ echo "</div>\n";
127
+ } else
128
+ $this->print_message('warning', sprintf(__('Downgrading to versions earlier than %s is not supported because doing so will result the loss of some or all of your SEO Ultimate settings.', 'seo-ultimate'), SU_DOWNGRADE_LIMIT));
129
+ } else
130
+ $this->print_message('error', __('There was an error retrieving the list of available versions. Please try again later.', 'seo-ultimate'));
131
+ }
132
+
133
+ function reinstall_tab() {
134
+
135
+ if (!$this->current_user_can_reinstall()) {
136
+ $this->print_message('error', __('You do not have sufficient permissions to reinstall plugins on this site.', 'seo-ultimate'));
137
+ return;
138
+ }
139
+
140
+ echo "\n<p>";
141
+ _e('To download and install a fresh copy of the SEO Ultimate version you are currently using, click the &#8220;Reinstall&#8221; button below.', 'seo-ultimate');
142
+ echo "</p>\n";
143
+
144
+ $this->admin_form_start(false, false);
145
+ echo "<input type='hidden' name='version' id='version' value='".su_esc_attr(SU_VERSION)."' />\n";
146
+ $this->admin_form_end(__('Reinstall', 'seo-ultimate'), false);
147
+ }
148
+
149
+ function get_version_radiobuttons($min, $max, $limit=false) {
150
+
151
+ $this->update_setting('version', SU_VERSION);
152
+
153
+ $versions = $this->plugin->download_changelog();
154
+
155
+ if (is_array($versions) && count($versions)) {
156
+
157
+ $radiobuttons = array();
158
+ $i = 0;
159
+ foreach ($versions as $title => $changes) {
160
+ if (preg_match('|Version ([0-9.]{3,9}) |', $title, $matches)) {
161
+ $version = $matches[1];
162
+
163
+ if ($max && version_compare($version, $max, '>')) continue;
164
+ if ($min && version_compare($version, $min, '<')) break;
165
+
166
+ $changes = wptexturize($changes);
167
+ if ($version == SU_VERSION)
168
+ $message = __('Your Current Version', 'seo-ultimate');
169
+ elseif (0 == $i)
170
+ $message = __('Latest Version', 'seo-ultimate');
171
+ else
172
+ $message = '';
173
+ if ($message) $message = " &mdash; <em>$message</em>";
174
+
175
+ $radiobuttons[$version] = "<strong>$title</strong>$message</label>\n$changes\n";
176
+
177
+ if ($limit !== false && $limit > 0 && ++$i >= $limit) break;
178
+ }
179
+ }
180
+
181
+ return $radiobuttons;
182
+ }
183
+
184
+ return false; //Error
185
+ }
186
+
187
+ function do_installation() {
188
+
189
+ if (!isset($_POST['version'])) return false;
190
+
191
+ $nv = sustr::preg_filter('0-9a-zA-Z .', $_POST['version']);
192
+ if (!strlen($nv)) return false;
193
+
194
+ //Don't allow downgrading to anything below the minimum limit
195
+ if (version_compare(SU_DOWNGRADE_LIMIT, $nv, '>')) return;
196
+
197
+ switch (version_compare($nv, SU_VERSION)) {
198
+ case -1: //Downgrade
199
+ $title = __('Downgrade to SEO Ultimate %s', 'seo-ultimate');
200
+
201
+ if (!$this->current_user_can_downgrade()) {
202
+ wp_die(__('You do not have sufficient permissions to downgrade plugins on this site.', 'seo-ultimate'));
203
+ return;
204
+ }
205
+
206
+ break;
207
+ case 0: //Reinstall
208
+ $title = __('Reinstall SEO Ultimate %s', 'seo-ultimate');
209
+
210
+ if (!$this->current_user_can_reinstall()) {
211
+ wp_die(__('You do not have sufficient permissions to reinstall plugins on this site.', 'seo-ultimate'));
212
+ return;
213
+ }
214
+
215
+ break;
216
+ case 1: //Upgrade
217
+ $title = __('Upgrade to SEO Ultimate %s', 'seo-ultimate');
218
+
219
+ if (!$this->current_user_can_upgrade()) {
220
+ wp_die(__('You do not have sufficient permissions to upgrade plugins on this site.', 'seo-ultimate'));
221
+ return;
222
+ }
223
+
224
+ break;
225
+ default:
226
+ return;
227
+ }
228
+
229
+ $title = sprintf($title, $nv);
230
+ $nonce = 'su-install-plugin';
231
+ $plugin = 'seo-ultimate/seo-ultimate.php';
232
+ $url = 'update.php?action=upgrade-plugin&plugin='.$plugin;
233
+
234
+ include_once $this->plugin->plugin_dir_path.'plugin/class.su-installer.php';
235
+
236
+ $upgrader = new SU_Installer( new SU_Installer_Skin( compact('title', 'nonce', 'url', 'plugin') ) );
237
+ $upgrader->upgrade($plugin, SU_VERSION, $nv);
238
+
239
+ return true;
240
+ }
241
+ }
242
+
243
+ }
244
  ?>
modules/settings/settings-data.css CHANGED
@@ -1,20 +1,20 @@
1
- #su-settings table#manage-settings {
2
- border-collapse: collapse;
3
- margin-top: 2em;
4
- }
5
-
6
- #su-settings table#manage-settings td {
7
- width: 100%;
8
- }
9
-
10
- #su-settings table#manage-settings th {
11
- font-weight: bold;
12
- padding-right: 2em;
13
- }
14
-
15
- #su-settings table#manage-settings td,
16
- #su-settings table#manage-settings th {
17
- padding-top: 2em;
18
- padding-bottom: 2em;
19
- border-top: 1px solid #ccc;
20
  }
1
+ #su-settings table#manage-settings {
2
+ border-collapse: collapse;
3
+ margin-top: 2em;
4
+ }
5
+
6
+ #su-settings table#manage-settings td {
7
+ width: 100%;
8
+ }
9
+
10
+ #su-settings table#manage-settings th {
11
+ font-weight: bold;
12
+ padding-right: 2em;
13
+ }
14
+
15
+ #su-settings table#manage-settings td,
16
+ #su-settings table#manage-settings th {
17
+ padding-top: 2em;
18
+ padding-bottom: 2em;
19
+ border-top: 1px solid #ccc;
20
  }
modules/settings/settings-data.php CHANGED
@@ -1,292 +1,292 @@
1
- <?php
2
- /**
3
- * Settings Data Manager Module
4
- *
5
- * @since 2.1
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_SettingsData extends SU_Module {
11
-
12
- static function get_parent_module() { return 'settings'; }
13
- static function get_child_order() { return 20; }
14
- static function is_independent_module() { return false; }
15
-
16
- static function get_module_title() { return __('Settings Data Manager', 'seo-ultimate'); }
17
- function get_module_subtitle() { return __('Manage Settings Data', 'seo-ultimate'); }
18
-
19
- function get_admin_page_tabs() {
20
- return array(
21
- array('title' => __('Import', 'seo-ultimate'), 'id' => 'su-import', 'callback' => 'import_tab')
22
- , array('title' => __('Export', 'seo-ultimate'), 'id' => 'su-export', 'callback' => 'export_tab')
23
- , array('title' => __('Reset', 'seo-ultimate'), 'id' => 'su-reset', 'callback' => 'reset_tab')
24
- );
25
- }
26
-
27
- function portable_options() {
28
- return array('settings', 'modules');
29
- }
30
-
31
- function init() {
32
-
33
- if ($this->is_action('su-export')) {
34
- header('Content-Type: application/octet-stream');
35
- header('Content-Disposition: attachment; filename="SEO Ultimate Settings ('.date('Y-m-d').').dat"');
36
-
37
- $export = array();
38
-
39
- $psdata = (array)get_option('seo_ultimate', array());
40
-
41
- //Module statuses
42
- $export['modules'] = apply_filters('su_modules_export_array', $psdata['modules']);
43
-
44
- //Module settings
45
- $modules = array_keys($psdata['modules']);
46
- $module_settings = array();
47
- foreach($modules as $module) {
48
- if (!$this->plugin->call_module_func($module, 'get_settings_key', $key) || !$key)
49
- $key = $module;
50
-
51
- $msdata = (array)get_option("seo_ultimate_module_$key", array());
52
- if ($msdata) $module_settings[$key] = $msdata;
53
- }
54
- $export['settings'] = apply_filters('su_settings_export_array', $module_settings);
55
-
56
- //Encode
57
- $export = base64_encode(serialize($export));
58
-
59
- //Output
60
- echo $export;
61
- die();
62
-
63
- } elseif ($this->is_action('su-import')) {
64
-
65
- if (strlen($_FILES['settingsfile']['name'])) {
66
-
67
- $file = $_FILES['settingsfile']['tmp_name'];
68
- if (is_uploaded_file($file)) {
69
- $import = base64_decode(file_get_contents($file));
70
- if (is_serialized($import)) {
71
- $import = unserialize($import);
72
-
73
- //Module statuses
74
- $psdata = (array)get_option('seo_ultimate', array());
75
- $psdata['modules'] = array_merge($psdata['modules'], $import['modules']);
76
- update_option('seo_ultimate', $psdata);
77
-
78
- //Module settings
79
- $module_settings = apply_filters('su_settings_import_array', $import['settings']);
80
- foreach ($module_settings as $key => $module_settings) {
81
- $msdata = (array)get_option("seo_ultimate_module_$key", array());
82
- $msdata = array_merge($msdata, $module_settings);
83
- update_option("seo_ultimate_module_$key", $msdata);
84
- }
85
-
86
- $this->queue_message('success', __('Settings successfully imported.', 'seo-ultimate'));
87
- } else
88
- $this->queue_message('error', __('The uploaded file is not in the proper format. Settings could not be imported.', 'seo-ultimate'));
89
- } else
90
- $this->queue_message('error', __('The settings file could not be uploaded successfully.', 'seo-ultimate'));
91
-
92
- } else
93
- $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'));
94
-
95
- } elseif ($this->is_action('su-reset')) {
96
-
97
- $psdata = (array)get_option('seo_ultimate', array());
98
- $modules = array_keys($psdata['modules']);
99
- foreach ($modules as $module) {
100
-
101
- if (!$this->plugin->call_module_func($module, 'get_settings_key', $key) || !$key)
102
- $key = $module;
103
-
104
- delete_option("seo_ultimate_module_$key");
105
- }
106
- unset($psdata['modules']);
107
- update_option('seo_ultimate', $psdata);
108
-
109
- $this->load_default_settings();
110
-
111
- } elseif ($this->is_action('dj-export')) {
112
- header('Content-Disposition: attachment; filename="Deeplink Juggernaut Content Links ('.date('Y-m-d').').csv"');
113
-
114
- $djlinks = $this->get_setting('links', array(), 'autolinks');
115
- $csv_headers = array(
116
- 'anchor' => 'Anchor'
117
- , 'to_type' => 'Destination Type'
118
- , 'to_id' => 'Destination'
119
- , 'title' => 'Title'
120
- , 'sitewide_lpa' => 'Site Cap'
121
- , 'nofollow' => 'Nofollow'
122
- , 'target' => 'Target'
123
- );
124
- if (is_array($djlinks) && count($djlinks))
125
- $djlinks = suarr::key_replace($djlinks, $csv_headers, true, true);
126
- else
127
- $djlinks = array(array_fill_keys($csv_headers, ''));
128
-
129
- suio::export_csv($djlinks);
130
- die();
131
-
132
- } elseif ($this->is_action('dj-import')) {
133
-
134
- if (strlen($_FILES['settingsfile']['name'])) {
135
-
136
- $file = $_FILES['settingsfile']['tmp_name'];
137
- if (is_uploaded_file($file)) {
138
- $import = suio::import_csv($file);
139
- if ($import === false)
140
- $this->queue_message('error', __('The uploaded file is not in the proper format. Links could not be imported.', 'seo-ultimate'));
141
- else {
142
- $import = suarr::key_replace($import, array(
143
- 'Anchor' => 'anchor'
144
- , 'Destination Type' => 'to_type'
145
- , 'Destination' => 'to_id'
146
- , 'URL' => 'to_id'
147
- , 'Title' => 'title'
148
- , 'Site Cap' => 'sidewide_lpa'
149
- , 'Nofollow' => 'nofollow'
150
- , 'Target' => 'target'
151
- ), true, true);
152
- $import = suarr::value_replace($import, array(
153
- 'No' => false
154
- , 'Yes' => true
155
- , 'URL' => 'url'
156
- ), true, false);
157
-
158
- $djlinks = array();
159
- foreach ($import as $link) {
160
-
161
- //Validate destination type
162
- if ($link['to_type'] != 'url'
163
- && !sustr::startswith($link['to_type'], 'posttype_')
164
- && !sustr::startswith($link['to_type'], 'taxonomy_'))
165
- $link['to_type'] = 'url';
166
-
167
- //Validate nofollow
168
- if (!is_bool($link['nofollow']))
169
- $link['nofollow'] = false;
170
-
171
- //Validate target
172
- $link['target'] = ltrim($link['target'], '_');
173
- if (!in_array($link['target'], array('self', 'blank'))) //Only _self or _blank are supported right now
174
- $link['target'] = 'self';
175
-
176
- //Add link!
177
- $djlinks[] = $link;
178
- }
179
-
180
- $this->update_setting('links', $djlinks, 'autolinks');
181
-
182
- $this->queue_message('success', __('Links successfully imported.', 'seo-ultimate'));
183
- }
184
- } else
185
- $this->queue_message('error', __('The CSV file could not be uploaded successfully.', 'seo-ultimate'));
186
-
187
- } else
188
- $this->queue_message('warning', __('Links could not be imported because no CSV file was selected. Please click the &#8220;Browse&#8221; button and select a file to import.', 'seo-ultimate'));
189
-
190
- }
191
- }
192
-
193
- function import_tab() {
194
- $this->print_messages();
195
- $hook = $this->plugin->key_to_hook($this->get_module_or_parent_key());
196
-
197
- //SEO Ultimate
198
- $this->admin_subheader(__('Import SEO Ultimate Settings File', 'seo-ultimate'));
199
- echo "\n<p>";
200
- _e('You can use this form to upload and import an SEO Ultimate settings file stored on your computer. (These files can be created using the Export tool.) Note that importing a file will overwrite your existing settings with those in the file.', 'seo-ultimate');
201
- echo "</p>\n";
202
- echo "<form enctype='multipart/form-data' method='post' action='?page=$hook&amp;action=su-import#su-import'>\n";
203
- echo "\t<input name='settingsfile' type='file' /> ";
204
- $confirm = __('Are you sure you want to import this settings file? This will overwrite your current settings and cannot be undone.', 'seo-ultimate');
205
- echo "<input type='submit' class='button-primary' value='".__('Import Settings File', 'seo-ultimate')."' onclick=\"javascript:return confirm('$confirm')\" />\n";
206
- wp_nonce_field($this->get_nonce_handle('su-import'));
207
- echo "</form>\n";
208
-
209
- if ($this->plugin->module_exists('content-autolinks')) {
210
- //Deeplink Juggernaut
211
- $this->admin_subheader(__('Import Deeplink Juggernaut CSV File', 'seo-ultimate'));
212
- echo "\n<p>";
213
- _e('You can use this form to upload and import a Deeplink Juggernaut CSV file stored on your computer. (These files can be created using the Export tool.) Note that importing a file will overwrite your existing links with those in the file.', 'seo-ultimate');
214
- echo "</p>\n";
215
- echo "<form enctype='multipart/form-data' method='post' action='?page=$hook&amp;action=dj-import#su-import'>\n";
216
- echo "\t<input name='settingsfile' type='file' /> ";
217
- $confirm = __('Are you sure you want to import this CSV file? This will overwrite your current Deeplink Juggernaut links and cannot be undone.', 'seo-ultimate');
218
- echo "<input type='submit' class='button-primary' value='".__('Import CSV File', 'seo-ultimate')."' onclick=\"javascript:return confirm('$confirm')\" />\n";
219
- wp_nonce_field($this->get_nonce_handle('dj-import'));
220
- echo "</form>\n";
221
- }
222
-
223
- //Import from other plugins
224
- $importmodules = array();
225
- foreach ($this->plugin->modules as $key => $x_module) {
226
- $module =& $this->plugin->modules[$key];
227
- if (is_a($module, 'SU_ImportModule')) {
228
- $importmodules[$key] =& $module;
229
- }
230
- }
231
-
232
- if (count($importmodules)) {
233
- $this->admin_subheader(__('Import from Other Plugins', 'seo-ultimate'));
234
- echo "\n<p>";
235
- _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');
236
- echo "</p>\n";
237
- echo "<table class='widefat'>\n";
238
-
239
- $class = '';
240
- foreach ($importmodules as $key => $x_module) {
241
- $module =& $importmodules[$key];
242
- $title = $module->get_op_title();
243
- $desc = $module->get_import_desc();
244
- $url = $module->get_admin_url();
245
- $class = ($class) ? '' : 'alternate';
246
- echo "\t<tr class='$class'><td><a href='$url'>$title</a></td><td>$desc</td></tr>\n";
247
- }
248
-
249
- echo "</table>\n";
250
- }
251
- }
252
-
253
- function export_tab() {
254
- //SEO Ultimate
255
- $this->admin_subheader(__('Export SEO Ultimate Settings File', 'seo-ultimate'));
256
- echo "\n<p>";
257
- _e('You can use this export tool to download an SEO Ultimate settings file to your computer.', 'seo-ultimate');
258
- echo "</p>\n<p>";
259
- _e('A settings file includes the data of every checkbox and textbox of every installed module. It does NOT include site-specific data like logged 404s or post/page title/meta data (this data would be included in a standard database backup, however).', 'seo-ultimate');
260
- echo "</p>\n<p>";
261
- $url = $this->get_nonce_url('su-export');
262
- echo "<a href='$url' class='button-primary'>".__('Download Settings File', 'seo-ultimate')."</a>";
263
- echo "</p>\n";
264
-
265
- if ($this->plugin->module_exists('content-autolinks')) {
266
- //Deeplink Juggernaut
267
- $this->admin_subheader(__('Export Deeplink Juggernaut CSV File', 'seo-ultimate'));
268
- echo "\n<p>";
269
- _e('You can use this export tool to download a CSV file (comma-separated values file) that contains your Deeplink Juggernaut links. Once you download this file to your computer, you can edit it using your favorite spreadsheet program. When you&#8217;re done editing, you can re-upload the file using the Import tool.', 'seo-ultimate');
270
- echo "</p>\n<p>";
271
- $url = $this->get_nonce_url('dj-export');
272
- echo "<a href='$url' class='button-primary'>".__('Download CSV File', 'seo-ultimate')."</a>";
273
- echo "</p>\n";
274
- }
275
- }
276
-
277
- function reset_tab() {
278
- if ($this->is_action('su-reset'))
279
- $this->print_message('success', __('All settings have been erased and defaults have been restored.', 'seo-ultimate'));
280
- echo "\n<p>";
281
- _e('You can erase all your SEO Ultimate settings and restore them to &#8220;factory defaults&#8221; by clicking the button below.', 'seo-ultimate');
282
- echo "</p>\n<p>";
283
- $url = $this->get_nonce_url('su-reset');
284
- $confirm = __('Are you sure you want to erase all module settings? This cannot be undone.', 'seo-ultimate');
285
- echo "<a href='$url#su-reset' class='button-primary' onclick=\"javascript:return confirm('$confirm')\">".__('Restore Default Settings', 'seo-ultimate')."</a>";
286
- echo "</p>\n";
287
- }
288
- }
289
-
290
- }
291
-
292
  ?>
1
+ <?php
2
+ /**
3
+ * Settings Data Manager Module
4
+ *
5
+ * @since 2.1
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_SettingsData extends SU_Module {
11
+
12
+ static function get_parent_module() { return 'settings'; }
13
+ static function get_child_order() { return 20; }
14
+ static function is_independent_module() { return false; }
15
+
16
+ static function get_module_title() { return __('Settings Data Manager', 'seo-ultimate'); }
17
+ function get_module_subtitle() { return __('Manage Settings Data', 'seo-ultimate'); }
18
+
19
+ function get_admin_page_tabs() {
20
+ return array(
21
+ array('title' => __('Import', 'seo-ultimate'), 'id' => 'su-import', 'callback' => 'import_tab')
22
+ , array('title' => __('Export', 'seo-ultimate'), 'id' => 'su-export', 'callback' => 'export_tab')
23
+ , array('title' => __('Reset', 'seo-ultimate'), 'id' => 'su-reset', 'callback' => 'reset_tab')
24
+ );
25
+ }
26
+
27
+ function portable_options() {
28
+ return array('settings', 'modules');
29
+ }
30
+
31
+ function init() {
32
+
33
+ if ($this->is_action('su-export')) {
34
+ header('Content-Type: application/octet-stream');
35
+ header('Content-Disposition: attachment; filename="SEO Ultimate Settings ('.date('Y-m-d').').dat"');
36
+
37
+ $export = array();
38
+
39
+ $psdata = (array)get_option('seo_ultimate', array());
40
+
41
+ //Module statuses
42
+ $export['modules'] = apply_filters('su_modules_export_array', $psdata['modules']);
43
+
44
+ //Module settings
45
+ $modules = array_keys($psdata['modules']);
46
+ $module_settings = array();
47
+ foreach($modules as $module) {
48
+ if (!$this->plugin->call_module_func($module, 'get_settings_key', $key) || !$key)
49
+ $key = $module;
50
+
51
+ $msdata = (array)get_option("seo_ultimate_module_$key", array());
52
+ if ($msdata) $module_settings[$key] = $msdata;
53
+ }
54
+ $export['settings'] = apply_filters('su_settings_export_array', $module_settings);
55
+
56
+ //Encode
57
+ $export = base64_encode(serialize($export));
58
+
59
+ //Output
60
+ echo $export;
61
+ die();
62
+
63
+ } elseif ($this->is_action('su-import')) {
64
+
65
+ if (strlen($_FILES['settingsfile']['name'])) {
66
+
67
+ $file = $_FILES['settingsfile']['tmp_name'];
68
+ if (is_uploaded_file($file)) {
69
+ $import = base64_decode(file_get_contents($file));
70
+ if (is_serialized($import)) {
71
+ $import = unserialize($import);
72
+
73
+ //Module statuses
74
+ $psdata = (array)get_option('seo_ultimate', array());
75
+ $psdata['modules'] = array_merge($psdata['modules'], $import['modules']);
76
+ update_option('seo_ultimate', $psdata);
77
+
78
+ //Module settings
79
+ $module_settings = apply_filters('su_settings_import_array', $import['settings']);
80
+ foreach ($module_settings as $key => $module_settings) {
81
+ $msdata = (array)get_option("seo_ultimate_module_$key", array());
82
+ $msdata = array_merge($msdata, $module_settings);
83
+ update_option("seo_ultimate_module_$key", $msdata);
84
+ }
85
+
86
+ $this->queue_message('success', __('Settings successfully imported.', 'seo-ultimate'));
87
+ } else
88
+ $this->queue_message('error', __('The uploaded file is not in the proper format. Settings could not be imported.', 'seo-ultimate'));
89
+ } else
90
+ $this->queue_message('error', __('The settings file could not be uploaded successfully.', 'seo-ultimate'));
91
+
92
+ } else
93
+ $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'));
94
+
95
+ } elseif ($this->is_action('su-reset')) {
96
+
97
+ $psdata = (array)get_option('seo_ultimate', array());
98
+ $modules = array_keys($psdata['modules']);
99
+ foreach ($modules as $module) {
100
+
101
+ if (!$this->plugin->call_module_func($module, 'get_settings_key', $key) || !$key)
102
+ $key = $module;
103
+
104
+ delete_option("seo_ultimate_module_$key");
105
+ }
106
+ unset($psdata['modules']);
107
+ update_option('seo_ultimate', $psdata);
108
+
109
+ $this->load_default_settings();
110
+
111
+ } elseif ($this->is_action('dj-export')) {
112
+ header('Content-Disposition: attachment; filename="Deeplink Juggernaut Content Links ('.date('Y-m-d').').csv"');
113
+
114
+ $djlinks = $this->get_setting('links', array(), 'autolinks');
115
+ $csv_headers = array(
116
+ 'anchor' => 'Anchor'
117
+ , 'to_type' => 'Destination Type'
118
+ , 'to_id' => 'Destination'
119
+ , 'title' => 'Title'
120
+ , 'sitewide_lpa' => 'Site Cap'
121
+ , 'nofollow' => 'Nofollow'
122
+ , 'target' => 'Target'
123
+ );
124
+ if (is_array($djlinks) && count($djlinks))
125
+ $djlinks = suarr::key_replace($djlinks, $csv_headers, true, true);
126
+ else
127
+ $djlinks = array(array_fill_keys($csv_headers, ''));
128
+
129
+ suio::export_csv($djlinks);
130
+ die();
131
+
132
+ } elseif ($this->is_action('dj-import')) {
133
+
134
+ if (strlen($_FILES['settingsfile']['name'])) {
135
+
136
+ $file = $_FILES['settingsfile']['tmp_name'];
137
+ if (is_uploaded_file($file)) {
138
+ $import = suio::import_csv($file);
139
+ if ($import === false)
140
+ $this->queue_message('error', __('The uploaded file is not in the proper format. Links could not be imported.', 'seo-ultimate'));
141
+ else {
142
+ $import = suarr::key_replace($import, array(
143
+ 'Anchor' => 'anchor'
144
+ , 'Destination Type' => 'to_type'
145
+ , 'Destination' => 'to_id'
146
+ , 'URL' => 'to_id'
147
+ , 'Title' => 'title'
148
+ , 'Site Cap' => 'sidewide_lpa'
149
+ , 'Nofollow' => 'nofollow'
150
+ , 'Target' => 'target'
151
+ ), true, true);
152
+ $import = suarr::value_replace($import, array(
153
+ 'No' => false
154
+ , 'Yes' => true
155
+ , 'URL' => 'url'
156
+ ), true, false);
157
+
158
+ $djlinks = array();
159
+ foreach ($import as $link) {
160
+
161
+ //Validate destination type
162
+ if ($link['to_type'] != 'url'
163
+ && !sustr::startswith($link['to_type'], 'posttype_')
164
+ && !sustr::startswith($link['to_type'], 'taxonomy_'))
165
+ $link['to_type'] = 'url';
166
+
167
+ //Validate nofollow
168
+ if (!is_bool($link['nofollow']))
169
+ $link['nofollow'] = false;
170
+
171
+ //Validate target
172
+ $link['target'] = ltrim($link['target'], '_');
173
+ if (!in_array($link['target'], array('self', 'blank'))) //Only _self or _blank are supported right now
174
+ $link['target'] = 'self';
175
+
176
+ //Add link!
177
+ $djlinks[] = $link;
178
+ }
179
+
180
+ $this->update_setting('links', $djlinks, 'autolinks');
181
+
182
+ $this->queue_message('success', __('Links successfully imported.', 'seo-ultimate'));
183
+ }
184
+ } else
185
+ $this->queue_message('error', __('The CSV file could not be uploaded successfully.', 'seo-ultimate'));
186
+
187
+ } else
188
+ $this->queue_message('warning', __('Links could not be imported because no CSV file was selected. Please click the &#8220;Browse&#8221; button and select a file to import.', 'seo-ultimate'));
189
+
190
+ }
191
+ }
192
+
193
+ function import_tab() {
194
+ $this->print_messages();
195
+ $hook = $this->plugin->key_to_hook($this->get_module_or_parent_key());
196
+
197
+ //SEO Ultimate
198
+ $this->admin_subheader(__('Import SEO Ultimate Settings File', 'seo-ultimate'));
199
+ echo "\n<p>";
200
+ _e('You can use this form to upload and import an SEO Ultimate settings file stored on your computer. (These files can be created using the Export tool.) Note that importing a file will overwrite your existing settings with those in the file.', 'seo-ultimate');
201
+ echo "</p>\n";
202
+ echo "<form enctype='multipart/form-data' method='post' action='?page=$hook&amp;action=su-import#su-import'>\n";
203
+ echo "\t<input name='settingsfile' type='file' /> ";
204
+ $confirm = __('Are you sure you want to import this settings file? This will overwrite your current settings and cannot be undone.', 'seo-ultimate');
205
+ echo "<input type='submit' class='button-primary' value='".__('Import Settings File', 'seo-ultimate')."' onclick=\"javascript:return confirm('$confirm')\" />\n";
206
+ wp_nonce_field($this->get_nonce_handle('su-import'));
207
+ echo "</form>\n";
208
+
209
+ if ($this->plugin->module_exists('content-autolinks')) {
210
+ //Deeplink Juggernaut
211
+ $this->admin_subheader(__('Import Deeplink Juggernaut CSV File', 'seo-ultimate'));
212
+ echo "\n<p>";
213
+ _e('You can use this form to upload and import a Deeplink Juggernaut CSV file stored on your computer. (These files can be created using the Export tool.) Note that importing a file will overwrite your existing links with those in the file.', 'seo-ultimate');
214
+ echo "</p>\n";
215
+ echo "<form enctype='multipart/form-data' method='post' action='?page=$hook&amp;action=dj-import#su-import'>\n";
216
+ echo "\t<input name='settingsfile' type='file' /> ";
217
+ $confirm = __('Are you sure you want to import this CSV file? This will overwrite your current Deeplink Juggernaut links and cannot be undone.', 'seo-ultimate');
218
+ echo "<input type='submit' class='button-primary' value='".__('Import CSV File', 'seo-ultimate')."' onclick=\"javascript:return confirm('$confirm')\" />\n";
219
+ wp_nonce_field($this->get_nonce_handle('dj-import'));
220
+ echo "</form>\n";
221
+ }
222
+
223
+ //Import from other plugins
224
+ $importmodules = array();
225
+ foreach ($this->plugin->modules as $key => $x_module) {
226
+ $module =& $this->plugin->modules[$key];
227
+ if (is_a($module, 'SU_ImportModule')) {
228
+ $importmodules[$key] =& $module;
229
+ }
230
+ }
231
+
232
+ if (count($importmodules)) {
233
+ $this->admin_subheader(__('Import from Other Plugins', 'seo-ultimate'));
234
+ echo "\n<p>";
235
+ _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');
236
+ echo "</p>\n";
237
+ echo "<table class='widefat'>\n";
238
+
239
+ $class = '';
240
+ foreach ($importmodules as $key => $x_module) {
241
+ $module =& $importmodules[$key];
242
+ $title = $module->get_op_title();
243
+ $desc = $module->get_import_desc();
244
+ $url = $module->get_admin_url();
245
+ $class = ($class) ? '' : 'alternate';
246
+ echo "\t<tr class='$class'><td><a href='$url'>$title</a></td><td>$desc</td></tr>\n";
247
+ }
248
+
249
+ echo "</table>\n";
250
+ }
251
+ }
252
+
253
+ function export_tab() {
254
+ //SEO Ultimate
255
+ $this->admin_subheader(__('Export SEO Ultimate Settings File', 'seo-ultimate'));
256
+ echo "\n<p>";
257
+ _e('You can use this export tool to download an SEO Ultimate settings file to your computer.', 'seo-ultimate');
258
+ echo "</p>\n<p>";
259
+ _e('A settings file includes the data of every checkbox and textbox of every installed module. It does NOT include site-specific data like logged 404s or post/page title/meta data (this data would be included in a standard database backup, however).', 'seo-ultimate');
260
+ echo "</p>\n<p>";
261
+ $url = $this->get_nonce_url('su-export');
262
+ echo "<a href='$url' class='button-primary'>".__('Download Settings File', 'seo-ultimate')."</a>";
263
+ echo "</p>\n";
264
+
265
+ if ($this->plugin->module_exists('content-autolinks')) {
266
+ //Deeplink Juggernaut
267
+ $this->admin_subheader(__('Export Deeplink Juggernaut CSV File', 'seo-ultimate'));
268
+ echo "\n<p>";
269
+ _e('You can use this export tool to download a CSV file (comma-separated values file) that contains your Deeplink Juggernaut links. Once you download this file to your computer, you can edit it using your favorite spreadsheet program. When you&#8217;re done editing, you can re-upload the file using the Import tool.', 'seo-ultimate');
270
+ echo "</p>\n<p>";
271
+ $url = $this->get_nonce_url('dj-export');
272
+ echo "<a href='$url' class='button-primary'>".__('Download CSV File', 'seo-ultimate')."</a>";
273
+ echo "</p>\n";
274
+ }
275
+ }
276
+
277
+ function reset_tab() {
278
+ if ($this->is_action('su-reset'))
279
+ $this->print_message('success', __('All settings have been erased and defaults have been restored.', 'seo-ultimate'));
280
+ echo "\n<p>";
281
+ _e('You can erase all your SEO Ultimate settings and restore them to &#8220;factory defaults&#8221; by clicking the button below.', 'seo-ultimate');
282
+ echo "</p>\n<p>";
283
+ $url = $this->get_nonce_url('su-reset');
284
+ $confirm = __('Are you sure you want to erase all module settings? This cannot be undone.', 'seo-ultimate');
285
+ echo "<a href='$url#su-reset' class='button-primary' onclick=\"javascript:return confirm('$confirm')\">".__('Restore Default Settings', 'seo-ultimate')."</a>";
286
+ echo "</p>\n";
287
+ }
288
+ }
289
+
290
+ }
291
+
292
  ?>
modules/settings/settings.php CHANGED
@@ -1,94 +1,94 @@
1
- <?php
2
- /**
3
- * SEO Ultimate Plugin Settings Module
4
- *
5
- * @since 0.2
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_Settings extends SU_Module {
11
-
12
- static function get_module_title() {
13
- if (is_network_admin())
14
- return __('Plugin Management', 'seo-ultimate');
15
-
16
- return __('Plugin Settings', 'seo-ultimate');
17
- }
18
-
19
- function get_page_title() {
20
- if (is_network_admin())
21
- return __('SEO Ultimate Plugin Management', 'seo-ultimate');
22
-
23
- return __('SEO Ultimate Plugin Settings', 'seo-ultimate');
24
- }
25
-
26
- static function get_menu_title() { return __('SEO Ultimate', 'seo-ultimate'); }
27
-
28
- function get_menu_parent() {
29
- if (is_network_admin())
30
- return 'plugins.php';
31
-
32
- return 'options-general.php';
33
- }
34
-
35
- function admin_page_contents() { $this->children_admin_page_tabs(); }
36
-
37
- function belongs_in_admin($admin_scope = null) {
38
-
39
- if ($admin_scope === null)
40
- $admin_scope = suwp::get_admin_scope();
41
-
42
- switch ($admin_scope) {
43
- case 'blog':
44
- return true;
45
- case 'network':
46
-
47
- if ( ! function_exists( 'is_plugin_active_for_network' ) )
48
- require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
49
-
50
- return is_plugin_active_for_network($this->plugin->plugin_basename);
51
-
52
- break;
53
- default:
54
- return false;
55
- break;
56
- }
57
- }
58
-
59
- function add_help_tabs($screen) {
60
-
61
- $screen->add_help_tab(array(
62
- 'id' => 'su-settings-overview'
63
- , 'title' => __('Overview', 'seo-ultimate')
64
- , 'content' => __("
65
- <p>The Settings module lets you manage settings related to the SEO Ultimate plugin as a whole.</p>
66
- ", 'seo-ultimate')));
67
-
68
- $screen->add_help_tab(array(
69
- 'id' => 'su-settings-settings'
70
- , 'title' => __('Global Settings', 'seo-ultimate')
71
- , 'content' => __("
72
- <p>Here&#8217;s information on some of the settings:</p>
73
- <ul>
74
- <li><strong>Identify the plugin&#8217;s HTML code insertions with HTML comment tags</strong> &mdash; If enabled, SEO Ultimate will use HTML comments to identify all code it inserts into your <code>&lt;head&gt;</code> 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.</li>
75
- <li><strong>Enable nofollow&#8217;d attribution link on my site</strong> &mdash; If enabled, the plugin will display an attribution link on your site.</li>
76
- </ul>
77
- ", 'seo-ultimate')));
78
-
79
- $screen->add_help_tab(array(
80
- 'id' => 'su-settings-faq'
81
- , 'title' => __('FAQ', 'seo-ultimate')
82
- , 'content' => __("
83
- <ul>
84
- <li>
85
- <p><strong>Why doesn&#8217;t the settings exporter include all my data in an export?</strong><br />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&#8217;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.</p>
86
- <p>If you&#8217;re moving a site to a different server or restoring a crashed site, you should do so with database backup/restore.</p>
87
- </li>
88
- </ul>
89
- ", 'seo-ultimate')));
90
- }
91
- }
92
-
93
- }
94
  ?>
1
+ <?php
2
+ /**
3
+ * SEO Ultimate Plugin Settings Module
4
+ *
5
+ * @since 0.2
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_Settings extends SU_Module {
11
+
12
+ static function get_module_title() {
13
+ if (is_network_admin())
14
+ return __('Plugin Management', 'seo-ultimate');
15
+
16
+ return __('Plugin Settings', 'seo-ultimate');
17
+ }
18
+
19
+ function get_page_title() {
20
+ if (is_network_admin())
21
+ return __('SEO Ultimate Plugin Management', 'seo-ultimate');
22
+
23
+ return __('SEO Ultimate Plugin Settings', 'seo-ultimate');
24
+ }
25
+
26
+ static function get_menu_title() { return __('SEO Ultimate', 'seo-ultimate'); }
27
+
28
+ function get_menu_parent() {
29
+ if (is_network_admin())
30
+ return 'plugins.php';
31
+
32
+ return 'options-general.php';
33
+ }
34
+
35
+ function admin_page_contents() { $this->children_admin_page_tabs(); }
36
+
37
+ function belongs_in_admin($admin_scope = null) {
38
+
39
+ if ($admin_scope === null)
40
+ $admin_scope = suwp::get_admin_scope();
41
+
42
+ switch ($admin_scope) {
43
+ case 'blog':
44
+ return true;
45
+ case 'network':
46
+
47
+ if ( ! function_exists( 'is_plugin_active_for_network' ) )
48
+ require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
49
+
50
+ return is_plugin_active_for_network($this->plugin->plugin_basename);
51
+
52
+ break;
53
+ default:
54
+ return false;
55
+ break;
56
+ }
57
+ }
58
+
59
+ function add_help_tabs($screen) {
60
+
61
+ $screen->add_help_tab(array(
62
+ 'id' => 'su-settings-overview'
63
+ , 'title' => __('Overview', 'seo-ultimate')
64
+ , 'content' => __("
65
+ <p>The Settings module lets you manage settings related to the SEO Ultimate plugin as a whole.</p>
66
+ ", 'seo-ultimate')));
67
+
68
+ $screen->add_help_tab(array(
69
+ 'id' => 'su-settings-settings'
70
+ , 'title' => __('Global Settings', 'seo-ultimate')
71
+ , 'content' => __("
72
+ <p>Here&#8217;s information on some of the settings:</p>
73
+ <ul>
74
+ <li><strong>Identify the plugin&#8217;s HTML code insertions with HTML comment tags</strong> &mdash; If enabled, SEO Ultimate will use HTML comments to identify all code it inserts into your <code>&lt;head&gt;</code> 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.</li>
75
+ <li><strong>Enable nofollow&#8217;d attribution link on my site</strong> &mdash; If enabled, the plugin will display an attribution link on your site.</li>
76
+ </ul>
77
+ ", 'seo-ultimate')));
78
+
79
+ $screen->add_help_tab(array(
80
+ 'id' => 'su-settings-faq'
81
+ , 'title' => __('FAQ', 'seo-ultimate')
82
+ , 'content' => __("
83
+ <ul>
84
+ <li>
85
+ <p><strong>Why doesn&#8217;t the settings exporter include all my data in an export?</strong><br />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&#8217;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.</p>
86
+ <p>If you&#8217;re moving a site to a different server or restoring a crashed site, you should do so with database backup/restore.</p>
87
+ </li>
88
+ </ul>
89
+ ", 'seo-ultimate')));
90
+ }
91
+ }
92
+
93
+ }
94
  ?>
modules/settings/uninstall.php CHANGED
@@ -1,109 +1,109 @@
1
- <?php
2
- /**
3
- * Uninstaller Module
4
- *
5
- * @since 2.1
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_Uninstall extends SU_Module {
11
-
12
- static function get_parent_module() { return 'settings'; }
13
- static function get_child_order() { return 40; }
14
- static function is_independent_module() { return false; }
15
- function get_settings_key() { return $this->get_module_key(); }
16
-
17
- static function get_module_title() { return __('Uninstaller', 'seo-ultimate'); }
18
- function get_module_subtitle() { return __('Uninstall', 'seo-ultimate'); }
19
-
20
- function get_admin_page_tabs() {
21
- if ($this->current_user_can_uninstall())
22
- return array(array('title' => __('Uninstall', 'seo-ultimate'), 'id' => 'su-uninstall', 'callback' => 'uninstall_tab'));
23
- else
24
- return false;
25
- }
26
-
27
- function belongs_in_admin($admin_scope = null) {
28
-
29
- if ($admin_scope === null)
30
- $admin_scope = suwp::get_admin_scope();
31
-
32
- switch ($admin_scope) {
33
- case 'blog':
34
-
35
- if ( ! function_exists( 'is_plugin_active_for_network' ) )
36
- require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
37
-
38
- return !is_multisite() || !is_plugin_active_for_network($this->plugin->plugin_basename);
39
- break;
40
- case 'network':
41
- return true;
42
- break;
43
- default:
44
- return false;
45
- break;
46
- }
47
- }
48
-
49
- function current_user_can_uninstall() {
50
- return current_user_can('delete_plugins') && (!is_multisite() || is_super_admin());
51
- }
52
-
53
- function init() {
54
- if ($this->is_action('su-uninstall'))
55
- add_filter('su_custom_admin_page-settings', array(&$this, 'do_uninstall'));
56
- }
57
-
58
- function uninstall_tab() {
59
-
60
- if (!$this->current_user_can_uninstall()) {
61
- $this->print_message('error', __('You do not have sufficient permissions to delete plugins on this site.', 'seo-ultimate'));
62
- return;
63
- }
64
-
65
- echo "\n<p>";
66
- _e('Uninstalling SEO Ultimate will delete your settings and the plugin&#8217;s files.', 'seo-ultimate');
67
- echo "</p>\n";
68
- $url = $this->get_nonce_url('su-uninstall');
69
- $confirm = __('Are you sure you want to uninstall SEO Ultimate? This will permanently erase your SEO Ultimate settings and cannot be undone.', 'seo-ultimate');
70
- echo "<p><a href='$url' class='button-primary' onclick=\"javascript:return confirm('$confirm')\">".__('Uninstall Now', 'seo-ultimate')."</a></p>";
71
- }
72
-
73
- function enable_post_uninstall_page() {
74
- add_submenu_page('su-hidden-modules', __('Uninstall SEO Ultimate', 'seo-ultimate'), 'Uninstall',
75
- 'manage_options', 'seo-ultimate', array(&$this->parent_module, 'admin_page_contents'));
76
- }
77
-
78
- function do_uninstall() {
79
-
80
- if (!$this->current_user_can_uninstall())
81
- wp_die(__('You do not have sufficient permissions to delete plugins on this site.', 'seo-ultimate'));
82
-
83
- echo "<script type='text/javascript'>jQuery('#adminmenu .current').hide(); jQuery('#toplevel_page_seo').hide();</script>";
84
- echo "<div class=\"wrap\">\n";
85
- echo "\n<h2>".__('Uninstall SEO Ultimate', 'seo-ultimate')."</h2>\n";
86
-
87
- //Delete settings and do miscellaneous clean up
88
- $this->plugin->uninstall();
89
- $this->print_mini_message('success', __('Deleted settings.', 'seo-ultimate'));
90
-
91
- //Deactivate the plugin
92
- deactivate_plugins(array($this->plugin->plugin_basename), true);
93
-
94
- //Attempt to delete the plugin's files and output result
95
- if (is_wp_error($error = delete_plugins(array($this->plugin->plugin_basename))))
96
- $this->print_mini_message('error', __('An error occurred while deleting files.', 'seo-ultimate').'<br />'.$error->get_error_message());
97
- else {
98
- $this->print_mini_message('success', __('Deleted files.', 'seo-ultimate'));
99
- $this->print_mini_message('success', __('Uninstallation complete. Thanks for trying SEO Ultimate.', 'seo-ultimate'));
100
- }
101
-
102
- echo "\n</div>\n";
103
-
104
- return true;
105
- }
106
- }
107
-
108
- }
109
  ?>
1
+ <?php
2
+ /**
3
+ * Uninstaller Module
4
+ *
5
+ * @since 2.1
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_Uninstall extends SU_Module {
11
+
12
+ static function get_parent_module() { return 'settings'; }
13
+ static function get_child_order() { return 40; }
14
+ static function is_independent_module() { return false; }
15
+ function get_settings_key() { return $this->get_module_key(); }
16
+
17
+ static function get_module_title() { return __('Uninstaller', 'seo-ultimate'); }
18
+ function get_module_subtitle() { return __('Uninstall', 'seo-ultimate'); }
19
+
20
+ function get_admin_page_tabs() {
21
+ if ($this->current_user_can_uninstall())
22
+ return array(array('title' => __('Uninstall', 'seo-ultimate'), 'id' => 'su-uninstall', 'callback' => 'uninstall_tab'));
23
+ else
24
+ return false;
25
+ }
26
+
27
+ function belongs_in_admin($admin_scope = null) {
28
+
29
+ if ($admin_scope === null)
30
+ $admin_scope = suwp::get_admin_scope();
31
+
32
+ switch ($admin_scope) {
33
+ case 'blog':
34
+
35
+ if ( ! function_exists( 'is_plugin_active_for_network' ) )
36
+ require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
37
+
38
+ return !is_multisite() || !is_plugin_active_for_network($this->plugin->plugin_basename);
39
+ break;
40
+ case 'network':
41
+ return true;
42
+ break;
43
+ default:
44
+ return false;
45
+ break;
46
+ }
47
+ }
48
+
49
+ function current_user_can_uninstall() {
50
+ return current_user_can('delete_plugins') && (!is_multisite() || is_super_admin());
51
+ }
52
+
53
+ function init() {
54
+ if ($this->is_action('su-uninstall'))
55
+ add_filter('su_custom_admin_page-settings', array(&$this, 'do_uninstall'));
56
+ }
57
+
58
+ function uninstall_tab() {
59
+
60
+ if (!$this->current_user_can_uninstall()) {
61
+ $this->print_message('error', __('You do not have sufficient permissions to delete plugins on this site.', 'seo-ultimate'));
62
+ return;
63
+ }
64
+
65
+ echo "\n<p>";
66
+ _e('Uninstalling SEO Ultimate will delete your settings and the plugin&#8217;s files.', 'seo-ultimate');
67
+ echo "</p>\n";
68
+ $url = $this->get_nonce_url('su-uninstall');
69
+ $confirm = __('Are you sure you want to uninstall SEO Ultimate? This will permanently erase your SEO Ultimate settings and cannot be undone.', 'seo-ultimate');
70
+ echo "<p><a href='$url' class='button-primary' onclick=\"javascript:return confirm('$confirm')\">".__('Uninstall Now', 'seo-ultimate')."</a></p>";
71
+ }
72
+
73
+ function enable_post_uninstall_page() {
74
+ add_submenu_page('su-hidden-modules', __('Uninstall SEO Ultimate', 'seo-ultimate'), 'Uninstall',
75
+ 'manage_options', 'seo-ultimate', array(&$this->parent_module, 'admin_page_contents'));
76
+ }
77
+
78
+ function do_uninstall() {
79
+
80
+ if (!$this->current_user_can_uninstall())
81
+ wp_die(__('You do not have sufficient permissions to delete plugins on this site.', 'seo-ultimate'));
82
+
83
+ echo "<script type='text/javascript'>jQuery('#adminmenu .current').hide(); jQuery('#toplevel_page_seo').hide();</script>";
84
+ echo "<div class=\"wrap\">\n";
85
+ echo "\n<h2>".__('Uninstall SEO Ultimate', 'seo-ultimate')."</h2>\n";
86
+
87
+ //Delete settings and do miscellaneous clean up
88
+ $this->plugin->uninstall();
89
+ $this->print_mini_message('success', __('Deleted settings.', 'seo-ultimate'));
90
+
91
+ //Deactivate the plugin
92
+ deactivate_plugins(array($this->plugin->plugin_basename), true);
93
+
94
+ //Attempt to delete the plugin's files and output result
95
+ if (is_wp_error($error = delete_plugins(array($this->plugin->plugin_basename))))
96
+ $this->print_mini_message('error', __('An error occurred while deleting files.', 'seo-ultimate').'<br />'.$error->get_error_message());
97
+ else {
98
+ $this->print_mini_message('success', __('Deleted files.', 'seo-ultimate'));
99
+ $this->print_mini_message('success', __('Uninstallation complete. Thanks for trying SEO Ultimate.', 'seo-ultimate'));
100
+ }
101
+
102
+ echo "\n</div>\n";
103
+
104
+ return true;
105
+ }
106
+ }
107
+
108
+ }
109
  ?>
modules/sharing-buttons/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/sharing-buttons/sharing-buttons.css CHANGED
@@ -1,14 +1,14 @@
1
-
2
- #su-sharing-buttons table.form-table label {
3
- display: block;
4
- margin-top: 1em;
5
- }
6
-
7
- #su-sharing-buttons table.form-table label.first {
8
- margin-top: 0;
9
- }
10
-
11
- #su-sharing-buttons table.form-table input.subfield {
12
- margin-left: 2em;
13
- width: 90%;
14
  }
1
+
2
+ #su-sharing-buttons table.form-table label {
3
+ display: block;
4
+ margin-top: 1em;
5
+ }
6
+
7
+ #su-sharing-buttons table.form-table label.first {
8
+ margin-top: 0;
9
+ }
10
+
11
+ #su-sharing-buttons table.form-table input.subfield {
12
+ margin-left: 2em;
13
+ width: 90%;
14
  }
modules/sharing-buttons/sharing-buttons.php CHANGED
@@ -1,97 +1,97 @@
1
- <?php
2
- /**
3
- * Sharing Facilitator Module
4
- *
5
- * @since 3.5
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_SharingButtons extends SU_Module {
11
-
12
- static function get_module_title() { return __('Sharing Facilitator', 'seo-ultimate'); }
13
-
14
- static function get_parent_module() { return 'misc'; }
15
- function get_settings_key() { return 'sharing-buttons'; }
16
-
17
- function init() {
18
- add_filter('the_content', array(&$this, 'add_sharing_buttons'));
19
- }
20
-
21
- function get_default_settings() {
22
- return array(
23
- 'provider' => 'none'
24
- , 'sharethis_code' => '<script type="text/javascript" charset="utf-8" src="http://w.sharethis.com/widget/?wp={wpver}"></script>'
25
- , 'addthis_code' => '<a class="addthis_button" href="http://addthis.com/bookmark.php?v=250"><img src="http://s7.addthis.com/static/btn/v2/lg-share-en.gif" width="125" height="16" alt="' . __('Bookmark and Share', 'seo-ultimate') . '" style="border:0"/></a><script type="text/javascript" src="http://s7.addthis.com/js/250/addthis_widget.js"></script>'
26
- );
27
- }
28
-
29
- /*
30
- function get_admin_page_tabs() {
31
- return array(
32
- __('Providers', 'seo-ultimate') => 'providers_tab'
33
- );
34
- }
35
- */
36
-
37
- function admin_page_contents() {
38
- $this->child_admin_form_start();
39
- $this->radiobuttons('provider', array(
40
- 'none' => __('None; disable sharing buttons', 'seo-ultimate')
41
- , 'sharethis' => __('Use the ShareThis button', 'seo-ultimate') //: %s{sharethis_code}
42
- , 'addthis' => __('Use the AddThis button', 'seo-ultimate') //: %s{addthis_code}
43
- ), __('Which provider would you like to use for your sharing buttons?', 'seo-ultimate'));
44
- $this->child_admin_form_end();
45
- }
46
-
47
- function add_sharing_buttons($content) {
48
- if (!is_feed()) {
49
- switch ($this->get_setting('provider', 'none')) {
50
- case 'sharethis': $code = $this->get_setting('sharethis_code', ''); break;
51
- case 'addthis': $code = $this->get_setting('addthis_code', ''); break;
52
- default: return $content; break;
53
- }
54
-
55
- if ($code) {
56
- $code = str_replace(array(
57
- '{wpver}'
58
- ), array (
59
- get_bloginfo('version')
60
- ), $code);
61
- return $content . $code;
62
- }
63
- }
64
- return $content;
65
- }
66
-
67
- function add_help_tabs($screen) {
68
-
69
- $overview = __("
70
- <ul>
71
- <li><strong>What it does:</strong> Sharing Facilitator adds buttons to your posts/pages that make it easy for visitors to share your content.</li>
72
- <li><strong>Why it helps:</strong> When visitors share your content on social networking sites, this can build links to your site. Sharing Facilitator makes it easy for visitors to do this.</li>
73
- <li><strong>How to use it:</strong> Pick which button type you&#8217;d like to use (ShareThis or AddThis) and click Save Changes. Try enabling each button on your site and see which one you like better.</li>
74
- </ul>
75
- ", 'seo-ultimate');
76
-
77
- if ($this->has_enabled_parent()) {
78
- $screen->add_help_tab(array(
79
- 'id' => 'su-sharing-buttons-help'
80
- , 'title' => __('Sharing Facilitator', 'seo-ultimate')
81
- , 'content' =>
82
- '<h3>' . __('Overview', 'seo-ultimate') . '</h3>' . $overview
83
- ));
84
- } else {
85
-
86
- $screen->add_help_tab(array(
87
- 'id' => 'su-sharing-buttons-overview'
88
- , 'title' => __('Overview', 'seo-ultimate')
89
- , 'content' => $overview));
90
-
91
- }
92
- }
93
-
94
- }
95
-
96
- }
97
  ?>
1
+ <?php
2
+ /**
3
+ * Sharing Facilitator Module
4
+ *
5
+ * @since 3.5
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_SharingButtons extends SU_Module {
11
+
12
+ static function get_module_title() { return __('Sharing Facilitator', 'seo-ultimate'); }
13
+
14
+ static function get_parent_module() { return 'misc'; }
15
+ function get_settings_key() { return 'sharing-buttons'; }
16
+
17
+ function init() {
18
+ add_filter('the_content', array(&$this, 'add_sharing_buttons'));
19
+ }
20
+
21
+ function get_default_settings() {
22
+ return array(
23
+ 'provider' => 'none'
24
+ , 'sharethis_code' => '<script type="text/javascript" charset="utf-8" src="http://w.sharethis.com/widget/?wp={wpver}"></script>'
25
+ , 'addthis_code' => '<a class="addthis_button" href="http://addthis.com/bookmark.php?v=250"><img src="http://s7.addthis.com/static/btn/v2/lg-share-en.gif" width="125" height="16" alt="' . __('Bookmark and Share', 'seo-ultimate') . '" style="border:0"/></a><script type="text/javascript" src="http://s7.addthis.com/js/250/addthis_widget.js"></script>'
26
+ );
27
+ }
28
+
29
+ /*
30
+ function get_admin_page_tabs() {
31
+ return array(
32
+ __('Providers', 'seo-ultimate') => 'providers_tab'
33
+ );
34
+ }
35
+ */
36
+
37
+ function admin_page_contents() {
38
+ $this->child_admin_form_start();
39
+ $this->radiobuttons('provider', array(
40
+ 'none' => __('None; disable sharing buttons', 'seo-ultimate')
41
+ , 'sharethis' => __('Use the ShareThis button', 'seo-ultimate') //: %s{sharethis_code}
42
+ , 'addthis' => __('Use the AddThis button', 'seo-ultimate') //: %s{addthis_code}
43
+ ), __('Which provider would you like to use for your sharing buttons?', 'seo-ultimate'));
44
+ $this->child_admin_form_end();
45
+ }
46
+
47
+ function add_sharing_buttons($content) {
48
+ if (!is_feed()) {
49
+ switch ($this->get_setting('provider', 'none')) {
50
+ case 'sharethis': $code = $this->get_setting('sharethis_code', ''); break;
51
+ case 'addthis': $code = $this->get_setting('addthis_code', ''); break;
52
+ default: return $content; break;
53
+ }
54
+
55
+ if ($code) {
56
+ $code = str_replace(array(
57
+ '{wpver}'
58
+ ), array (
59
+ get_bloginfo('version')
60
+ ), $code);
61
+ return $content . $code;
62
+ }
63
+ }
64
+ return $content;
65
+ }
66
+
67
+ function add_help_tabs($screen) {
68
+
69
+ $overview = __("
70
+ <ul>
71
+ <li><strong>What it does:</strong> Sharing Facilitator adds buttons to your posts/pages that make it easy for visitors to share your content.</li>
72
+ <li><strong>Why it helps:</strong> When visitors share your content on social networking sites, this can build links to your site. Sharing Facilitator makes it easy for visitors to do this.</li>
73
+ <li><strong>How to use it:</strong> Pick which button type you&#8217;d like to use (ShareThis or AddThis) and click Save Changes. Try enabling each button on your site and see which one you like better.</li>
74
+ </ul>
75
+ ", 'seo-ultimate');
76
+
77
+ if ($this->has_enabled_parent()) {
78
+ $screen->add_help_tab(array(
79
+ 'id' => 'su-sharing-buttons-help'
80
+ , 'title' => __('Sharing Facilitator', 'seo-ultimate')
81
+ , 'content' =>
82
+ '<h3>' . __('Overview', 'seo-ultimate') . '</h3>' . $overview
83
+ ));
84
+ } else {
85
+
86
+ $screen->add_help_tab(array(
87
+ 'id' => 'su-sharing-buttons-overview'
88
+ , 'title' => __('Overview', 'seo-ultimate')
89
+ , 'content' => $overview));
90
+
91
+ }
92
+ }
93
+
94
+ }
95
+
96
+ }
97
  ?>
modules/slugs/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/slugs/slugs.php CHANGED
@@ -1,141 +1,141 @@
1
- <?php
2
- /**
3
- * Slug Optimizer Module
4
- *
5
- * @since 0.9
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_Slugs extends SU_Module {
11
-
12
- static function get_module_title() { return __('Slug Optimizer', 'seo-ultimate'); }
13
-
14
- static function get_parent_module() { return 'misc'; }
15
- function get_settings_key() { return 'slugs'; }
16
- function get_default_status() { return SU_MODULE_DISABLED; }
17
-
18
- function admin_page_contents() {
19
- $this->child_admin_form_start();
20
- $this->textarea('words_to_remove', __('Words to Remove', 'seo-ultimate'), 20);
21
- $this->child_admin_form_end();
22
- }
23
-
24
- function init() {
25
-
26
- add_filter('name_save_pre', array(&$this, 'optimize_slug'), 0);
27
-
28
- //Only sanitize if a permalink is being requested via AJAX
29
- if (isset($_POST['action']) && $_POST['action'] == 'sample-permalink')
30
- //The filter priority is very important to ensure our function runs before WordPress's sanitize_title_with_dashes() function
31
- add_filter('sanitize_title', array(&$this, 'optimize_slug_ajax'), 9);
32
- }
33
-
34
- function optimize_slug_ajax($title) {
35
-
36
- if (strcmp($title, $_POST['new_title']) == 0)
37
- //An empty slug was given, so the post title is being used as the default! Call to action!
38
- return $this->optimize_slug($title);
39
-
40
- return $title;
41
- }
42
-
43
- function optimize_slug($slug) {
44
-
45
- //If no slug exists, start off with the post title
46
- if (empty($slug) && isset($_POST['post_title'])) $slug = $_POST['post_title'];
47
-
48
- //Prepare the title and the words for comparison
49
- $slug = sustr::tolower(stripslashes($slug));
50
- $words = sustr::tolower(stripslashes($this->get_setting('words_to_remove')));
51
-
52
- //Remove the stopwords from the slug
53
- $newslug = implode("-", array_diff(explode(" ", $slug), suarr::explode_lines($words)));
54
-
55
- //Make sure we haven't removed too much!
56
- if (empty($newslug))
57
- return $slug;
58
- else
59
- return $newslug;
60
- }
61
-
62
- function get_default_settings() {
63
-
64
- //Special thanks to the "SEO Slugs" plugin for the stopwords array.
65
- //http://wordpress.org/extend/plugins/seo-slugs/
66
- $defaults = array ("a", "able", "about", "above", "abroad", "according", "accordingly", "across", "actually", "adj", "after", "afterwards", "again", "against", "ago", "ahead", "ain't", "all", "allow", "allows", "almost", "alone", "along", "alongside", "already", "also", "although", "always", "am", "amid", "amidst", "among", "amongst", "an", "and", "another", "any", "anybody", "anyhow", "anyone", "anything", "anyway", "anyways", "anywhere", "apart", "appear", "appreciate", "appropriate", "are", "aren't", "around", "as", "a's", "aside", "ask", "asking", "associated", "at", "available", "away", "awfully", "b", "back", "backward", "backwards", "be", "became", "because", "become", "becomes", "becoming", "been", "before", "beforehand", "begin", "behind", "being", "believe", "below", "beside", "besides", "best", "better", "between", "beyond", "both", "brief", "but", "by", "c", "came", "can", "cannot", "cant", "can't", "caption", "cause", "causes", "certain", "certainly", "changes", "clearly", "c'mon", "co", "co.", "com", "come", "comes", "concerning", "consequently", "consider", "considering", "contain", "containing", "contains", "corresponding", "could", "couldn't", "course", "c's", "currently", "d", "dare", "daren't", "definitely", "described", "despite", "did", "didn't", "different", "directly", "do", "does", "doesn't", "doing", "done", "don't", "down", "downwards", "during", "e", "each", "edu", "eg", "eight", "eighty", "either", "else", "elsewhere", "end", "ending", "enough", "entirely", "especially", "et", "etc", "even", "ever", "evermore", "every", "everybody", "everyone", "everything", "everywhere", "ex", "exactly", "example", "except", "f", "fairly", "far", "farther", "few", "fewer", "fifth", "first", "five", "followed", "following", "follows", "for", "forever", "former", "formerly", "forth", "forward", "found", "four", "from", "further", "furthermore", "g", "get", "gets", "getting", "given", "gives", "go", "goes", "going", "gone", "got", "gotten", "greetings", "h", "had", "hadn't", "half", "happens", "hardly", "has", "hasn't", "have", "haven't", "having", "he", "he'd", "he'll", "hello", "help", "hence", "her", "here", "hereafter", "hereby", "herein", "here's", "hereupon", "hers", "herself", "he's", "hi", "him", "himself", "his", "hither", "hopefully", "how", "howbeit", "however", "hundred", "i", "i'd", "ie", "if", "ignored", "i'll", "i'm", "immediate", "in", "inasmuch", "inc", "inc.", "indeed", "indicate", "indicated", "indicates", "inner", "inside", "insofar", "instead", "into", "inward", "is", "isn't", "it", "it'd", "it'll", "its", "it's", "itself", "i've", "j", "just", "k", "keep", "keeps", "kept", "know", "known", "knows", "l", "last", "lately", "later", "latter", "latterly", "least", "less", "lest", "let", "let's", "like", "liked", "likely", "likewise", "little", "look", "looking", "looks", "low", "lower", "ltd", "m", "made", "mainly", "make", "makes", "many", "may", "maybe", "mayn't", "me", "mean", "meantime", "meanwhile", "merely", "might", "mightn't", "mine", "minus", "miss", "more", "moreover", "most", "mostly", "mr", "mrs", "much", "must", "mustn't", "my", "myself", "n", "name", "namely", "nd", "near", "nearly", "necessary", "need", "needn't", "needs", "neither", "never", "neverf", "neverless", "nevertheless", "new", "next", "nine", "ninety", "no", "nobody", "non", "none", "nonetheless", "noone", "no-one", "nor", "normally", "not", "nothing", "notwithstanding", "novel", "now", "nowhere", "o", "obviously", "of", "off", "often", "oh", "ok", "okay", "old", "on", "once", "one", "ones", "one's", "only", "onto", "opposite", "or", "other", "others", "otherwise", "ought", "oughtn't", "our", "ours", "ourselves", "out", "outside", "over", "overall", "own", "p", "particular", "particularly", "past", "per", "perhaps", "placed", "please", "plus", "possible", "presumably", "probably", "provided", "provides", "q", "que", "quite", "qv", "r", "rather", "rd", "re", "really", "reasonably", "recent", "recently", "regarding", "regardless", "regards", "relatively", "respectively", "right", "round", "s", "said", "same", "saw", "say", "saying", "says", "second", "secondly", "see", "seeing", "seem", "seemed", "seeming", "seems", "seen", "self", "selves", "sensible", "sent", "serious", "seriously", "seven", "several", "shall", "shan't", "she", "she'd", "she'll", "she's", "should", "shouldn't", "since", "six", "so", "some", "somebody", "someday", "somehow", "someone", "something", "sometime", "sometimes", "somewhat", "somewhere", "soon", "sorry", "specified", "specify", "specifying", "still", "sub", "such", "sup", "sure", "t", "take", "taken", "taking", "tell", "tends", "th", "than", "thank", "thanks", "thanx", "that", "that'll", "thats", "that's", "that've", "the", "their", "theirs", "them", "themselves", "then", "thence", "there", "thereafter", "thereby", "there'd", "therefore", "therein", "there'll", "there're", "theres", "there's", "thereupon", "there've", "these", "they", "they'd", "they'll", "they're", "they've", "thing", "things", "think", "third", "thirty", "this", "thorough", "thoroughly", "those", "though", "three", "through", "throughout", "thru", "thus", "till", "to", "together", "too", "took", "toward", "towards", "tried", "tries", "truly", "try", "trying", "t's", "twice", "two", "u", "un", "under", "underneath", "undoing", "unfortunately", "unless", "unlike", "unlikely", "until", "unto", "up", "upon", "upwards", "us", "use", "used", "useful", "uses", "using", "usually", "v", "value", "various", "versus", "very", "via", "viz", "vs", "w", "want", "wants", "was", "wasn't", "way", "we", "we'd", "welcome", "well", "we'll", "went", "were", "we're", "weren't", "we've", "what", "whatever", "what'll", "what's", "what've", "when", "whence", "whenever", "where", "whereafter", "whereas", "whereby", "wherein", "where's", "whereupon", "wherever", "whether", "which", "whichever", "while", "whilst", "whither", "who", "who'd", "whoever", "whole", "who'll", "whom", "whomever", "who's", "whose", "why", "will", "willing", "wish", "with", "within", "without", "wonder", "won't", "would", "wouldn't", "x", "y", "yes", "yet", "you", "you'd", "you'll", "your", "you're", "yours", "yourself", "yourselves", "you've", "z", "zero");
67
-
68
- return array(
69
-
70
- 'words_to_remove' => implode("\n", $defaults)
71
-
72
- );
73
- }
74
-
75
- function add_help_tabs($screen) {
76
-
77
- $overview = __("
78
- <ul>
79
- <li><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;)</li>
80
- <li><strong>Why it helps:</strong> Slug Optimizer increases keyword potency because there are fewer words in your URLs competing for relevance.</li>
81
- <li><strong>How to use it:</strong> Slug Optimizer works without any action required on your part. When you add a new post in your WordPress admin and specify a title for it, WordPress will generate a slug and the new post&#8217;s future URL will appear below the title box. While WordPress is generating the slug, Slug Optimizer takes common words out of it. You can use the textbox on Slug Optimizer&#8217;s admin page to specify which common words are removed.</li>
82
- </ul>
83
- ", 'seo-ultimate');
84
-
85
- $faq = __("
86
- <ul>
87
- <li><strong>What&#8217;s a slug?</strong><br />The slug of a post or page is the portion of its URL that is based on its title. When you edit a post or Page in WordPress, the slug is the yellow-highlighted portion of the Permalink beneath the Title textbox.</li>
88
- <li><strong>Does the Slug Optimizer change my existing URLs?</strong><br />No. Slug Optimizer will not relocate your content by changing existing URLs. Slug Optimizer only takes effect on new posts and pages.</li>
89
- <li>
90
- <p><strong>How do I see Slug Optimizer in action?</strong><br />Follow these steps:</p>
91
- <ol>
92
- <li>Create a new post/Page in WordPress.</li>
93
- <li>Type in a title containing some common and uncommon words.</li>
94
- <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>
95
- </ol>
96
- </li>
97
- <li><strong>What if I want to include a common word in my slug?</strong><br />When editing the post or page in question, just click the &#8220;Edit&#8221; button next to the permalink and change the slug as desired. The Slug Optimizer won&#8217;t remove words from a manually-edited slug.</li>
98
- <li><strong>If I edit the optimized slug but then change my mind, how do I revert back to the optimized slug?</strong><br />When editing the post or page in question, just click the &#8220;Edit&#8221; button next to the permalink; a &#8220;Save&#8221; button will appear in its place. Next erase the contents of the textbox, and then click the aforementioned &#8220;Save&#8221; button.</li>
99
- </ul>
100
- ", 'seo-ultimate');
101
-
102
- $troubleshooting = __("
103
- <ul>
104
- <li><strong>Why didn&#8217;t the Slug Optimizer remove common words from my slug?</strong><br />It&#8217;s possible that every word in your post title is in the list of words to remove. In this case, Slug Optimizer doesn&#8217;t remove the words, because if it did, you&#8217;d end up with a blank slug.</li>
105
- </ul>
106
- ", 'seo-ultimate');
107
-
108
- if ($this->has_enabled_parent()) {
109
- $screen->add_help_tab(array(
110
- 'id' => 'su-slugs-help'
111
- , 'title' => __('Slug Optimizer', 'seo-ultimate')
112
- , 'content' =>
113
- '<h3>' . __('Overview', 'seo-ultimate') . '</h3>' . $overview .
114
- '<h3>' . __('FAQ', 'seo-ultimate') . '</h3>' . $faq .
115
- '<h3>' . __('Troubleshooting', 'seo-ultimate') . '</h3>' . $troubleshooting
116
- ));
117
- } else {
118
-
119
- $screen->add_help_tab(array(
120
- 'id' => 'su-slugs-overview'
121
- , 'title' => __('Overview', 'seo-ultimate')
122
- , 'content' => $overview));
123
-
124
- $screen->add_help_tab(array(
125
- 'id' => 'su-slugs-faq'
126
- , 'title' => __('FAQ', 'seo-ultimate')
127
- , 'content' => $faq));
128
-
129
- $screen->add_help_tab(array(
130
- 'id' => 'su-slugs-troubleshooting'
131
- , 'title' => __('Troubleshooting', 'seo-ultimate')
132
- , 'content' => $troubleshooting));
133
- }
134
- }
135
- }
136
-
137
-
138
-
139
- }
140
-
141
  ?>
1
+ <?php
2
+ /**
3
+ * Slug Optimizer Module
4
+ *
5
+ * @since 0.9
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_Slugs extends SU_Module {
11
+
12
+ static function get_module_title() { return __('Slug Optimizer', 'seo-ultimate'); }
13
+
14
+ static function get_parent_module() { return 'misc'; }
15
+ function get_settings_key() { return 'slugs'; }
16
+ function get_default_status() { return SU_MODULE_DISABLED; }
17
+
18
+ function admin_page_contents() {
19
+ $this->child_admin_form_start();
20
+ $this->textarea('words_to_remove', __('Words to Remove', 'seo-ultimate'), 20);
21
+ $this->child_admin_form_end();
22
+ }
23
+
24
+ function init() {
25
+
26
+ add_filter('name_save_pre', array(&$this, 'optimize_slug'), 0);
27
+
28
+ //Only sanitize if a permalink is being requested via AJAX
29
+ if (isset($_POST['action']) && $_POST['action'] == 'sample-permalink')
30
+ //The filter priority is very important to ensure our function runs before WordPress's sanitize_title_with_dashes() function
31
+ add_filter('sanitize_title', array(&$this, 'optimize_slug_ajax'), 9);
32
+ }
33
+
34
+ function optimize_slug_ajax($title) {
35
+
36
+ if (strcmp($title, $_POST['new_title']) == 0)
37
+ //An empty slug was given, so the post title is being used as the default! Call to action!
38
+ return $this->optimize_slug($title);
39
+
40
+ return $title;
41
+ }
42
+
43
+ function optimize_slug($slug) {
44
+
45
+ //If no slug exists, start off with the post title
46
+ if (empty($slug) && isset($_POST['post_title'])) $slug = $_POST['post_title'];
47
+
48
+ //Prepare the title and the words for comparison
49
+ $slug = sustr::tolower(stripslashes($slug));
50
+ $words = sustr::tolower(stripslashes($this->get_setting('words_to_remove')));
51
+
52
+ //Remove the stopwords from the slug
53
+ $newslug = implode("-", array_diff(explode(" ", $slug), suarr::explode_lines($words)));
54
+
55
+ //Make sure we haven't removed too much!
56
+ if (empty($newslug))
57
+ return $slug;
58
+ else
59
+ return $newslug;
60
+ }
61
+
62
+ function get_default_settings() {
63
+
64
+ //Special thanks to the "SEO Slugs" plugin for the stopwords array.
65
+ //http://wordpress.org/extend/plugins/seo-slugs/
66
+ $defaults = array ("a", "able", "about", "above", "abroad", "according", "accordingly", "across", "actually", "adj", "after", "afterwards", "again", "against", "ago", "ahead", "ain't", "all", "allow", "allows", "almost", "alone", "along", "alongside", "already", "also", "although", "always", "am", "amid", "amidst", "among", "amongst", "an", "and", "another", "any", "anybody", "anyhow", "anyone", "anything", "anyway", "anyways", "anywhere", "apart", "appear", "appreciate", "appropriate", "are", "aren't", "around", "as", "a's", "aside", "ask", "asking", "associated", "at", "available", "away", "awfully", "b", "back", "backward", "backwards", "be", "became", "because", "become", "becomes", "becoming", "been", "before", "beforehand", "begin", "behind", "being", "believe", "below", "beside", "besides", "best", "better", "between", "beyond", "both", "brief", "but", "by", "c", "came", "can", "cannot", "cant", "can't", "caption", "cause", "causes", "certain", "certainly", "changes", "clearly", "c'mon", "co", "co.", "com", "come", "comes", "concerning", "consequently", "consider", "considering", "contain", "containing", "contains", "corresponding", "could", "couldn't", "course", "c's", "currently", "d", "dare", "daren't", "definitely", "described", "despite", "did", "didn't", "different", "directly", "do", "does", "doesn't", "doing", "done", "don't", "down", "downwards", "during", "e", "each", "edu", "eg", "eight", "eighty", "either", "else", "elsewhere", "end", "ending", "enough", "entirely", "especially", "et", "etc", "even", "ever", "evermore", "every", "everybody", "everyone", "everything", "everywhere", "ex", "exactly", "example", "except", "f", "fairly", "far", "farther", "few", "fewer", "fifth", "first", "five", "followed", "following", "follows", "for", "forever", "former", "formerly", "forth", "forward", "found", "four", "from", "further", "furthermore", "g", "get", "gets", "getting", "given", "gives", "go", "goes", "going", "gone", "got", "gotten", "greetings", "h", "had", "hadn't", "half", "happens", "hardly", "has", "hasn't", "have", "haven't", "having", "he", "he'd", "he'll", "hello", "help", "hence", "her", "here", "hereafter", "hereby", "herein", "here's", "hereupon", "hers", "herself", "he's", "hi", "him", "himself", "his", "hither", "hopefully", "how", "howbeit", "however", "hundred", "i", "i'd", "ie", "if", "ignored", "i'll", "i'm", "immediate", "in", "inasmuch", "inc", "inc.", "indeed", "indicate", "indicated", "indicates", "inner", "inside", "insofar", "instead", "into", "inward", "is", "isn't", "it", "it'd", "it'll", "its", "it's", "itself", "i've", "j", "just", "k", "keep", "keeps", "kept", "know", "known", "knows", "l", "last", "lately", "later", "latter", "latterly", "least", "less", "lest", "let", "let's", "like", "liked", "likely", "likewise", "little", "look", "looking", "looks", "low", "lower", "ltd", "m", "made", "mainly", "make", "makes", "many", "may", "maybe", "mayn't", "me", "mean", "meantime", "meanwhile", "merely", "might", "mightn't", "mine", "minus", "miss", "more", "moreover", "most", "mostly", "mr", "mrs", "much", "must", "mustn't", "my", "myself", "n", "name", "namely", "nd", "near", "nearly", "necessary", "need", "needn't", "needs", "neither", "never", "neverf", "neverless", "nevertheless", "new", "next", "nine", "ninety", "no", "nobody", "non", "none", "nonetheless", "noone", "no-one", "nor", "normally", "not", "nothing", "notwithstanding", "novel", "now", "nowhere", "o", "obviously", "of", "off", "often", "oh", "ok", "okay", "old", "on", "once", "one", "ones", "one's", "only", "onto", "opposite", "or", "other", "others", "otherwise", "ought", "oughtn't", "our", "ours", "ourselves", "out", "outside", "over", "overall", "own", "p", "particular", "particularly", "past", "per", "perhaps", "placed", "please", "plus", "possible", "presumably", "probably", "provided", "provides", "q", "que", "quite", "qv", "r", "rather", "rd", "re", "really", "reasonably", "recent", "recently", "regarding", "regardless", "regards", "relatively", "respectively", "right", "round", "s", "said", "same", "saw", "say", "saying", "says", "second", "secondly", "see", "seeing", "seem", "seemed", "seeming", "seems", "seen", "self", "selves", "sensible", "sent", "serious", "seriously", "seven", "several", "shall", "shan't", "she", "she'd", "she'll", "she's", "should", "shouldn't", "since", "six", "so", "some", "somebody", "someday", "somehow", "someone", "something", "sometime", "sometimes", "somewhat", "somewhere", "soon", "sorry", "specified", "specify", "specifying", "still", "sub", "such", "sup", "sure", "t", "take", "taken", "taking", "tell", "tends", "th", "than", "thank", "thanks", "thanx", "that", "that'll", "thats", "that's", "that've", "the", "their", "theirs", "them", "themselves", "then", "thence", "there", "thereafter", "thereby", "there'd", "therefore", "therein", "there'll", "there're", "theres", "there's", "thereupon", "there've", "these", "they", "they'd", "they'll", "they're", "they've", "thing", "things", "think", "third", "thirty", "this", "thorough", "thoroughly", "those", "though", "three", "through", "throughout", "thru", "thus", "till", "to", "together", "too", "took", "toward", "towards", "tried", "tries", "truly", "try", "trying", "t's", "twice", "two", "u", "un", "under", "underneath", "undoing", "unfortunately", "unless", "unlike", "unlikely", "until", "unto", "up", "upon", "upwards", "us", "use", "used", "useful", "uses", "using", "usually", "v", "value", "various", "versus", "very", "via", "viz", "vs", "w", "want", "wants", "was", "wasn't", "way", "we", "we'd", "welcome", "well", "we'll", "went", "were", "we're", "weren't", "we've", "what", "whatever", "what'll", "what's", "what've", "when", "whence", "whenever", "where", "whereafter", "whereas", "whereby", "wherein", "where's", "whereupon", "wherever", "whether", "which", "whichever", "while", "whilst", "whither", "who", "who'd", "whoever", "whole", "who'll", "whom", "whomever", "who's", "whose", "why", "will", "willing", "wish", "with", "within", "without", "wonder", "won't", "would", "wouldn't", "x", "y", "yes", "yet", "you", "you'd", "you'll", "your", "you're", "yours", "yourself", "yourselves", "you've", "z", "zero");
67
+
68
+ return array(
69
+
70
+ 'words_to_remove' => implode("\n", $defaults)
71
+
72
+ );
73
+ }
74
+
75
+ function add_help_tabs($screen) {
76
+
77
+ $overview = __("
78
+ <ul>
79
+ <li><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;)</li>
80
+ <li><strong>Why it helps:</strong> Slug Optimizer increases keyword potency because there are fewer words in your URLs competing for relevance.</li>
81
+ <li><strong>How to use it:</strong> Slug Optimizer works without any action required on your part. When you add a new post in your WordPress admin and specify a title for it, WordPress will generate a slug and the new post&#8217;s future URL will appear below the title box. While WordPress is generating the slug, Slug Optimizer takes common words out of it. You can use the textbox on Slug Optimizer&#8217;s admin page to specify which common words are removed.</li>
82
+ </ul>
83
+ ", 'seo-ultimate');
84
+
85
+ $faq = __("
86
+ <ul>
87
+ <li><strong>What&#8217;s a slug?</strong><br />The slug of a post or page is the portion of its URL that is based on its title. When you edit a post or Page in WordPress, the slug is the yellow-highlighted portion of the Permalink beneath the Title textbox.</li>
88
+ <li><strong>Does the Slug Optimizer change my existing URLs?</strong><br />No. Slug Optimizer will not relocate your content by changing existing URLs. Slug Optimizer only takes effect on new posts and pages.</li>
89
+ <li>
90
+ <p><strong>How do I see Slug Optimizer in action?</strong><br />Follow these steps:</p>
91
+ <ol>
92
+ <li>Create a new post/Page in WordPress.</li>
93
+ <li>Type in a title containing some common and uncommon words.</li>
94
+ <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>
95
+ </ol>
96
+ </li>
97
+ <li><strong>What if I want to include a common word in my slug?</strong><br />When editing the post or page in question, just click the &#8220;Edit&#8221; button next to the permalink and change the slug as desired. The Slug Optimizer won&#8217;t remove words from a manually-edited slug.</li>
98
+ <li><strong>If I edit the optimized slug but then change my mind, how do I revert back to the optimized slug?</strong><br />When editing the post or page in question, just click the &#8220;Edit&#8221; button next to the permalink; a &#8220;Save&#8221; button will appear in its place. Next erase the contents of the textbox, and then click the aforementioned &#8220;Save&#8221; button.</li>
99
+ </ul>
100
+ ", 'seo-ultimate');
101
+
102
+ $troubleshooting = __("
103
+ <ul>
104
+ <li><strong>Why didn&#8217;t the Slug Optimizer remove common words from my slug?</strong><br />It&#8217;s possible that every word in your post title is in the list of words to remove. In this case, Slug Optimizer doesn&#8217;t remove the words, because if it did, you&#8217;d end up with a blank slug.</li>
105
+ </ul>
106
+ ", 'seo-ultimate');
107
+
108
+ if ($this->has_enabled_parent()) {
109
+ $screen->add_help_tab(array(
110
+ 'id' => 'su-slugs-help'
111
+ , 'title' => __('Slug Optimizer', 'seo-ultimate')
112
+ , 'content' =>
113
+ '<h3>' . __('Overview', 'seo-ultimate') . '</h3>' . $overview .
114
+ '<h3>' . __('FAQ', 'seo-ultimate') . '</h3>' . $faq .
115
+ '<h3>' . __('Troubleshooting', 'seo-ultimate') . '</h3>' . $troubleshooting
116
+ ));
117
+ } else {
118
+
119
+ $screen->add_help_tab(array(
120
+ 'id' => 'su-slugs-overview'
121
+ , 'title' => __('Overview', 'seo-ultimate')
122
+ , 'content' => $overview));
123
+
124
+ $screen->add_help_tab(array(
125
+ 'id' => 'su-slugs-faq'
126
+ , 'title' => __('FAQ', 'seo-ultimate')
127
+ , 'content' => $faq));
128
+
129
+ $screen->add_help_tab(array(
130
+ 'id' => 'su-slugs-troubleshooting'
131
+ , 'title' => __('Troubleshooting', 'seo-ultimate')
132
+ , 'content' => $troubleshooting));
133
+ }
134
+ }
135
+ }
136
+
137
+
138
+
139
+ }
140
+
141
  ?>
modules/titles/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/titles/titles.php CHANGED
@@ -1,489 +1,489 @@
1
- <?php
2
- /**
3
- * Title Tag Rewriter Module
4
- *
5
- * @since 0.1
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- function su_titles_export_filter($all_settings) {
11
- unset($all_settings['titles']['taxonomy_titles']);
12
- return $all_settings;
13
- }
14
- add_filter('su_settings_export_array', 'su_titles_export_filter');
15
-
16
- class SU_Titles extends SU_Module {
17
-
18
- static function get_module_title() { return __('Title Tag Rewriter', 'seo-ultimate'); }
19
- static function get_menu_title() { return __('Title Tag Rewriter', 'seo-ultimate'); }
20
-
21
- function init() {
22
-
23
- switch ($this->get_setting('rewrite_method', 'ob')) {
24
- case 'filter':
25
- add_filter('wp_title', array(&$this, 'get_title'));
26
- break;
27
- case 'ob':
28
- default:
29
- add_action('template_redirect', array(&$this, 'before_header'), 0);
30
- add_action('wp_head', array(&$this, 'after_header'), 1000);
31
- break;
32
- }
33
-
34
- add_filter('su_postmeta_help', array(&$this, 'postmeta_help'), 10);
35
- }
36
-
37
- function get_admin_page_tabs() {
38
- return array_merge(
39
- array(
40
- array('title' => __('Default Formats', 'seo-ultimate'), 'id' => 'su-default-formats', 'callback' => 'formats_tab')
41
- , array('title' => __('Settings', 'seo-ultimate'), 'id' => 'su-settings', 'callback' => 'settings_tab')
42
- )
43
- , $this->get_meta_edit_tabs(array(
44
- 'type' => 'textbox'
45
- , 'name' => 'title'
46
- , 'term_settings_key' => 'taxonomy_titles'
47
- , 'label' => __('Title Tag', 'seo-ultimate')
48
- ))
49
- );
50
- }
51
-
52
- function formats_tab() {
53
- //echo "<table class='form-table'>\n";
54
- $this->textboxes($this->get_supported_settings(), $this->get_default_settings());
55
- //echo "</table>";
56
- }
57
-
58
- function settings_tab() {
59
- $this->admin_form_table_start();
60
- $this->checkbox('terms_ucwords', __('Convert lowercase category/tag names to title case when used in title tags.', 'seo-ultimate'), __('Title Tag Variables', 'seo-ultimate'));
61
- $this->radiobuttons('rewrite_method', array(
62
- 'ob' => __('Use output buffering &mdash; no configuration required, but slower (default)', 'seo-ultimate')
63
- , 'filter' => __('Use filtering &mdash; faster, but configuration required (see the &#8220;Settings Tab&#8221 section of the &#8220;Help&#8221; dropdown for details)', 'seo-ultimate')
64
- ), __('Rewrite Method', 'seo-ultimate'));
65
- $this->admin_form_table_end();
66
- }
67
-
68
- function get_default_settings() {
69
-
70
- //We internationalize even non-text formats (like "{post} | {blog}") to allow RTL languages to switch the order of the variables
71
- return array(
72
- 'title_home' => __('{blog}', 'seo-ultimate')
73
- , 'title_single' => __('{post} | {blog}', 'seo-ultimate')
74
- , 'title_page' => __('{page} | {blog}', 'seo-ultimate')
75
- , 'title_category' => __('{category} | {blog}', 'seo-ultimate')
76
- , 'title_tag' => __('{tag} | {blog}', 'seo-ultimate')
77
- , 'title_day' => __('Archives for {month} {day}, {year} | {blog}', 'seo-ultimate')
78
- , 'title_month' => __('Archives for {month} {year} | {blog}', 'seo-ultimate')
79
- , 'title_year' => __('Archives for {year} | {blog}', 'seo-ultimate')
80
- , 'title_author' => __('Posts by {author} | {blog}', 'seo-ultimate')
81
- , 'title_search' => __('Search Results for {query} | {blog}', 'seo-ultimate')
82
- , 'title_404' => __('404 Not Found | {blog}', 'seo-ultimate')
83
- , 'title_paged' => __('{title} - Page {num}', 'seo-ultimate')
84
- , 'terms_ucwords' => true
85
- , 'rewrite_method' => 'ob'
86
- );
87
- }
88
-
89
- function get_supported_settings() {
90
- return array(
91
- 'title_home' => __('Blog Homepage Title', 'seo-ultimate')
92
- , 'title_single' => __('Post Title Format', 'seo-ultimate')
93
- , 'title_page' => __('Page Title Format', 'seo-ultimate')
94
- , 'title_category' => __('Category Title Format', 'seo-ultimate')
95
- , 'title_tag' => __('Tag Title Format', 'seo-ultimate')
96
- , 'title_day' => __('Day Archive Title Format', 'seo-ultimate')
97
- , 'title_month' => __('Month Archive Title Format', 'seo-ultimate')
98
- , 'title_year' => __('Year Archive Title Format', 'seo-ultimate')
99
- , 'title_author' => __('Author Archive Title Format', 'seo-ultimate')
100
- , 'title_search' => __('Search Title Format', 'seo-ultimate')
101
- , 'title_404' => __('404 Title Format', 'seo-ultimate')
102
- , 'title_paged' => __('Pagination Title Format', 'seo-ultimate')
103
- );
104
- }
105
-
106
- function get_title_format() {
107
- if ($key = $this->get_current_page_type())
108
- return $this->get_setting("title_$key");
109
-
110
- return false;
111
- }
112
-
113
- function get_current_page_type() {
114
- $pagetypes = $this->get_supported_settings();
115
- unset($pagetypes['title_paged']);
116
-
117
- foreach ($pagetypes as $key => $title) {
118
- $key = str_replace('title_', '', $key);
119
- if (call_user_func("is_$key")) return $key;
120
- }
121
-
122
- return false;
123
- }
124
-
125
- function should_rewrite_title() {
126
- return (!is_admin() && !is_feed());
127
- }
128
-
129
- function before_header() {
130
- if ($this->should_rewrite_title()) ob_start(array(&$this, 'change_title_tag'));
131
- }
132
-
133
- function after_header() {
134
- if ($this->should_rewrite_title()) {
135
-
136
- $handlers = ob_list_handlers();
137
- if (count($handlers) > 0 && strcasecmp($handlers[count($handlers)-1], 'SU_Titles::change_title_tag') == 0)
138
- ob_end_flush();
139
- else
140
- su_debug_log(__FILE__, __CLASS__, __FUNCTION__, __LINE__, "Other ob_list_handlers found:\n".print_r($handlers, true));
141
- }
142
- }
143
-
144
- function change_title_tag($head) {
145
-
146
- $title = $this->get_title();
147
- if (!$title) return $head;
148
- // Pre-parse the title replacement text to escape the $ ($n backreferences) when followed by a number 0-99 because of preg_replace issue
149
- $title = preg_replace('/\$(\d)/', '\\\$$1', $title);
150
- //Replace the old title with the new and return
151
- return preg_replace('/<title>[^<]*<\/title>/i', '<title>'.$title.'</title>', $head);
152
- }
153
-
154
- function get_title() {
155
-
156
- global $wp_query, $wp_locale;
157
-
158
- //Custom post/page title?
159
- if ($post_title = $this->get_postmeta('title'))
160
- return htmlspecialchars($this->get_title_paged($post_title));
161
-
162
- //Custom taxonomy title?
163
- if (suwp::is_tax()) {
164
- $tax_titles = $this->get_setting('taxonomy_titles');
165
- if ($tax_title = $tax_titles[$wp_query->get_queried_object_id()])
166
- return htmlspecialchars($this->get_title_paged($tax_title));
167
- }
168
-
169
- //Get format
170
- if (!$this->should_rewrite_title()) return '';
171
- if (!($format = $this->get_title_format())) return '';
172
-
173
- //Load post/page titles
174
- $post_id = 0;
175
- $post_title = '';
176
- $parent_title = '';
177
- if (is_singular()) {
178
- $post = $wp_query->get_queried_object();
179
- $post_title = strip_tags( apply_filters( 'single_post_title', $post->post_title ) );
180
- $post_id = $post->ID;
181
-
182
- if ($parent = $post->post_parent) {
183
- $parent = get_post($parent);
184
- $parent_title = strip_tags( apply_filters( 'single_post_title', $parent->post_title ) );
185
- }
186
- }
187
-
188
- //Load date-based archive titles
189
- if ($m = get_query_var('m')) {
190
- $year = substr($m, 0, 4);
191
- $monthnum = intval(substr($m, 4, 2));
192
- $daynum = intval(substr($m, 6, 2));
193
- } else {
194
- $year = get_query_var('year');
195
- $monthnum = get_query_var('monthnum');
196
- $daynum = get_query_var('day');
197
- }
198
- $month = $wp_locale->get_month($monthnum);
199
- $monthnum = zeroise($monthnum, 2);
200
- $day = date('jS', mktime(12,0,0,$monthnum,$daynum,$year));
201
- $daynum = zeroise($daynum, 2);
202
-
203
- //Load category titles
204
- $cat_title = $cat_titles = $cat_desc = '';
205
- if (is_category()) {
206
- $cat_title = single_cat_title('', false);
207
- $cat_desc = category_description();
208
- } elseif (count($categories = get_the_category())) {
209
- $cat_titles = su_lang_implode($categories, 'name');
210
- usort($categories, '_usort_terms_by_ID');
211
- $cat_title = $categories[0]->name;
212
- $cat_desc = category_description($categories[0]->term_id);
213
- }
214
- if (strlen($cat_title) && $this->get_setting('terms_ucwords', true))
215
- $cat_title = sustr::tclcwords($cat_title);
216
-
217
- //Load tag titles
218
- $tag_title = $tag_desc = '';
219
- if (is_tag()) {
220
- $tag_title = single_tag_title('', false);
221
- $tag_desc = tag_description();
222
-
223
- if ($this->get_setting('terms_ucwords', true))
224
- $tag_title = sustr::tclcwords($tag_title);
225
- }
226
-
227
- //Load author titles
228
- if (is_author()) {
229
- $author_obj = $wp_query->get_queried_object();
230
- } elseif (is_singular()) {
231
- global $authordata;
232
- $author_obj = $authordata;
233
- } else {
234
- $author_obj = null;
235
- }
236
- if ($author_obj)
237
- $author = array(
238
- 'username' => $author_obj->user_login
239
- , 'name' => $author_obj->display_name
240
- , 'firstname' => get_the_author_meta('first_name', $author_obj->ID)
241
- , 'lastname' => get_the_author_meta('last_name', $author_obj->ID)
242
- , 'nickname' => get_the_author_meta('nickname', $author_obj->ID)
243
- );
244
- else
245
- $author = array(
246
- 'username' => ''
247
- , 'name' => ''
248
- , 'firstname' => ''
249
- , 'lastname' => ''
250
- , 'nickname' => ''
251
- );
252
-
253
- $variables = array(
254
- '{blog}' => get_bloginfo('name')
255
- , '{tagline}' => get_bloginfo('description')
256
- , '{post}' => $post_title
257
- , '{page}' => $post_title
258
- , '{page_parent}' => $parent_title
259
- , '{category}' => $cat_title
260
- , '{categories}' => $cat_titles
261
- , '{category_description}' => $cat_desc
262
- , '{tag}' => $tag_title
263
- , '{tag_description}' => $tag_desc
264
- , '{tags}' => su_lang_implode(get_the_tags($post_id), 'name', true)
265
- , '{daynum}' => $daynum
266
- , '{day}' => $day
267
- , '{monthnum}' => $monthnum
268
- , '{month}' => $month
269
- , '{year}' => $year
270
- , '{author}' => $author['name']
271
- , '{author_name}' => $author['name']
272
- , '{author_username}' => $author['username']
273
- , '{author_firstname}' => $author['firstname']
274
- , '{author_lastname}' => $author['lastname']
275
- , '{author_nickname}' => $author['nickname']
276
- , '{query}' => su_esc_attr(get_search_query())
277
- , '{ucquery}' => su_esc_attr(ucwords(get_search_query()))
278
- , '{url_words}' => $this->get_url_words($_SERVER['REQUEST_URI'])
279
- );
280
-
281
- $title = str_replace(array_keys($variables), array_values($variables), htmlspecialchars($format));
282
-
283
- return $this->get_title_paged($title);
284
- }
285
-
286
- function get_title_paged($title) {
287
-
288
- global $wp_query, $numpages;
289
-
290
- if (is_paged() || get_query_var('page')) {
291
-
292
- if (is_paged()) {
293
- $num = absint(get_query_var('paged'));
294
- $max = absint($wp_query->max_num_pages);
295
- } else {
296
- $num = absint(get_query_var('page'));
297
-
298
- if (is_singular()) {
299
- $post = $wp_query->get_queried_object();
300
- $max = count(explode('<!--nextpage-->', $post->post_content));
301
- } else
302
- $max = '';
303
- }
304
-
305
- return str_replace(
306
- array('{title}', '{num}', '{max}'),
307
- array( $title, $num, $max ),
308
- $this->get_setting('title_paged'));
309
- } else
310
- return $title;
311
- }
312
-
313
- function get_url_words($url) {
314
-
315
- //Remove any extensions (.html, .php, etc)
316
- $url = preg_replace('|\\.[a-zA-Z]{1,4}$|', ' ', $url);
317
-
318
- //Turn slashes to >>
319
- $url = str_replace('/', ' &raquo; ', $url);
320
-
321
- //Remove word separators
322
- $url = str_replace(array('.', '/', '-'), ' ', $url);
323
-
324
- //Capitalize the first letter of every word
325
- $url = explode(' ', $url);
326
- $url = array_map('trim', $url);
327
- $url = array_map('ucwords', $url);
328
- $url = implode(' ', $url);
329
- $url = trim($url);
330
-
331
- return $url;
332
- }
333
-
334
- function postmeta_fields($fields, $screen) {
335
- $id = "_su_title";
336
- $value = su_esc_attr($this->get_postmeta('title'));
337
- $fields['serp'][10]['title'] =
338
- "<div class='form-group su textbox'>\n<label class='col-sm-4 col-md-4 control-label' for='$id'>".__('Title Tag:', 'seo-ultimate')."</label>\n<div class='col-sm-4 col-md-4'><input name='$id' id='$id' type='text' value='$value' class='form-control input-sm regular-text' tabindex='2'"
339
- . " onkeyup=\"javascript:document.getElementById('su_title_charcount').innerHTML = document.getElementById('_su_title').value.length\" />"
340
- . "</div>\n<div class='col-sm-4 col-md-4 help-text'>".sprintf(__('You&#8217;ve entered %s characters. Most search engines use up to 70.', 'seo-ultimate'), "<strong id='su_title_charcount'>".strlen($value)."</strong>")
341
- . "</div>\n</div>\n";
342
-
343
-
344
- return $fields;
345
- }
346
-
347
- function postmeta_help($help) {
348
- $help[] = __('<strong>Title Tag</strong> &mdash; The exact contents of the &lt;title&gt; tag. The title appears in visitors&#8217; title bars and in search engine result titles. 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');
349
- return $help;
350
- }
351
-
352
- function add_help_tabs($screen) {
353
-
354
- $screen->add_help_tab(array(
355
- 'id' => 'su-titles-overview'
356
- , 'title' => __('Overview', 'seo-ultimate')
357
- , 'content' => __("
358
- <ul>
359
- <li><strong>What it does:</strong> Title Tag Rewriter helps you customize the contents of your website&#8217;s <code>&lt;title&gt;</code> tags. The tag contents are displayed in web browser title bars and in search engine result pages.</li>
360
- <li><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. This is an important foundation for WordPress SEO.</li>
361
- <li><strong>How to use it:</strong> Title Tag Rewriter enables recommended settings automatically, so you shouldn&#8217;t need to change anything. If you do wish to edit the rewriting formats, you can do so using the textboxes below (the &#8220;Formats & Variables&#8221; help tab includes additional information on this). You also have the option of overriding the <code>&lt;title&gt;</code> tag of an individual post/page/category/tag/etc. using the appropriate tabs below, or by using the &#8220;Title Tag&#8221; textbox that Title Tag Rewriter adds to the post/page editors.</li>
362
- </ul>
363
- ", 'seo-ultimate')));
364
-
365
- $screen->add_help_tab(array(
366
- 'id' => 'su-titles-vars'
367
- , 'title' => __('Default Formats Tab', 'seo-ultimate')
368
- , 'content' => __("
369
- <p>Various variables, surrounded in {curly brackets}, are provided for use in the title formats. All settings support the {blog} variable, which is replaced with the name of the blog, and the {tagline} variable, which is replaced with the blog tagline as set under <a href='options-general.php'>Settings &rArr; General</a>.</p>
370
-
371
- <p>Here&#8217;s information on each of the settings and its supported variables:</p>
372
-
373
- <ul>
374
- <li><strong>Blog Homepage Title</strong> &mdash; Displays on the main blog posts page.</li>
375
- <li>
376
- <p><strong>Post Title Format</strong> &mdash; Displays on single-post pages. Supports these variables:</p>
377
- <ul>
378
- <li>{post} &mdash; The post&#8217;s title.</li>
379
- <li>{category} &mdash; The title of the post category with the lowest ID number.</li>
380
- <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>
381
- <li>{tags} &mdash; A natural-language list of the post's tags (e.g. &#8220;Tag A, Tag B, and Tag C&#8221;).</li>
382
- <li>{author} &mdash; The Display Name of the post's author.</li>
383
- <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>
384
- </ul>
385
- </li>
386
- <li>
387
- <p><strong>Page Title Format</strong> &mdash; Displays on WordPress Pages. Supports these variables:
388
- <ul>
389
- <li>{page} &mdash; The page&#8217;s title.</li>
390
- <li>{page_parent} &mdash; The title of the page&#8217;s parent page.</li>
391
- <li>{author} &mdash; The Display Name of the page&#8217;s author.</li>
392
- <li>{author_username}, {author_firstname}, {author_lastname}, {author_nickname} &mdash; The username, first name, last name, and nickname of the page&#8217;s author, respectively, as set in his or her profile.</li>
393
- </ul>
394
- </li>
395
- <li><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.</li>
396
- <li><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.</li>
397
- <li>
398
- <p><strong>Day Archive Title Format</strong> &mdash; Displays on day archives. Supports these variables:</p>
399
- <ul>
400
- <li>{day} &mdash; The day number, with ordinal suffix, e.g. 23rd</li>
401
- <li>{daynum} &mdash; The two-digit day number, e.g. 23</li>
402
- <li>{month} &mdash; The name of the month, e.g. April</li>
403
- <li>{monthnum} &mdash; The two-digit number of the month, e.g. 04</li>
404
- <li>{year} &mdash; The year, e.g. 2009</li>
405
- </ul>
406
- </li>
407
- <li><strong>Month Archive Title Format</strong> &mdash; Displays on month archives. Supports {month}, {monthnum}, and {year}.</li>
408
- <li><strong>Year Archive Title Format</strong> &mdash; Displays on year archives. Supports the {year} variable.</li>
409
- <li><strong>Author Archive Title Format</strong> &mdash; 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}.</li>
410
- <li><strong>Search Title Format</strong> &mdash; Displays on the result pages for WordPress&#8217;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.</li>
411
- <li>
412
- <p><strong>404 Title Format</strong> &mdash; Displays whenever a URL doesn&#8217;t go anywhere. Supports this variable:</p>
413
- <ul>
414
- <li>{url_words} &mdash; The words used in the error-generating URL. The first letter of each word will be capitalized.</li>
415
- </ul>
416
- </li>
417
- <li>
418
- <p><strong>Pagination Title Format</strong> &mdash; Displays whenever the visitor is on a subpage (page 2, page 3, etc.) of the homepage or of an archive. Supports these variables:</p>
419
- <ul>
420
- <li>{title} &mdash; The title that would normally be displayed on page 1</li>
421
- <li>{num} &mdash; The current page number (2, 3, etc.)</li>
422
- <li>{max} &mdash; The total number of subpages available. Would usually be used like this: Page {num} of {max}</li>
423
- </ul>
424
- </li>
425
- </ul>
426
- ", 'seo-ultimate')));
427
-
428
- $screen->add_help_tab(array(
429
- 'id' => 'su-titles-settings'
430
- , 'title' => __('Settings Tab', 'seo-ultimate')
431
- , 'content' => __("
432
- <p>Here&#8217;s documentation for the options on the &#8220;Settings&#8221; tab.</p>
433
- <ul>
434
- <li><strong>Convert lowercase category/tag names to title case when used in title tags</strong> &mdash; If your Tag Title Format is set to <code>{tag} | {blog}</code> and you have a tag called &#8220;blue widgets,&#8221; your title tag would be <code>blue widgets | My WordPress Blog</code>. Enabling this setting would capitalize the words in &#8220;blue widgets&#8221; so that the title tag would be <code>Blue Widgets | My WordPress Blog</code> instead.</li>
435
- <li>
436
- <p><strong>Rewrite Method</strong> &mdash; This setting controls the method by which Title Tag Rewriter edits your site&#8217;s <code>&lt;title&gt;</code> tags.</p>
437
- <ul>
438
- <li><strong>Use output buffering</strong> &mdash; This is the &#8220;traditional&#8221; method that most SEO plugins use.
439
- With this method, SEO Ultimate will intercept your site&#8217;s <code>&lt;head&gt;</code> tag section as it&#8217;s being outputted,
440
- locate the <code>&lt;title&gt;</code> tag, edit its value, and then output the edited <code>&lt;head&gt;</code> data.
441
- The good thing about this method is that you don&#8217;t have to edit your theme in any way, as SEO Ultimate will overwrite
442
- whatever your theme puts in your <code>&lt;title&gt;</code> tag. The bad thing is that this output interception takes a few extra
443
- milliseconds to complete. If you are concerned about performance, are comfortable editing your theme&#8217;s header.php file,
444
- and will remember to edit the header.php file of any new themes you activate, you may want to try the filtering rewrite method.</li>
445
- <li>
446
- <p><strong>Use filtering</strong> &mdash; With this method, SEO Ultimate will register itself with WordPress and will replace
447
- WordPress&#8217;s <code>&lt;title&gt;</code> tag output with its own. This method can only edit the text that WordPress itself
448
- generates for the <code>&lt;title&gt;</code> tag; the filtering method can&#8217;t edit anything extra your theme may add.
449
- For this reason, you need to edit your theme to make sure it&#8217;s only pulling <code>&lt;title&gt;</code> tag data from WordPress
450
- and is not adding anything else.</p>
451
- <p>Here&#8217;s how to set up filtering:</p>
452
- <ol>
453
- <li>Go to <a href='theme-editor.php'>Appearance &rArr; Editor</a> (if you get a permissions error, you may be on a WordPress multi-site environment and may not be able to use the filtering rewrite method)</li>
454
- <li>Click &#8220;Header (header.php)&#8221;</li>
455
- <li>Look for the <code>&lt;title&gt;</code> start tag and the <code>&lt;/title&gt;</code> end tag</li>
456
- <li>Edit the text in between those tags so that it looks like this: <code>&lt;title&gt;&lt;?php wp_title(''); ?&gt;&lt;/title&gt;</code></li>
457
- <li>Click &#8220;Update File&#8221;</li>
458
- <li>Return to the &#8220;Settings&#8221; tab of Title Tag Rewriter, select &#8220;Use filtering,&#8221; and click &#8220;Save Changes&#8221;</li>
459
- </ol>
460
- </li>
461
- </ul>
462
- </li>
463
- </ul>
464
- ", 'seo-ultimate')));
465
-
466
- $screen->add_help_tab(array(
467
- 'id' => 'su-titles-faq'
468
- , 'title' => __('FAQ', 'seo-ultimate')
469
- , 'content' => __("
470
- <ul>
471
- <li><strong>Does the Title Tag Rewriter edit my post/page titles?</strong><br />No. The Title Tag Rewriter edits the <code>&lt;title&gt;</code> tags of your site, not your post/page titles.</li>
472
- <li><strong>Will rewriting the title tags of my posts change their permalinks/URLs?</strong><br />No.</li>
473
- <li><strong>What&#8217;s the difference between the &#8220;title&#8221; and the &#8220;title tag&#8221; of a post/page?</strong><br />The &#8220;title&#8221; is the title of your post or page that&#8217;s used in your site&#8217;s theme, in your site&#8217;s admin, in your site&#8217;s RSS feeds, and in your site&#8217;s <code>&lt;title&gt;</code> tags. A <code>&lt;title&gt;</code> tag is the title of a specific webpage, and it appears in your browser&#8217;s title bar and in search result listings. Title Tag Rewriter lets you edit your post&#8217;s <code>&lt;title&gt;</code> tags without editing their actual titles. This means you can edit a post&#8217;s title as it appears in search results, but not as it appears on your site.</li>
474
- </ul>
475
- ", 'seo-ultimate')));
476
-
477
- $screen->add_help_tab(array(
478
- 'id' => 'su-titles-troubleshooting'
479
- , 'title' => __('Troubleshooting', 'seo-ultimate')
480
- , 'content' => __("
481
- <ul>
482
- <li><strong>Why isn&#8217;t Title Tag Rewriter changing my <code>&lt;title&gt;</code> tags?</strong><br />Try disabling other SEO plugins, as they may be conflicting with SEO Ultimate. If you&#8217;re using the default &#8220;output buffering&#8221; rewrite method, check to make sure your theme is <a href='http://johnlamansky.com/wordpress/theme-plugin-hooks/' target='_blank'>plugin-friendly</a>. If you're using the &#8220;filtering&#8221; rewrite method, check your theme&#8217;s <code>header.php</code> file and make sure the <code>&lt;title&gt;</code> tag looks like this: <code>&lt;title&gt;&lt;?php wp_title(''); ?&gt;&lt;/title&gt;</code>.</li>
483
- </ul>
484
- ", 'seo-ultimate')));
485
- }
486
- }
487
-
488
- }
489
  ?>
1
+ <?php
2
+ /**
3
+ * Title Tag Rewriter Module
4
+ *
5
+ * @since 0.1
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ function su_titles_export_filter($all_settings) {
11
+ unset($all_settings['titles']['taxonomy_titles']);
12
+ return $all_settings;
13
+ }
14
+ add_filter('su_settings_export_array', 'su_titles_export_filter');
15
+
16
+ class SU_Titles extends SU_Module {
17
+
18
+ static function get_module_title() { return __('Title Tag Rewriter', 'seo-ultimate'); }
19
+ static function get_menu_title() { return __('Title Tag Rewriter', 'seo-ultimate'); }
20
+
21
+ function init() {
22
+
23
+ switch ($this->get_setting('rewrite_method', 'ob')) {
24
+ case 'filter':
25
+ add_filter('wp_title', array(&$this, 'get_title'));
26
+ break;
27
+ case 'ob':
28
+ default:
29
+ add_action('template_redirect', array(&$this, 'before_header'), 0);
30
+ add_action('wp_head', array(&$this, 'after_header'), 1000);
31
+ break;
32
+ }
33
+
34
+ add_filter('su_postmeta_help', array(&$this, 'postmeta_help'), 10);
35
+ }
36
+
37
+ function get_admin_page_tabs() {
38
+ return array_merge(
39
+ array(
40
+ array('title' => __('Default Formats', 'seo-ultimate'), 'id' => 'su-default-formats', 'callback' => 'formats_tab')
41
+ , array('title' => __('Settings', 'seo-ultimate'), 'id' => 'su-settings', 'callback' => 'settings_tab')
42
+ )
43
+ , $this->get_meta_edit_tabs(array(
44
+ 'type' => 'textbox'
45
+ , 'name' => 'title'
46
+ , 'term_settings_key' => 'taxonomy_titles'
47
+ , 'label' => __('Title Tag', 'seo-ultimate')
48
+ ))
49
+ );
50
+ }
51
+
52
+ function formats_tab() {
53
+ //echo "<table class='form-table'>\n";
54
+ $this->textboxes($this->get_supported_settings(), $this->get_default_settings());
55
+ //echo "</table>";
56
+ }
57
+
58
+ function settings_tab() {
59
+ $this->admin_form_table_start();
60
+ $this->checkbox('terms_ucwords', __('Convert lowercase category/tag names to title case when used in title tags.', 'seo-ultimate'), __('Title Tag Variables', 'seo-ultimate'));
61
+ $this->radiobuttons('rewrite_method', array(
62
+ 'ob' => __('Use output buffering &mdash; no configuration required, but slower (default)', 'seo-ultimate')
63
+ , 'filter' => __('Use filtering &mdash; faster, but configuration required (see the &#8220;Settings Tab&#8221 section of the &#8220;Help&#8221; dropdown for details)', 'seo-ultimate')
64
+ ), __('Rewrite Method', 'seo-ultimate'));
65
+ $this->admin_form_table_end();
66
+ }
67
+
68
+ function get_default_settings() {
69
+
70
+ //We internationalize even non-text formats (like "{post} | {blog}") to allow RTL languages to switch the order of the variables
71
+ return array(
72
+ 'title_home' => __('{blog}', 'seo-ultimate')
73
+ , 'title_single' => __('{post} | {blog}', 'seo-ultimate')
74
+ , 'title_page' => __('{page} | {blog}', 'seo-ultimate')
75
+ , 'title_category' => __('{category} | {blog}', 'seo-ultimate')
76
+ , 'title_tag' => __('{tag} | {blog}', 'seo-ultimate')
77
+ , 'title_day' => __('Archives for {month} {day}, {year} | {blog}', 'seo-ultimate')
78
+ , 'title_month' => __('Archives for {month} {year} | {blog}', 'seo-ultimate')
79
+ , 'title_year' => __('Archives for {year} | {blog}', 'seo-ultimate')
80
+ , 'title_author' => __('Posts by {author} | {blog}', 'seo-ultimate')
81
+ , 'title_search' => __('Search Results for {query} | {blog}', 'seo-ultimate')
82
+ , 'title_404' => __('404 Not Found | {blog}', 'seo-ultimate')
83
+ , 'title_paged' => __('{title} - Page {num}', 'seo-ultimate')
84
+ , 'terms_ucwords' => true
85
+ , 'rewrite_method' => 'ob'
86
+ );
87
+ }
88
+
89
+ function get_supported_settings() {
90
+ return array(
91
+ 'title_home' => __('Blog Homepage Title', 'seo-ultimate')
92
+ , 'title_single' => __('Post Title Format', 'seo-ultimate')
93
+ , 'title_page' => __('Page Title Format', 'seo-ultimate')
94
+ , 'title_category' => __('Category Title Format', 'seo-ultimate')
95
+ , 'title_tag' => __('Tag Title Format', 'seo-ultimate')
96
+ , 'title_day' => __('Day Archive Title Format', 'seo-ultimate')
97
+ , 'title_month' => __('Month Archive Title Format', 'seo-ultimate')
98
+ , 'title_year' => __('Year Archive Title Format', 'seo-ultimate')
99
+ , 'title_author' => __('Author Archive Title Format', 'seo-ultimate')
100
+ , 'title_search' => __('Search Title Format', 'seo-ultimate')
101
+ , 'title_404' => __('404 Title Format', 'seo-ultimate')
102
+ , 'title_paged' => __('Pagination Title Format', 'seo-ultimate')
103
+ );
104
+ }
105
+
106
+ function get_title_format() {
107
+ if ($key = $this->get_current_page_type())
108
+ return $this->get_setting("title_$key");
109
+
110
+ return false;
111
+ }
112
+
113
+ function get_current_page_type() {
114
+ $pagetypes = $this->get_supported_settings();
115
+ unset($pagetypes['title_paged']);
116
+
117
+ foreach ($pagetypes as $key => $title) {
118
+ $key = str_replace('title_', '', $key);
119
+ if (call_user_func("is_$key")) return $key;
120
+ }
121
+
122
+ return false;
123
+ }
124
+
125
+ function should_rewrite_title() {
126
+ return (!is_admin() && !is_feed());
127
+ }
128
+
129
+ function before_header() {
130
+ if ($this->should_rewrite_title()) ob_start(array(&$this, 'change_title_tag'));
131
+ }
132
+
133
+ function after_header() {
134
+ if ($this->should_rewrite_title()) {
135
+
136
+ $handlers = ob_list_handlers();
137
+ if (count($handlers) > 0 && strcasecmp($handlers[count($handlers)-1], 'SU_Titles::change_title_tag') == 0)
138
+ ob_end_flush();
139
+ else
140
+ su_debug_log(__FILE__, __CLASS__, __FUNCTION__, __LINE__, "Other ob_list_handlers found:\n".print_r($handlers, true));
141
+ }
142
+ }
143
+
144
+ function change_title_tag($head) {
145
+
146
+ $title = $this->get_title();
147
+ if (!$title) return $head;
148
+ // Pre-parse the title replacement text to escape the $ ($n backreferences) when followed by a number 0-99 because of preg_replace issue
149
+ $title = preg_replace('/\$(\d)/', '\\\$$1', $title);
150
+ //Replace the old title with the new and return
151
+ return preg_replace('/<title>[^<]*<\/title>/i', '<title>'.$title.'</title>', $head);
152
+ }
153
+
154
+ function get_title() {
155
+
156
+ global $wp_query, $wp_locale;
157
+
158
+ //Custom post/page title?
159
+ if ($post_title = $this->get_postmeta('title'))
160
+ return htmlspecialchars($this->get_title_paged($post_title));
161
+
162
+ //Custom taxonomy title?
163
+ if (suwp::is_tax()) {
164
+ $tax_titles = $this->get_setting('taxonomy_titles');
165
+ if ($tax_title = $tax_titles[$wp_query->get_queried_object_id()])
166
+ return htmlspecialchars($this->get_title_paged($tax_title));
167
+ }
168
+
169
+ //Get format
170
+ if (!$this->should_rewrite_title()) return '';
171
+ if (!($format = $this->get_title_format())) return '';
172
+
173
+ //Load post/page titles
174
+ $post_id = 0;
175
+ $post_title = '';
176
+ $parent_title = '';
177
+ if (is_singular()) {
178
+ $post = $wp_query->get_queried_object();
179
+ $post_title = strip_tags( apply_filters( 'single_post_title', $post->post_title ) );
180
+ $post_id = $post->ID;
181
+
182
+ if ($parent = $post->post_parent) {
183
+ $parent = get_post($parent);
184
+ $parent_title = strip_tags( apply_filters( 'single_post_title', $parent->post_title ) );
185
+ }
186
+ }
187
+
188
+ //Load date-based archive titles
189
+ if ($m = get_query_var('m')) {
190
+ $year = substr($m, 0, 4);
191
+ $monthnum = intval(substr($m, 4, 2));
192
+ $daynum = intval(substr($m, 6, 2));
193
+ } else {
194
+ $year = get_query_var('year');
195
+ $monthnum = get_query_var('monthnum');
196
+ $daynum = get_query_var('day');
197
+ }
198
+ $month = $wp_locale->get_month($monthnum);
199
+ $monthnum = zeroise($monthnum, 2);
200
+ $day = date('jS', mktime(12,0,0,$monthnum,$daynum,$year));
201
+ $daynum = zeroise($daynum, 2);
202
+
203
+ //Load category titles
204
+ $cat_title = $cat_titles = $cat_desc = '';
205
+ if (is_category()) {
206
+ $cat_title = single_cat_title('', false);
207
+ $cat_desc = category_description();
208
+ } elseif (count($categories = get_the_category())) {
209
+ $cat_titles = su_lang_implode($categories, 'name');
210
+ usort($categories, '_usort_terms_by_ID');
211
+ $cat_title = $categories[0]->name;
212
+ $cat_desc = category_description($categories[0]->term_id);
213
+ }
214
+ if (strlen($cat_title) && $this->get_setting('terms_ucwords', true))
215
+ $cat_title = sustr::tclcwords($cat_title);
216
+
217
+ //Load tag titles
218
+ $tag_title = $tag_desc = '';
219
+ if (is_tag()) {
220
+ $tag_title = single_tag_title('', false);
221
+ $tag_desc = tag_description();
222
+
223
+ if ($this->get_setting('terms_ucwords', true))
224
+ $tag_title = sustr::tclcwords($tag_title);
225
+ }
226
+
227
+ //Load author titles
228
+ if (is_author()) {
229
+ $author_obj = $wp_query->get_queried_object();
230
+ } elseif (is_singular()) {
231
+ global $authordata;
232
+ $author_obj = $authordata;
233
+ } else {
234
+ $author_obj = null;
235
+ }
236
+ if ($author_obj)
237
+ $author = array(
238
+ 'username' => $author_obj->user_login
239
+ , 'name' => $author_obj->display_name
240
+ , 'firstname' => get_the_author_meta('first_name', $author_obj->ID)
241
+ , 'lastname' => get_the_author_meta('last_name', $author_obj->ID)
242
+ , 'nickname' => get_the_author_meta('nickname', $author_obj->ID)
243
+ );
244
+ else
245
+ $author = array(
246
+ 'username' => ''
247
+ , 'name' => ''
248
+ , 'firstname' => ''
249
+ , 'lastname' => ''
250
+ , 'nickname' => ''
251
+ );
252
+
253
+ $variables = array(
254
+ '{blog}' => get_bloginfo('name')
255
+ , '{tagline}' => get_bloginfo('description')
256
+ , '{post}' => $post_title
257
+ , '{page}' => $post_title
258
+ , '{page_parent}' => $parent_title
259
+ , '{category}' => $cat_title
260
+ , '{categories}' => $cat_titles
261
+ , '{category_description}' => $cat_desc
262
+ , '{tag}' => $tag_title
263
+ , '{tag_description}' => $tag_desc
264
+ , '{tags}' => su_lang_implode(get_the_tags($post_id), 'name', true)
265
+ , '{daynum}' => $daynum
266
+ , '{day}' => $day
267
+ , '{monthnum}' => $monthnum
268
+ , '{month}' => $month
269
+ , '{year}' => $year
270
+ , '{author}' => $author['name']
271
+ , '{author_name}' => $author['name']
272
+ , '{author_username}' => $author['username']
273
+ , '{author_firstname}' => $author['firstname']
274
+ , '{author_lastname}' => $author['lastname']
275
+ , '{author_nickname}' => $author['nickname']
276
+ , '{query}' => su_esc_attr(get_search_query())
277
+ , '{ucquery}' => su_esc_attr(ucwords(get_search_query()))
278
+ , '{url_words}' => $this->get_url_words($_SERVER['REQUEST_URI'])
279
+ );
280
+
281
+ $title = str_replace(array_keys($variables), array_values($variables), htmlspecialchars($format));
282
+
283
+ return $this->get_title_paged($title);
284
+ }
285
+
286
+ function get_title_paged($title) {
287
+
288
+ global $wp_query, $numpages;
289
+
290
+ if (is_paged() || get_query_var('page')) {
291
+
292
+ if (is_paged()) {
293
+ $num = absint(get_query_var('paged'));
294
+ $max = absint($wp_query->max_num_pages);
295
+ } else {
296
+ $num = absint(get_query_var('page'));
297
+
298
+ if (is_singular()) {
299
+ $post = $wp_query->get_queried_object();
300
+ $max = count(explode('<!--nextpage-->', $post->post_content));
301
+ } else
302
+ $max = '';
303
+ }
304
+
305
+ return str_replace(
306
+ array('{title}', '{num}', '{max}'),
307
+ array( $title, $num, $max ),
308
+ $this->get_setting('title_paged'));
309
+ } else
310
+ return $title;
311
+ }
312
+
313
+ function get_url_words($url) {
314
+
315
+ //Remove any extensions (.html, .php, etc)
316
+ $url = preg_replace('|\\.[a-zA-Z]{1,4}$|', ' ', $url);
317
+
318
+ //Turn slashes to >>
319
+ $url = str_replace('/', ' &raquo; ', $url);
320
+
321
+ //Remove word separators
322
+ $url = str_replace(array('.', '/', '-'), ' ', $url);
323
+
324
+ //Capitalize the first letter of every word
325
+ $url = explode(' ', $url);
326
+ $url = array_map('trim', $url);
327
+ $url = array_map('ucwords', $url);
328
+ $url = implode(' ', $url);
329
+ $url = trim($url);
330
+
331
+ return $url;
332
+ }
333
+
334
+ function postmeta_fields($fields, $screen) {
335
+ $id = "_su_title";
336
+ $value = su_esc_attr($this->get_postmeta('title'));
337
+ $fields['serp'][10]['title'] =
338
+ "<div class='form-group su textbox'>\n<label class='col-sm-4 col-md-4 control-label' for='$id'>".__('Title Tag:', 'seo-ultimate')."</label>\n<div class='col-sm-4 col-md-4'><input name='$id' id='$id' type='text' value='$value' class='form-control input-sm regular-text' tabindex='2'"
339
+ . " onkeyup=\"javascript:document.getElementById('su_title_charcount').innerHTML = document.getElementById('_su_title').value.length\" />"
340
+ . "</div>\n<div class='col-sm-4 col-md-4 help-text'>".sprintf(__('You&#8217;ve entered %s characters. Most search engines use up to 70.', 'seo-ultimate'), "<strong id='su_title_charcount'>".strlen($value)."</strong>")
341
+ . "</div>\n</div>\n";
342
+
343
+
344
+ return $fields;
345
+ }
346
+
347
+ function postmeta_help($help) {
348
+ $help[] = __('<strong>Title Tag</strong> &mdash; The exact contents of the &lt;title&gt; tag. The title appears in visitors&#8217; title bars and in search engine result titles. 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');
349
+ return $help;
350
+ }
351
+
352
+ function add_help_tabs($screen) {
353
+
354
+ $screen->add_help_tab(array(
355
+ 'id' => 'su-titles-overview'
356
+ , 'title' => __('Overview', 'seo-ultimate')
357
+ , 'content' => __("
358
+ <ul>
359
+ <li><strong>What it does:</strong> Title Tag Rewriter helps you customize the contents of your website&#8217;s <code>&lt;title&gt;</code> tags. The tag contents are displayed in web browser title bars and in search engine result pages.</li>
360
+ <li><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. This is an important foundation for WordPress SEO.</li>
361
+ <li><strong>How to use it:</strong> Title Tag Rewriter enables recommended settings automatically, so you shouldn&#8217;t need to change anything. If you do wish to edit the rewriting formats, you can do so using the textboxes below (the &#8220;Formats & Variables&#8221; help tab includes additional information on this). You also have the option of overriding the <code>&lt;title&gt;</code> tag of an individual post/page/category/tag/etc. using the appropriate tabs below, or by using the &#8220;Title Tag&#8221; textbox that Title Tag Rewriter adds to the post/page editors.</li>
362
+ </ul>
363
+ ", 'seo-ultimate')));
364
+
365
+ $screen->add_help_tab(array(
366
+ 'id' => 'su-titles-vars'
367
+ , 'title' => __('Default Formats Tab', 'seo-ultimate')
368
+ , 'content' => __("
369
+ <p>Various variables, surrounded in {curly brackets}, are provided for use in the title formats. All settings support the {blog} variable, which is replaced with the name of the blog, and the {tagline} variable, which is replaced with the blog tagline as set under <a href='options-general.php'>Settings &rArr; General</a>.</p>
370
+
371
+ <p>Here&#8217;s information on each of the settings and its supported variables:</p>
372
+
373
+ <ul>
374
+ <li><strong>Blog Homepage Title</strong> &mdash; Displays on the main blog posts page.</li>
375
+ <li>
376
+ <p><strong>Post Title Format</strong> &mdash; Displays on single-post pages. Supports these variables:</p>
377
+ <ul>
378
+ <li>{post} &mdash; The post&#8217;s title.</li>
379
+ <li>{category} &mdash; The title of the post category with the lowest ID number.</li>
380
+ <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>
381
+ <li>{tags} &mdash; A natural-language list of the post's tags (e.g. &#8220;Tag A, Tag B, and Tag C&#8221;).</li>
382
+ <li>{author} &mdash; The Display Name of the post's author.</li>
383
+ <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>
384
+ </ul>
385
+ </li>
386
+ <li>
387
+ <p><strong>Page Title Format</strong> &mdash; Displays on WordPress Pages. Supports these variables:
388
+ <ul>
389
+ <li>{page} &mdash; The page&#8217;s title.</li>
390
+ <li>{page_parent} &mdash; The title of the page&#8217;s parent page.</li>
391
+ <li>{author} &mdash; The Display Name of the page&#8217;s author.</li>
392
+ <li>{author_username}, {author_firstname}, {author_lastname}, {author_nickname} &mdash; The username, first name, last name, and nickname of the page&#8217;s author, respectively, as set in his or her profile.</li>
393
+ </ul>
394
+ </li>
395
+ <li><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.</li>
396
+ <li><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.</li>
397
+ <li>
398
+ <p><strong>Day Archive Title Format</strong> &mdash; Displays on day archives. Supports these variables:</p>
399
+ <ul>
400
+ <li>{day} &mdash; The day number, with ordinal suffix, e.g. 23rd</li>
401
+ <li>{daynum} &mdash; The two-digit day number, e.g. 23</li>
402
+ <li>{month} &mdash; The name of the month, e.g. April</li>
403
+ <li>{monthnum} &mdash; The two-digit number of the month, e.g. 04</li>
404
+ <li>{year} &mdash; The year, e.g. 2009</li>
405
+ </ul>
406
+ </li>
407
+ <li><strong>Month Archive Title Format</strong> &mdash; Displays on month archives. Supports {month}, {monthnum}, and {year}.</li>
408
+ <li><strong>Year Archive Title Format</strong> &mdash; Displays on year archives. Supports the {year} variable.</li>
409
+ <li><strong>Author Archive Title Format</strong> &mdash; 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}.</li>
410
+ <li><strong>Search Title Format</strong> &mdash; Displays on the result pages for WordPress&#8217;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.</li>
411
+ <li>
412
+ <p><strong>404 Title Format</strong> &mdash; Displays whenever a URL doesn&#8217;t go anywhere. Supports this variable:</p>
413
+ <ul>
414
+ <li>{url_words} &mdash; The words used in the error-generating URL. The first letter of each word will be capitalized.</li>
415
+ </ul>
416
+ </li>
417
+ <li>
418
+ <p><strong>Pagination Title Format</strong> &mdash; Displays whenever the visitor is on a subpage (page 2, page 3, etc.) of the homepage or of an archive. Supports these variables:</p>
419
+ <ul>
420
+ <li>{title} &mdash; The title that would normally be displayed on page 1</li>
421
+ <li>{num} &mdash; The current page number (2, 3, etc.)</li>
422
+ <li>{max} &mdash; The total number of subpages available. Would usually be used like this: Page {num} of {max}</li>
423
+ </ul>
424
+ </li>
425
+ </ul>
426
+ ", 'seo-ultimate')));
427
+
428
+ $screen->add_help_tab(array(
429
+ 'id' => 'su-titles-settings'
430
+ , 'title' => __('Settings Tab', 'seo-ultimate')
431
+ , 'content' => __("
432
+ <p>Here&#8217;s documentation for the options on the &#8220;Settings&#8221; tab.</p>
433
+ <ul>
434
+ <li><strong>Convert lowercase category/tag names to title case when used in title tags</strong> &mdash; If your Tag Title Format is set to <code>{tag} | {blog}</code> and you have a tag called &#8220;blue widgets,&#8221; your title tag would be <code>blue widgets | My WordPress Blog</code>. Enabling this setting would capitalize the words in &#8220;blue widgets&#8221; so that the title tag would be <code>Blue Widgets | My WordPress Blog</code> instead.</li>
435
+ <li>
436
+ <p><strong>Rewrite Method</strong> &mdash; This setting controls the method by which Title Tag Rewriter edits your site&#8217;s <code>&lt;title&gt;</code> tags.</p>
437
+ <ul>
438
+ <li><strong>Use output buffering</strong> &mdash; This is the &#8220;traditional&#8221; method that most SEO plugins use.
439
+ With this method, SEO Ultimate will intercept your site&#8217;s <code>&lt;head&gt;</code> tag section as it&#8217;s being outputted,
440
+ locate the <code>&lt;title&gt;</code> tag, edit its value, and then output the edited <code>&lt;head&gt;</code> data.
441
+ The good thing about this method is that you don&#8217;t have to edit your theme in any way, as SEO Ultimate will overwrite
442
+ whatever your theme puts in your <code>&lt;title&gt;</code> tag. The bad thing is that this output interception takes a few extra
443
+ milliseconds to complete. If you are concerned about performance, are comfortable editing your theme&#8217;s header.php file,
444
+ and will remember to edit the header.php file of any new themes you activate, you may want to try the filtering rewrite method.</li>
445
+ <li>
446
+ <p><strong>Use filtering</strong> &mdash; With this method, SEO Ultimate will register itself with WordPress and will replace
447
+ WordPress&#8217;s <code>&lt;title&gt;</code> tag output with its own. This method can only edit the text that WordPress itself
448
+ generates for the <code>&lt;title&gt;</code> tag; the filtering method can&#8217;t edit anything extra your theme may add.
449
+ For this reason, you need to edit your theme to make sure it&#8217;s only pulling <code>&lt;title&gt;</code> tag data from WordPress
450
+ and is not adding anything else.</p>
451
+ <p>Here&#8217;s how to set up filtering:</p>
452
+ <ol>
453
+ <li>Go to <a href='theme-editor.php'>Appearance &rArr; Editor</a> (if you get a permissions error, you may be on a WordPress multi-site environment and may not be able to use the filtering rewrite method)</li>
454
+ <li>Click &#8220;Header (header.php)&#8221;</li>
455
+ <li>Look for the <code>&lt;title&gt;</code> start tag and the <code>&lt;/title&gt;</code> end tag</li>
456
+ <li>Edit the text in between those tags so that it looks like this: <code>&lt;title&gt;&lt;?php wp_title(''); ?&gt;&lt;/title&gt;</code></li>
457
+ <li>Click &#8220;Update File&#8221;</li>
458
+ <li>Return to the &#8220;Settings&#8221; tab of Title Tag Rewriter, select &#8220;Use filtering,&#8221; and click &#8220;Save Changes&#8221;</li>
459
+ </ol>
460
+ </li>
461
+ </ul>
462
+ </li>
463
+ </ul>
464
+ ", 'seo-ultimate')));
465
+
466
+ $screen->add_help_tab(array(
467
+ 'id' => 'su-titles-faq'
468
+ , 'title' => __('FAQ', 'seo-ultimate')
469
+ , 'content' => __("
470
+ <ul>
471
+ <li><strong>Does the Title Tag Rewriter edit my post/page titles?</strong><br />No. The Title Tag Rewriter edits the <code>&lt;title&gt;</code> tags of your site, not your post/page titles.</li>
472
+ <li><strong>Will rewriting the title tags of my posts change their permalinks/URLs?</strong><br />No.</li>
473
+ <li><strong>What&#8217;s the difference between the &#8220;title&#8221; and the &#8220;title tag&#8221; of a post/page?</strong><br />The &#8220;title&#8221; is the title of your post or page that&#8217;s used in your site&#8217;s theme, in your site&#8217;s admin, in your site&#8217;s RSS feeds, and in your site&#8217;s <code>&lt;title&gt;</code> tags. A <code>&lt;title&gt;</code> tag is the title of a specific webpage, and it appears in your browser&#8217;s title bar and in search result listings. Title Tag Rewriter lets you edit your post&#8217;s <code>&lt;title&gt;</code> tags without editing their actual titles. This means you can edit a post&#8217;s title as it appears in search results, but not as it appears on your site.</li>
474
+ </ul>
475
+ ", 'seo-ultimate')));
476
+
477
+ $screen->add_help_tab(array(
478
+ 'id' => 'su-titles-troubleshooting'
479
+ , 'title' => __('Troubleshooting', 'seo-ultimate')
480
+ , 'content' => __("
481
+ <ul>
482
+ <li><strong>Why isn&#8217;t Title Tag Rewriter changing my <code>&lt;title&gt;</code> tags?</strong><br />Try disabling other SEO plugins, as they may be conflicting with SEO Ultimate. If you&#8217;re using the default &#8220;output buffering&#8221; rewrite method, check to make sure your theme is <a href='http://johnlamansky.com/wordpress/theme-plugin-hooks/' target='_blank'>plugin-friendly</a>. If you're using the &#8220;filtering&#8221; rewrite method, check your theme&#8217;s <code>header.php</code> file and make sure the <code>&lt;title&gt;</code> tag looks like this: <code>&lt;title&gt;&lt;?php wp_title(''); ?&gt;&lt;/title&gt;</code>.</li>
483
+ </ul>
484
+ ", 'seo-ultimate')));
485
+ }
486
+ }
487
+
488
+ }
489
  ?>
modules/user-code/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/user-code/user-code.php CHANGED
@@ -1,126 +1,126 @@
1
- <?php
2
- /**
3
- * Code Inserter Module
4
- *
5
- * @since 2.7
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- function su_user_code_import_filter($all_settings) {
11
-
12
- if (!SU_UserCode::user_authorized())
13
- unset($all_settings['user-code']);
14
-
15
- return $all_settings;
16
- }
17
- add_filter('su_settings_import_array', 'su_user_code_import_filter');
18
-
19
- class SU_UserCode extends SU_Module {
20
-
21
- static function get_module_title() { return __('Code Inserter', 'seo-ultimate'); }
22
- static function get_menu_title() { return __('Code Inserter', 'seo-ultimate'); }
23
-
24
- function get_default_settings() {
25
- return array(
26
- 'global_wp_head' => $this->flush_setting('custom_html', '', 'meta')
27
- );
28
- }
29
-
30
- function get_default_status() {
31
- if (is_multisite())
32
- return SU_MODULE_DISABLED;
33
-
34
- return SU_MODULE_ENABLED;
35
- }
36
-
37
- function user_authorized() {
38
- return current_user_can('unfiltered_html');
39
- }
40
-
41
- function init() {
42
- $hooks = array('su_head', 'the_content', 'wp_footer');
43
- foreach ($hooks as $hook) add_filter($hook, array(&$this, "{$hook}_code"), 'su_head' == $hook ? 11 : 10);
44
- }
45
-
46
-
47
-
48
- function admin_page_contents() {
49
-
50
- if ($this->should_show_sdf_theme_promo()) {
51
- echo "\n\n<div class='row'>\n";
52
- echo "\n\n<div class='col-sm-8 col-md-9'>\n";
53
- }
54
-
55
- $this->admin_form_start(false, false);
56
- $textareas = array(
57
- 'wp_head' => __('&lt;head&gt; Tag', 'seo-ultimate')
58
- , 'the_content_before' => __('Before Item Content', 'seo-ultimate')
59
- , 'the_content_after' => __('After Item Content', 'seo-ultimate')
60
- , 'wp_footer' => __('Footer', 'seo-ultimate')
61
- );
62
- $textareas = suarr::aprintf("global_%s", false, $textareas);
63
- $this->textareas($textareas, 5, 30, array('disabled' => !$this->user_authorized()));
64
- $this->admin_form_end(null, false);
65
-
66
- if ($this->should_show_sdf_theme_promo()) {
67
- echo "\n\n</div>\n";
68
- echo "\n\n<div class='col-sm-4 col-md-3'>\n";
69
- $this->promo_sdf_banners();
70
- echo "\n\n</div>\n";
71
- echo "\n\n</div>\n";
72
- }
73
- }
74
-
75
- function get_usercode($field) {
76
-
77
- $code = $this->get_setting("global_$field", '');
78
- if (is_front_page()) $code .= $this->get_setting("frontpage_$field", '');
79
-
80
- return $this->plugin->mark_code($code, __('Code Inserter module', 'seo-ultimate'), $field == 'wp_head');
81
- }
82
-
83
- function su_head_code() {
84
- echo $this->get_usercode('wp_head');
85
- }
86
-
87
- function wp_footer_code() {
88
- echo $this->get_usercode('wp_footer');
89
- }
90
-
91
- function the_content_code($content) {
92
- return $this->get_usercode('the_content_before') . $content . $this->get_usercode('the_content_after');
93
- }
94
-
95
- function add_help_tabs($screen) {
96
-
97
- $screen->add_help_tab(array(
98
- 'id' => 'su-user-code-overview'
99
- , 'title' => __('Overview', 'seo-ultimate')
100
- , 'content' => __("
101
- <ul>
102
- <li><strong>What it does:</strong> Code Inserter can add custom HTML code to various parts of your site.</li>
103
- <li>
104
- <p><strong>Why it helps:</strong> Code Inserter is useful for inserting third-party code that can improve the SEO or user experience of your site. For example, you can use Code Inserter to add Google Analytics code to your footer, Feedburner FeedFlares or social media widgets after your posts, or Google AdSense section targeting code before/after your content.</p>
105
- <p>Using Code Inserter is easier than editing your theme manually because your custom code is stored in one convenient location and will be added to your site even if you change your site&#8217;s theme.</p>
106
- </li>
107
- <li><strong>How to use it:</strong> Just paste the desired HTML code into the appropriate fields and then click Save Changes.</li>
108
- </ul>
109
- ", 'seo-ultimate')));
110
-
111
- $screen->add_help_tab(array(
112
- 'id' => 'su-user-code-troubleshooting'
113
- , 'title' => __('Troubleshooting', 'seo-ultimate')
114
- , 'content' => __("
115
- <ul>
116
- <li><p><strong>Why do I get a message saying my account doesn&#8217;t have permission to insert arbitrary HTML code?</strong><br />WordPress has a security feature that only allows administrators to insert arbitrary, unfiltered HTML into the site. On single-site setups, site administrators have this capability. On multisite setups, only network admins have this capability. This is done for security reasons, since site users with the ability to insert arbitrary HTML could theoretically insert malicious code that could be used to hijack control of the site.</p><p>If you are the administrator of a site running on a network, then you will not be able to use Code Inserter under default security settings. However, the network administrator <em>will</em> be able to edit the fields on this page. If you have code that you really want inserted into a certain part of your site, ask your network administrator to do it for you.</p><p>If you are the network administrator of a multisite WordPress setup, and you completely trust all of the administrators and editors of the various sites on your network, you can install the <a href='http://wordpress.org/extend/plugins/unfiltered-mu/' target='_blank'>Unfiltered MU</a> plugin to enable the Code Inserter for all of those users.</p></li>
117
- <li><strong>Why doesn't my code appear on my site?</strong><br />It&#8217;s possible that your theme doesn't have the proper &#8220;hooks,&#8221; which are pieces of code that let WordPress plugins insert custom HTML into your theme. <a href='http://johnlamansky.com/wordpress/theme-plugin-hooks/' target='_blank'>Click here</a> for information on how to check your theme and add the hooks if needed.</li>
118
- </ul>
119
- ", 'seo-ultimate')));
120
-
121
- }
122
- }
123
-
124
- }
125
-
126
  ?>
1
+ <?php
2
+ /**
3
+ * Code Inserter Module
4
+ *
5
+ * @since 2.7
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ function su_user_code_import_filter($all_settings) {
11
+
12
+ if (!SU_UserCode::user_authorized())
13
+ unset($all_settings['user-code']);
14
+
15
+ return $all_settings;
16
+ }
17
+ add_filter('su_settings_import_array', 'su_user_code_import_filter');
18
+
19
+ class SU_UserCode extends SU_Module {
20
+
21
+ static function get_module_title() { return __('Code Inserter', 'seo-ultimate'); }
22
+ static function get_menu_title() { return __('Code Inserter', 'seo-ultimate'); }
23
+
24
+ function get_default_settings() {
25
+ return array(
26
+ 'global_wp_head' => $this->flush_setting('custom_html', '', 'meta')
27
+ );
28
+ }
29
+
30
+ function get_default_status() {
31
+ if (is_multisite())
32
+ return SU_MODULE_DISABLED;
33
+
34
+ return SU_MODULE_ENABLED;
35
+ }
36
+
37
+ function user_authorized() {
38
+ return current_user_can('unfiltered_html');
39
+ }
40
+
41
+ function init() {
42
+ $hooks = array('su_head', 'the_content', 'wp_footer');
43
+ foreach ($hooks as $hook) add_filter($hook, array(&$this, "{$hook}_code"), 'su_head' == $hook ? 11 : 10);
44
+ }
45
+
46
+
47
+
48
+ function admin_page_contents() {
49
+
50
+ if ($this->should_show_sdf_theme_promo()) {
51
+ echo "\n\n<div class='row'>\n";
52
+ echo "\n\n<div class='col-sm-8 col-md-9'>\n";
53
+ }
54
+
55
+ $this->admin_form_start(false, false);
56
+ $textareas = array(
57
+ 'wp_head' => __('&lt;head&gt; Tag', 'seo-ultimate')
58
+ , 'the_content_before' => __('Before Item Content', 'seo-ultimate')
59
+ , 'the_content_after' => __('After Item Content', 'seo-ultimate')
60
+ , 'wp_footer' => __('Footer', 'seo-ultimate')
61
+ );
62
+ $textareas = suarr::aprintf("global_%s", false, $textareas);
63
+ $this->textareas($textareas, 5, 30, array('disabled' => !$this->user_authorized()));
64
+ $this->admin_form_end(null, false);
65
+
66
+ if ($this->should_show_sdf_theme_promo()) {
67
+ echo "\n\n</div>\n";
68
+ echo "\n\n<div class='col-sm-4 col-md-3'>\n";
69
+ $this->promo_sdf_banners();
70
+ echo "\n\n</div>\n";
71
+ echo "\n\n</div>\n";
72
+ }
73
+ }
74
+
75
+ function get_usercode($field) {
76
+
77
+ $code = $this->get_setting("global_$field", '');
78
+ if (is_front_page()) $code .= $this->get_setting("frontpage_$field", '');
79
+
80
+ return $this->plugin->mark_code($code, __('Code Inserter module', 'seo-ultimate'), $field == 'wp_head');
81
+ }
82
+
83
+ function su_head_code() {
84
+ echo $this->get_usercode('wp_head');
85
+ }
86
+
87
+ function wp_footer_code() {
88
+ echo $this->get_usercode('wp_footer');
89
+ }
90
+
91
+ function the_content_code($content) {
92
+ return $this->get_usercode('the_content_before') . $content . $this->get_usercode('the_content_after');
93
+ }
94
+
95
+ function add_help_tabs($screen) {
96
+
97
+ $screen->add_help_tab(array(
98
+ 'id' => 'su-user-code-overview'
99
+ , 'title' => __('Overview', 'seo-ultimate')
100
+ , 'content' => __("
101
+ <ul>
102
+ <li><strong>What it does:</strong> Code Inserter can add custom HTML code to various parts of your site.</li>
103
+ <li>
104
+ <p><strong>Why it helps:</strong> Code Inserter is useful for inserting third-party code that can improve the SEO or user experience of your site. For example, you can use Code Inserter to add Google Analytics code to your footer, Feedburner FeedFlares or social media widgets after your posts, or Google AdSense section targeting code before/after your content.</p>
105
+ <p>Using Code Inserter is easier than editing your theme manually because your custom code is stored in one convenient location and will be added to your site even if you change your site&#8217;s theme.</p>
106
+ </li>
107
+ <li><strong>How to use it:</strong> Just paste the desired HTML code into the appropriate fields and then click Save Changes.</li>
108
+ </ul>
109
+ ", 'seo-ultimate')));
110
+
111
+ $screen->add_help_tab(array(
112
+ 'id' => 'su-user-code-troubleshooting'
113
+ , 'title' => __('Troubleshooting', 'seo-ultimate')
114
+ , 'content' => __("
115
+ <ul>
116
+ <li><p><strong>Why do I get a message saying my account doesn&#8217;t have permission to insert arbitrary HTML code?</strong><br />WordPress has a security feature that only allows administrators to insert arbitrary, unfiltered HTML into the site. On single-site setups, site administrators have this capability. On multisite setups, only network admins have this capability. This is done for security reasons, since site users with the ability to insert arbitrary HTML could theoretically insert malicious code that could be used to hijack control of the site.</p><p>If you are the administrator of a site running on a network, then you will not be able to use Code Inserter under default security settings. However, the network administrator <em>will</em> be able to edit the fields on this page. If you have code that you really want inserted into a certain part of your site, ask your network administrator to do it for you.</p><p>If you are the network administrator of a multisite WordPress setup, and you completely trust all of the administrators and editors of the various sites on your network, you can install the <a href='http://wordpress.org/extend/plugins/unfiltered-mu/' target='_blank'>Unfiltered MU</a> plugin to enable the Code Inserter for all of those users.</p></li>
117
+ <li><strong>Why doesn't my code appear on my site?</strong><br />It&#8217;s possible that your theme doesn't have the proper &#8220;hooks,&#8221; which are pieces of code that let WordPress plugins insert custom HTML into your theme. <a href='http://johnlamansky.com/wordpress/theme-plugin-hooks/' target='_blank'>Click here</a> for information on how to check your theme and add the hooks if needed.</li>
118
+ </ul>
119
+ ", 'seo-ultimate')));
120
+
121
+ }
122
+ }
123
+
124
+ }
125
+
126
  ?>
modules/widgets/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/widgets/widgets.php CHANGED
@@ -1,243 +1,243 @@
1
- <?php
2
- /**
3
- * Widgets Module
4
- *
5
- * @since 6.6
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_Widgets extends SU_Module {
11
-
12
- static function get_module_title() { return __('SEO Ultimate Widgets', 'seo-ultimate'); }
13
- static function get_menu_title() { return false; }
14
-
15
- function get_admin_url($key = false) {
16
-
17
- if ($key)
18
- return parent::get_admin_url($key);
19
-
20
- if (is_network_admin())
21
- return false;
22
-
23
- return 'widgets.php';
24
- }
25
-
26
- function __construct() {
27
- add_action('widgets_init', array(&$this, 'register_widgets'));
28
- }
29
-
30
- function register_widgets() {
31
- register_widget('SU_Widget_SiloedTerms');
32
-
33
- if ($this->plugin->module_exists('footer-autolinks'))
34
- register_widget('SU_Widget_FooterLinks');
35
- }
36
- }
37
-
38
- }
39
-
40
- if (class_exists('WP_Widget')) {
41
-
42
- //Based on WordPress' WP_Widget_Categories & WP_Widget_Tag_Cloud
43
- class SU_Widget_SiloedTerms extends WP_Widget {
44
-
45
- function __construct() {
46
- $widget_ops = array( 'description' => __( "On category archives, displays a list of child categories and/or posts in the category. Displays a list of top-level categories everywhere else. Powered by the SEO Ultimate plugin.", 'seo-ultimate' ) );
47
- parent::__construct('su_siloed_terms', __('Siloed Categories', 'seo-ultimate'), $widget_ops);
48
- }
49
-
50
- function widget( $args, $instance ) {
51
- global $wp_query;
52
-
53
- extract( $args );
54
-
55
- $current_taxonomy = $this->_get_current_taxonomy($instance);
56
-
57
- if ( !empty($instance['title']) ) {
58
- $title = $instance['title'];
59
- } else {
60
- if ( 'post_tag' == $current_taxonomy ) {
61
- $title = __('Tags');
62
- } else {
63
- $tax = get_taxonomy($current_taxonomy);
64
- $title = $tax->labels->name;
65
- }
66
- }
67
-
68
- $use_desc_for_title = isset($instance['use_desc_for_title']) ? $instance['use_desc_for_title'] : true;
69
- $count = isset($instance['count']) ? $instance['count'] : false;
70
-
71
- $title = apply_filters('widget_title', $title, $instance, $this->id_base);
72
- $current_term = false;
73
- $current_term_id = $current_post_id = 0;
74
-
75
- if (suwp::is_tax($current_taxonomy)) {
76
- $current_term = $wp_query->get_queried_object();
77
- $current_term_id = $wp_query->get_queried_object_id();
78
- $title = $current_term->name;
79
- } elseif (is_singular()) {
80
- $current_post_id = $wp_query->get_queried_object_id();
81
- $post_terms = get_the_terms($current_post_id, $current_taxonomy);
82
- if (is_array($post_terms) && count($post_terms)) {
83
- $current_term = reset($post_terms);
84
- $current_term_id = $current_term->term_id;
85
- $title = $current_term->name;
86
- }
87
- }
88
-
89
- $term_args = array('taxonomy' => $current_taxonomy, 'orderby' => 'name', 'show_count' => $count ? '1' : '0', 'hierarchical' => '0', 'title_li' => '', 'parent' => $current_term_id, 'show_option_none' => false, 'use_desc_for_title' => $use_desc_for_title ? '1' : '0', 'echo' => false);
90
-
91
- $category_output = $post_output = '';
92
-
93
- if (!$current_term || is_taxonomy_hierarchical($current_taxonomy))
94
- $category_output = wp_list_categories($term_args);
95
-
96
- if ($current_term) {
97
- $child_posts = get_posts(array('taxonomy' => $current_taxonomy, 'term' => $current_term->slug, 'numberposts' => 5));
98
-
99
- foreach ($child_posts as $child_post) {
100
-
101
- $css_class = '';
102
- if ($child_post->ID == $current_post_id)
103
- $css_class = 'current_post_item';
104
-
105
- $post_output .= "\n\t\t\t<li class=\"" . $css_class . '"><a href="' . get_permalink($child_post->ID) . '" title="' . esc_attr( wp_strip_all_tags( apply_filters( 'the_title', $child_post->post_title, $child_post->ID ) ) ) . '">' . apply_filters( 'the_title', $child_post->post_title, $child_post->ID ) . "</a></li>\n";
106
- }
107
- }
108
-
109
- if ($category_output || $post_output) {
110
- echo $before_widget;
111
- if ( $title )
112
- echo $before_title . $title . $after_title;
113
- echo "\n\t\t<ul>\n";
114
- echo $category_output;
115
- echo $post_output;
116
- echo "\n\t\t</ul>\n";
117
- echo $after_widget;
118
- }
119
- }
120
-
121
- function update( $new_instance, $old_instance ) {
122
- $instance = $old_instance;
123
- $instance['title'] = strip_tags(stripslashes($new_instance['title']));
124
- $instance['taxonomy'] = stripslashes($new_instance['taxonomy']);
125
- $instance['count'] = !empty($new_instance['count']) ? 1 : 0;
126
- $instance['use_desc_for_title'] = !empty($new_instance['use_desc_for_title']) ? 1 : 0;
127
-
128
- return $instance;
129
- }
130
-
131
- function form( $instance ) {
132
- $current_taxonomy = $this->_get_current_taxonomy($instance);
133
-
134
- //Defaults
135
- $instance = wp_parse_args( (array) $instance, array( 'title' => '') );
136
- $title = esc_attr( $instance['title'] );
137
- $count = isset($instance['count']) ? (bool)$instance['count'] : false;
138
- $use_desc_for_title = isset($instance['use_desc_for_title']) ? (bool)$instance['use_desc_for_title'] : true;
139
- ?>
140
- <p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e( 'Title:', 'seo-ultimate' ); ?></label>
141
- <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo $title; ?>" /></p>
142
-
143
- <p><input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id('count'); ?>" name="<?php echo $this->get_field_name('count'); ?>"<?php checked( $count ); ?> />
144
- <label for="<?php echo $this->get_field_id('count'); ?>"><?php _e( 'Show post counts', 'seo-ultimate' ); ?></label>
145
- <br /><input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id('use_desc_for_title'); ?>" name="<?php echo $this->get_field_name('use_desc_for_title'); ?>"<?php checked( $use_desc_for_title ); ?> />
146
- <label for="<?php echo $this->get_field_id('use_desc_for_title'); ?>"><?php _e( 'Use term descriptions in title attributes', 'seo-ultimate' ); ?></label></p>
147
-
148
- <p><label for="<?php echo $this->get_field_id('taxonomy'); ?>"><?php _e('Taxonomy:', 'seo-ultimate') ?></label>
149
- <select class="widefat" id="<?php echo $this->get_field_id('taxonomy'); ?>" name="<?php echo $this->get_field_name('taxonomy'); ?>">
150
- <?php foreach ( get_object_taxonomies('post') as $taxonomy ) :
151
- $tax = get_taxonomy($taxonomy);
152
- if ( empty($tax->labels->name) )
153
- continue;
154
- ?>
155
- <option value="<?php echo esc_attr($taxonomy) ?>" <?php selected($taxonomy, $current_taxonomy) ?>><?php echo $tax->labels->name; ?></option>
156
- <?php endforeach; ?>
157
- </select></p>
158
- <?php
159
- }
160
-
161
- function _get_current_taxonomy($instance) {
162
- if ( !empty($instance['taxonomy']) && taxonomy_exists($instance['taxonomy']) )
163
- return $instance['taxonomy'];
164
-
165
- return 'category';
166
- }
167
-
168
- }
169
-
170
- class SU_Widget_FooterLinks extends WP_Widget {
171
-
172
- function __construct() {
173
- $widget_ops = array( 'description' => __( "Add this widget to display Deeplink Juggernaut&#8217;s Footer Links in a widget area of your choosing rather than the default wp_footer section. Powered by the SEO Ultimate plugin.", 'seo-ultimate' ) );
174
- parent::__construct('su_footer_autolinks', __('Footer Links', 'seo-ultimate'), $widget_ops);
175
- }
176
-
177
- function widget( $args, $instance ) {
178
-
179
- extract( $args );
180
-
181
- global $seo_ultimate;
182
- $display = empty($instance['display']) ? 'list' : $instance['display'];
183
-
184
- $title = empty($instance['title']) ? false : $instance['title'];
185
- $title = apply_filters('widget_title', $title, $instance, $this->id_base);
186
-
187
- echo $before_widget;
188
- if ( $title )
189
- echo $before_title . $title . $after_title;
190
-
191
- switch ($display) {
192
- case 'list':
193
- $args = array(
194
- 'footer_link_section_format' => "\n\t\t<ul>{links}\n\t\t</ul>\n"
195
- , 'footer_link_format' => "\n\t\t\t<li>{link}</li>"
196
- , 'footer_link_sep' => ''
197
- );
198
- break;
199
-
200
- default:
201
- $args = array();
202
- break;
203
- }
204
-
205
- if ($seo_ultimate->call_module_func('footer-autolinks', 'autolink_footer', $unused, $args))
206
- $seo_ultimate->set_module_var('footer-autolinks', 'already_outputted', true);
207
-
208
- echo $after_widget;
209
- }
210
-
211
- function update( $new_instance, $old_instance ) {
212
- $instance = $old_instance;
213
- $instance['title'] = strip_tags(stripslashes($new_instance['title']));
214
- $instance['display'] = stripslashes($new_instance['display']);
215
-
216
- return $instance;
217
- }
218
-
219
- function form( $instance ) {
220
- global $seo_ultimate;
221
-
222
- //Defaults
223
- $instance = wp_parse_args( (array) $instance, array( 'title' => '') );
224
- $title = esc_attr( $instance['title'] );
225
- $display = empty($instance['display']) ? 'list' : $instance['display'];
226
- ?>
227
- <p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e( 'Title: <em>(optional)</em>', 'seo-ultimate' ); ?></label>
228
- <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo $title; ?>" /></p>
229
-
230
- <p>
231
- <label><input type="radio" name="<?php echo $this->get_field_name('display'); ?>" value="list" <?php checked('list', $display); ?>/> <?php _e('Display as a list', 'seo-ultimate'); ?></label><br />
232
- <label><input type="radio" name="<?php echo $this->get_field_name('display'); ?>" value="usersettings" <?php checked('usersettings', $display); ?>/> <?php
233
- $seo_ultimate->call_module_func('footer-autolinks-settings', 'get_admin_url', $formats_url);
234
- printf(__('Use my <a href="%s" target="_blank">footer link HTML formats</a>', 'seo-ultimate'), $formats_url);
235
- ?></label>
236
- </p>
237
- <?php
238
- }
239
- }
240
-
241
- }
242
-
243
  ?>
1
+ <?php
2
+ /**
3
+ * Widgets Module
4
+ *
5
+ * @since 6.6
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_Widgets extends SU_Module {
11
+
12
+ static function get_module_title() { return __('SEO Ultimate Widgets', 'seo-ultimate'); }
13
+ static function get_menu_title() { return false; }
14
+
15
+ function get_admin_url($key = false) {
16
+
17
+ if ($key)
18
+ return parent::get_admin_url($key);
19
+
20
+ if (is_network_admin())
21
+ return false;
22
+
23
+ return 'widgets.php';
24
+ }
25
+
26
+ function __construct() {
27
+ add_action('widgets_init', array(&$this, 'register_widgets'));
28
+ }
29
+
30
+ function register_widgets() {
31
+ register_widget('SU_Widget_SiloedTerms');
32
+
33
+ if ($this->plugin->module_exists('footer-autolinks'))
34
+ register_widget('SU_Widget_FooterLinks');
35
+ }
36
+ }
37
+
38
+ }
39
+
40
+ if (class_exists('WP_Widget')) {
41
+
42
+ //Based on WordPress' WP_Widget_Categories & WP_Widget_Tag_Cloud
43
+ class SU_Widget_SiloedTerms extends WP_Widget {
44
+
45
+ function __construct() {
46
+ $widget_ops = array( 'description' => __( "On category archives, displays a list of child categories and/or posts in the category. Displays a list of top-level categories everywhere else. Powered by the SEO Ultimate plugin.", 'seo-ultimate' ) );
47
+ parent::__construct('su_siloed_terms', __('Siloed Categories', 'seo-ultimate'), $widget_ops);
48
+ }
49
+
50
+ function widget( $args, $instance ) {
51
+ global $wp_query;
52
+
53
+ extract( $args );
54
+
55
+ $current_taxonomy = $this->_get_current_taxonomy($instance);
56
+
57
+ if ( !empty($instance['title']) ) {
58
+ $title = $instance['title'];
59
+ } else {
60
+ if ( 'post_tag' == $current_taxonomy ) {
61
+ $title = __('Tags');
62
+ } else {
63
+ $tax = get_taxonomy($current_taxonomy);
64
+ $title = $tax->labels->name;
65
+ }
66
+ }
67
+
68
+ $use_desc_for_title = isset($instance['use_desc_for_title']) ? $instance['use_desc_for_title'] : true;
69
+ $count = isset($instance['count']) ? $instance['count'] : false;
70
+
71
+ $title = apply_filters('widget_title', $title, $instance, $this->id_base);
72
+ $current_term = false;
73
+ $current_term_id = $current_post_id = 0;
74
+
75
+ if (suwp::is_tax($current_taxonomy)) {
76
+ $current_term = $wp_query->get_queried_object();
77
+ $current_term_id = $wp_query->get_queried_object_id();
78
+ $title = $current_term->name;
79
+ } elseif (is_singular()) {
80
+ $current_post_id = $wp_query->get_queried_object_id();
81
+ $post_terms = get_the_terms($current_post_id, $current_taxonomy);
82
+ if (is_array($post_terms) && count($post_terms)) {
83
+ $current_term = reset($post_terms);
84
+ $current_term_id = $current_term->term_id;
85
+ $title = $current_term->name;
86
+ }
87
+ }
88
+
89
+ $term_args = array('taxonomy' => $current_taxonomy, 'orderby' => 'name', 'show_count' => $count ? '1' : '0', 'hierarchical' => '0', 'title_li' => '', 'parent' => $current_term_id, 'show_option_none' => false, 'use_desc_for_title' => $use_desc_for_title ? '1' : '0', 'echo' => false);
90
+
91
+ $category_output = $post_output = '';
92
+
93
+ if (!$current_term || is_taxonomy_hierarchical($current_taxonomy))
94
+ $category_output = wp_list_categories($term_args);
95
+
96
+ if ($current_term) {
97
+ $child_posts = get_posts(array('taxonomy' => $current_taxonomy, 'term' => $current_term->slug, 'numberposts' => 5));
98
+
99
+ foreach ($child_posts as $child_post) {
100
+
101
+ $css_class = '';
102
+ if ($child_post->ID == $current_post_id)
103
+ $css_class = 'current_post_item';
104
+
105
+ $post_output .= "\n\t\t\t<li class=\"" . $css_class . '"><a href="' . get_permalink($child_post->ID) . '" title="' . esc_attr( wp_strip_all_tags( apply_filters( 'the_title', $child_post->post_title, $child_post->ID ) ) ) . '">' . apply_filters( 'the_title', $child_post->post_title, $child_post->ID ) . "</a></li>\n";
106
+ }
107
+ }
108
+
109
+ if ($category_output || $post_output) {
110
+ echo $before_widget;
111
+ if ( $title )
112
+ echo $before_title . $title . $after_title;
113
+ echo "\n\t\t<ul>\n";
114
+ echo $category_output;
115
+ echo $post_output;
116
+ echo "\n\t\t</ul>\n";
117
+ echo $after_widget;
118
+ }
119
+ }
120
+
121
+ function update( $new_instance, $old_instance ) {
122
+ $instance = $old_instance;
123
+ $instance['title'] = strip_tags(stripslashes($new_instance['title']));
124
+ $instance['taxonomy'] = stripslashes($new_instance['taxonomy']);
125
+ $instance['count'] = !empty($new_instance['count']) ? 1 : 0;
126
+ $instance['use_desc_for_title'] = !empty($new_instance['use_desc_for_title']) ? 1 : 0;
127
+
128
+ return $instance;
129
+ }
130
+
131
+ function form( $instance ) {
132
+ $current_taxonomy = $this->_get_current_taxonomy($instance);
133
+
134
+ //Defaults
135
+ $instance = wp_parse_args( (array) $instance, array( 'title' => '') );
136
+ $title = esc_attr( $instance['title'] );
137
+ $count = isset($instance['count']) ? (bool)$instance['count'] : false;
138
+ $use_desc_for_title = isset($instance['use_desc_for_title']) ? (bool)$instance['use_desc_for_title'] : true;
139
+ ?>
140
+ <p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e( 'Title:', 'seo-ultimate' ); ?></label>
141
+ <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo $title; ?>" /></p>
142
+
143
+ <p><input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id('count'); ?>" name="<?php echo $this->get_field_name('count'); ?>"<?php checked( $count ); ?> />
144
+ <label for="<?php echo $this->get_field_id('count'); ?>"><?php _e( 'Show post counts', 'seo-ultimate' ); ?></label>
145
+ <br /><input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id('use_desc_for_title'); ?>" name="<?php echo $this->get_field_name('use_desc_for_title'); ?>"<?php checked( $use_desc_for_title ); ?> />
146
+ <label for="<?php echo $this->get_field_id('use_desc_for_title'); ?>"><?php _e( 'Use term descriptions in title attributes', 'seo-ultimate' ); ?></label></p>
147
+
148
+ <p><label for="<?php echo $this->get_field_id('taxonomy'); ?>"><?php _e('Taxonomy:', 'seo-ultimate') ?></label>
149
+ <select class="widefat" id="<?php echo $this->get_field_id('taxonomy'); ?>" name="<?php echo $this->get_field_name('taxonomy'); ?>">
150
+ <?php foreach ( get_object_taxonomies('post') as $taxonomy ) :
151
+ $tax = get_taxonomy($taxonomy);
152
+ if ( empty($tax->labels->name) )
153
+ continue;
154
+ ?>
155
+ <option value="<?php echo esc_attr($taxonomy) ?>" <?php selected($taxonomy, $current_taxonomy) ?>><?php echo $tax->labels->name; ?></option>
156
+ <?php endforeach; ?>
157
+ </select></p>
158
+ <?php
159
+ }
160
+
161
+ function _get_current_taxonomy($instance) {
162
+ if ( !empty($instance['taxonomy']) && taxonomy_exists($instance['taxonomy']) )
163
+ return $instance['taxonomy'];
164
+
165
+ return 'category';
166
+ }
167
+
168
+ }
169
+
170
+ class SU_Widget_FooterLinks extends WP_Widget {
171
+
172
+ function __construct() {
173
+ $widget_ops = array( 'description' => __( "Add this widget to display Deeplink Juggernaut&#8217;s Footer Links in a widget area of your choosing rather than the default wp_footer section. Powered by the SEO Ultimate plugin.", 'seo-ultimate' ) );
174
+ parent::__construct('su_footer_autolinks', __('Footer Links', 'seo-ultimate'), $widget_ops);
175
+ }
176
+
177
+ function widget( $args, $instance ) {
178
+
179
+ extract( $args );
180
+
181
+ global $seo_ultimate;
182
+ $display = empty($instance['display']) ? 'list' : $instance['display'];
183
+
184
+ $title = empty($instance['title']) ? false : $instance['title'];
185
+ $title = apply_filters('widget_title', $title, $instance, $this->id_base);
186
+
187
+ echo $before_widget;
188
+ if ( $title )
189
+ echo $before_title . $title . $after_title;
190
+
191
+ switch ($display) {
192
+ case 'list':
193
+ $args = array(
194
+ 'footer_link_section_format' => "\n\t\t<ul>{links}\n\t\t</ul>\n"
195
+ , 'footer_link_format' => "\n\t\t\t<li>{link}</li>"
196
+ , 'footer_link_sep' => ''
197
+ );
198
+ break;
199
+
200
+ default:
201
+ $args = array();
202
+ break;
203
+ }
204
+
205
+ if ($seo_ultimate->call_module_func('footer-autolinks', 'autolink_footer', $unused, $args))
206
+ $seo_ultimate->set_module_var('footer-autolinks', 'already_outputted', true);
207
+
208
+ echo $after_widget;
209
+ }
210
+
211
+ function update( $new_instance, $old_instance ) {
212
+ $instance = $old_instance;
213
+ $instance['title'] = strip_tags(stripslashes($new_instance['title']));
214
+ $instance['display'] = stripslashes($new_instance['display']);
215
+
216
+ return $instance;
217
+ }
218
+
219
+ function form( $instance ) {
220
+ global $seo_ultimate;
221
+
222
+ //Defaults
223
+ $instance = wp_parse_args( (array) $instance, array( 'title' => '') );
224
+ $title = esc_attr( $instance['title'] );
225
+ $display = empty($instance['display']) ? 'list' : $instance['display'];
226
+ ?>
227
+ <p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e( 'Title: <em>(optional)</em>', 'seo-ultimate' ); ?></label>
228
+ <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo $title; ?>" /></p>
229
+
230
+ <p>
231
+ <label><input type="radio" name="<?php echo $this->get_field_name('display'); ?>" value="list" <?php checked('list', $display); ?>/> <?php _e('Display as a list', 'seo-ultimate'); ?></label><br />
232
+ <label><input type="radio" name="<?php echo $this->get_field_name('display'); ?>" value="usersettings" <?php checked('usersettings', $display); ?>/> <?php
233
+ $seo_ultimate->call_module_func('footer-autolinks-settings', 'get_admin_url', $formats_url);
234
+ printf(__('Use my <a href="%s" target="_blank">footer link HTML formats</a>', 'seo-ultimate'), $formats_url);
235
+ ?></label>
236
+ </p>
237
+ <?php
238
+ }
239
+ }
240
+
241
+ }
242
+
243
  ?>
modules/wp-settings/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
modules/wp-settings/wp-settings.php CHANGED
@@ -1,112 +1,112 @@
1
- <?php
2
- /**
3
- * Settings Monitor Module
4
- *
5
- * @since 6.9
6
- */
7
-
8
- if (class_exists('SU_Module')) {
9
-
10
- class SU_WpSettings extends SU_Module {
11
-
12
- var $results = array();
13
-
14
- static function get_module_title() { return __('Settings Monitor', 'seo-ultimate'); }
15
- static function get_menu_title() { return __('Settings Monitor', 'seo-ultimate'); }
16
-
17
- static function has_menu_count() { return true; }
18
- function get_menu_count() {
19
- $count = 0;
20
- foreach ($this->results as $data) {
21
- if ($data[0] == SU_RESULT_ERROR) $count++;
22
- }
23
- return $count;
24
- }
25
-
26
- function init() {
27
-
28
- if (is_admin()) {
29
- if (get_option('blog_public'))
30
- $this->results[] = array(SU_RESULT_OK, __('Blog is visible to search engines', 'seo-ultimate'),
31
- __('WordPress will allow search engines to visit your site.', 'seo-ultimate'));
32
- else
33
- $this->results[] = array(SU_RESULT_ERROR, __('Blog is hidden from search engines', 'seo-ultimate'),
34
- __('WordPress is configured to discourage search engines. This will nullify your site&#8217;s SEO and should be resolved immediately.', 'seo-ultimate'), 'options-reading.php');
35
-
36
- switch (suwp::permalink_mode()) {
37
- case SUWP_QUERY_PERMALINKS:
38
- $this->results[] = array(SU_RESULT_ERROR, __('Query-string permalinks enabled', 'seo-ultimate'),
39
- __('It is highly recommended that you use a non-default and non-numeric permalink structure.', 'seo-ultimate'), 'options-permalink.php');
40
- break;
41
-
42
- case SUWP_INDEX_PERMALINKS:
43
- $this->results[] = array(SU_RESULT_WARNING, __('Pathinfo permalinks enabled', 'seo-ultimate'),
44
- __('Pathinfo permalinks add a keyword-less &#8220;index.php&#8221; prefix. This is not ideal, but it may be beyond your control (since it&#8217;s likely caused by your site&#8217;s web hosting setup).', 'seo-ultimate'), 'options-permalink.php');
45
-
46
- case SUWP_PRETTY_PERMALINKS:
47
-
48
- if (strpos(get_option('permalink_structure'), '%postname%') !== false)
49
- $this->results[] = array(SU_RESULT_OK, __('Permalinks include the post slug', 'seo-ultimate'),
50
- __('Including a version of the post&#8217;s title helps provide keyword-rich URLs.', 'seo-ultimate'));
51
- else
52
- $this->results[] = array(SU_RESULT_ERROR, __('Permalinks do not include the post slug', 'seo-ultimate'),
53
- __('It is highly recommended that you include the %postname% variable in the permalink structure.', 'seo-ultimate'), 'options-permalink.php');
54
-
55
- break;
56
- }
57
- }
58
- }
59
-
60
- function admin_page_contents() {
61
-
62
- if ($this->should_show_sdf_theme_promo()) {
63
- echo "\n\n<div class='row'>\n";
64
- echo "\n\n<div class='col-sm-8 col-md-9'>\n";
65
- }
66
-
67
- echo "\n<p>";
68
- _e("Settings Monitor analyzes your blog&#8217;s settings and notifies you of any problems. If any issues are found, they will show up in red or yellow below.", 'seo-ultimate');
69
- echo "</p>\n";
70
-
71
- echo "<table class='report'>\n";
72
-
73
- $first = true;
74
- foreach ($this->results as $data) {
75
-
76
- $result = $data[0];
77
- $title = $data[1];
78
- $desc = $data[2];
79
- $url = isset($data[3]) ? $data[3] : false;
80
- $action = isset($data[4]) ? $data[4] : __('Go to setting &raquo;', 'seo-ultimate');
81
-
82
- switch ($result) {
83
- case SU_RESULT_OK: $class='success'; break;
84
- case SU_RESULT_ERROR: $class='error'; break;
85
- default: $class='warning'; break;
86
- }
87
-
88
- if ($result == SU_RESULT_OK || !$url)
89
- $link='';
90
- else {
91
- if (substr($url, 0, 7) == 'http://') $target = " target='_blank'"; else $target='';
92
- $link = "<a href='$url'$target>$action</a>";
93
- }
94
-
95
- if ($first) { $firstclass = " class='first'"; $first = false; } else $firstclass='';
96
- echo "\t<tr$firstclass>\n\t\t<td><div class='su-$class'><strong>$title</strong></div><div>$desc</div><div>$link</div></td>\n\t</tr>\n";
97
- }
98
-
99
- echo "</table>\n\n";
100
-
101
- if ($this->should_show_sdf_theme_promo()) {
102
- echo "\n\n</div>\n";
103
- echo "\n\n<div class='col-sm-4 col-md-3'>\n";
104
- $this->promo_sdf_banners();
105
- echo "\n\n</div>\n";
106
- echo "\n\n</div>\n";
107
- }
108
- }
109
- }
110
-
111
- }
112
  ?>
1
+ <?php
2
+ /**
3
+ * Settings Monitor Module
4
+ *
5
+ * @since 6.9
6
+ */
7
+
8
+ if (class_exists('SU_Module')) {
9
+
10
+ class SU_WpSettings extends SU_Module {
11
+
12
+ var $results = array();
13
+
14
+ static function get_module_title() { return __('Settings Monitor', 'seo-ultimate'); }
15
+ static function get_menu_title() { return __('Settings Monitor', 'seo-ultimate'); }
16
+
17
+ static function has_menu_count() { return true; }
18
+ function get_menu_count() {
19
+ $count = 0;
20
+ foreach ($this->results as $data) {
21
+ if ($data[0] == SU_RESULT_ERROR) $count++;
22
+ }
23
+ return $count;
24
+ }
25
+
26
+ function init() {
27
+
28
+ if (is_admin()) {
29
+ if (get_option('blog_public'))
30
+ $this->results[] = array(SU_RESULT_OK, __('Blog is visible to search engines', 'seo-ultimate'),
31
+ __('WordPress will allow search engines to visit your site.', 'seo-ultimate'));
32
+ else
33
+ $this->results[] = array(SU_RESULT_ERROR, __('Blog is hidden from search engines', 'seo-ultimate'),
34
+ __('WordPress is configured to discourage search engines. This will nullify your site&#8217;s SEO and should be resolved immediately.', 'seo-ultimate'), 'options-reading.php');
35
+
36
+ switch (suwp::permalink_mode()) {
37
+ case SUWP_QUERY_PERMALINKS:
38
+ $this->results[] = array(SU_RESULT_ERROR, __('Query-string permalinks enabled', 'seo-ultimate'),
39
+ __('It is highly recommended that you use a non-default and non-numeric permalink structure.', 'seo-ultimate'), 'options-permalink.php');
40
+ break;
41
+
42
+ case SUWP_INDEX_PERMALINKS:
43
+ $this->results[] = array(SU_RESULT_WARNING, __('Pathinfo permalinks enabled', 'seo-ultimate'),
44
+ __('Pathinfo permalinks add a keyword-less &#8220;index.php&#8221; prefix. This is not ideal, but it may be beyond your control (since it&#8217;s likely caused by your site&#8217;s web hosting setup).', 'seo-ultimate'), 'options-permalink.php');
45
+
46
+ case SUWP_PRETTY_PERMALINKS:
47
+
48
+ if (strpos(get_option('permalink_structure'), '%postname%') !== false)
49
+ $this->results[] = array(SU_RESULT_OK, __('Permalinks include the post slug', 'seo-ultimate'),
50
+ __('Including a version of the post&#8217;s title helps provide keyword-rich URLs.', 'seo-ultimate'));
51
+ else
52
+ $this->results[] = array(SU_RESULT_ERROR, __('Permalinks do not include the post slug', 'seo-ultimate'),
53
+ __('It is highly recommended that you include the %postname% variable in the permalink structure.', 'seo-ultimate'), 'options-permalink.php');
54
+
55
+ break;
56
+ }
57
+ }
58
+ }
59
+
60
+ function admin_page_contents() {
61
+
62
+ if ($this->should_show_sdf_theme_promo()) {
63
+ echo "\n\n<div class='row'>\n";
64
+ echo "\n\n<div class='col-sm-8 col-md-9'>\n";
65
+ }
66
+
67
+ echo "\n<p>";
68
+ _e("Settings Monitor analyzes your blog&#8217;s settings and notifies you of any problems. If any issues are found, they will show up in red or yellow below.", 'seo-ultimate');
69
+ echo "</p>\n";
70
+
71
+ echo "<table class='report'>\n";
72
+
73
+ $first = true;
74
+ foreach ($this->results as $data) {
75
+
76
+ $result = $data[0];
77
+ $title = $data[1];
78
+ $desc = $data[2];
79
+ $url = isset($data[3]) ? $data[3] : false;
80
+ $action = isset($data[4]) ? $data[4] : __('Go to setting &raquo;', 'seo-ultimate');
81
+
82
+ switch ($result) {
83
+ case SU_RESULT_OK: $class='success'; break;
84
+ case SU_RESULT_ERROR: $class='error'; break;
85
+ default: $class='warning'; break;
86
+ }
87
+
88
+ if ($result == SU_RESULT_OK || !$url)
89
+ $link='';
90
+ else {
91
+ if (substr($url, 0, 7) == 'http://') $target = " target='_blank'"; else $target='';
92
+ $link = "<a href='$url'$target>$action</a>";
93
+ }
94
+
95
+ if ($first) { $firstclass = " class='first'"; $first = false; } else $firstclass='';
96
+ echo "\t<tr$firstclass>\n\t\t<td><div class='su-$class'><strong>$title</strong></div><div>$desc</div><div>$link</div></td>\n\t</tr>\n";
97
+ }
98
+
99
+ echo "</table>\n\n";
100
+
101
+ if ($this->should_show_sdf_theme_promo()) {
102
+ echo "\n\n</div>\n";
103
+ echo "\n\n<div class='col-sm-4 col-md-3'>\n";
104
+ $this->promo_sdf_banners();
105
+ echo "\n\n</div>\n";
106
+ echo "\n\n</div>\n";
107
+ }
108
+ }
109
+ }
110
+
111
+ }
112
  ?>
plugin/class.seo-ultimate.php CHANGED
@@ -1088,20 +1088,20 @@ class SEO_Ultimate {
1088
  $pages = array( 'index.php', 'edit.php', 'post.php', 'post-new.php' );
1089
  $sdf_admin_pages = array('sdf','sdf-settings','sdf-silo','sdf-silo-manual-builder','sdf-header','sdf-layout','sdf-shortcode','sdf-styles','revslider','sdf-footer','seo', 'su-fofs', 'su-misc', 'su-user-code', 'su-autolinks', 'su-files', 'su-internal-link-aliases', 'su-meta-descriptions', 'su-meta-keywords', 'su-meta-robots', 'su-opengraph', 'seo-ultimate', 'su-wp-settings', 'su-titles', 'su-sds-blog');
1090
  if( in_array( $pagenow, $pages ) || in_array( $current, $sdf_admin_pages )) {
1091
- // admin styles
1092
- wp_register_style('sdf-bootstrap-admin', $this->plugin_dir_url.'plugin/sdf/bootstrap/css/bootstrap.admin.css', array(), '3.0.3', 'screen');
1093
- wp_register_style('sdf-bootstrap-admin-theme', $this->plugin_dir_url.'plugin/sdf/bootstrap/css/bootstrap-theme.admin.css', array(), '3.0.3', 'screen');
1094
- wp_register_style('sdf-font-awesome', 'https://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css', array(), '4.0.3', 'screen');
1095
- wp_register_style('sdf-css-admin', $this->plugin_dir_url.'plugin/sdf/sdf.admin.css', array(), '3.0.3', 'screen');
1096
  wp_enqueue_style('sdf-bootstrap-admin');
1097
  wp_enqueue_style('sdf-bootstrap-admin-theme');
1098
  wp_enqueue_style('sdf-font-awesome');
1099
- wp_enqueue_style('sdf-css-admin');
1100
 
1101
- wp_register_script('sdf_bs_js', 'https://netdna.bootstrapcdn.com/bootstrap/3.0.3/js/bootstrap.min.js', array('jquery'), '3.0.3', false);
1102
- wp_register_script('sdf_admin_js', $this->plugin_dir_url.'plugin/sdf/sdf.admin.js', array('jquery'), '');
1103
  wp_enqueue_script('sdf_bs_js');
1104
- wp_enqueue_script('sdf_admin_js');
1105
  wp_enqueue_media();
1106
  }
1107
 
@@ -2002,7 +2002,7 @@ class SEO_Ultimate {
2002
  if ($c = count($tabs)) {
2003
 
2004
  if ($c >= 1) {
2005
- echo "\n\n<div class='sdf-meta-wrap'>\n";
2006
  echo "\n\n<ul class='nav nav-tabs' id='su-tabset'>\n";
2007
  }
2008
 
@@ -2117,4 +2117,4 @@ class SEO_Ultimate {
2117
  //echo "";
2118
  }
2119
  }
2120
- ?>
1088
  $pages = array( 'index.php', 'edit.php', 'post.php', 'post-new.php' );
1089
  $sdf_admin_pages = array('sdf','sdf-settings','sdf-silo','sdf-silo-manual-builder','sdf-header','sdf-layout','sdf-shortcode','sdf-styles','revslider','sdf-footer','seo', 'su-fofs', 'su-misc', 'su-user-code', 'su-autolinks', 'su-files', 'su-internal-link-aliases', 'su-meta-descriptions', 'su-meta-keywords', 'su-meta-robots', 'su-opengraph', 'seo-ultimate', 'su-wp-settings', 'su-titles', 'su-sds-blog');
1090
  if( in_array( $pagenow, $pages ) || in_array( $current, $sdf_admin_pages )) {
1091
+ // admin styles
1092
+ wp_register_style('sdf-bootstrap-admin', $this->plugin_dir_url.'plugin/sdf/bootstrap/css/bootstrap.admin.css', array(), null, 'screen');
1093
+ wp_register_style('sdf-bootstrap-admin-theme', $this->plugin_dir_url.'plugin/sdf/bootstrap/css/bootstrap-theme.admin.css', array(), null, 'screen');
1094
+ wp_register_style('sdf-font-awesome', 'https://netdna.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css', array(), null, 'screen');
1095
+ wp_register_style('seo-css-admin', $this->plugin_dir_url.'plugin/seo.admin.css', array(), null, 'screen');
1096
  wp_enqueue_style('sdf-bootstrap-admin');
1097
  wp_enqueue_style('sdf-bootstrap-admin-theme');
1098
  wp_enqueue_style('sdf-font-awesome');
1099
+ wp_enqueue_style('seo-css-admin');
1100
 
1101
+ wp_register_script('sdf_bs_js', 'https://netdna.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js', array('jquery'), null, true);
1102
+ wp_register_script('media_upload_js', $this->plugin_dir_url.'plugin/sdf/sdf.media.upload.js', array('jquery'), '');
1103
  wp_enqueue_script('sdf_bs_js');
1104
+ wp_enqueue_script('media_upload_js');
1105
  wp_enqueue_media();
1106
  }
1107
 
2002
  if ($c = count($tabs)) {
2003
 
2004
  if ($c >= 1) {
2005
+ echo "\n\n<div class='seo-meta-wrap'>\n";
2006
  echo "\n\n<ul class='nav nav-tabs' id='su-tabset'>\n";
2007
  }
2008
 
2117
  //echo "";
2118
  }
2119
  }
2120
+ ?>
plugin/class.su-installer.php CHANGED
@@ -1,86 +1,86 @@
1
- <?php
2
- if (!defined('ABSPATH')) die();
3
-
4
- include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
5
-
6
- class SU_Installer extends Plugin_Upgrader {
7
-
8
- function su_strings($cv, $nv) {
9
-
10
- //Generic
11
- $this->strings['no_package'] = __('Package not available.', 'seo-ultimate');
12
-
13
- //Upgrade
14
- $this->strings['remove_old'] = __('Removing the current version of the plugin&#8230;', 'seo-ultimate');
15
- $this->strings['remove_old_failed'] = __('Could not remove the current version of the plugin.', 'seo-ultimate');
16
-
17
- switch (version_compare($nv, $cv)) {
18
- case -1: //Downgrade
19
- $this->strings['downloading_package'] = __('Downloading old version from <span class="code">%s</span>&#8230;', 'seo-ultimate');
20
- $this->strings['unpack_package'] = __('Unpacking the downgrade&#8230;', 'seo-ultimate');
21
- $this->strings['installing_package'] = __('Installing the downgrade&#8230;', 'seo-ultimate');
22
- $this->strings['process_failed'] = __('Plugin downgrade failed.', 'seo-ultimate');
23
- $this->strings['process_success'] = __('Plugin downgraded successfully.', 'seo-ultimate');
24
- break;
25
- case 0: //Reinstall
26
- $this->strings['downloading_package'] = __('Downloading from <span class="code">%s</span>&#8230;', 'seo-ultimate');
27
- $this->strings['unpack_package'] = __('Unpacking the reinstall&#8230;', 'seo-ultimate');
28
- $this->strings['installing_package'] = __('Reinstalling the current version&#8230;', 'seo-ultimate');
29
- $this->strings['process_failed'] = __('Plugin reinstallation failed.', 'seo-ultimate');
30
- $this->strings['process_success'] = __('Plugin reinstalled successfully.', 'seo-ultimate');
31
- break;
32
- case 1: //Upgrade
33
- default:
34
- $this->strings['downloading_package'] = __('Downloading upgrade from <span class="code">%s</span>&#8230;', 'seo-ultimate');
35
- $this->strings['unpack_package'] = __('Unpacking the upgrade&#8230;', 'seo-ultimate');
36
- $this->strings['installing_package'] = __('Installing the upgrade&#8230;', 'seo-ultimate');
37
- $this->strings['process_failed'] = __('Plugin upgrade failed.', 'seo-ultimate');
38
- $this->strings['process_success'] = __('Plugin upgraded successfully.', 'seo-ultimate');
39
- break;
40
- }
41
- }
42
-
43
- function upgrade($plugin, $cv, $nv) {
44
-
45
- $this->init();
46
- $this->upgrade_strings();
47
- $this->su_strings($cv, $nv);
48
-
49
- add_filter('upgrader_pre_install', array(&$this, 'deactivate_plugin_before_upgrade'), 10, 2);
50
- add_filter('upgrader_clear_destination', array(&$this, 'delete_old_plugin'), 10, 4);
51
-
52
- $this->run(array(
53
- 'package' => "http://downloads.wordpress.org/plugin/seo-ultimate.$nv.zip",
54
- 'destination' => WP_PLUGIN_DIR,
55
- 'clear_destination' => true,
56
- 'clear_working' => true,
57
- 'hook_extra' => array(
58
- 'plugin' => $plugin
59
- )
60
- ));
61
-
62
- // Clean up our hooks, in case something else does an upgrade
63
- remove_filter('upgrader_pre_install', array(&$this, 'deactivate_plugin_before_upgrade'));
64
- remove_filter('upgrader_clear_destination', array(&$this, 'delete_old_plugin'));
65
-
66
- if ( ! $this->result || is_wp_error($this->result) )
67
- return $this->result;
68
-
69
- // Force refresh of plugin update information
70
- delete_site_transient('update_plugins');
71
- }
72
- }
73
-
74
- class SU_Installer_Skin extends Plugin_Upgrader_Skin {
75
-
76
- function header() {
77
- if ( $this->done_header )
78
- return;
79
- $this->done_header = true;
80
- echo '<div class="wrap">';
81
- echo screen_icon('plugins');
82
- echo '<h2>' . $this->options['title'] . '</h2>';
83
- }
84
-
85
- }
86
  ?>
1
+ <?php
2
+ if (!defined('ABSPATH')) die();
3
+
4
+ include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
5
+
6
+ class SU_Installer extends Plugin_Upgrader {
7
+
8
+ function su_strings($cv, $nv) {
9
+
10
+ //Generic
11
+ $this->strings['no_package'] = __('Package not available.', 'seo-ultimate');
12
+
13
+ //Upgrade
14
+ $this->strings['remove_old'] = __('Removing the current version of the plugin&#8230;', 'seo-ultimate');
15
+ $this->strings['remove_old_failed'] = __('Could not remove the current version of the plugin.', 'seo-ultimate');
16
+
17
+ switch (version_compare($nv, $cv)) {
18
+ case -1: //Downgrade
19
+ $this->strings['downloading_package'] = __('Downloading old version from <span class="code">%s</span>&#8230;', 'seo-ultimate');
20
+ $this->strings['unpack_package'] = __('Unpacking the downgrade&#8230;', 'seo-ultimate');
21
+ $this->strings['installing_package'] = __('Installing the downgrade&#8230;', 'seo-ultimate');
22
+ $this->strings['process_failed'] = __('Plugin downgrade failed.', 'seo-ultimate');
23
+ $this->strings['process_success'] = __('Plugin downgraded successfully.', 'seo-ultimate');
24
+ break;
25
+ case 0: //Reinstall
26
+ $this->strings['downloading_package'] = __('Downloading from <span class="code">%s</span>&#8230;', 'seo-ultimate');
27
+ $this->strings['unpack_package'] = __('Unpacking the reinstall&#8230;', 'seo-ultimate');
28
+ $this->strings['installing_package'] = __('Reinstalling the current version&#8230;', 'seo-ultimate');
29
+ $this->strings['process_failed'] = __('Plugin reinstallation failed.', 'seo-ultimate');
30
+ $this->strings['process_success'] = __('Plugin reinstalled successfully.', 'seo-ultimate');
31
+ break;
32
+ case 1: //Upgrade
33
+ default:
34
+ $this->strings['downloading_package'] = __('Downloading upgrade from <span class="code">%s</span>&#8230;', 'seo-ultimate');
35
+ $this->strings['unpack_package'] = __('Unpacking the upgrade&#8230;', 'seo-ultimate');
36
+ $this->strings['installing_package'] = __('Installing the upgrade&#8230;', 'seo-ultimate');
37
+ $this->strings['process_failed'] = __('Plugin upgrade failed.', 'seo-ultimate');
38
+ $this->strings['process_success'] = __('Plugin upgraded successfully.', 'seo-ultimate');
39
+ break;
40
+ }
41
+ }
42
+
43
+ function upgrade($plugin, $cv, $nv) {
44
+
45
+ $this->init();
46
+ $this->upgrade_strings();
47
+ $this->su_strings($cv, $nv);
48
+
49
+ add_filter('upgrader_pre_install', array(&$this, 'deactivate_plugin_before_upgrade'), 10, 2);
50
+ add_filter('upgrader_clear_destination', array(&$this, 'delete_old_plugin'), 10, 4);
51
+
52
+ $this->run(array(
53
+ 'package' => "http://downloads.wordpress.org/plugin/seo-ultimate.$nv.zip",
54
+ 'destination' => WP_PLUGIN_DIR,
55
+ 'clear_destination' => true,
56
+ 'clear_working' => true,
57
+ 'hook_extra' => array(
58
+ 'plugin' => $plugin
59
+ )
60
+ ));
61
+
62
+ // Clean up our hooks, in case something else does an upgrade
63
+ remove_filter('upgrader_pre_install', array(&$this, 'deactivate_plugin_before_upgrade'));
64
+ remove_filter('upgrader_clear_destination', array(&$this, 'delete_old_plugin'));
65
+
66
+ if ( ! $this->result || is_wp_error($this->result) )
67
+ return $this->result;
68
+
69
+ // Force refresh of plugin update information
70
+ delete_site_transient('update_plugins');
71
+ }
72
+ }
73
+
74
+ class SU_Installer_Skin extends Plugin_Upgrader_Skin {
75
+
76
+ function header() {
77
+ if ( $this->done_header )
78
+ return;
79
+ $this->done_header = true;
80
+ echo '<div class="wrap">';
81
+ echo screen_icon('plugins');
82
+ echo '<h2>' . $this->options['title'] . '</h2>';
83
+ }
84
+
85
+ }
86
  ?>
plugin/global.css CHANGED
@@ -1,275 +1,275 @@
1
- /*
2
- SEO Ultimate CSS
3
- These styles are sometimes or always referenced outside of SEO Ultimate's admin pages, so we include this file throughout the WordPress admin.
4
- */
5
-
6
- /* MENU */
7
-
8
- #adminmenu .toplevel_page_seo div.wp-menu-image {
9
- background-image: url(img/icon.png);
10
- background-position: 2px -30px;
11
- }
12
-
13
- #adminmenu .toplevel_page_seo:hover div.wp-menu-image,
14
- #adminmenu .toplevel_page_seo .wp-has-current-submenu div.wp-menu-image {
15
- background-position: 2px 2px;
16
- }
17
-
18
- /* MESSAGES */
19
-
20
- .su-success, .su-error,
21
- .su-warning, .su-info {
22
- padding-left: 21px;
23
- background-repeat: no-repeat;
24
- background-position: 0px center;
25
- }
26
-
27
- .su-success {
28
- background-image: url(img/success.png);
29
- color: #008000;
30
- }
31
-
32
- .su-error {
33
- background-image: url(img/error.png);
34
- color: #FF0000;
35
- }
36
-
37
- .su-warning {
38
- background-image: url(img/warning.png);
39
- color: #FF8C00;
40
- }
41
-
42
- .su-info {
43
- background-image: url(img/info.png);
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
- border-radius: 4px;
65
- }
66
-
67
- .su-message .su-success {
68
- background-color: #DFFFE3;
69
- border-color: #61DF6F;
70
- }
71
-
72
- .su-message .su-error, .plugin-update-tr.su-plugin-notice .update-message {
73
- background-color: #FFBFBF;
74
- border-color: #FF0000;
75
- }
76
-
77
- .su-message .su-warning {
78
- background-color: #FFFFE0;
79
- border-color: orange;
80
- }
81
-
82
- .su-message .su-info {
83
- background-color: #DFEEFF;
84
- border-color: #8F93FF;
85
- }
86
-
87
- /* CONTEXTUAL HELP */
88
-
89
- div.su-help div.metabox-prefs {
90
- margin-bottom: 2em;
91
- }
92
-
93
- div.su-help ul {
94
- list-style-type: disc;
95
- padding-left: 1em;
96
- margin-left: 1em;
97
- }
98
-
99
- div.su-help h6 {
100
- font-size: 0.9em;
101
- font-weight: bold;
102
- margin: 2em 0 0 0;
103
- padding: 0;
104
- }
105
-
106
- /* POSTMETA BOX */
107
-
108
- #su-postmeta-box table th.su,
109
- #su-postmeta-box table td.su {
110
- padding: 0.5em 0;
111
- }
112
-
113
- #su-postmeta-box table th.su {
114
- text-align: right;
115
- font-weight: bold;
116
- padding-right: 0.5em;
117
- white-space: nowrap;
118
- }
119
-
120
- #su-postmeta-box table tr[valign="top"] th.su {
121
- padding-top: 0.7em;
122
- }
123
-
124
- #su-postmeta-box table tr.textarea th.su label {
125
- display: block;
126
- margin-top: 5px;
127
- }
128
-
129
- #su-postmeta-box table th.su em {
130
- font-weight: normal;
131
- }
132
-
133
- #su-postmeta-box table td.su {
134
- width: 100%;
135
- }
136
-
137
- #su-postmeta-box table td.su.group table {
138
- border-spacing: 0;
139
- }
140
-
141
- #su-postmeta-box table td.su.group th {
142
- text-align: right;
143
- font-weight: normal;
144
- white-space: nowrap;
145
- padding: 0 0.5em;
146
- vertical-align: middle;
147
- }
148
-
149
- #su-postmeta-box table td.su.group {
150
- padding: 0.4em;
151
- }
152
-
153
- #su-postmeta-box table td.su.group td {
154
- width: 100%;
155
- }
156
-
157
- #su-postmeta-box table,
158
- #su-postmeta-box table td input.regular-text,
159
- #su-postmeta-box table td textarea {
160
- width: 100%;
161
- }
162
-
163
- #su-postmeta-box select optgroup,
164
- div.sdf-admin select optgroup {
165
- margin-top: 1em;
166
- }
167
-
168
- #su-postmeta-box select optgroup option,
169
- div.sdf-admin select optgroup option {
170
- margin-left: 1em;
171
- }
172
-
173
- #su-postmeta-box table.widefat {
174
- width: auto;
175
- }
176
-
177
- #su-postmeta-box table.widefat td {
178
- vertical-align: middle;
179
- }
180
-
181
- #su-postmeta-box .su-postmeta-box-footer {
182
- color: #999;
183
- margin: 0;
184
- padding: 0.5em 1em;
185
- text-align: right;
186
- }
187
-
188
- #su-postmeta-box .su-postmeta-box-footer a {
189
- color: #999;
190
- text-decoration: none;
191
- }
192
-
193
- #su-postmeta-box input[type="tel"] {
194
- box-sizing: border-box;
195
- }
196
-
197
-
198
- /* PLUGIN NOTICES */
199
-
200
- #wpwrap .su-plugin-notice .update-message, #wpwrap .su-plugin-update-info {
201
- font-weight: normal;
202
- }
203
-
204
- /* TABS (Heavily based on CSS from the Breadcrumbs NavXT plugin) */
205
-
206
- .su-tabs ul.ui-tabs-nav {
207
- border-bottom: 1px solid #dfdfdf;
208
- font-size: 12px;
209
- height: 29px;
210
- list-style: none;
211
- margin: 13px 0 0;
212
- overflow: visible;
213
- padding: 0 0 0 8px;
214
- }
215
-
216
- .su-tabs ul.ui-tabs-nav li {
217
- display: block;
218
- float: left;
219
- line-height: 200%;
220
- list-style: none;
221
- margin: 0;
222
- padding: 0;
223
- position: relative;
224
- text-align: center;
225
- white-space: nowrap;
226
- width: auto;
227
- }
228
-
229
-
230
- .su-tabs ul.ui-tabs-nav li a {
231
- border-bottom: 1px solid #dfdfdf;
232
- display: block;
233
- float: left;
234
- line-height: 28px;
235
- padding: 1px 10px 0;
236
- position: relative;
237
- text-decoration: none;
238
- }
239
-
240
- .su-tabs ul.ui-tabs-nav li.ui-state-active a {
241
- -moz-border-radius-topleft: 4px;
242
- -moz-border-radius-topright: 4px;
243
- -webkit-border-top-left-radius: 4px;
244
- -webkit-border-top-right-radius: 4px;
245
- border-top-left-radius: 4px;
246
- border-top-right-radius: 4px;
247
- border: 1px solid #dfdfdf;
248
- color: #333333;
249
- font-weight: normal;
250
- padding: 0 9px;
251
- }
252
-
253
- .su-tabs ul.ui-tabs-nav li.ui-state-active a {
254
- border-bottom-color: #fff;
255
- }
256
-
257
- #su-postmeta-box .su-tabs ul.ui-tabs-nav li.ui-state-active a {
258
- background-color: white;
259
- }
260
-
261
- .su-tabs fieldset {
262
- clear: left;
263
- }
264
-
265
- div.sdf-admin .su-tabs .su-tab-contents {
266
- margin-top: 1em;
267
- }
268
-
269
- #su-postmeta-box .su-tabs .su-tab-contents {
270
- padding: 1em;
271
- background-color: white;
272
- border: 1px solid #dfdfdf;
273
- border-top: 0 none;
274
- background-color: white;
275
- }
1
+ /*
2
+ SEO Ultimate CSS
3
+ These styles are sometimes or always referenced outside of SEO Ultimate's admin pages, so we include this file throughout the WordPress admin.
4
+ */
5
+
6
+ /* MENU */
7
+
8
+ #adminmenu .toplevel_page_seo div.wp-menu-image {
9
+ background-image: url(img/icon.png);
10
+ background-position: 2px -30px;
11
+ }
12
+
13
+ #adminmenu .toplevel_page_seo:hover div.wp-menu-image,
14
+ #adminmenu .toplevel_page_seo .wp-has-current-submenu div.wp-menu-image {
15
+ background-position: 2px 2px;
16
+ }
17
+
18
+ /* MESSAGES */
19
+
20
+ .su-success, .su-error,
21
+ .su-warning, .su-info {
22
+ padding-left: 21px;
23
+ background-repeat: no-repeat;
24
+ background-position: 0px center;
25
+ }
26
+
27
+ .su-success {
28
+ background-image: url(img/success.png);
29
+ color: #008000;
30
+ }
31
+
32
+ .su-error {
33
+ background-image: url(img/error.png);
34
+ color: #FF0000;
35
+ }
36
+
37
+ .su-warning {
38
+ background-image: url(img/warning.png);
39
+ color: #FF8C00;
40
+ }
41
+
42
+ .su-info {
43
+ background-image: url(img/info.png);
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
+ border-radius: 4px;
65
+ }
66
+
67
+ .su-message .su-success {
68
+ background-color: #DFFFE3;
69
+ border-color: #61DF6F;
70
+ }
71
+
72
+ .su-message .su-error, .plugin-update-tr.su-plugin-notice .update-message {
73
+ background-color: #FFBFBF;
74
+ border-color: #FF0000;
75
+ }
76
+
77
+ .su-message .su-warning {
78
+ background-color: #FFFFE0;
79
+ border-color: orange;
80
+ }
81
+
82
+ .su-message .su-info {
83
+ background-color: #DFEEFF;
84
+ border-color: #8F93FF;
85
+ }
86
+
87
+ /* CONTEXTUAL HELP */
88
+
89
+ div.su-help div.metabox-prefs {
90
+ margin-bottom: 2em;
91
+ }
92
+
93
+ div.su-help ul {
94
+ list-style-type: disc;
95
+ padding-left: 1em;
96
+ margin-left: 1em;
97
+ }
98
+
99
+ div.su-help h6 {
100
+ font-size: 0.9em;
101
+ font-weight: bold;
102
+ margin: 2em 0 0 0;
103
+ padding: 0;
104
+ }
105
+
106
+ /* POSTMETA BOX */
107
+
108
+ #su-postmeta-box table th.su,
109
+ #su-postmeta-box table td.su {
110
+ padding: 0.5em 0;
111
+ }
112
+
113
+ #su-postmeta-box table th.su {
114
+ text-align: right;
115
+ font-weight: bold;
116
+ padding-right: 0.5em;
117
+ white-space: nowrap;
118
+ }
119
+
120
+ #su-postmeta-box table tr[valign="top"] th.su {
121
+ padding-top: 0.7em;
122
+ }
123
+
124
+ #su-postmeta-box table tr.textarea th.su label {
125
+ display: block;
126
+ margin-top: 5px;
127
+ }
128
+
129
+ #su-postmeta-box table th.su em {
130
+ font-weight: normal;
131
+ }
132
+
133
+ #su-postmeta-box table td.su {
134
+ width: 100%;
135
+ }
136
+
137
+ #su-postmeta-box table td.su.group table {
138
+ border-spacing: 0;
139
+ }
140
+
141
+ #su-postmeta-box table td.su.group th {
142
+ text-align: right;
143
+ font-weight: normal;
144
+ white-space: nowrap;
145
+ padding: 0 0.5em;
146
+ vertical-align: middle;
147
+ }
148
+
149
+ #su-postmeta-box table td.su.group {
150
+ padding: 0.4em;
151
+ }
152
+
153
+ #su-postmeta-box table td.su.group td {
154
+ width: 100%;
155
+ }
156
+
157
+ #su-postmeta-box table,
158
+ #su-postmeta-box table td input.regular-text,
159
+ #su-postmeta-box table td textarea {
160
+ width: 100%;
161
+ }
162
+
163
+ #su-postmeta-box select optgroup,
164
+ div.sdf-admin select optgroup {
165
+ margin-top: 1em;
166
+ }
167
+
168
+ #su-postmeta-box select optgroup option,
169
+ div.sdf-admin select optgroup option {
170
+ margin-left: 1em;
171
+ }
172
+
173
+ #su-postmeta-box table.widefat {
174
+ width: auto;
175
+ }
176
+
177
+ #su-postmeta-box table.widefat td {
178
+ vertical-align: middle;
179
+ }
180
+
181
+ #su-postmeta-box .su-postmeta-box-footer {
182
+ color: #999;
183
+ margin: 0;
184
+ padding: 0.5em 1em;
185
+ text-align: right;
186
+ }
187
+
188
+ #su-postmeta-box .su-postmeta-box-footer a {
189
+ color: #999;
190
+ text-decoration: none;
191
+ }
192
+
193
+ #su-postmeta-box input[type="tel"] {
194
+ box-sizing: border-box;
195
+ }
196
+
197
+
198
+ /* PLUGIN NOTICES */
199
+
200
+ #wpwrap .su-plugin-notice .update-message, #wpwrap .su-plugin-update-info {
201
+ font-weight: normal;
202
+ }
203
+
204
+ /* TABS (Heavily based on CSS from the Breadcrumbs NavXT plugin) */
205
+
206
+ .su-tabs ul.ui-tabs-nav {
207
+ border-bottom: 1px solid #dfdfdf;
208
+ font-size: 12px;
209
+ height: 29px;
210
+ list-style: none;
211
+ margin: 13px 0 0;
212
+ overflow: visible;
213
+ padding: 0 0 0 8px;
214
+ }
215
+
216
+ .su-tabs ul.ui-tabs-nav li {
217
+ display: block;
218
+ float: left;
219
+ line-height: 200%;
220
+ list-style: none;
221
+ margin: 0;
222
+ padding: 0;
223
+ position: relative;
224
+ text-align: center;
225
+ white-space: nowrap;
226
+ width: auto;
227
+ }
228
+
229
+
230
+ .su-tabs ul.ui-tabs-nav li a {
231
+ border-bottom: 1px solid #dfdfdf;
232
+ display: block;
233
+ float: left;
234
+ line-height: 28px;
235
+ padding: 1px 10px 0;
236
+ position: relative;
237
+ text-decoration: none;
238
+ }
239
+
240
+ .su-tabs ul.ui-tabs-nav li.ui-state-active a {
241
+ -moz-border-radius-topleft: 4px;
242
+ -moz-border-radius-topright: 4px;
243
+ -webkit-border-top-left-radius: 4px;
244
+ -webkit-border-top-right-radius: 4px;
245
+ border-top-left-radius: 4px;
246
+ border-top-right-radius: 4px;
247
+ border: 1px solid #dfdfdf;
248
+ color: #333333;
249
+ font-weight: normal;
250
+ padding: 0 9px;
251
+ }
252
+
253
+ .su-tabs ul.ui-tabs-nav li.ui-state-active a {
254
+ border-bottom-color: #fff;
255
+ }
256
+
257
+ #su-postmeta-box .su-tabs ul.ui-tabs-nav li.ui-state-active a {
258
+ background-color: white;
259
+ }
260
+
261
+ .su-tabs fieldset {
262
+ clear: left;
263
+ }
264
+
265
+ div.sdf-admin .su-tabs .su-tab-contents {
266
+ margin-top: 1em;
267
+ }
268
+
269
+ #su-postmeta-box .su-tabs .su-tab-contents {
270
+ padding: 1em;
271
+ background-color: white;
272
+ border: 1px solid #dfdfdf;
273
+ border-top: 0 none;
274
+ background-color: white;
275
+ }
plugin/global.js CHANGED
@@ -1,9 +1,9 @@
1
-
2
- function su_toggle_select_children(select) {
3
- var i=0;
4
- for (i=0;i<select.options.length;i++) {
5
- var option = select.options[i];
6
- var c = ".su_" + select.name.replace("_su_", "") + "_" + option.value + "_subsection";
7
- if (option.index == select.selectedIndex) jQuery(c).show().removeClass("hidden"); else jQuery(c).hide();
8
- }
9
- }
1
+
2
+ function su_toggle_select_children(select) {
3
+ var i=0;
4
+ for (i=0;i<select.options.length;i++) {
5
+ var option = select.options[i];
6
+ var c = ".su_" + select.name.replace("_su_", "") + "_" + option.value + "_subsection";
7
+ if (option.index == select.selectedIndex) jQuery(c).show().removeClass("hidden"); else jQuery(c).hide();
8
+ }
9
+ }
plugin/img/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
plugin/index.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
- header('Status: 403 Forbidden');
3
- header('HTTP/1.1 403 Forbidden');
4
  ?>
1
+ <?php
2
+ header('Status: 403 Forbidden');
3
+ header('HTTP/1.1 403 Forbidden');
4
  ?>
plugin/sdf/bootstrap/css/bootstrap-theme.admin.css CHANGED
@@ -1,386 +1,386 @@
1
- .sdf-admin .btn-default,
2
- .sdf-admin .btn-primary,
3
- .sdf-admin .btn-success,
4
- .sdf-admin .btn-info,
5
- .sdf-admin .btn-warning,
6
- .sdf-admin .btn-danger {
7
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
8
- -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
9
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
10
- }
11
-
12
- .sdf-admin .btn-default:active,
13
- .sdf-admin .btn-primary:active,
14
- .sdf-admin .btn-success:active,
15
- .sdf-admin .btn-info:active,
16
- .sdf-admin .btn-warning:active,
17
- .sdf-admin .btn-danger:active,
18
- .sdf-admin .btn-default.active,
19
- .sdf-admin .btn-primary.active,
20
- .sdf-admin .btn-success.active,
21
- .sdf-admin .btn-info.active,
22
- .sdf-admin .btn-warning.active,
23
- .sdf-admin .btn-danger.active {
24
- -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
25
- box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
26
- }
27
-
28
- .sdf-admin .btn:active,
29
- .sdf-admin .btn.active {
30
- background-image: none;
31
- }
32
-
33
- .sdf-admin .btn-default {
34
- text-shadow: 0 1px 0 #fff;
35
- background-image: -webkit-gradient(linear, left 0%, left 100%, from(#ffffff), to(#e6e6e6));
36
- background-image: -webkit-linear-gradient(top, #ffffff, 0%, #e6e6e6, 100%);
37
- background-image: -moz-linear-gradient(top, #ffffff 0%, #e6e6e6 100%);
38
- background-image: linear-gradient(to bottom, #ffffff 0%, #e6e6e6 100%);
39
- background-repeat: repeat-x;
40
- border-color: #e0e0e0;
41
- border-color: #ccc;
42
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);
43
- }
44
-
45
- .sdf-admin .btn-default:active,
46
- .sdf-admin .btn-default.active {
47
- background-color: #e6e6e6;
48
- border-color: #e0e0e0;
49
- }
50
-
51
- .sdf-admin .btn-primary {
52
- background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#3071a9));
53
- background-image: -webkit-linear-gradient(top, #428bca, 0%, #3071a9, 100%);
54
- background-image: -moz-linear-gradient(top, #428bca 0%, #3071a9 100%);
55
- background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
56
- background-repeat: repeat-x;
57
- border-color: #2d6ca2;
58
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
59
- }
60
-
61
- .sdf-admin .btn-primary:active,
62
- .sdf-admin .btn-primary.active {
63
- background-color: #3071a9;
64
- border-color: #2d6ca2;
65
- }
66
-
67
- .sdf-admin .btn-success {
68
- background-image: -webkit-gradient(linear, left 0%, left 100%, from(#5cb85c), to(#449d44));
69
- background-image: -webkit-linear-gradient(top, #5cb85c, 0%, #449d44, 100%);
70
- background-image: -moz-linear-gradient(top, #5cb85c 0%, #449d44 100%);
71
- background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
72
- background-repeat: repeat-x;
73
- border-color: #419641;
74
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
75
- }
76
-
77
- .sdf-admin .btn-success:active,
78
- .sdf-admin .btn-success.active {
79
- background-color: #449d44;
80
- border-color: #419641;
81
- }
82
-
83
- .sdf-admin .btn-warning {
84
- background-image: -webkit-gradient(linear, left 0%, left 100%, from(#f0ad4e), to(#ec971f));
85
- background-image: -webkit-linear-gradient(top, #f0ad4e, 0%, #ec971f, 100%);
86
- background-image: -moz-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
87
- background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
88
- background-repeat: repeat-x;
89
- border-color: #eb9316;
90
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
91
- }
92
-
93
- .sdf-admin .btn-warning:active,
94
- .sdf-admin .btn-warning.active {
95
- background-color: #ec971f;
96
- border-color: #eb9316;
97
- }
98
-
99
- .sdf-admin .btn-danger {
100
- background-image: -webkit-gradient(linear, left 0%, left 100%, from(#d9534f), to(#c9302c));
101
- background-image: -webkit-linear-gradient(top, #d9534f, 0%, #c9302c, 100%);
102
- background-image: -moz-linear-gradient(top, #d9534f 0%, #c9302c 100%);
103
- background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
104
- background-repeat: repeat-x;
105
- border-color: #c12e2a;
106
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
107
- }
108
-
109
- .sdf-admin .btn-danger:active,
110
- .sdf-admin .btn-danger.active {
111
- background-color: #c9302c;
112
- border-color: #c12e2a;
113
- }
114
-
115
- .sdf-admin .btn-info {
116
- background-image: -webkit-gradient(linear, left 0%, left 100%, from(#5bc0de), to(#31b0d5));
117
- background-image: -webkit-linear-gradient(top, #5bc0de, 0%, #31b0d5, 100%);
118
- background-image: -moz-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
119
- background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
120
- background-repeat: repeat-x;
121
- border-color: #2aabd2;
122
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
123
- }
124
-
125
- .sdf-admin .btn-info:active,
126
- .sdf-admin .btn-info.active {
127
- background-color: #31b0d5;
128
- border-color: #2aabd2;
129
- }
130
- /* SDF Buttons */
131
- .sdf-admin .btn-custom {
132
- -webkit-font-smoothing: antialiased;
133
- background-repeat: repeat-x !important;
134
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=rgb(242, 160, 67), endColorstr=rgb(245, 143, 29));
135
- background-image: -webkit-linear-gradient(top, rgb(242, 160, 67), rgb(245, 143, 29)) !important;
136
- background-image: -khtml-gradient(linear, left top, left bottom, from(rgb(242, 160, 67)), to( rgb(245, 143, 29)));
137
- background-image: -moz-linear-gradient(top, rgb(242, 160, 67), rgb(245, 143, 29));
138
- background-image: -ms-linear-gradient(top, rgb(242, 160, 67), rgb(245, 143, 29));
139
- background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgb(242, 160, 67)), color-stop(100%, rgb(245, 143, 29)));
140
- background-image: -o-linear-gradienttop, rgb(242, 160, 67), rgb(245, 143, 29));
141
- background-image: linear-gradient( rgb(242, 160, 67), rgb(245, 143, 29));
142
- background-color: rgb(245, 143, 29) !important;
143
- border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25) !important;
144
- color: rgb(255, 255, 255) !important;
145
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25) !important;
146
- text-decoration: none;
147
- }
148
- .sdf-admin .btn-custom:hover,
149
- .sdf-admin .btn-custom:focus {
150
- -webkit-font-smoothing: antialiased;
151
- background-repeat: repeat-x !important;
152
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=rgb(242, 160, 67), endColorstr=rgb(245, 143, 29));
153
- background-image: -webkit-linear-gradient(top, rgb(242, 160, 67), rgb(245, 143, 29)) !important;
154
- background-image: -khtml-gradient(linear, left top, left bottom, from(rgb(242, 160, 67)), to( rgb(245, 143, 29)));
155
- background-image: -moz-linear-gradient(top, rgb(242, 160, 67), rgb(245, 143, 29));
156
- background-image: -ms-linear-gradient(top, rgb(242, 160, 67), rgb(245, 143, 29));
157
- background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgb(242, 160, 67)), color-stop(100%, rgb(245, 143, 29)));
158
- background-image: -o-linear-gradienttop, rgb(242, 160, 67), rgb(245, 143, 29));
159
- background-image: linear-gradient( rgb(242, 160, 67), rgb(245, 143, 29));
160
- background-color: rgb(245, 143, 29) !important;
161
- border-color: rgba(0, 0, 0, 0.2) rgba(0, 0, 0, 0.2) rgba(0, 0, 0, 0.35) !important;
162
- color: rgb(255, 255, 255) !important;
163
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25) !important;
164
- text-decoration: none;
165
- }
166
- .sdf-admin .btn-sdf-grey {
167
- font-weight:bold !important;
168
- -webkit-font-smoothing: antialiased;
169
- background-repeat: repeat-x !important;
170
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=rgb(125, 125, 125), endColorstr=rgb(118, 118, 118));
171
- background-image: -webkit-linear-gradient(top, rgb(125, 125, 125), rgb(118, 118, 118)) !important;
172
- background-image: -khtml-gradient(linear, left top, left bottom, from(rgb(125, 125, 125)), to( rgb(118, 118, 118)));
173
- background-image: -moz-linear-gradient(top, rgb(125, 125, 125), rgb(118, 118, 118));
174
- background-image: -ms-linear-gradient(top, rgb(125, 125, 125), rgb(118, 118, 118));
175
- background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgb(125, 125, 125)), color-stop(100%, rgb(118, 118, 118)));
176
- background-image: -o-linear-gradienttop, rgb(125, 125, 125), rgb(118, 118, 118));
177
- background-image: linear-gradient( rgb(125, 125, 125), rgb(118, 118, 118));
178
- background-color: rgb(118, 118, 118) !important;
179
- border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25) !important;
180
- color: rgb(255, 255, 255) !important;
181
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25) !important;
182
- text-decoration: none;
183
- }
184
- .sdf-admin .btn-sdf-grey:hover,
185
- .sdf-admin .btn-sdf-grey:focus {
186
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=rgb(104, 104, 104), endColorstr=rgb(97, 97, 97));
187
- background-image: -webkit-linear-gradient(top, rgb(104, 104, 104), rgb(97, 97, 97)) !important;
188
- background-image: -khtml-gradient(linear, left top, left bottom, from(rgb(104, 104, 104)), to( rgb(97, 97, 97)));
189
- background-image: -moz-linear-gradient(top, rgb(104, 104, 104), rgb(97, 97, 97));
190
- background-image: -ms-linear-gradient(top, rgb(104, 104, 104), rgb(97, 97, 97));
191
- background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgb(104, 104, 104)), color-stop(100%, rgb(97, 97, 97)));
192
- background-image: -o-linear-gradienttop, rgb(104, 104, 104), rgb(97, 97, 97));
193
- background-image: linear-gradient( rgb(104, 104, 104), rgb(97, 97, 97));
194
- background-color: rgb(97, 97, 97) !important;
195
- border-color: rgba(0, 0, 0, 0.25) rgba(0, 0, 0, 0.25) rgba(0, 0, 0, 0.35) !important;
196
- }
197
- .sdf-admin .thumbnail,
198
- .sdf-admin .img-thumbnail {
199
- -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
200
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
201
- }
202
-
203
- .sdf-admin .alert {
204
- text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);
205
- -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);
206
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);
207
- }
208
-
209
- .sdf-admin .alert-success {
210
- background-image: -webkit-gradient(linear, left 0%, left 100%, from(#dff0d8), to(#c8e5bc));
211
- background-image: -webkit-linear-gradient(top, #dff0d8, 0%, #c8e5bc, 100%);
212
- background-image: -moz-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
213
- background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
214
- background-repeat: repeat-x;
215
- border-color: #b2dba1;
216
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
217
- }
218
-
219
- .sdf-admin .alert-info {
220
- background-image: -webkit-gradient(linear, left 0%, left 100%, from(#d9edf7), to(#b9def0));
221
- background-image: -webkit-linear-gradient(top, #d9edf7, 0%, #b9def0, 100%);
222
- background-image: -moz-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
223
- background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
224
- background-repeat: repeat-x;
225
- border-color: #9acfea;
226
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
227
- }
228
-
229
- .sdf-admin .alert-warning {
230
- background-image: -webkit-gradient(linear, left 0%, left 100%, from(#fcf8e3), to(#f8efc0));
231
- background-image: -webkit-linear-gradient(top, #fcf8e3, 0%, #f8efc0, 100%);
232
- background-image: -moz-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
233
- background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
234
- background-repeat: repeat-x;
235
- border-color: #f5e79e;
236
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
237
- }
238
-
239
- .sdf-admin .alert-danger {
240
- background-image: -webkit-gradient(linear, left 0%, left 100%, from(#f2dede), to(#e7c3c3));
241
- background-image: -webkit-linear-gradient(top, #f2dede, 0%, #e7c3c3, 100%);
242
- background-image: -moz-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
243
- background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
244
- background-repeat: repeat-x;
245
- border-color: #dca7a7;
246
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
247
- }
248
-
249
- .sdf-admin .progress {
250
- background-image: -webkit-gradient(linear, left 0%, left 100%, from(#ebebeb), to(#f5f5f5));
251
- background-image: -webkit-linear-gradient(top, #ebebeb, 0%, #f5f5f5, 100%);
252
- background-image: -moz-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
253
- background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
254
- background-repeat: repeat-x;
255
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
256
- }
257
-
258
- .sdf-admin .progress-bar {
259
- background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#3071a9));
260
- background-image: -webkit-linear-gradient(top, #428bca, 0%, #3071a9, 100%);
261
- background-image: -moz-linear-gradient(top, #428bca 0%, #3071a9 100%);
262
- background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
263
- background-repeat: repeat-x;
264
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
265
- }
266
-
267
- .sdf-admin .progress-bar-success {
268
- background-image: -webkit-gradient(linear, left 0%, left 100%, from(#5cb85c), to(#449d44));
269
- background-image: -webkit-linear-gradient(top, #5cb85c, 0%, #449d44, 100%);
270
- background-image: -moz-linear-gradient(top, #5cb85c 0%, #449d44 100%);
271
- background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
272
- background-repeat: repeat-x;
273
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
274
- }
275
-
276
- .sdf-admin .progress-bar-info {
277
- background-image: -webkit-gradient(linear, left 0%, left 100%, from(#5bc0de), to(#31b0d5));
278
- background-image: -webkit-linear-gradient(top, #5bc0de, 0%, #31b0d5, 100%);
279
- background-image: -moz-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
280
- background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
281
- background-repeat: repeat-x;
282
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
283
- }
284
-
285
- .sdf-admin .progress-bar-warning {
286
- background-image: -webkit-gradient(linear, left 0%, left 100%, from(#f0ad4e), to(#ec971f));
287
- background-image: -webkit-linear-gradient(top, #f0ad4e, 0%, #ec971f, 100%);
288
- background-image: -moz-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
289
- background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
290
- background-repeat: repeat-x;
291
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
292
- }
293
-
294
- .sdf-admin .progress-bar-danger {
295
- background-image: -webkit-gradient(linear, left 0%, left 100%, from(#d9534f), to(#c9302c));
296
- background-image: -webkit-linear-gradient(top, #d9534f, 0%, #c9302c, 100%);
297
- background-image: -moz-linear-gradient(top, #d9534f 0%, #c9302c 100%);
298
- background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
299
- background-repeat: repeat-x;
300
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
301
- }
302
-
303
- .sdf-admin .list-group {
304
- border-radius: 4px;
305
- -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
306
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
307
- }
308
-
309
- .sdf-admin .list-group-item.active,
310
- .sdf-admin .list-group-item.active:hover,
311
- .sdf-admin .list-group-item.active:focus {
312
- text-shadow: 0 -1px 0 #3071a9;
313
- background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#3278b3));
314
- background-image: -webkit-linear-gradient(top, #428bca, 0%, #3278b3, 100%);
315
- background-image: -moz-linear-gradient(top, #428bca 0%, #3278b3 100%);
316
- background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%);
317
- background-repeat: repeat-x;
318
- border-color: #3278b3;
319
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);
320
- }
321
-
322
- .sdf-admin .panel {
323
- -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
324
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
325
- }
326
-
327
- .sdf-admin .panel-default > .panel-heading {
328
- background-image: -webkit-gradient(linear, left 0%, left 100%, from(#f5f5f5), to(#e8e8e8));
329
- background-image: -webkit-linear-gradient(top, #f5f5f5, 0%, #e8e8e8, 100%);
330
- background-image: -moz-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
331
- background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
332
- background-repeat: repeat-x;
333
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
334
- }
335
-
336
- .sdf-admin .panel-primary > .panel-heading {
337
- background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#357ebd));
338
- background-image: -webkit-linear-gradient(top, #428bca, 0%, #357ebd, 100%);
339
- background-image: -moz-linear-gradient(top, #428bca 0%, #357ebd 100%);
340
- background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
341
- background-repeat: repeat-x;
342
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
343
- }
344
-
345
- .sdf-admin .panel-success > .panel-heading {
346
- background-image: -webkit-gradient(linear, left 0%, left 100%, from(#dff0d8), to(#d0e9c6));
347
- background-image: -webkit-linear-gradient(top, #dff0d8, 0%, #d0e9c6, 100%);
348
- background-image: -moz-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
349
- background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
350
- background-repeat: repeat-x;
351
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
352
- }
353
-
354
- .sdf-admin .panel-info > .panel-heading {
355
- background-image: -webkit-gradient(linear, left 0%, left 100%, from(#d9edf7), to(#c4e3f3));
356
- background-image: -webkit-linear-gradient(top, #d9edf7, 0%, #c4e3f3, 100%);
357
- background-image: -moz-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
358
- background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
359
- background-repeat: repeat-x;
360
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
361
- }
362
-
363
- .sdf-admin .panel-warning > .panel-heading {
364
- background-image: -webkit-gradient(linear, left 0%, left 100%, from(#fcf8e3), to(#faf2cc));
365
- background-image: -webkit-linear-gradient(top, #fcf8e3, 0%, #faf2cc, 100%);
366
- background-image: -moz-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
367
- background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
368
- background-repeat: repeat-x;
369
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
370
- }
371
-
372
- .sdf-admin .panel-danger > .panel-heading {
373
- background-image: -webkit-gradient(linear, left 0%, left 100%, from(#f2dede), to(#ebcccc));
374
- background-image: -webkit-linear-gradient(top, #f2dede, 0%, #ebcccc, 100%);
375
- background-image: -moz-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
376
- background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
377
- background-repeat: repeat-x;
378
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
379
- }
380
-
381
- .sdf-admin .well {
382
- background-color: #fcfcfc;
383
- border-color: #f2f2f2;
384
- -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.02), 0 1px 0 rgba(255, 255, 255, 0.1);
385
- box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.02), 0 1px 0 rgba(255, 255, 255, 0.1);
386
  }
1
+ .sdf-admin .btn-default,
2
+ .sdf-admin .btn-primary,
3
+ .sdf-admin .btn-success,
4
+ .sdf-admin .btn-info,
5
+ .sdf-admin .btn-warning,
6
+ .sdf-admin .btn-danger {
7
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
8
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
9
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
10
+ }
11
+
12
+ .sdf-admin .btn-default:active,
13
+ .sdf-admin .btn-primary:active,
14
+ .sdf-admin .btn-success:active,
15
+ .sdf-admin .btn-info:active,
16
+ .sdf-admin .btn-warning:active,
17
+ .sdf-admin .btn-danger:active,
18
+ .sdf-admin .btn-default.active,
19
+ .sdf-admin .btn-primary.active,
20
+ .sdf-admin .btn-success.active,
21
+ .sdf-admin .btn-info.active,
22
+ .sdf-admin .btn-warning.active,
23
+ .sdf-admin .btn-danger.active {
24
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
25
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
26
+ }
27
+
28
+ .sdf-admin .btn:active,
29
+ .sdf-admin .btn.active {
30
+ background-image: none;
31
+ }
32
+
33
+ .sdf-admin .btn-default {
34
+ text-shadow: 0 1px 0 #fff;
35
+ background-image: -webkit-gradient(linear, left 0%, left 100%, from(#ffffff), to(#e6e6e6));
36
+ background-image: -webkit-linear-gradient(top, #ffffff, 0%, #e6e6e6, 100%);
37
+ background-image: -moz-linear-gradient(top, #ffffff 0%, #e6e6e6 100%);
38
+ background-image: linear-gradient(to bottom, #ffffff 0%, #e6e6e6 100%);
39
+ background-repeat: repeat-x;
40
+ border-color: #e0e0e0;
41
+ border-color: #ccc;
42
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);
43
+ }
44
+
45
+ .sdf-admin .btn-default:active,
46
+ .sdf-admin .btn-default.active {
47
+ background-color: #e6e6e6;
48
+ border-color: #e0e0e0;
49
+ }
50
+
51
+ .sdf-admin .btn-primary {
52
+ background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#3071a9));
53
+ background-image: -webkit-linear-gradient(top, #428bca, 0%, #3071a9, 100%);
54
+ background-image: -moz-linear-gradient(top, #428bca 0%, #3071a9 100%);
55
+ background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
56
+ background-repeat: repeat-x;
57
+ border-color: #2d6ca2;
58
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
59
+ }
60
+
61
+ .sdf-admin .btn-primary:active,
62
+ .sdf-admin .btn-primary.active {
63
+ background-color: #3071a9;
64
+ border-color: #2d6ca2;
65
+ }
66
+
67
+ .sdf-admin .btn-success {
68
+ background-image: -webkit-gradient(linear, left 0%, left 100%, from(#5cb85c), to(#449d44));
69
+ background-image: -webkit-linear-gradient(top, #5cb85c, 0%, #449d44, 100%);
70
+ background-image: -moz-linear-gradient(top, #5cb85c 0%, #449d44 100%);
71
+ background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
72
+ background-repeat: repeat-x;
73
+ border-color: #419641;
74
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
75
+ }
76
+
77
+ .sdf-admin .btn-success:active,
78
+ .sdf-admin .btn-success.active {
79
+ background-color: #449d44;
80
+ border-color: #419641;
81
+ }
82
+
83
+ .sdf-admin .btn-warning {
84
+ background-image: -webkit-gradient(linear, left 0%, left 100%, from(#f0ad4e), to(#ec971f));
85
+ background-image: -webkit-linear-gradient(top, #f0ad4e, 0%, #ec971f, 100%);
86
+ background-image: -moz-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
87
+ background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
88
+ background-repeat: repeat-x;
89
+ border-color: #eb9316;
90
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
91
+ }
92
+
93
+ .sdf-admin .btn-warning:active,
94
+ .sdf-admin .btn-warning.active {
95
+ background-color: #ec971f;
96
+ border-color: #eb9316;
97
+ }
98
+
99
+ .sdf-admin .btn-danger {
100
+ background-image: -webkit-gradient(linear, left 0%, left 100%, from(#d9534f), to(#c9302c));
101
+ background-image: -webkit-linear-gradient(top, #d9534f, 0%, #c9302c, 100%);
102
+ background-image: -moz-linear-gradient(top, #d9534f 0%, #c9302c 100%);
103
+ background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
104
+ background-repeat: repeat-x;
105
+ border-color: #c12e2a;
106
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
107
+ }
108
+
109
+ .sdf-admin .btn-danger:active,
110
+ .sdf-admin .btn-danger.active {
111
+ background-color: #c9302c;
112
+ border-color: #c12e2a;
113
+ }
114
+
115
+ .sdf-admin .btn-info {
116
+ background-image: -webkit-gradient(linear, left 0%, left 100%, from(#5bc0de), to(#31b0d5));
117
+ background-image: -webkit-linear-gradient(top, #5bc0de, 0%, #31b0d5, 100%);
118
+ background-image: -moz-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
119
+ background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
120
+ background-repeat: repeat-x;
121
+ border-color: #2aabd2;
122
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
123
+ }
124
+
125
+ .sdf-admin .btn-info:active,
126
+ .sdf-admin .btn-info.active {
127
+ background-color: #31b0d5;
128
+ border-color: #2aabd2;
129
+ }
130
+ /* SDF Buttons */
131
+ .sdf-admin .btn-custom {
132
+ -webkit-font-smoothing: antialiased;
133
+ background-repeat: repeat-x !important;
134
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=rgb(242, 160, 67), endColorstr=rgb(245, 143, 29));
135
+ background-image: -webkit-linear-gradient(top, rgb(242, 160, 67), rgb(245, 143, 29)) !important;
136
+ background-image: -khtml-gradient(linear, left top, left bottom, from(rgb(242, 160, 67)), to( rgb(245, 143, 29)));
137
+ background-image: -moz-linear-gradient(top, rgb(242, 160, 67), rgb(245, 143, 29));
138
+ background-image: -ms-linear-gradient(top, rgb(242, 160, 67), rgb(245, 143, 29));
139
+ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgb(242, 160, 67)), color-stop(100%, rgb(245, 143, 29)));
140
+ background-image: -o-linear-gradienttop, rgb(242, 160, 67), rgb(245, 143, 29));
141
+ background-image: linear-gradient( rgb(242, 160, 67), rgb(245, 143, 29));
142
+ background-color: rgb(245, 143, 29) !important;
143
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25) !important;
144
+ color: rgb(255, 255, 255) !important;
145
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25) !important;
146
+ text-decoration: none;
147
+ }
148
+ .sdf-admin .btn-custom:hover,
149
+ .sdf-admin .btn-custom:focus {
150
+ -webkit-font-smoothing: antialiased;
151
+ background-repeat: repeat-x !important;
152
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=rgb(242, 160, 67), endColorstr=rgb(245, 143, 29));
153
+ background-image: -webkit-linear-gradient(top, rgb(242, 160, 67), rgb(245, 143, 29)) !important;
154
+ background-image: -khtml-gradient(linear, left top, left bottom, from(rgb(242, 160, 67)), to( rgb(245, 143, 29)));
155
+ background-image: -moz-linear-gradient(top, rgb(242, 160, 67), rgb(245, 143, 29));
156
+ background-image: -ms-linear-gradient(top, rgb(242, 160, 67), rgb(245, 143, 29));
157
+ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgb(242, 160, 67)), color-stop(100%, rgb(245, 143, 29)));
158
+ background-image: -o-linear-gradienttop, rgb(242, 160, 67), rgb(245, 143, 29));
159
+ background-image: linear-gradient( rgb(242, 160, 67), rgb(245, 143, 29));
160
+ background-color: rgb(245, 143, 29) !important;
161
+ border-color: rgba(0, 0, 0, 0.2) rgba(0, 0, 0, 0.2) rgba(0, 0, 0, 0.35) !important;
162
+ color: rgb(255, 255, 255) !important;
163
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25) !important;
164
+ text-decoration: none;
165
+ }
166
+ .sdf-admin .btn-sdf-grey {
167
+ font-weight:bold !important;
168
+ -webkit-font-smoothing: antialiased;
169
+ background-repeat: repeat-x !important;
170
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=rgb(125, 125, 125), endColorstr=rgb(118, 118, 118));
171
+ background-image: -webkit-linear-gradient(top, rgb(125, 125, 125), rgb(118, 118, 118)) !important;
172
+ background-image: -khtml-gradient(linear, left top, left bottom, from(rgb(125, 125, 125)), to( rgb(118, 118, 118)));
173
+ background-image: -moz-linear-gradient(top, rgb(125, 125, 125), rgb(118, 118, 118));
174
+ background-image: -ms-linear-gradient(top, rgb(125, 125, 125), rgb(118, 118, 118));
175
+ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgb(125, 125, 125)), color-stop(100%, rgb(118, 118, 118)));
176
+ background-image: -o-linear-gradienttop, rgb(125, 125, 125), rgb(118, 118, 118));
177
+ background-image: linear-gradient( rgb(125, 125, 125), rgb(118, 118, 118));
178
+ background-color: rgb(118, 118, 118) !important;
179
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25) !important;
180
+ color: rgb(255, 255, 255) !important;
181
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25) !important;
182
+ text-decoration: none;
183
+ }
184
+ .sdf-admin .btn-sdf-grey:hover,
185
+ .sdf-admin .btn-sdf-grey:focus {
186
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=rgb(104, 104, 104), endColorstr=rgb(97, 97, 97));
187
+ background-image: -webkit-linear-gradient(top, rgb(104, 104, 104), rgb(97, 97, 97)) !important;
188
+ background-image: -khtml-gradient(linear, left top, left bottom, from(rgb(104, 104, 104)), to( rgb(97, 97, 97)));
189
+ background-image: -moz-linear-gradient(top, rgb(104, 104, 104), rgb(97, 97, 97));
190
+ background-image: -ms-linear-gradient(top, rgb(104, 104, 104), rgb(97, 97, 97));
191
+ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgb(104, 104, 104)), color-stop(100%, rgb(97, 97, 97)));
192
+ background-image: -o-linear-gradienttop, rgb(104, 104, 104), rgb(97, 97, 97));
193
+ background-image: linear-gradient( rgb(104, 104, 104), rgb(97, 97, 97));
194
+ background-color: rgb(97, 97, 97) !important;
195
+ border-color: rgba(0, 0, 0, 0.25) rgba(0, 0, 0, 0.25) rgba(0, 0, 0, 0.35) !important;
196
+ }
197
+ .sdf-admin .thumbnail,
198
+ .sdf-admin .img-thumbnail {
199
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
200
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
201
+ }
202
+
203
+ .sdf-admin .alert {
204
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);
205
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);
206
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);
207
+ }
208
+
209
+ .sdf-admin .alert-success {
210
+ background-image: -webkit-gradient(linear, left 0%, left 100%, from(#dff0d8), to(#c8e5bc));
211
+ background-image: -webkit-linear-gradient(top, #dff0d8, 0%, #c8e5bc, 100%);
212
+ background-image: -moz-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
213
+ background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
214
+ background-repeat: repeat-x;
215
+ border-color: #b2dba1;
216
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
217
+ }
218
+
219
+ .sdf-admin .alert-info {
220
+ background-image: -webkit-gradient(linear, left 0%, left 100%, from(#d9edf7), to(#b9def0));
221
+ background-image: -webkit-linear-gradient(top, #d9edf7, 0%, #b9def0, 100%);
222
+ background-image: -moz-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
223
+ background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
224
+ background-repeat: repeat-x;
225
+ border-color: #9acfea;
226
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
227
+ }
228
+
229
+ .sdf-admin .alert-warning {
230
+ background-image: -webkit-gradient(linear, left 0%, left 100%, from(#fcf8e3), to(#f8efc0));
231
+ background-image: -webkit-linear-gradient(top, #fcf8e3, 0%, #f8efc0, 100%);
232
+ background-image: -moz-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
233
+ background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
234
+ background-repeat: repeat-x;
235
+ border-color: #f5e79e;
236
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
237
+ }
238
+
239
+ .sdf-admin .alert-danger {
240
+ background-image: -webkit-gradient(linear, left 0%, left 100%, from(#f2dede), to(#e7c3c3));
241
+ background-image: -webkit-linear-gradient(top, #f2dede, 0%, #e7c3c3, 100%);
242
+ background-image: -moz-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
243
+ background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
244
+ background-repeat: repeat-x;
245
+ border-color: #dca7a7;
246
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
247
+ }
248
+
249
+ .sdf-admin .progress {
250
+ background-image: -webkit-gradient(linear, left 0%, left 100%, from(#ebebeb), to(#f5f5f5));
251
+ background-image: -webkit-linear-gradient(top, #ebebeb, 0%, #f5f5f5, 100%);
252
+ background-image: -moz-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
253
+ background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
254
+ background-repeat: repeat-x;
255
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
256
+ }
257
+
258
+ .sdf-admin .progress-bar {
259
+ background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#3071a9));
260
+ background-image: -webkit-linear-gradient(top, #428bca, 0%, #3071a9, 100%);
261
+ background-image: -moz-linear-gradient(top, #428bca 0%, #3071a9 100%);
262
+ background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
263
+ background-repeat: repeat-x;
264
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
265
+ }
266
+
267
+ .sdf-admin .progress-bar-success {
268
+ background-image: -webkit-gradient(linear, left 0%, left 100%, from(#5cb85c), to(#449d44));
269
+ background-image: -webkit-linear-gradient(top, #5cb85c, 0%, #449d44, 100%);
270
+ background-image: -moz-linear-gradient(top, #5cb85c 0%, #449d44 100%);
271
+ background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
272
+ background-repeat: repeat-x;
273
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
274
+ }
275
+
276
+ .sdf-admin .progress-bar-info {
277
+ background-image: -webkit-gradient(linear, left 0%, left 100%, from(#5bc0de), to(#31b0d5));
278
+ background-image: -webkit-linear-gradient(top, #5bc0de, 0%, #31b0d5, 100%);
279
+ background-image: -moz-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
280
+ background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
281
+ background-repeat: repeat-x;
282
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
283
+ }
284
+
285
+ .sdf-admin .progress-bar-warning {
286
+ background-image: -webkit-gradient(linear, left 0%, left 100%, from(#f0ad4e), to(#ec971f));
287
+ background-image: -webkit-linear-gradient(top, #f0ad4e, 0%, #ec971f, 100%);
288
+ background-image: -moz-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
289
+ background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
290
+ background-repeat: repeat-x;
291
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
292
+ }
293
+
294
+ .sdf-admin .progress-bar-danger {
295
+ background-image: -webkit-gradient(linear, left 0%, left 100%, from(#d9534f), to(#c9302c));
296
+ background-image: -webkit-linear-gradient(top, #d9534f, 0%, #c9302c, 100%);
297
+ background-image: -moz-linear-gradient(top, #d9534f 0%, #c9302c 100%);
298
+ background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
299
+ background-repeat: repeat-x;
300
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
301
+ }
302
+
303
+ .sdf-admin .list-group {
304
+ border-radius: 4px;
305
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
306
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
307
+ }
308
+
309
+ .sdf-admin .list-group-item.active,
310
+ .sdf-admin .list-group-item.active:hover,
311
+ .sdf-admin .list-group-item.active:focus {
312
+ text-shadow: 0 -1px 0 #3071a9;
313
+ background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#3278b3));
314
+ background-image: -webkit-linear-gradient(top, #428bca, 0%, #3278b3, 100%);
315
+ background-image: -moz-linear-gradient(top, #428bca 0%, #3278b3 100%);
316
+ background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%);
317
+ background-repeat: repeat-x;
318
+ border-color: #3278b3;
319
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);
320
+ }
321
+
322
+ .sdf-admin .panel {
323
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
324
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
325
+ }
326
+
327
+ .sdf-admin .panel-default > .panel-heading {
328
+ background-image: -webkit-gradient(linear, left 0%, left 100%, from(#f5f5f5), to(#e8e8e8));
329
+ background-image: -webkit-linear-gradient(top, #f5f5f5, 0%, #e8e8e8, 100%);
330
+ background-image: -moz-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
331
+ background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
332
+ background-repeat: repeat-x;
333
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
334
+ }
335
+
336
+ .sdf-admin .panel-primary > .panel-heading {
337
+ background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#357ebd));
338
+ background-image: -webkit-linear-gradient(top, #428bca, 0%, #357ebd, 100%);
339
+ background-image: -moz-linear-gradient(top, #428bca 0%, #357ebd 100%);
340
+ background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
341
+ background-repeat: repeat-x;
342
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
343
+ }
344
+
345
+ .sdf-admin .panel-success > .panel-heading {
346
+ background-image: -webkit-gradient(linear, left 0%, left 100%, from(#dff0d8), to(#d0e9c6));
347
+ background-image: -webkit-linear-gradient(top, #dff0d8, 0%, #d0e9c6, 100%);
348
+ background-image: -moz-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
349
+ background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
350
+ background-repeat: repeat-x;
351
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
352
+ }
353
+
354
+ .sdf-admin .panel-info > .panel-heading {
355
+ background-image: -webkit-gradient(linear, left 0%, left 100%, from(#d9edf7), to(#c4e3f3));
356
+ background-image: -webkit-linear-gradient(top, #d9edf7, 0%, #c4e3f3, 100%);
357
+ background-image: -moz-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
358
+ background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
359
+ background-repeat: repeat-x;
360
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
361
+ }
362
+
363
+ .sdf-admin .panel-warning > .panel-heading {
364
+ background-image: -webkit-gradient(linear, left 0%, left 100%, from(#fcf8e3), to(#faf2cc));
365
+ background-image: -webkit-linear-gradient(top, #fcf8e3, 0%, #faf2cc, 100%);
366
+ background-image: -moz-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
367
+ background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
368
+ background-repeat: repeat-x;
369
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
370
+ }
371
+
372
+ .sdf-admin .panel-danger > .panel-heading {
373
+ background-image: -webkit-gradient(linear, left 0%, left 100%, from(#f2dede), to(#ebcccc));
374
+ background-image: -webkit-linear-gradient(top, #f2dede, 0%, #ebcccc, 100%);
375
+ background-image: -moz-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
376
+ background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
377
+ background-repeat: repeat-x;
378
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
379
+ }
380
+
381
+ .sdf-admin .well {
382
+ background-color: #fcfcfc;
383
+ border-color: #f2f2f2;
384
+ -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.02), 0 1px 0 rgba(255, 255, 255, 0.1);
385
+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.02), 0 1px 0 rgba(255, 255, 255, 0.1);
386
  }
plugin/sdf/bootstrap/css/bootstrap.admin.css CHANGED
@@ -1,5551 +1,6544 @@
1
- /*!
2
- * Bootstrap v3.0.0
3
- *
4
- * Copyright 2013 Twitter, Inc
5
- * Licensed under the Apache License v2.0
6
- * http://www.apache.org/licenses/LICENSE-2.0
7
- *
8
- * Designed and built with all the love in the world by @mdo and @fat.
9
- */
10
-
11
- /*! normalize.css v2.1.0 | MIT License | git.io/normalize */
12
-
13
- .sdf-admin article,
14
- .sdf-admin aside,
15
- .sdf-admin details,
16
- .sdf-admin figcaption,
17
- .sdf-admin figure,
18
- .sdf-admin footer,
19
- .sdf-admin header,
20
- .sdf-admin hgroup,
21
- .sdf-admin main,
22
- .sdf-admin nav,
23
- .sdf-admin section,
24
- .sdf-admin summary {
25
- display: block;
26
- }
27
-
28
- .sdf-admin audio,
29
- .sdf-admin canvas,
30
- .sdf-admin video {
31
- display: inline-block;
32
- }
33
-
34
- .sdf-admin audio:not([controls]) {
35
- display: none;
36
- height: 0;
37
- }
38
-
39
- .sdf-admin [hidden] {
40
- display: none;
41
- }
42
-
43
- html .sdf-admin {
44
- -webkit-text-size-adjust: 100%;
45
- -ms-text-size-adjust: 100%;
46
- }
47
-
48
- body .sdf-admin {
49
- margin: 0;
50
- }
51
-
52
- .sdf-admin a:focus {
53
- outline: thin dotted;
54
- }
55
-
56
- .sdf-admin a:active,
57
- a:hover {
58
- outline: 0;
59
- }
60
-
61
- .sdf-admin h1 {
62
- margin: 0.67em 0;
63
- font-size: 2em;
64
- }
65
-
66
- .sdf-admin abbr[title] {
67
- border-bottom: 1px dotted;
68
- }
69
-
70
- .sdf-admin b,
71
- .sdf-admin strong {
72
- font-weight: bold;
73
- }
74
-
75
- .sdf-admin dfn {
76
- font-style: italic;
77
- }
78
-
79
- .sdf-admin hr {
80
- height: 0;
81
- -moz-box-sizing: content-box;
82
- box-sizing: content-box;
83
- }
84
-
85
- .sdf-admin mark {
86
- color: #000;
87
- background: #ff0;
88
- }
89
-
90
- .sdf-admin code,
91
- .sdf-admin kbd,
92
- .sdf-admin pre,
93
- .sdf-admin samp {
94
- font-family: monospace, serif;
95
- font-size: 1em;
96
- }
97
-
98
- .sdf-admin pre {
99
- white-space: pre-wrap;
100
- }
101
-
102
- .sdf-admin q {
103
- quotes: "\201C" "\201D" "\2018" "\2019";
104
- }
105
-
106
- .sdf-admin small {
107
- font-size: 80%;
108
- }
109
-
110
- .sdf-admin sub,
111
- .sdf-admin sup {
112
- position: relative;
113
- font-size: 75%;
114
- line-height: 0;
115
- vertical-align: baseline;
116
- }
117
-
118
- .sdf-admin sup {
119
- top: -0.5em;
120
- }
121
-
122
- .sdf-admin sub {
123
- bottom: -0.25em;
124
- }
125
-
126
- .sdf-admin img {
127
- border: 0;
128
- }
129
-
130
- .sdf-admin svg:not(:root) {
131
- overflow: hidden;
132
- }
133
-
134
- .sdf-admin figure {
135
- margin: 0;
136
- }
137
-
138
- .sdf-admin fieldset {
139
- padding: 0.35em 0.625em 0.75em;
140
- margin: 0 2px;
141
- border: 1px solid #c0c0c0;
142
- }
143
-
144
- .sdf-admin legend {
145
- padding: 0;
146
- border: 0;
147
- }
148
-
149
- .sdf-admin button,
150
- .sdf-admin input,
151
- .sdf-admin select,
152
- .sdf-admin textarea {
153
- margin: 0;
154
- font-family: inherit;
155
- font-size: 100%;
156
- }
157
-
158
- .sdf-admin button,
159
- .sdf-admin input {
160
- line-height: normal;
161
- }
162
-
163
- .sdf-admin button,
164
- .sdf-admin select {
165
- text-transform: none;
166
- }
167
-
168
- .sdf-admin button,
169
- html .sdf-admin input[type="button"],
170
- .sdf-admin input[type="reset"],
171
- .sdf-admin input[type="submit"] {
172
- cursor: pointer;
173
- -webkit-appearance: button;
174
- }
175
-
176
- .sdf-admin button[disabled],
177
- html .sdf-admin input[disabled] {
178
- cursor: default;
179
- }
180
-
181
- .sdf-admin input[type="checkbox"],
182
- .sdf-admin input[type="radio"] {
183
- padding: 0;
184
- box-sizing: border-box;
185
- }
186
-
187
- .sdf-admin input[type="search"] {
188
- -webkit-box-sizing: content-box;
189
- -moz-box-sizing: content-box;
190
- box-sizing: content-box;
191
- -webkit-appearance: textfield;
192
- }
193
-
194
- .sdf-admin input[type="search"]::-webkit-search-cancel-button,
195
- .sdf-admin input[type="search"]::-webkit-search-decoration {
196
- -webkit-appearance: none;
197
- }
198
-
199
- .sdf-admin button::-moz-focus-inner,
200
- .sdf-admin input::-moz-focus-inner {
201
- padding: 0;
202
- border: 0;
203
- }
204
-
205
- .sdf-admin textarea {
206
- overflow: auto;
207
- vertical-align: top;
208
- }
209
-
210
- .sdf-admin table {
211
- border-collapse: collapse;
212
- border-spacing: 0;
213
- }
214
-
215
- @media print {
216
- .sdf-admin * {
217
- color: #000 !important;
218
- text-shadow: none !important;
219
- background: transparent !important;
220
- box-shadow: none !important;
221
- }
222
- .sdf-admin a,
223
- .sdf-admin a:visited {
224
- text-decoration: underline;
225
- }
226
- .sdf-admin a[href]:after {
227
- content: " (" attr(href) ")";
228
- }
229
- .sdf-admin abbr[title]:after {
230
- content: " (" attr(title) ")";
231
- }
232
- .sdf-admin .ir a:after,
233
- .sdf-admin a[href^="javascript:"]:after,
234
- .sdf-admin a[href^="#"]:after {
235
- content: "";
236
- }
237
- .sdf-admin pre,
238
- .sdf-admin blockquote {
239
- border: 1px solid #999;
240
- page-break-inside: avoid;
241
- }
242
- .sdf-admin thead {
243
- display: table-header-group;
244
- }
245
- .sdf-admin tr,
246
- .sdf-admin img {
247
- page-break-inside: avoid;
248
- }
249
- .sdf-admin img {
250
- max-width: 100% !important;
251
- }
252
- @page {
253
- margin: 2cm .5cm;
254
- }
255
- .sdf-admin p,
256
- .sdf-admin h2,
257
- .sdf-admin h3 {
258
- orphans: 3;
259
- widows: 3;
260
- }
261
- .sdf-admin h2,
262
- .sdf-admin h3 {
263
- page-break-after: avoid;
264
- }
265
- .sdf-admin .navbar {
266
- display: none;
267
- }
268
- .sdf-admin .table td,
269
- .sdf-admin .table th {
270
- background-color: #fff !important;
271
- }
272
- .sdf-admin .btn > .caret,
273
- .sdf-admin .dropup > .btn > .caret {
274
- border-top-color: #000 !important;
275
- }
276
- .sdf-admin .label {
277
- border: 1px solid #000;
278
- }
279
- .sdf-admin .table {
280
- border-collapse: collapse !important;
281
- }
282
- .sdf-admin .table-bordered th,
283
- .sdf-admin .table-bordered td {
284
- border: 1px solid #ddd !important;
285
- }
286
- }
287
-
288
- .sdf-admin *,
289
- .sdf-admin *:before,
290
- .sdf-admin *:after {
291
- -webkit-box-sizing: border-box;
292
- -moz-box-sizing: border-box;
293
- box-sizing: border-box;
294
- }
295
-
296
- html .sdf-admin {
297
- font-size: 62.5%;
298
- -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
299
- }
300
-
301
- body .sdf-admin {
302
- font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
303
- font-size: 14px;
304
- line-height: 1.428571429;
305
- color: #333333;
306
- }
307
-
308
- .sdf-admin input,
309
- .sdf-admin button,
310
- .sdf-admin select,
311
- .sdf-admin textarea {
312
- font-family: inherit;
313
- font-size: inherit;
314
- line-height: inherit;
315
- }
316
-
317
- .sdf-admin button,
318
- .sdf-admin input,
319
- .sdf-admin select[multiple],
320
- .sdf-admin textarea {
321
- background-image: none;
322
- }
323
-
324
- .sdf-admin a {
325
- color: #8D8D8D;
326
- text-decoration: none;
327
- }
328
-
329
- .sdf-admin a:hover,
330
- .sdf-admin a:focus {
331
- color: #6D6D6D;
332
- text-decoration: underline;
333
- }
334
-
335
- .sdf-admin a:focus {
336
- outline: thin dotted #333;
337
- outline: 5px auto -webkit-focus-ring-color;
338
- outline-offset: -2px;
339
- }
340
-
341
- .sdf-admin img {
342
- vertical-align: middle;
343
- }
344
- .sdf-admin .img-responsive {
345
- display: block;
346
- height: auto;
347
- max-width: 100%;
348
- }
349
- .sdf-admin .img-rounded {
350
- border-radius: 6px;
351
- }
352
- .sdf-admin .img-thumbnail {
353
- display: inline-block;
354
- height: auto;
355
- max-width: 100%;
356
- padding: 4px;
357
- line-height: 1.428571429;
358
- background-color: #ffffff;
359
- border: 1px solid #dddddd;
360
- border-radius: 4px;
361
- -webkit-transition: all 0.2s ease-in-out;
362
- transition: all 0.2s ease-in-out;
363
- }
364
- .sdf-admin .img-circle {
365
- border-radius: 50%;
366
- }
367
-
368
- .sdf-admin hr {
369
- margin-top: 20px;
370
- margin-bottom: 20px;
371
- border: 0;
372
- border-top: 1px solid #eeeeee;
373
- }
374
- .sdf-admin .sr-only {
375
- position: absolute;
376
- width: 1px;
377
- height: 1px;
378
- padding: 0;
379
- margin: -1px;
380
- overflow: hidden;