PluginProbe
Ebook Store / 6.25
Ebook Store v6.25
6.25 6.24 6.23 6.22 6.21 6.20 trunk
ebook-store / settings-EPUB-Protection.php

settings-EPUB-Protection.php in Ebook Store 6.25, at settings-EPUB-Protection.php

373 lines 14.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Ebook Store - "ePub 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 * EPUB cannot be password-encrypted and stay readable in e-readers, so protection
9 * here is social DRM: the buyer's identity is watermarked into the book and stamped
10 * into its metadata, while the file stays a valid ePub. Reading order: Mark (what
11 * the watermark says) -> Place (where it appears) -> Stamp (buyer in the metadata).
12 *
13 * PHP 7.4 compatible.
14 *
15 * @package EbookStore
16 */
17
18 if ( ! defined( 'ABSPATH' ) ) {
19 exit;
20 }
21
22 settings_fields( 'ebook-settings-group-epub-protection' );
23 do_settings_sections( 'ebook-settings-group-epub-protection' );
24
25 $wm_on = ( '1' === (string) get_option( 'ebook_store_epub_watermark', 0 ) );
26 $wm_text = (string) get_option( 'ebook_store_epub_watermark_text', 'Licensed to %%first_name%% %%last_name%% - %%payer_email%%. Please do not share.' );
27 $wm_scope = (string) get_option( 'ebook_store_epub_watermark_scope', 'first' );
28 $wm_position = (string) get_option( 'ebook_store_epub_watermark_position', 'bottom' );
29 $wm_style = (string) get_option( 'ebook_store_epub_watermark_style', 'subtle' );
30 $meta_on = ( '1' === (string) get_option( 'ebook_store_epub_stamp_metadata', 0 ) );
31 $qr_on = ( '1' === (string) get_option( 'ebook_store_epub_qr', 0 ) );
32 $qr_scope = (string) get_option( 'ebook_store_epub_qr_scope', 'first' );
33 $qr_position = (string) get_option( 'ebook_store_epub_qr_position', 'bottom' );
34
35 $scope_options = array(
36 'first' => __( 'The opening page only', 'ebook-store' ),
37 'every' => __( 'The start of every chapter', 'ebook-store' ),
38 'colophon' => __( 'A dedicated licence page at the end', 'ebook-store' ),
39 );
40
41 $position_options = array(
42 'top' => __( 'Top of the page', 'ebook-store' ),
43 'bottom' => __( 'Bottom of the page', 'ebook-store' ),
44 );
45
46 $style_options = array(
47 'subtle' => __( 'Subtle — a small, muted line', 'ebook-store' ),
48 'box' => __( 'Boxed — a bordered licence notice', 'ebook-store' ),
49 );
50
51 $scope_where = array(
52 'first' => __( 'the opening page', 'ebook-store' ),
53 'every' => __( 'the start of every chapter', 'ebook-store' ),
54 'colophon' => __( 'a licence page at the end', 'ebook-store' ),
55 );
56 $where_phrase = isset( $scope_where[ $wm_scope ] ) ? $scope_where[ $wm_scope ] : $scope_where['first'];
57 $qr_where_phrase = isset( $scope_where[ $qr_scope ] ) ? $scope_where[ $qr_scope ] : $scope_where['first'];
58
59 $pdf_tab_url = function_exists( 'ebook_store_get_settings_tab_url' )
60 ? ebook_store_get_settings_tab_url( 'PDF-Protection' )
61 : admin_url( 'options-general.php?page=ebook_options.php&tab=PDF-Protection' );
62
63 /*
64 * ---------------------------------------------------------------------------
65 * Hero + "what gets stamped" status card.
66 * ---------------------------------------------------------------------------
67 */
68 ebook_store_render_hero(
69 array(
70 'eyebrow' => __( 'ePub protection', 'ebook-store' ),
71 'title' => __( 'Trace the ePubs you sell back to their buyer.', 'ebook-store' ),
72 'intro' => __( 'An ePub is a website in a box, and unlike a PDF it cannot be locked with a password without breaking e-readers. So instead of locking it, Ebook Store stamps each buyer\'s name into the book and its metadata. The copy stays a perfectly valid ePub that opens everywhere — but if it turns up on a sharing site, it points straight back to the order it came from.', 'ebook-store' ),
73 'aside' => function () use ( $wm_on, $where_phrase, $wm_style, $meta_on, $qr_on, $qr_where_phrase ) {
74 ?>
75 <aside class="ebook-settings-status-card">
76 <h4><?php echo esc_html__( 'What gets stamped', 'ebook-store' ); ?></h4>
77 <ul class="ebook-settings-status-list">
78 <?php
79 ebook_store_status_row(
80 __( 'Visible watermark', 'ebook-store' ),
81 $wm_on ? 'ok' : 'muted',
82 $wm_on
83 ? ( $wm_style === 'box'
84 ? __( 'A bordered licence notice with the buyer\'s name.', 'ebook-store' )
85 : __( 'A small, muted line with the buyer\'s name.', 'ebook-store' ) )
86 : __( 'Off. ePubs are delivered exactly as uploaded.', 'ebook-store' )
87 );
88
89 if ( $wm_on ) {
90 ebook_store_status_row(
91 __( 'Where it lands', 'ebook-store' ),
92 'ok',
93 sprintf(
94 /* translators: %s: a place in the book, e.g. the opening page. */
95 __( 'Printed on %s.', 'ebook-store' ),
96 $where_phrase
97 )
98 );
99 }
100
101 ebook_store_status_row(
102 __( 'Metadata stamp', 'ebook-store' ),
103 $meta_on ? 'ok' : 'muted',
104 $meta_on
105 ? __( 'The buyer is recorded in the file\'s hidden metadata too.', 'ebook-store' )
106 : __( 'Off. Only the visible watermark is added.', 'ebook-store' )
107 );
108
109 ebook_store_status_row(
110 __( 'QR verification code', 'ebook-store' ),
111 $qr_on ? 'ok' : 'muted',
112 $qr_on
113 ? sprintf(
114 /* translators: %s: a place in the book, e.g. the opening page. */
115 __( 'A scannable code that links back to the order, on %s.', 'ebook-store' ),
116 $qr_where_phrase
117 )
118 : __( 'Off. No QR code is added.', 'ebook-store' )
119 );
120
121 ebook_store_status_row(
122 __( 'Still a valid ebook', 'ebook-store' ),
123 'ok',
124 __( 'The file opens normally in Apple Books, Kindle, Kobo and others.', 'ebook-store' )
125 );
126
127 ebook_store_status_row(
128 __( 'Any language', 'ebook-store' ),
129 'ok',
130 __( 'Buyer names in Cyrillic, Hebrew or Arabic are stamped correctly.', 'ebook-store' )
131 );
132 ?>
133 </ul>
134 </aside>
135 <?php
136 },
137 )
138 );
139
140 ebook_store_pro_banner( __( 'ePub protection', 'ebook-store' ) );
141
142 ebook_store_callout(
143 sprintf(
144 /* translators: %s: link to the PDF protection tab. */
145 __( 'This tab is for ePub files. ePubs are watermarked and traceable, not locked — encryption would stop e-readers opening them. To encrypt and password-protect PDFs instead, use the %s.', 'ebook-store' ),
146 '<a href="' . esc_url( $pdf_tab_url ) . '">' . esc_html__( 'PDF protection tab', 'ebook-store' ) . '</a>'
147 ),
148 'info',
149 __( 'How ePub protection works:', 'ebook-store' )
150 );
151
152 /*
153 * ---------------------------------------------------------------------------
154 * Section 1 · Mark — turn it on and choose what the watermark says.
155 * ---------------------------------------------------------------------------
156 */
157 ebook_store_section_open(
158 array(
159 'eyebrow' => __( 'Mark', 'ebook-store' ),
160 'title' => __( 'Watermark each ePub', 'ebook-store' ),
161 'intro' => __( 'Print the buyer\'s identity into the book so every copy is traceable to the order it came from.', 'ebook-store' ),
162 'id' => 'ebook-epub-watermark',
163 'pro' => true,
164 )
165 );
166
167 ebook_store_toggle_grid_open();
168 ebook_store_toggle(
169 array(
170 'name' => 'ebook_store_epub_watermark',
171 'id' => 'ebook_store_epub_watermark',
172 'title' => __( 'Watermark every ePub I sell', 'ebook-store' ),
173 'description' => __( 'When a buyer downloads an ePub, a per-order copy is generated with their details stamped in. The original upload is never changed.', 'ebook-store' ),
174 'checked' => $wm_on ? '1' : '',
175 'pro' => true,
176 )
177 );
178 ebook_store_toggle_grid_close();
179
180 if ( ! $wm_on ) {
181 ebook_store_callout(
182 __( 'The wording and placement below are saved, but no ePub is watermarked until you switch this on.', 'ebook-store' ),
183 'soft',
184 __( 'Heads up:', 'ebook-store' )
185 );
186 }
187
188 ebook_store_field(
189 array(
190 'type' => 'textarea',
191 'name' => 'ebook_store_epub_watermark_text',
192 'id' => 'ebook_store_epub_watermark_text',
193 'label' => __( 'What the watermark should say', 'ebook-store' ),
194 'value' => $wm_text,
195 'wide' => true,
196 'pro' => true,
197 'help' => sprintf(
198 /* translators: 1-4: merge codes shown in code style. */
199 __( 'Use these merge codes and they are replaced with the buyer\'s real details: %1$s, %2$s, %3$s, %4$s. Example: "Licensed to %1$s %2$s (%3$s)".', 'ebook-store' ),
200 '<code>%%first_name%%</code>',
201 '<code>%%last_name%%</code>',
202 '<code>%%payer_email%%</code>',
203 '<code>%%residence_country%%</code>'
204 ),
205 'hint' => __( 'The buyer\'s name is escaped before it is inserted, so a name containing < > & or quotes cannot break the book, and any script (Latin, Cyrillic, Hebrew, Arabic) is stamped correctly. Leaving this empty turns watermarking off for that download.', 'ebook-store' ),
206 )
207 );
208
209 ebook_store_section_close();
210
211 /*
212 * ---------------------------------------------------------------------------
213 * Section 2 · Place — where and how the watermark appears.
214 * ---------------------------------------------------------------------------
215 */
216 ebook_store_section_open(
217 array(
218 'eyebrow' => __( 'Place', 'ebook-store' ),
219 'title' => __( 'Where the watermark appears', 'ebook-store' ),
220 'intro' => __( 'Balance how visible the watermark is against how little it gets in the reader\'s way.', 'ebook-store' ),
221 'id' => 'ebook-epub-placement',
222 'pro' => true,
223 )
224 );
225
226 ebook_store_grid_open( 2 );
227
228 ebook_store_field(
229 array(
230 'type' => 'select',
231 'name' => 'ebook_store_epub_watermark_scope',
232 'id' => 'ebook_store_epub_watermark_scope',
233 'label' => __( 'Where to place it', 'ebook-store' ),
234 'value' => $wm_scope,
235 'options' => $scope_options,
236 'pro' => true,
237 'help' => __( 'The opening page is a balanced default. Every chapter is the hardest to remove. A licence page at the end is the least intrusive for the reader.', 'ebook-store' ),
238 )
239 );
240
241 ebook_store_field(
242 array(
243 'type' => 'select',
244 'name' => 'ebook_store_epub_watermark_position',
245 'id' => 'ebook_store_epub_watermark_position',
246 'label' => __( 'Position on the page', 'ebook-store' ),
247 'value' => $wm_position,
248 'options' => $position_options,
249 'pro' => true,
250 'help' => __( 'Top or bottom of the chosen page. Ignored for the dedicated licence page, which is a page of its own.', 'ebook-store' ),
251 )
252 );
253
254 ebook_store_field(
255 array(
256 'type' => 'select',
257 'name' => 'ebook_store_epub_watermark_style',
258 'id' => 'ebook_store_epub_watermark_style',
259 'label' => __( 'How it looks', 'ebook-store' ),
260 'value' => $wm_style,
261 'options' => $style_options,
262 'wide' => true,
263 'pro' => true,
264 'help' => __( 'Subtle is a faint single line. Boxed draws a bordered notice that is harder to overlook.', 'ebook-store' ),
265 )
266 );
267
268 ebook_store_grid_close();
269
270 ebook_store_section_close();
271
272 /*
273 * ---------------------------------------------------------------------------
274 * Section · Verify — a QR code, and where it goes.
275 * ---------------------------------------------------------------------------
276 */
277 ebook_store_section_open(
278 array(
279 'eyebrow' => __( 'Verify', 'ebook-store' ),
280 'title' => __( 'QR verification code', 'ebook-store' ),
281 'intro' => __( 'Add a scannable QR code that opens this order\'s verification page, so any copy can be traced back to the sale it came from. Choose where it goes.', 'ebook-store' ),
282 'id' => 'ebook-epub-qr',
283 'pro' => true,
284 )
285 );
286
287 ebook_store_toggle_grid_open();
288 ebook_store_toggle(
289 array(
290 'name' => 'ebook_store_epub_qr',
291 'id' => 'ebook_store_epub_qr',
292 'title' => __( 'Add a QR verification code', 'ebook-store' ),
293 'description' => __( 'Embeds a scannable code (as a real image inside the book) that links to this order\'s verification page.', 'ebook-store' ),
294 'checked' => $qr_on ? '1' : '',
295 'pro' => true,
296 )
297 );
298 ebook_store_toggle_grid_close();
299
300 ebook_store_grid_open( 2 );
301
302 ebook_store_field(
303 array(
304 'type' => 'select',
305 'name' => 'ebook_store_epub_qr_scope',
306 'id' => 'ebook_store_epub_qr_scope',
307 'label' => __( 'Where to place the QR code', 'ebook-store' ),
308 'value' => $qr_scope,
309 'options' => $scope_options,
310 'pro' => true,
311 'help' => __( 'By default it sits on the opening page. Put it on every chapter for the strongest trace, or on the licence page at the end to keep it out of the way.', 'ebook-store' ),
312 )
313 );
314
315 ebook_store_field(
316 array(
317 'type' => 'select',
318 'name' => 'ebook_store_epub_qr_position',
319 'id' => 'ebook_store_epub_qr_position',
320 'label' => __( 'Position on the page', 'ebook-store' ),
321 'value' => $qr_position,
322 'options' => $position_options,
323 'pro' => true,
324 'help' => __( 'Top or bottom of the chosen page. Ignored for the licence page, which is a page of its own.', 'ebook-store' ),
325 )
326 );
327
328 ebook_store_grid_close();
329
330 ebook_store_callout(
331 __( 'The QR code is drawn on your own server and embedded as an image inside the book, so it scans on any reader background and needs no outside service to generate. Scanning it opens the verification page, which needs internet.', 'ebook-store' ),
332 'soft',
333 __( 'Good to know:', 'ebook-store' )
334 );
335
336 ebook_store_section_close();
337
338 /*
339 * ---------------------------------------------------------------------------
340 * Section · Stamp — record the buyer in the file metadata too.
341 * ---------------------------------------------------------------------------
342 */
343 ebook_store_section_open(
344 array(
345 'eyebrow' => __( 'Stamp', 'ebook-store' ),
346 'title' => __( 'Stamp the buyer into the metadata', 'ebook-store' ),
347 'intro' => __( 'Add the buyer to the book\'s hidden metadata as well as the visible watermark, so the trace survives even if the visible line is edited out.', 'ebook-store' ),
348 'id' => 'ebook-epub-metadata',
349 'pro' => true,
350 )
351 );
352
353 ebook_store_toggle_grid_open();
354 ebook_store_toggle(
355 array(
356 'name' => 'ebook_store_epub_stamp_metadata',
357 'id' => 'ebook_store_epub_stamp_metadata',
358 'title' => __( 'Record the buyer in the file\'s metadata', 'ebook-store' ),
359 'description' => __( 'Adds the buyer as a contributor and rights holder inside the book\'s package file. Invisible to the reader, visible to library and forensic tools.', 'ebook-store' ),
360 'checked' => $meta_on ? '1' : '',
361 'pro' => true,
362 )
363 );
364 ebook_store_toggle_grid_close();
365
366 ebook_store_callout(
367 __( 'Whatever you choose here, the delivered file stays a valid ePub: its mimetype marker stays first and uncompressed, every file stays listed in the book\'s manifest, and the pages stay well-formed. Files that carry their own DRM or a digital signature are passed through untouched, and a paid download is never blocked if watermarking cannot run.', 'ebook-store' ),
368 'soft',
369 __( 'Stays a valid ebook:', 'ebook-store' )
370 );
371
372 ebook_store_section_close();
373