PluginProbe
Ebook Store / trunk
Ebook Store vtrunk
6.24 6.23 6.22 6.21 6.20 trunk
ebook-store / settings-PDF-Protection.php

settings-PDF-Protection.php in Ebook Store trunk, at settings-PDF-Protection.php

500 lines 19.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Ebook Store - "PDF protection" settings tab.
4 *
5 * Rendered inside <div class="ebook-settings-panel"> by ebook_options.php, so this
6 * file emits sections only: no table rows, no cells.
7 *
8 * Three-layer reading order: Lock (encryption + password) -> Restrict (what a
9 * reader may do) -> Trace (watermark + QR code). All option names are unchanged;
10 * only the presentation is new.
11 *
12 * PHP 7.4 compatible.
13 *
14 * @package EbookStore
15 */
16
17 if ( ! defined( 'ABSPATH' ) ) {
18 exit;
19 }
20
21 settings_fields( 'ebook-settings-group-pdf-protection' );
22 do_settings_sections( 'ebook-settings-group-pdf-protection' );
23
24 $encrypt_pdf = (string) get_option( 'encrypt_pdf', 0 );
25 $random_password = (string) get_option( 'ebook_store_random_password', isset( $op->ebook_store_random_password ) ? $op->ebook_store_random_password : '' );
26 $blank_password = (string) get_option( 'ebook_store_blank_password', isset( $op->ebook_store_blank_password ) ? $op->ebook_store_blank_password : '' );
27 $encrypt_logged_in_free_files = (string) get_option( 'encrypt_files_for_logged_in_users', 0 );
28 $owner_password = (string) get_option( 'ebook_store_owner_password', isset( $op->ebook_store_owner_password ) ? $op->ebook_store_owner_password : '' );
29 $disable_printing = (string) get_option( 'disable_pdf_printing', 0 );
30 $disable_copy = (string) get_option( 'disable_pdf_copy', 0 );
31 $disable_modify = (string) get_option( 'disable_pdf_modify', 0 );
32 $disable_forms = (string) get_option( 'disable_annot-forms', 0 );
33 $buyer_info = (string) get_option( 'buyer_info', isset( $op->buyer_info ) ? $op->buyer_info : '' );
34 $buyer_info_text = (string) get_option( 'buyer_info_text', isset( $op->buyer_info_text ) ? $op->buyer_info_text : '' );
35 $watermark_position = (string) get_option( 'ebook_store_buyer_info_position', isset( $op->ebook_store_buyer_info_position ) ? $op->ebook_store_buyer_info_position : 'top' );
36 $watermark_mode = (string) get_option( 'ebook_store_watermark_mode', isset( $op->ebook_store_watermark_mode ) ? $op->ebook_store_watermark_mode : 'every' );
37 $watermark_color = (string) get_option( 'ebook_store_watermark_color_hex', isset( $op->ebook_store_watermark_color_hex ) ? $op->ebook_store_watermark_color_hex : '#FF0000' );
38 $qr_code = (string) get_option( 'qr_code', 0 );
39
40 $encryption_on = ( '1' === $encrypt_pdf );
41 $watermark_on = ( '1' === $buyer_info );
42 $qr_on = ( '1' === $qr_code );
43 $blank_on = ( '1' === $blank_password );
44 $random_on = ( '1' === $random_password );
45 $restrictions_on = ( '1' === $disable_printing || '1' === $disable_copy || '1' === $disable_modify || '1' === $disable_forms );
46
47 // Blank wins over random in the delivery code, so derive the single password
48 // mode in that order: blank -> random -> email (the invisible default).
49 $pw_mode = $blank_on ? 'none' : ( $random_on ? 'random' : 'email' );
50
51 $general_tab_url = function_exists( 'ebook_store_get_settings_tab_url' )
52 ? ebook_store_get_settings_tab_url( 'General' )
53 : admin_url( 'options-general.php?page=ebook_options.php' );
54
55 $position_options = array(
56 'top' => __( 'Top of the page', 'ebook-store' ),
57 'middle' => __( 'Middle of the page', 'ebook-store' ),
58 'bottom' => __( 'Bottom of the page', 'ebook-store' ),
59 );
60
61 $mode_options = array(
62 'first' => __( 'First page only', 'ebook-store' ),
63 'every' => __( 'Every page', 'ebook-store' ),
64 );
65
66 if ( 'none' === $pw_mode ) {
67 $password_summary = __( 'The file opens without a password. Only the watermark and the reader restrictions protect it.', 'ebook-store' );
68 } elseif ( 'random' === $pw_mode ) {
69 $password_summary = __( 'Each order gets its own password, shown in the order email and on the thank-you page.', 'ebook-store' );
70 } else {
71 $password_summary = __( 'The buyer opens the file by typing the email address they ordered with.', 'ebook-store' );
72 }
73
74 ebook_store_render_hero(
75 array(
76 'eyebrow' => __( 'PDF protection', 'ebook-store' ),
77 'title' => __( 'Stop the PDFs you sell being shared.', 'ebook-store' ),
78 'intro' => __( 'Three layers protect the PDFs you sell. Lock the file so only your buyer can open it, restrict what a reader may do with it, and trace every copy back to the order it came from. Turn on as many as you like — start with the lock at the top.', 'ebook-store' ),
79 'aside' => function () use ( $encryption_on, $password_summary, $restrictions_on, $watermark_on, $qr_on ) {
80 ?>
81 <aside class="ebook-settings-status-card">
82 <h4><?php echo esc_html__( 'Protection summary', 'ebook-store' ); ?></h4>
83 <ul class="ebook-settings-status-list">
84 <?php
85 ebook_store_status_row(
86 __( 'The lock', 'ebook-store' ),
87 $encryption_on ? 'ok' : 'muted',
88 $encryption_on
89 ? __( 'On — paid PDFs are encrypted before delivery.', 'ebook-store' )
90 : __( 'Off — buyers get your original file unchanged.', 'ebook-store' )
91 );
92
93 if ( $encryption_on ) {
94 ebook_store_status_row(
95 __( 'Opening the file', 'ebook-store' ),
96 'ok',
97 $password_summary
98 );
99 }
100
101 ebook_store_status_row(
102 __( 'Reader restrictions', 'ebook-store' ),
103 $restrictions_on ? 'ok' : 'muted',
104 $restrictions_on
105 ? __( 'At least one of print, copy, edit or annotate is blocked.', 'ebook-store' )
106 : __( 'None — readers can print, copy and edit.', 'ebook-store' )
107 );
108
109 ebook_store_status_row(
110 __( 'Buyer watermark', 'ebook-store' ),
111 $watermark_on ? 'ok' : 'muted',
112 $watermark_on
113 ? __( 'Buyer details are printed on the pages of every delivered copy.', 'ebook-store' )
114 : __( 'Off — nothing on the page identifies the buyer.', 'ebook-store' )
115 );
116
117 ebook_store_status_row(
118 __( 'QR trace code', 'ebook-store' ),
119 $qr_on ? 'ok' : 'muted',
120 $qr_on
121 ? __( 'A scannable code linking back to the order is stamped on the pages.', 'ebook-store' )
122 : __( 'Off.', 'ebook-store' )
123 );
124
125 ebook_store_status_row(
126 __( 'Any language', 'ebook-store' ),
127 'ok',
128 __( 'Watermarks render in any script — Latin, Cyrillic, Hebrew, Arabic — with no extra server settings.', 'ebook-store' )
129 );
130 ?>
131 </ul>
132 </aside>
133 <?php
134 },
135 )
136 );
137
138 ebook_store_pro_banner( __( 'PDF protection', 'ebook-store' ) );
139
140 /* ---------------------------------------------------------------------------
141 * Layer 1 · Lock the file
142 * ------------------------------------------------------------------------ */
143
144 ebook_store_section_open(
145 array(
146 'eyebrow' => __( 'Layer 1 · Lock', 'ebook-store' ),
147 'title' => __( 'Lock the file', 'ebook-store' ),
148 'intro' => __( 'When this is on, every PDF is rebuilt and password-locked the moment it’s sent. Your original upload is never touched. Nothing further down this page does anything until the lock is on.', 'ebook-store' ),
149 'id' => 'ebook-pdf-encryption',
150 'pro' => true,
151 )
152 );
153
154 ebook_store_toggle_grid_open();
155
156 ebook_store_toggle(
157 array(
158 'name' => 'encrypt_pdf',
159 'title' => __( 'Lock every PDF I sell', 'ebook-store' ),
160 'description' => __( 'Encrypts each paid PDF before it’s emailed or offered for download, so a stray copy can’t just be opened. Large files take a few extra seconds to prepare.', 'ebook-store' ),
161 'checked' => $encrypt_pdf,
162 'pro' => true,
163 )
164 );
165
166 ebook_store_toggle_grid_close();
167
168 if ( ! $encryption_on ) {
169 ebook_store_callout(
170 esc_html__( 'The lock is currently off, so the password choice, restrictions, watermark and QR code below are saved but not applied to any file.', 'ebook-store' ),
171 'info',
172 __( 'Heads up:', 'ebook-store' )
173 );
174 }
175
176 ?>
177 <div class="ebook-settings-field ebook-settings-field--wide"
178 data-ebook-search="<?php echo esc_attr__( 'password mode email random blank no password', 'ebook-store' ); ?>">
179 <label><?php echo esc_html__( 'What the buyer types to open the file', 'ebook-store' ); ?></label>
180 <p class="description"><?php echo esc_html__( 'Pick one. The stricter the password, the more support email you will get from people who cannot open their purchase.', 'ebook-store' ); ?></p>
181 </div>
182 <?php
183
184 ebook_store_radio_group(
185 array(
186 'name' => 'ebook_pw_mode',
187 'selected' => $pw_mode,
188 'pro' => true,
189 'choices' => array(
190 'email' => array(
191 'title' => __( 'The buyer’s email address', 'ebook-store' ),
192 'description' => __( 'The buyer types the email they ordered with. Easiest for customers.', 'ebook-store' ),
193 'sets' => array(
194 'es_pw_random' => '',
195 'es_pw_blank' => '',
196 ),
197 ),
198 'random' => array(
199 'title' => __( 'A unique password per order', 'ebook-store' ),
200 'description' => __( 'The plugin makes one per order and prints it in the delivery email and on the thank-you page. Safest if buyers forward receipts.', 'ebook-store' ),
201 'sets' => array(
202 'es_pw_random' => '1',
203 'es_pw_blank' => '',
204 ),
205 ),
206 'none' => array(
207 'title' => __( 'No password', 'ebook-store' ),
208 'description' => __( 'The file opens for anyone who has it — only the restrictions and watermark protect you.', 'ebook-store' ),
209 'sets' => array(
210 'es_pw_random' => '',
211 'es_pw_blank' => '1',
212 ),
213 ),
214 ),
215 'hidden' => array(
216 'es_pw_random' => array(
217 'name' => 'ebook_store_random_password',
218 'value' => $random_on ? '1' : '',
219 ),
220 'es_pw_blank' => array(
221 'name' => 'ebook_store_blank_password',
222 'value' => $blank_on ? '1' : '',
223 ),
224 ),
225 )
226 );
227
228 ebook_store_callout(
229 sprintf(
230 /* translators: %s: link to the General settings tab. */
231 esc_html__( 'The password reaches the buyer through your delivery email and thank-you page, so check that email delivery is working under %s.', 'ebook-store' ),
232 '<a href="' . esc_url( $general_tab_url ) . '">' . esc_html__( 'General settings', 'ebook-store' ) . '</a>'
233 ),
234 'soft'
235 );
236
237 ebook_store_callout(
238 esc_html__( 'Your PDF must be a normal, unprotected file in PDF 1.4 (Acrobat 5) format or newer. If a file is already password-protected, or was exported in an unusual way, the delivery will stop with an error instead of sending a broken file.', 'ebook-store' ),
239 'soft',
240 __( 'Before you switch the lock on:', 'ebook-store' )
241 );
242
243 ebook_store_advanced_open();
244
245 ebook_store_toggle_grid_open();
246
247 ebook_store_toggle(
248 array(
249 'name' => 'encrypt_files_for_logged_in_users',
250 'title' => __( 'Also lock free downloads for signed-in members', 'ebook-store' ),
251 'description' => __( 'Applies the same lock to free files for logged-in visitors, using their account email as the password. Visitors who are not signed in still get the file unlocked.', 'ebook-store' ),
252 'checked' => $encrypt_logged_in_free_files,
253 'pro' => true,
254 )
255 );
256
257 ebook_store_toggle_grid_close();
258
259 ebook_store_grid_open( 2 );
260
261 ebook_store_field(
262 array(
263 'type' => 'text',
264 'name' => 'ebook_store_owner_password',
265 'label' => __( 'Master password (kept private, never shown to buyers)', 'ebook-store' ),
266 'value' => $owner_password,
267 'placeholder' => __( 'Leave empty for a different password on every file', 'ebook-store' ),
268 'mono' => true,
269 'pro' => true,
270 'help' => __( 'This is the password that would be needed to strip the reader restrictions from a file. Leave blank and the plugin invents a fresh, unguessable one per file — the safest choice. Fill it in only if you need to unlock your own files later, and keep it private: anyone who learns it can remove the protection from every file you have sold.', 'ebook-store' ),
271 )
272 );
273
274 ?>
275 <div class="ebook-settings-aside-card">
276 <h4><?php echo esc_html__( 'What buyers will experience', 'ebook-store' ); ?></h4>
277 <ul class="ebook-settings-checklist">
278 <li><?php echo esc_html__( 'Buyer’s email address: they type the email used for the order.', 'ebook-store' ); ?></li>
279 <li><?php echo esc_html__( 'Unique password per order: they type the password printed in their order email.', 'ebook-store' ); ?></li>
280 <li><?php echo esc_html__( 'No password: the file simply opens, on any device.', 'ebook-store' ); ?></li>
281 </ul>
282 <p><?php echo esc_html( $password_summary ); ?></p>
283 </div>
284 <?php
285
286 ebook_store_grid_close();
287
288 ebook_store_advanced_close();
289
290 ebook_store_section_close();
291
292 /* ---------------------------------------------------------------------------
293 * Layer 2 · Restrict what readers can do
294 * ------------------------------------------------------------------------ */
295
296 ebook_store_section_open(
297 array(
298 'eyebrow' => __( 'Layer 2 · Restrict', 'ebook-store' ),
299 'title' => __( 'Control what readers can do', 'ebook-store' ),
300 'intro' => __( 'These limits are written into the PDF and obeyed by Adobe Acrobat and other well-behaved readers. They’re a deterrent, not a guarantee — pair them with a watermark below.', 'ebook-store' ),
301 'id' => 'ebook-pdf-restrictions',
302 'pro' => true,
303 )
304 );
305
306 ebook_store_toggle_grid_open();
307
308 ebook_store_toggle(
309 array(
310 'name' => 'disable_pdf_printing',
311 'title' => __( 'Block printing', 'ebook-store' ),
312 'description' => __( 'Greys out Print. Think twice for workbooks or sheet music people expect to print.', 'ebook-store' ),
313 'checked' => $disable_printing,
314 'pro' => true,
315 )
316 );
317
318 ebook_store_toggle(
319 array(
320 'name' => 'disable_pdf_copy',
321 'title' => __( 'Block copying text', 'ebook-store' ),
322 'description' => __( 'Stops select-and-paste. Note this also blocks screen readers used by blind customers, so skip it if accessibility matters.', 'ebook-store' ),
323 'checked' => $disable_copy,
324 'pro' => true,
325 )
326 );
327
328 ebook_store_toggle(
329 array(
330 'name' => 'disable_pdf_modify',
331 'title' => __( 'Block editing the document', 'ebook-store' ),
332 'description' => __( 'Stops readers rearranging or deleting pages — which is how someone would try to cut a watermark out.', 'ebook-store' ),
333 'checked' => $disable_modify,
334 'pro' => true,
335 )
336 );
337
338 ebook_store_toggle(
339 array(
340 'name' => 'disable_annot-forms',
341 'title' => __( 'Block notes, highlights and form filling', 'ebook-store' ),
342 'description' => __( 'Skip this if you sell fillable forms, checklists or study material meant to be written on.', 'ebook-store' ),
343 'checked' => $disable_forms,
344 'pro' => true,
345 )
346 );
347
348 ebook_store_toggle_grid_close();
349
350 ebook_store_section_close();
351
352 /* ---------------------------------------------------------------------------
353 * Layer 3 · Trace every copy
354 * ------------------------------------------------------------------------ */
355
356 ebook_store_section_open(
357 array(
358 'eyebrow' => __( 'Layer 3 · Trace', 'ebook-store' ),
359 'title' => __( 'Trace every copy', 'ebook-store' ),
360 'intro' => __( 'A visible line naming the buyer is the single best deterrent against casual sharing — and it tells you exactly which order a leaked copy came from.', 'ebook-store' ),
361 'id' => 'ebook-pdf-watermark',
362 'pro' => true,
363 )
364 );
365
366 ebook_store_toggle_grid_open();
367
368 ebook_store_toggle(
369 array(
370 'name' => 'buyer_info',
371 'title' => __( 'Print the buyer’s details on every page', 'ebook-store' ),
372 'description' => __( 'Stamps the line you write below onto the delivered PDF, filled in with that buyer’s details.', 'ebook-store' ),
373 'checked' => $buyer_info,
374 'pro' => true,
375 )
376 );
377
378 ebook_store_toggle(
379 array(
380 'name' => 'qr_code',
381 'title' => __( 'Add a scannable trace code', 'ebook-store' ),
382 'description' => __( 'Stamps a QR code in the corner linking to a page on your own site that shows which order a copy belongs to. Scan a leaked copy with your phone to identify the buyer. The code holds a link only, never personal details.', 'ebook-store' ),
383 'checked' => $qr_code,
384 'pro' => true,
385 )
386 );
387
388 ebook_store_toggle_grid_close();
389
390 if ( ( $watermark_on || $qr_on ) && ! $encryption_on ) {
391 ebook_store_callout(
392 esc_html__( 'The watermark and QR code are only added while files are being locked, and the lock is switched off in Layer 1. Turn it on above, otherwise buyers receive an unmarked file.', 'ebook-store' ),
393 'warning',
394 __( 'This will not appear yet:', 'ebook-store' )
395 );
396 }
397
398 ebook_store_field(
399 array(
400 'type' => 'text',
401 'name' => 'buyer_info_text',
402 'label' => __( 'What the stamp should say', 'ebook-store' ),
403 'value' => $buyer_info_text,
404 'wide' => true,
405 'pro' => true,
406 'help' => sprintf(
407 /* translators: 1: comma-separated list of merge codes, 2: example sentence using merge codes. */
408 __( 'Write it as you want it to read, and drop in %1$s wherever the buyer’s own details belong. For example: %2$s. Codes that your store has no value for are simply left blank, so keep the sentence short enough to fit across the page.', 'ebook-store' ),
409 '<code>%%first_name%%</code>, <code>%%last_name%%</code>, <code>%%payer_email%%</code>, <code>%%residence_country%%</code>',
410 '<code>' . esc_html__( 'Licensed to %%first_name%% %%last_name%% (%%payer_email%%) - please do not share.', 'ebook-store' ) . '</code>'
411 ),
412 )
413 );
414
415 if ( $qr_on ) {
416 ?>
417 <ul class="ebook-settings-status-list">
418 <?php
419 ebook_store_status_row(
420 __( 'Drawn on your server', 'ebook-store' ),
421 'ok',
422 __( 'The QR code is generated on your own server as part of the PDF — nothing is fetched from an outside service, and no special server settings are needed.', 'ebook-store' )
423 );
424
425 if ( ! $encryption_on ) {
426 ebook_store_status_row(
427 __( 'The lock', 'ebook-store' ),
428 'warn',
429 __( 'Switched off in Layer 1, so no QR code is added to delivered files yet.', 'ebook-store' ),
430 array(
431 'label' => __( 'Go to Layer 1', 'ebook-store' ),
432 'url' => '#ebook-pdf-encryption',
433 )
434 );
435 }
436 ?>
437 </ul>
438 <?php
439 }
440
441 ebook_store_callout(
442 '<a href="https://shopfiles.com/samples/protected_cv.pdf" target="_blank" rel="noopener noreferrer">' . esc_html__( 'Open an example of a protected, watermarked PDF', 'ebook-store' ) . '</a>',
443 'soft',
444 __( 'See what buyers get:', 'ebook-store' )
445 );
446
447 ebook_store_advanced_open( __( 'Watermark appearance', 'ebook-store' ) );
448
449 ebook_store_grid_open( 2 );
450
451 ebook_store_field(
452 array(
453 'type' => 'select',
454 'name' => 'ebook_store_buyer_info_position',
455 'label' => __( 'Where the stamp sits', 'ebook-store' ),
456 'value' => $watermark_position,
457 'options' => $position_options,
458 'pro' => true,
459 'help' => __( 'Top is discreet and rarely covers your layout. Middle sits across the content, which is the hardest to crop away but also the most intrusive for the paying customer.', 'ebook-store' ),
460 )
461 );
462
463 ebook_store_field(
464 array(
465 'type' => 'select',
466 'name' => 'ebook_store_watermark_mode',
467 'label' => __( 'How often it’s stamped', 'ebook-store' ),
468 'value' => $watermark_mode,
469 'options' => $mode_options,
470 'pro' => true,
471 'help' => __( 'Every page is the strongest deterrent, because no single page can be shared anonymously. First page only keeps the rest of the book clean. This choice also governs how often the QR trace code is stamped.', 'ebook-store' ),
472 )
473 );
474
475 ebook_store_field(
476 array(
477 'type' => 'text',
478 'name' => 'ebook_store_watermark_color_hex',
479 'label' => __( 'Stamp colour', 'ebook-store' ),
480 'value' => $watermark_color,
481 'placeholder' => '#FF0000',
482 'mono' => true,
483 'pro' => true,
484 'help' => __( 'A hex colour code such as #FF0000 for red or #808080 for grey. Pick something that stays readable on your pages: a colour close to the page background can disappear completely.', 'ebook-store' ),
485 )
486 );
487
488 ?>
489 <div class="ebook-settings-aside-card">
490 <h4><?php echo esc_html__( 'Check it on a real file', 'ebook-store' ); ?></h4>
491 <p><?php echo esc_html__( 'After changing the wording, colour or position, buy one of your own books with a test order and open the delivered PDF. That is the only way to see how the line sits on your particular layout.', 'ebook-store' ); ?></p>
492 </div>
493 <?php
494
495 ebook_store_grid_close();
496
497 ebook_store_advanced_close();
498
499 ebook_store_section_close();
500