| 1 |
/** |
| 2 |
* Reference material: the shortcode, the template functions, the JavaScript |
| 3 |
* helpers and what changed in each release. |
| 4 |
* |
| 5 |
* The per-option explanations deliberately live next to the options rather |
| 6 |
* than here -- this tab is for the things that have no control to sit beside. |
| 7 |
*/ |
| 8 |
|
| 9 |
import { useEffect, useState } from '@wordpress/element'; |
| 10 |
import apiFetch from '@wordpress/api-fetch'; |
| 11 |
import { __, _n, sprintf } from '@wordpress/i18n'; |
| 12 |
import { |
| 13 |
Card, |
| 14 |
CardBody, |
| 15 |
CardHeader, |
| 16 |
ExternalLink, |
| 17 |
} from '@wordpress/components'; |
| 18 |
|
| 19 |
function Snippet( { children } ) { |
| 20 |
return ( |
| 21 |
<pre className="cryptx-help__snippet"> |
| 22 |
<code>{ children }</code> |
| 23 |
</pre> |
| 24 |
); |
| 25 |
} |
| 26 |
|
| 27 |
/** |
| 28 |
* One release: its version and what changed in it. |
| 29 |
* |
| 30 |
* @param {Object} props Component props. |
| 31 |
* @param {Object} props.release The release, as the endpoint delivers it. |
| 32 |
* @param {boolean} props.isCurrent Whether this is the installed version. |
| 33 |
* @return {Element} The rendered release. |
| 34 |
*/ |
| 35 |
function Release( { release, isCurrent } ) { |
| 36 |
return ( |
| 37 |
<section className="cryptx-help__release"> |
| 38 |
<h3> |
| 39 |
{ release.version } |
| 40 |
{ isCurrent && ( |
| 41 |
<span className="cryptx-help__badge"> |
| 42 |
{ __( 'installed', 'cryptx' ) } |
| 43 |
</span> |
| 44 |
) } |
| 45 |
</h3> |
| 46 |
<ul> |
| 47 |
{ release.items.map( ( item, index ) => ( |
| 48 |
<li |
| 49 |
key={ index } |
| 50 |
// The entries come from readme.txt and were run through |
| 51 |
// wp_kses on the server; they carry links to the support |
| 52 |
// forum. |
| 53 |
|
| 54 |
dangerouslySetInnerHTML={ { __html: item } } |
| 55 |
/> |
| 56 |
) ) } |
| 57 |
</ul> |
| 58 |
</section> |
| 59 |
); |
| 60 |
} |
| 61 |
|
| 62 |
function Changelog() { |
| 63 |
const [ data, setData ] = useState( null ); |
| 64 |
|
| 65 |
useEffect( () => { |
| 66 |
apiFetch( { path: '/cryptx/v1/changelog' } ) |
| 67 |
.then( ( response ) => setData( response ) ) |
| 68 |
.catch( () => setData( { releases: [], current: '' } ) ); |
| 69 |
}, [] ); |
| 70 |
|
| 71 |
if ( data === null ) { |
| 72 |
return <p>{ __( 'Loading…', 'cryptx' ) }</p>; |
| 73 |
} |
| 74 |
|
| 75 |
const { releases, current } = data; |
| 76 |
|
| 77 |
if ( ! releases || releases.length === 0 ) { |
| 78 |
return <p>{ __( 'No changelog available.', 'cryptx' ) }</p>; |
| 79 |
} |
| 80 |
|
| 81 |
const [ newest, ...older ] = releases; |
| 82 |
|
| 83 |
return ( |
| 84 |
<div className="cryptx-help__changelog"> |
| 85 |
<Release |
| 86 |
release={ newest } |
| 87 |
isCurrent={ newest.version === current } |
| 88 |
/> |
| 89 |
|
| 90 |
{ /* Twelve releases printed in full ran to some two thousand pixels |
| 91 |
and buried the shortcode documentation above them. The one |
| 92 |
people came for is the newest; the rest are one click away |
| 93 |
rather than gone. */ } |
| 94 |
{ older.length > 0 && ( |
| 95 |
<details className="cryptx-help__older"> |
| 96 |
<summary> |
| 97 |
{ sprintf( |
| 98 |
/* translators: %d: number of older releases */ |
| 99 |
_n( |
| 100 |
'Show %d earlier release', |
| 101 |
'Show %d earlier releases', |
| 102 |
older.length, |
| 103 |
'cryptx' |
| 104 |
), |
| 105 |
older.length |
| 106 |
) } |
| 107 |
</summary> |
| 108 |
{ older.map( ( release ) => ( |
| 109 |
<Release |
| 110 |
key={ release.version } |
| 111 |
release={ release } |
| 112 |
isCurrent={ release.version === current } |
| 113 |
/> |
| 114 |
) ) } |
| 115 |
</details> |
| 116 |
) } |
| 117 |
</div> |
| 118 |
); |
| 119 |
} |
| 120 |
|
| 121 |
export default function HelpTab() { |
| 122 |
return ( |
| 123 |
<div |
| 124 |
className="cryptx-tab-panel" |
| 125 |
role="tabpanel" |
| 126 |
id="cryptx-panel-help" |
| 127 |
aria-labelledby="cryptx-tab-help" |
| 128 |
> |
| 129 |
<Card className="cryptx-section"> |
| 130 |
<CardHeader> |
| 131 |
<h2 className="cryptx-section__title"> |
| 132 |
{ __( 'Protect a single address', 'cryptx' ) } |
| 133 |
</h2> |
| 134 |
</CardHeader> |
| 135 |
<CardBody> |
| 136 |
<p> |
| 137 |
{ __( |
| 138 |
'In the editor, look for the "Protected email address" block — it does the same thing with fields instead of syntax, and it is the easier way in. The shortcode below is for everywhere a block cannot go: a widget, a custom field, a theme template.', |
| 139 |
'cryptx' |
| 140 |
) } |
| 141 |
</p> |
| 142 |
<p> |
| 143 |
{ __( |
| 144 |
'Both outrank the two ways of switching CryptX off: they work in posts you excluded, and inside them no address is exempt, however the list under Exceptions reads. That makes them the way to protect one address in otherwise untouched content.', |
| 145 |
'cryptx' |
| 146 |
) } |
| 147 |
</p> |
| 148 |
<Snippet>{ '[cryptx]info@example.com[/cryptx]' }</Snippet> |
| 149 |
<p> |
| 150 |
{ __( |
| 151 |
'Almost any setting from this screen can be overridden for a single shortcode by using its option name, written in lower case. The list of addresses to leave alone is the exception, and deliberately so: a shortcode says "protect this one", so nothing inside it is ever exempt.', |
| 152 |
'cryptx' |
| 153 |
) } |
| 154 |
</p> |
| 155 |
<Snippet> |
| 156 |
{ |
| 157 |
'[cryptx opt_linktext="1" alt_linktext="Contact us"]info@example.com[/cryptx]' |
| 158 |
} |
| 159 |
</Snippet> |
| 160 |
<p> |
| 161 |
{ __( |
| 162 |
'On top of the settings, four attributes describe the mail itself. They end up inside the encrypted link, so they stay hidden from spam bots just like the address:', |
| 163 |
'cryptx' |
| 164 |
) } |
| 165 |
</p> |
| 166 |
<Snippet> |
| 167 |
{ |
| 168 |
'[cryptx subject="Price enquiry" cc="sales@example.com"]info@example.com[/cryptx]' |
| 169 |
} |
| 170 |
</Snippet> |
| 171 |
<p> |
| 172 |
{ __( |
| 173 |
'Available are subject, body, cc and bcc — the headers RFC 6068 allows in a mailto link. Anything else is dropped. A link you wrote yourself with its own "?subject=" keeps it; the attribute only fills in where nothing is set.', |
| 174 |
'cryptx' |
| 175 |
) } |
| 176 |
</p> |
| 177 |
<p className="cryptx-help__note"> |
| 178 |
{ __( |
| 179 |
'The shortcode needs an address between its tags. Written self-closing, as [cryptx subject="…" /], there is nothing to protect and nothing is output — the attributes go nowhere.', |
| 180 |
'cryptx' |
| 181 |
) } |
| 182 |
</p> |
| 183 |
<p className="cryptx-help__note"> |
| 184 |
{ __( |
| 185 |
'Until 4.1.0 the attribute "subject" was accepted and then silently discarded, and an address written as "info@example.com?subject=…" lost its subject on the way as well. Both work now. The attribute "linktext", also listed by older versions of this page, never existed — use alt_linktext.', |
| 186 |
'cryptx' |
| 187 |
) } |
| 188 |
</p> |
| 189 |
</CardBody> |
| 190 |
</Card> |
| 191 |
|
| 192 |
<Card className="cryptx-section"> |
| 193 |
<CardHeader> |
| 194 |
<h2 className="cryptx-section__title"> |
| 195 |
{ __( 'In a theme', 'cryptx' ) } |
| 196 |
</h2> |
| 197 |
</CardHeader> |
| 198 |
<CardBody> |
| 199 |
<Snippet> |
| 200 |
{ |
| 201 |
"<?php echo cryptx_encrypt( 'info@example.com' ); ?>" |
| 202 |
} |
| 203 |
</Snippet> |
| 204 |
<p> |
| 205 |
{ __( |
| 206 |
'Takes an optional array of settings as its second argument, using the same option names as the shortcode.', |
| 207 |
'cryptx' |
| 208 |
) } |
| 209 |
</p> |
| 210 |
<p className="cryptx-help__note"> |
| 211 |
{ __( |
| 212 |
'The older function encryptx() still exists but is deprecated and will be removed in a future major release.', |
| 213 |
'cryptx' |
| 214 |
) } |
| 215 |
</p> |
| 216 |
</CardBody> |
| 217 |
</Card> |
| 218 |
|
| 219 |
<Card className="cryptx-section"> |
| 220 |
<CardHeader> |
| 221 |
<h2 className="cryptx-section__title"> |
| 222 |
{ __( 'In your own JavaScript', 'cryptx' ) } |
| 223 |
</h2> |
| 224 |
</CardHeader> |
| 225 |
<CardBody> |
| 226 |
<p> |
| 227 |
{ __( |
| 228 |
'For addresses that are added to the page after it loaded, and therefore never passed through the server side filters.', |
| 229 |
'cryptx' |
| 230 |
) } |
| 231 |
</p> |
| 232 |
<Snippet> |
| 233 |
{ `const link = document.createElement( 'a' ); |
| 234 |
link.href = generateDeCryptXHandler( 'info@example.com' ); |
| 235 |
link.textContent = 'Contact us';` } |
| 236 |
</Snippet> |
| 237 |
</CardBody> |
| 238 |
</Card> |
| 239 |
|
| 240 |
<Card className="cryptx-section"> |
| 241 |
<CardHeader> |
| 242 |
<h2 className="cryptx-section__title"> |
| 243 |
{ __( 'On the command line', 'cryptx' ) } |
| 244 |
</h2> |
| 245 |
</CardHeader> |
| 246 |
<CardBody> |
| 247 |
<p> |
| 248 |
{ __( |
| 249 |
'With WP-CLI installed. The first two read and write the settings, through the same validation this screen uses.', |
| 250 |
'cryptx' |
| 251 |
) } |
| 252 |
</p> |
| 253 |
<Snippet> |
| 254 |
{ `wp cryptx settings |
| 255 |
wp cryptx settings opt_linktext |
| 256 |
wp cryptx settings disable_rss 0` } |
| 257 |
</Snippet> |
| 258 |
<p> |
| 259 |
{ __( |
| 260 |
'The third is the one worth knowing about: it runs the body and the title of every published post through the filters that render it, and reports the ones that still carry a readable address. That is the question you have after changing a setting, and the preview above cannot answer it — it only ever renders a single sample.', |
| 261 |
'cryptx' |
| 262 |
) } |
| 263 |
</p> |
| 264 |
<Snippet>{ 'wp cryptx scan' }</Snippet> |
| 265 |
<p className="cryptx-help__note"> |
| 266 |
{ __( |
| 267 |
'A verdict of "encoded" means the address is in the page as HTML entities. That is invisible to a naive scanner and plain to anything that decodes them, which is most things — it is not the same as "hidden".', |
| 268 |
'cryptx' |
| 269 |
) } |
| 270 |
</p> |
| 271 |
<p className="cryptx-help__note"> |
| 272 |
{ __( |
| 273 |
'An address in a post title is always reported, because CryptX cannot protect one: the title reaches the document head through WordPress itself, along a path no plugin filter touches. Take it out of the title. And what the scan does not cover: widgets, comments, feeds, and whatever a theme prints on its own.', |
| 274 |
'cryptx' |
| 275 |
) } |
| 276 |
</p> |
| 277 |
<p> |
| 278 |
{ __( |
| 279 |
'On a multisite network both take --url, so one shell loop covers every site:', |
| 280 |
'cryptx' |
| 281 |
) } |
| 282 |
</p> |
| 283 |
<Snippet> |
| 284 |
{ |
| 285 |
'wp site list --field=url | xargs -I{} wp cryptx scan --url={}' |
| 286 |
} |
| 287 |
</Snippet> |
| 288 |
</CardBody> |
| 289 |
</Card> |
| 290 |
|
| 291 |
<Card className="cryptx-section"> |
| 292 |
<CardHeader> |
| 293 |
<h2 className="cryptx-section__title"> |
| 294 |
{ __( 'What changed', 'cryptx' ) } |
| 295 |
</h2> |
| 296 |
</CardHeader> |
| 297 |
<CardBody> |
| 298 |
<Changelog /> |
| 299 |
<p> |
| 300 |
<ExternalLink href="https://wordpress.org/plugins/cryptx/#developers"> |
| 301 |
{ __( 'Full history on wordpress.org', 'cryptx' ) } |
| 302 |
</ExternalLink> |
| 303 |
</p> |
| 304 |
</CardBody> |
| 305 |
</Card> |
| 306 |
</div> |
| 307 |
); |
| 308 |
} |
| 309 |
|