Easy Table of Contents - Version 2.0.25.1

Version Description

06/30/2022 = * BUG: Reusable Block Headings are not rendering in TOC titles #215

Download this release

Release Info

Developer magazine3
Plugin Icon 128x128 Easy Table of Contents
Version 2.0.25.1
Comparing to
See all releases

Code changes from version 2.0.25 to 2.0.25.1

README.txt CHANGED
@@ -1,535 +1,538 @@
1
- === Easy Table of Contents ===
2
- Contributors: magazine3
3
- Donate link: https://magazine3.company/
4
- Tags: table of contents, toc
5
- Requires at least: 5.3
6
- Tested up to: 6.0
7
- Requires PHP: 5.6.20
8
- Stable tag: 2.0.25
9
- License: GPLv2 or later
10
- License URI: https://www.gnu.org/licenses/gpl-2.0.html
11
-
12
- Adds a user friendly and fully automatic way to create and display a table of contents generated from the page content.
13
-
14
- == Description ==
15
-
16
- A user friendly, featured focused plugin which allows you to insert a table of contents into your posts, pages and custom post types.
17
-
18
- ### Features
19
- * Automatically generate a table of contents for your posts, pages and custom post types by parsing its contents for headers.
20
- * Supports the `<!--nextpage-->` tag.
21
- * Supports the Rank Math plugin.
22
- * Works with the Classic Editor, Gutenberg, Divi, Elementor, WPBakery Page Builder and Visual Composer page editors.
23
- * Optionally enable for pages and/or posts. Custom post types are supported, as long as their content is output with the `the_content()` template tag.
24
- * Optionally auto insert the table of contents into the page, selectable by enabled post type.
25
- * Provides many easy to understand options to configure when and where to insert the table of contents.
26
- * Many options are available to configure how the inserted table of contents appears which include several builtin themes. If the supplied themes do no meet you needs, you can create your own by choosing you own colors for the border, background and link color.
27
- * Multiple counter bullet formats to choose from; none, decimal, numeric and roman.
28
- * Choose to display the table of contents hierarchical or not. This means headings of lower priority will be nested under headings of higher priority.
29
- * User can optionally hide the table of contents. You full control of this feature. It can be disabled and you can choose to have it hidden by default.
30
- * Supports smooth scrolling.
31
- * Selectively enable or disabled the table of contents on a post by post basis.
32
- * Choose which headings are used to generate the table of contents. This too can be set on a post by post basis.
33
- * Easily exclude headers globally and on a post by post basis.
34
- * If you rather not insert the table of contents in the post content, you can use the supplied widget and place the table of contents in your theme's sidebar.
35
- * The widgets supports being affixed or stuck on the page so it is always visible as you scroll down the page. NOTE: this is an advanced option since every theme is different, you might need support from your theme developer to learn what the correct item selector to use in the settings to enable this feature.
36
- * The widget auto highlights the sections currently visible on the page. The highlight color is configurable.
37
- * Developer friendly with many action hooks and filters available. More can be added by request on [Github](https://github.com/shazahm1/Easy-Table-of-Contents). Pull requests are welcomed.
38
-
39
- ### Support
40
-
41
- We try our best to provide support on WordPress.org forums. However, We have a special [team support](https://magazine3.company/contact/) where you can ask us questions and get help. Delivering a good user experience means a lot to us and so we try our best to reply each and every question that gets asked.
42
-
43
- ### Bug Reports
44
-
45
- Bug reports for Easy Table of Contents are [welcomed on GitHub](https://github.com/ahmedkaludi/Easy-Table-of-Contents). Please note GitHub is not a support forum, and issues that aren't properly qualified as bugs will be closed.
46
-
47
- ### [JOIN TELEGRAM GROUP COMMUNITY](https://t.me/+XADGN24lHNk0YjE1/)**: Purpose of this group is to get proper suggestions and feedback from plugin users and the community so that we can make the plugin even better.
48
-
49
- ### Live Examples
50
-
51
- * [cMap Template Docs](http://connections-pro.com/documentation/cmap/)
52
- * [Circled Template Docs](http://connections-pro.com/documentation/circled/)
53
- * [Gridder Template Docs](http://connections-pro.com/documentation/gridder/)
54
-
55
- ### Roadmap
56
- * Fragment caching for improved performance.
57
- * Improve SEO by adding options to add nofollow to TOC link and wrap TOC nav in noindex tag.
58
- * Improve accessibility.
59
- * Add Bullet and Arrow options for list counter style.
60
-
61
- ### Credit
62
-
63
- Easy Table Contents is a fork of the excellent [Table of Contents Plus](https://wordpress.org/plugins/table-of-contents-plus/) plugin by [Michael Tran](http://dublue.com/plugins/toc/).
64
-
65
- ### Screenshots
66
-
67
- 1. The General section of the settings.
68
- 2. The Appearance section of the settings.
69
- 3. The Advanced section of the settings.
70
-
71
- ### Installation
72
-
73
- = Using the WordPress Plugin Search =
74
-
75
- 1. Navigate to the `Add New` sub-page under the Plugins admin page.
76
- 2. Search for `easy table of contents`.
77
- 3. The plugin should be listed first in the search results.
78
- 4. Click the `Install Now` link.
79
- 5. Lastly click the `Activate Plugin` link to activate the plugin.
80
-
81
- = Uploading in WordPress Admin =
82
-
83
- 1. [Download the plugin zip file](http://wordpress.org/plugins/easy-table-of-contents/) and save it to your computer.
84
- 2. Navigate to the `Add New` sub-page under the Plugins admin page.
85
- 3. Click the `Upload` link.
86
- 4. Select Easy Table of Contents zip file from where you saved the zip file on your computer.
87
- 5. Click the `Install Now` button.
88
- 6. Lastly click the `Activate Plugin` link to activate the plugin.
89
-
90
- = Using FTP =
91
-
92
- 1. [Download the plugin zip file](http://wordpress.org/plugins/easy-table-of-contents/) and save it to your computer.
93
- 2. Extract the Easy Table of Contents zip file.
94
- 3. Create a new directory named `easy-table-of-contents` directory in the `../wp-content/plugins/` directory.
95
- 4. Upload the files from the folder extracted in Step 2.
96
- 4. Activate the plugin on the Plugins admin page.
97
-
98
- == Changelog ==
99
-
100
- = 2.0.25 06/27/2022 =
101
- * TWEAK: Added Migration from Table of Contents Plus and LuckyWP Table of Contents #160
102
- * TWEAK: Added Option to add inline CSS and JS #189
103
- * TWEAK: Added Shortcode to show hidden view on particular posts #183
104
- * TWEAK: Added Hyphen Counter to display the TOC heading #192
105
- * TWEAK: Added Dot Counter to display the TOC heading #180
106
- * TWEAK: Improved the Web Accessibility in TOC Toggle #190
107
- * BUG: Shortcodes are not rendering in TOC titles #197
108
- * BUG: TOC heading are getting hidden in sticky header #186
109
- * BUG: No success or error message after support request is submitted #196
110
- * BUG: Same font size appearing in headings and sub-headings #161
111
- * BUG: Salient core plugin conflict with last update 2.0.24.1 #207
112
-
113
- = 2.0.24.1 06/14/2022 =
114
- * BUG: TOC not displaying properly when initial view option is disabled #195
115
- * BUG: Initial View option not working with Pure CSS Loading Method #194
116
-
117
- = 2.0.24 06/10/2022 =
118
- * TWEAK: Added TOC in Infinite Scroll #138
119
- * TWEAK: Improved the activation process #187
120
- * BUG: TOC Toggle not working with Magnolia Theme #174
121
- * BUG: Initial view not working with TOC Loading Method of CSS #179
122
- * BUG: Toggle is not visible when Display Header option is disable #171
123
- * BUG: CSS not loading when using shortcode in theme file #175
124
- * BUG: the_content filter run twice #182
125
- * BUG: Form UI looks ugly #169
126
- * BUG: Debug Warnings in multibyte string functions #185
127
-
128
- = 2.0.23 05/31/2022 =
129
- * TWEAK: Added filter to modify anchor links #167
130
- * TWEAK: Added filter to add TOC before or after the sidebar widget #166
131
- * TWEAK: Added option to align TOC to center #158
132
- * TWEAK: Design improvements in options panel #172
133
-
134
- = 2.0.22 05/06/2022 =
135
- * BUG: Double hyphens are getting removed from content issue fixed #163
136
-
137
- = 2.0.21 05/06/2022 =
138
- * BUG: Critical error fixed #147
139
-
140
- = 2.0.20 05/05/2022 =
141
- * TWEAK: Added Toggle with CSS for websites runs without jQuery #153
142
- * TWEAK: Added telegram group join link for suggestions and feedback #159
143
- * BUG: TOC links not jumping in some posts which have special characters #163
144
- * BUG: Incorrect email ID updated in the plugin #165
145
- * BUG: Proper documentation added for adding TOC with shortcodes & do_shortcode #152
146
- * BUG: TOC links not working when do_shortcode added directly in the template #147
147
- * BUG: TOC links not working with some specical character with Elementor #162
148
-
149
- = 2.0.19 04/16/2022 =
150
- * Bug Fixed : While Using Elementor Page builder TOC is not working when special characters are used in headings. #150
151
- * Bug Fixed : Need to load CSS/JS files only on the selected post types. #154
152
-
153
- = 2.0.18 03/29/2022 =
154
- * TWEAK: Added Technical Support Tab in Settings Panel.
155
-
156
- = 2.0.17 03/26/2021 =
157
- * TWEAK: Add additional check to prevent `Uncaught Error: Call to undefined function is_woocommerce()`.
158
- * TWEAK: Ensure an instance of `ezTOC_Post ` is returned before accessing methods/properties.
159
-
160
- = 2.0.16 02/01/2021 =
161
- * TWEAK: Remove special characters such as fancy quotes, en and, em dashes when generating in-page anchor IDs.
162
-
163
- = 2.0.15 01/27/2021 =
164
- * TWEAK: Remove additional reserved characters when generating in-page anchor IDs.
165
-
166
- = 2.0.14 01/26/2021 =
167
- * TWEAK: Refactor debug log as a Singleton.
168
- * TWEAK: Add additional logging to aid in debugging.
169
- * BUG: Correct logic for PHP where empty string no longer evaluates as integer `0`.
170
-
171
- = 2.0.13 01/25/2021 =
172
- * TWEAK: Restrict debug logging to when `WP_DEBUG` is enabled *and* current user capability of `manage_options`.
173
- * TWEAK: Add logging to aid in support.
174
- * DEV: phpDoc update.
175
-
176
- = 2.0.12 01/22/2021 =
177
- * TWEAK: Allow `_` and `-` in anchors.
178
- * TWEAK: Minor CSS tweaks that prevent theme from breaking the layout.
179
- * TWEAK: Minor tweak to class initialization.
180
- * TWEAK: Do not display the view toggle if JavaScript is broken on the site.
181
- * TWEAK: Add the ability to enable displaying of displaying debug information on the page.
182
- * BUG: Check for array and keys before accessing values.
183
- * BUG: Check for array key be fore access.
184
- * BUG: Remove reserved characters when generating in-page anchor IDs.
185
- * DEV: Remove unnecessary vendor library files.
186
- * DEV: Deal with phpStorm showing a warning about path not found when including files.
187
-
188
- = 2.0.11 05/01/2020 =
189
- * COMPATIBILITY: Add support for the Uncode theme.
190
- * COMPATIBILITY: Do not run on WooCommerce pages.
191
- * DEV: Correct typo in phpDoc.
192
-
193
- = 2.0.10 04/20/2020 =
194
- * TWEAK: Add trailing `span` to heading, to prepare for `#` option and to fix duplicate heading title matching.
195
- * TWEAK: Add second heading search/replace function to search for heading in content with heading html entities decoded. May help Beaver Builder users as it seems like it does not encode HTML entities as WP core does.
196
-
197
-
198
- = 2.0.9 04/08/2020 =
199
- * TWEAK: AMP/Caching plugins seems to break anchors with colons and periods even though they are valid characters for the id attribute in HTML5.
200
- * TWEAK: Replace multiple underscores with a single underscore.
201
- * DEV: Update the UWS library which fixes the deprecation notice for PHP 7.4.
202
- * DEV: Add phpcs.xml.dist.
203
- * DEV: Strict type checks.
204
- * DEV: Inline doc updates.
205
-
206
- = 2.0.8 04/03/2020 =
207
- * TWEAK: Convert `<br />` tags in headings to a space.
208
- * TWEAK: Add additional widget classes.
209
- * TWEAK: Improve the sanitization of the excluded headings field post setting.
210
- * TWEAK: Minor optimization of creating the matching pattern for excluding headings for improved performance.
211
- * COMPATIBILITY: Exclude Create by Mediavine from heading eligibility.
212
- * BUG: Ensure excluded headings are removed from the headings array.
213
- * BUG: Ensure empty headings are removed from the headings array.
214
-
215
- = 2.0.7 04/02/2020 =
216
- * NEW: Exclude any HTML nodes with the class of `.ez-toc-exclude-headings`.
217
- * TWEAK: Change smooth scroll selector from `'body a'` to `'a.ez-toc-link'`.
218
- * TWEAK: Declare JS variables.
219
- * TWEAK: Support unicode characters for the `id` attribute. Permitted by HTML5.
220
- * TWEAK: Move the in-page anchor/span to before the heading text to account for long headings where it line wraps.
221
- * TWEAK: Slight rework to ezTOC widget container classes logic.
222
- * TWEAK: Cache bust the JS to make dev easier.
223
- * TWEAK: JavaScript cleanup.
224
- * TWEAK: URI Encode the id attribute to deal with reserved characters in JavaScript. Technically not necessary for the id attribute but needed to work with the jQuery smoothScroll library.
225
- * COMPATIBILITY: Reintroduce filter to exclude Ultimate Addons for VC Composer Tabs from heading eligibility.
226
- * BUG: Correct array iteration logic when processing headings.
227
- * BUG: Tighten matching for headings in excluded HTML nodes. The loose matching was excluding far too many headings.
228
- * BUG: Use `esc_attr()` instead of `esc_url()` for the anchor href because valid id attribute characters would cause it to return an empty href which cause a nonworking link.
229
-
230
- = 2.0.6 03/30/2020 =
231
- * BUG: Ensure minified files are current.
232
-
233
- = 2.0.5 03/27/2020 =
234
- * BUG: Prevent possible "strpos(): Empty needle in" warnings when excluding nodes from TOC eligibility.
235
-
236
- = 2.0.4 03/16/2020 =
237
- * NEW: Introduce the `ez_toc_container_class` filter.
238
- * TWEAK: Slight rework to ezTOC container classes logic.
239
- * BUG: `sprintf()` was eating `%` in the TOC heading item.
240
- * BUG: Do not insert TOC at top of post if before first heading option is selected even if first heading can not be found. Some page builders cause the TOC to insert twice or on blog pages.
241
-
242
- = 2.0.3 03/12/2020 =
243
- * TWEAK: Slightly tighten heading matching, last update made it a little too loose.
244
- * BUG: Correct logic required to place TOC before first heading which is required for the more lax heading matching required for page builders.
245
-
246
- = 2.0.2 03/12/2020 =
247
- * COMPATIBILITY: Remove filter to exclude Ultimate Addons for VC Composer Tabs from heading eligibility.
248
- * COMPATIBILITY: Add additional filters to improve Elementor compatibility.
249
- * TWEAK: Loosen heading matching when doing find/replace to insert in page links. Excluding the opening heading tag to allow matching heading where page builders dynamically add classes and id which break heading matching during find/replace.
250
-
251
- = 2.0.1 03/09/2020 =
252
- * COMPATIBILITY: Exclude the WordPress Related Posts plugin nodes.
253
- * COMPATIBILITY: Exclude a couple Atomic Block plugin nodes.
254
- * COMPATIBILITY: Exclude JetPack Related Posts from heading eligibility.
255
- * COMPATIBILITY: Exclude Ultimate Addons for VC Composer Tabs from heading eligibility.
256
- * COMPATIBILITY: Exclude WP Product Reviews from heading eligibility.
257
- * TWEAK: Prevent possible "strpos(): Empty needle in" warnings when excluding nodes from TOC eligibility.
258
-
259
- = 2.0 02/01/2020 =
260
- * NEW: Major rewrite of all code and processing logic to make it faster and more reliable.
261
- * NEW: Support for the <!--nextpage--> tag.
262
- * NEW: Introduce helper functions for devs.
263
- * NEW: Support WPML.
264
- * NEW: Support Polylang.
265
- * NEW: Add filter to support the Rank Math plugin.
266
- * NEW: Introduce the `ez_toc_maybe_apply_the_content_filter` filter.
267
- * TWEAK: Improve translation compatibility.
268
- * TWEAK: Rework widget logic to allow multi-line TOC items, improve active item highlighting while removing the use of the jQuery Waypoints library.
269
- * TWEAK Add additional classes to TOC list items.
270
- * TWEAK: Add WOFF2 format for icon format and change font references in CSS.
271
- * TWEAK: Add font-display: swap for toggle icon.
272
- * TWEAK: Update JS Cookie to 2.2.1.
273
- * TWEAK: Update jQuery Smooth Scroll to 2.2.0.
274
- * TWEAK: Allow forward slash and angle brackets in headings and alternate headings.
275
- * TWEAK: Allow forward slash in excluded headings.
276
- * TWEAK: Remove new line/returns when matching excluded headings.
277
- * TWEAK: Simple transient cache to ensure a post is only processed once per request for a TOC.
278
- * TWEAK: Improve sanitization of alternate headings field value.
279
- * TWEAK: Deal with non-breaking-spaces in alternate headings.
280
- * TWEAK: Add the ability to exclude by selector content eligible to be included in the TOC.
281
- * TWEAK: Change the shortcode priority to a higher value.
282
- * TWEAK: Add filter to remove shortcodes from the content prior to the `the_content` filter being run to exclude shortcode content from being eligible as TOC items.
283
- * TWEAK: Add compatibility filters to remove shortcodes for Connections and Striking theme to remove them from eligible TOC item content.
284
- * TWEAK: Do not execute if root current filter is the `wp_head` or `get_the_excerpt` filters.
285
- * TWEAK: Add filter to exclude content by selector.
286
- * TWEAK: Move in-page anchor to after the heading instead of wrapping the heading to prevent conflicts with theme styling.
287
- * TWEAK: Utilize the `ez_toc_exclude_by_selector` filter the exclude the JetPack share buttons from eligible headings.
288
- * TWEAK: Remove the Elegant Themes Bloom plugin node from the post content before extracting headings.
289
- * TWEAK: Add compatibility filter for the Visual Composer plugin.
290
- * TWEAK: Utilize the `ez_toc_exclude_by_selector` filter the exclude the Starbox author heading from eligible headings.
291
- * I18N: Add wpml-config.xml file.
292
- * BUG: Correct option misspelling.
293
- * BUG: Do not need to run values for alternate and exclude headings thru `wp_unslash()` because `update_post_meta()` already does.
294
- * BUG: Do not need to run `stripslashes()` when escaping the alternate heading value.
295
- * BUG: Sanitize the excluded heading string before saving post meta.
296
- * DEV: Change PHP keywords to comply with PSR2.
297
- * DEV:Bump minimum PHP version to 5.6.20 which matches WP core.
298
-
299
- = 1.7 05/09/2018 =
300
- * NEW: Introduce the `ez_toc_shortcode` filter.
301
- * TWEAK: Fix notices due to late eligibility check. props unixtam
302
- * TWEAK: Tweak eligibility check to support the TOC widget.
303
- * TWEAK: Prefix a few CSS classes in order to prevent collisions with theme's and other plugins.
304
- * TWEAK: Avoid potential PHP notice in admin when saving the post by checking for nonce before validating it.
305
- * TWEAK: Using the shortcode now overrides global options.
306
- * TWEAK: `the_content()` now caches result of `is_eligible()`.
307
- * TWEAK: Refactor to pass the WP_Post object internally vs. accessing it via the `$wp_query->post` which may not in all cases exist.
308
- * TWEAK: Use `pre_replace()` to replace one or more spaces with an underscore.
309
- * TWEAK: Return original title in the `ez_toc_url_anchor_target` filter.
310
- * TWEAK: Strip `&nbsp;`, replacing it with a space character.
311
- * TWEAK: Minor tweaks to the in page URL creating.
312
- * TWEAK: Wrap TOC list in a nav element.
313
- * TWEAK: Init plugin on the `plugins_loaded` hook.
314
- * TWEAK: Tweak the minimum number of headers to 1.
315
- * BUG: The header options from the post meta should be used when building the TOC hierarchy, not the header options from the global settings.
316
- * BUG: Do not double escape field values.
317
- * BUG: Ensure Apostrophe / Single quote use in Exclude Headings work.
318
- * OTHER: Update CSS to include the newly prefixed classes.
319
- * DEV: Remove some commented out unused code.
320
-
321
- = 1.6.1 03/16/2018 =
322
- * TWEAK: Revert change made to allow HTML added via the `ez_toc_title` filter as it caused undesirable side effects.
323
- * BUG: Ensure Smooth Scroll Offset is parsed as an integer.
324
-
325
- = 1.6 03/15/2018 =
326
- * NEW: Add `px` option for font size unit.
327
- * NEW: Add title font size and weight settings options.
328
- * NEW: Add the Mobile Smooth Scroll Offset option.
329
- * TWEAK: Change default for font size unit from `px` to `%` to match the default options values.
330
- * TWEAK: Correct CSS selector so margin is properly applied between the title and TOC items.
331
- * TWEAK: Honor HTML added via `ez_toc_title` filter.
332
- * TWEAK: Ensure the ezTOC content filter is not applied when running `the_content` filter.
333
- * TWEAK: Only enqueue the javascript if the page is eligible for a TOC.
334
- * TWEAK: Update icomoon CSS to remove unecessary CSS selectors to prevent possible conflicts.
335
- * TWEAK: The smooth scroll offset needs to be taken into account when defining the offset_top property when affixing the widget.
336
- * OTHER: Update frontend minified CSS file.
337
- * OTHER: Update the frontend minified javascript file.
338
- * DEV: phpDoc corrections.
339
-
340
- = 1.5 02/20/2018 =
341
- * BUG: Correct CSS selector to properly target the link color.
342
- * OTHER: Update the WayPoints library.
343
- * DEV: Add a couple @todo's.
344
-
345
- = 1.4 01/29/2018 =
346
- * TWEAK: Change text domain from ez_toc to easy-table-of-contents.
347
- * TWEAK: Rename translation files with correct text domain.
348
- * BUG: Ensure page headers are processed to add the in page header link when using the shortcodes.
349
- * BUG: Add forward slash to domain path in the plugin header.
350
- * I18N: Update POT file.
351
- * I18N: Update Dutch (nl_NL) translation.
352
-
353
- = 1.3 12/18/2017 =
354
- * FEATURE: Add support for the `[ez-toc]` shortcode.
355
- * NEW: For backwards compatibility with "Table of Content Plus", register the `[toc]` shortcode.
356
- * NEW: Introduce the `ez_toc_extract_headings_content` filter.
357
- * TWEAK: Update the tested to and required readme header text.
358
- * TWEAK: Do not show the widget on the 404, archive, search and posts pages.
359
- * I18N: Add the nl_NL translation.
360
-
361
- = 1.2 04/29/2016 =
362
- * TWEAK: Remove the font family from styling the TOC title header.
363
- * TWEAK: Pass the raw title to the `ez_toc_title` filter.
364
- * BUG: A jQuery 1.12 fix for WordPress 4.5.
365
-
366
- = 1.1 02/24/2016 =
367
- * FEATURE: Add option to replace header wither alternate header text in the table of content.
368
- * NEW: Introduce the ez_toc_filter.
369
- * NEW: Introduce ezTOC_Option::textarea() to render textareas.
370
- * NEW: Introduce array_search_deep() to recursively search an array for a value.
371
- * TWEAK: Run table of contents headers thru wp_kses_post().
372
- * TWEAK: Escape URL.
373
- * TWEAK: Count excluded headings only once instead of multiple times.
374
- * TWEAK: Escape translated string before rendering.
375
- * TWEAK: Use wp_unslash() instead of stripslashes().
376
- * TWEAK: Escape translated string.
377
- * BUG: Fix restrict path logic.
378
- * OTHER: Readme tweaks.
379
- * I18N: Add POT file.
380
- * I18N: Add Dutch translation.
381
- * DEV: Update .gitignore to allow PO files.
382
- * DEV: phpDoc fix.
383
-
384
- = 1.0 09/08/2015 =
385
- * Initial release.
386
- - Complete refactor and restructure of the original code for better design and separation of function to make code base much easier to maintain and extend.
387
- - Update all third party libraries.
388
- - Make much better use of the WordPress Settings API.
389
- - Minified CSS and JS files are used by default. Using SCRIPT_DEBUG will use the un-minified versions.
390
- - Add substantial amounts of phpDoc for developers.
391
- - Add many hooks to permit third party integrations.
392
- - Widget can be affixed/stuck to the page so it is always visible.
393
- - Widget will highlight the table of content sections that are currently visible in the browser viewport.
394
- - Widget will now generate table of contents using output from third party shortcodes.
395
- - Use wpColorPicker instead of farbtastic.
396
- - Remove all shortcodes.
397
- - Per post options are saved in post meta instead of set by shortcode.
398
-
399
- == Frequently Asked Questions ==
400
-
401
- = Ok, I've installed this... what do I do next? =
402
-
403
- You first stop should be the Table of Contents settings admin page. You can find this under the Settings menu item.
404
-
405
- You first and only required decision is you need to decide which post types you want to enable Table of Contents support for. By default it is the Pages post type. If on Pages is the only place you plan on using Table of Contents, you have nothing to do on the Settings page. To keep things simple, I recommend not changing any of the other settings at this point. Many of the other settings control when and where the table of contents is inserted and changing these settings could cause it not to display making getting started a bit more difficult. After you get comfortable with how this works... then tweak away :)
406
-
407
- With that out of the way make sure to read the **How are the tables of contents created?** FAQ so you know how the Table of Contents is automatically generated. After you have the page headers setup, or before, either way... Scroll down on the page you'll see a metabox named "*Table of Contents*", enable the *Insert table of contents.* option and Update and/or Publish you page. The table of contents should automatically be shown at the top of the page.
408
-
409
- = How are the tables of contents created? =
410
-
411
- The table of contents is generated by the headers found on a page. Headers are the [`<h1>,<h2>,<h3>,<h4>,<h5>,<h6>` HTML tags](http://www.w3schools.com/tags/tag_hn.asp). If you are using the WordPres Visual Post Editor, these header tags are used and inserted into the post when you select one of the [*Heading n* options from the formatting drop down](http://torquemag.io/wordpress-heading-tags/). Each header that is found on the page will create a table of content item. Here's an example which will create a table of contents containing the six items.
412
-
413
- `<h1>Item 1</h1>
414
- <h1>Item 2</h1>
415
- <h1>Item 3</h1>
416
- <h1>Item 4</h1>
417
- <h1>Item 5</h1>
418
- <h1>Item 6</h1>`
419
-
420
- You can also create "nested" table of contents. This is difficult to explain so I'll illustrate building on the previous example. In this example a table of contents will be created with the same six items but now the first three will each an child item nested underneath it. The indentation is not necessary, it was only added for illustration purposes.
421
-
422
- `<h1>Item 1</h1>
423
- <h2>Item 1.1 -- Level 2</h2>
424
- <h1>Item 2</h1>
425
- <h2>Item 2.1 -- Level 2</h2>
426
- <h1>Item 3</h1>
427
- <h2>Item 3.1 -- Level 2</h2>
428
- <h1>Item 4</h1>
429
- <h1>Item 5</h1>
430
- <h1>Item 6</h1>`
431
-
432
- You are not limited to a single a single nested item either. You can add as many as you need. You can even create multiple nested levels...
433
-
434
- `<h1>Item 1</h1>
435
- <h2>Item 1.1 -- Level 2</h2>
436
- <h3>Item 1.1.1 -- Level 3</h3>
437
- <h3>Item 1.1.2 -- Level 3</h3>
438
- <h3>Item 1.1.3 -- Level 3</h3>
439
- <h2>Item 1.2 -- Level 2</h2>
440
- <h3>Item 1.2.1 -- Level 3</h3>
441
- <h3>Item 1.2.2 -- Level 3</h3>
442
- <h3>Item 1.2.3 -- Level 3</h3>
443
- <h2>Item 1.3 -- Level 2</h2>
444
- <h1>Item 2</h1>
445
- <h2>Item 2.1 -- Level 2</h2>
446
- <h2>Item 2.2 -- Level 2</h2>
447
- <h1>Item 3</h1>
448
- <h2>Item 3.1 -- Level 2</h2>
449
- <h2>Item 3.2 -- Level 2</h2>
450
- <h1>Item 4</h1>
451
- <h1>Item 5</h1>
452
- <h1>Item 6</h1>`
453
-
454
- You can nest up 6 levels deep if needed. I hope this helps you understand how to create and build your own auto generated table of contents on your sites!
455
-
456
- = Is there any shortcode to add the table of content to anywhere I want ? =
457
-
458
- Yes you can add the TOC with this shortcode – [ez-toc] and with the help of this you can easily add the TOC in the content or anywhere in the WordPress and if you want to add the shortcode on the theme file then you can add it with the help of this code – <?php echo do_shortcode( ‘[ez-toc]’ ); ?> and with this, you can add the TOC on any file according to your need.
459
-
460
- == Upgrade Notice ==
461
-
462
- = 1.0 =
463
- Initial release.
464
-
465
- = 1.3 =
466
- Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
467
-
468
- = 1.4 =
469
- Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
470
-
471
- = 1.5 =
472
- Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
473
-
474
- = 1.6 =
475
- Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
476
-
477
- = 1.6.1 =
478
- Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
479
-
480
- = 1.7 =
481
- Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
482
-
483
- = 2.0-rc4 =
484
- Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
485
-
486
- = 2.0.1 =
487
- Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
488
-
489
- = 2.0.2 =
490
- Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
491
-
492
- = 2.0.3 =
493
- Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
494
-
495
- = 2.0.4 =
496
- Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
497
-
498
- = 2.0.5 =
499
- Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
500
-
501
- = 2.0.6 =
502
- Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
503
-
504
- = 2.0.7 =
505
- Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
506
-
507
- = 2.0.8 =
508
- Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
509
-
510
- = 2.0.9 =
511
- Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
512
-
513
- = 2.0.10 =
514
- Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
515
-
516
- = 2.0.11 =
517
- Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
518
-
519
- = 2.0.12 =
520
- Requires WordPress >= 5.3 and PHP version >= 5.6.20 (>= 7.4 is recommended).
521
-
522
- = 2.0.13 =
523
- Requires WordPress >= 5.3 and PHP version >= 5.6.20 (>= 7.4 is recommended).
524
-
525
- = 2.0.14 =
526
- Requires WordPress >= 5.3 and PHP version >= 5.6.20 (>= 7.4 is recommended).
527
-
528
- = 2.0.15 =
529
- Requires WordPress >= 5.3 and PHP version >= 5.6.20 (>= 7.4 is recommended).
530
-
531
- = 2.0.16 =
532
- Requires WordPress >= 5.3 and PHP version >= 5.6.20 (>= 7.4 is recommended).
533
-
534
- = 2.0.17 =
535
- Requires WordPress >= 5.3 and PHP version >= 5.6.20 (>= 7.4 is recommended).
 
 
 
1
+ === Easy Table of Contents ===
2
+ Contributors: magazine3
3
+ Donate link: https://magazine3.company/
4
+ Tags: table of contents, toc
5
+ Requires at least: 5.3
6
+ Tested up to: 6.0
7
+ Requires PHP: 5.6.20
8
+ Stable tag: 2.0.25.1
9
+ License: GPLv2 or later
10
+ License URI: https://www.gnu.org/licenses/gpl-2.0.html
11
+
12
+ Adds a user friendly and fully automatic way to create and display a table of contents generated from the page content.
13
+
14
+ == Description ==
15
+
16
+ A user friendly, featured focused plugin which allows you to insert a table of contents into your posts, pages and custom post types.
17
+
18
+ ### Features
19
+ * Automatically generate a table of contents for your posts, pages and custom post types by parsing its contents for headers.
20
+ * Supports the `<!--nextpage-->` tag.
21
+ * Supports the Rank Math plugin.
22
+ * Works with the Classic Editor, Gutenberg, Divi, Elementor, WPBakery Page Builder and Visual Composer page editors.
23
+ * Optionally enable for pages and/or posts. Custom post types are supported, as long as their content is output with the `the_content()` template tag.
24
+ * Optionally auto insert the table of contents into the page, selectable by enabled post type.
25
+ * Provides many easy to understand options to configure when and where to insert the table of contents.
26
+ * Many options are available to configure how the inserted table of contents appears which include several builtin themes. If the supplied themes do no meet you needs, you can create your own by choosing you own colors for the border, background and link color.
27
+ * Multiple counter bullet formats to choose from; none, decimal, numeric and roman.
28
+ * Choose to display the table of contents hierarchical or not. This means headings of lower priority will be nested under headings of higher priority.
29
+ * User can optionally hide the table of contents. You full control of this feature. It can be disabled and you can choose to have it hidden by default.
30
+ * Supports smooth scrolling.
31
+ * Selectively enable or disabled the table of contents on a post by post basis.
32
+ * Choose which headings are used to generate the table of contents. This too can be set on a post by post basis.
33
+ * Easily exclude headers globally and on a post by post basis.
34
+ * If you rather not insert the table of contents in the post content, you can use the supplied widget and place the table of contents in your theme's sidebar.
35
+ * The widgets supports being affixed or stuck on the page so it is always visible as you scroll down the page. NOTE: this is an advanced option since every theme is different, you might need support from your theme developer to learn what the correct item selector to use in the settings to enable this feature.
36
+ * The widget auto highlights the sections currently visible on the page. The highlight color is configurable.
37
+ * Developer friendly with many action hooks and filters available. More can be added by request on [Github](https://github.com/shazahm1/Easy-Table-of-Contents). Pull requests are welcomed.
38
+
39
+ ### Support
40
+
41
+ We try our best to provide support on WordPress.org forums. However, We have a special [team support](https://magazine3.company/contact/) where you can ask us questions and get help. Delivering a good user experience means a lot to us and so we try our best to reply each and every question that gets asked.
42
+
43
+ ### Bug Reports
44
+
45
+ Bug reports for Easy Table of Contents are [welcomed on GitHub](https://github.com/ahmedkaludi/Easy-Table-of-Contents). Please note GitHub is not a support forum, and issues that aren't properly qualified as bugs will be closed.
46
+
47
+ ### [JOIN TELEGRAM GROUP COMMUNITY](https://t.me/+XADGN24lHNk0YjE1/)**: Purpose of this group is to get proper suggestions and feedback from plugin users and the community so that we can make the plugin even better.
48
+
49
+ ### Live Examples
50
+
51
+ * [cMap Template Docs](http://connections-pro.com/documentation/cmap/)
52
+ * [Circled Template Docs](http://connections-pro.com/documentation/circled/)
53
+ * [Gridder Template Docs](http://connections-pro.com/documentation/gridder/)
54
+
55
+ ### Roadmap
56
+ * Fragment caching for improved performance.
57
+ * Improve SEO by adding options to add nofollow to TOC link and wrap TOC nav in noindex tag.
58
+ * Improve accessibility.
59
+ * Add Bullet and Arrow options for list counter style.
60
+
61
+ ### Credit
62
+
63
+ Easy Table Contents is a fork of the excellent [Table of Contents Plus](https://wordpress.org/plugins/table-of-contents-plus/) plugin by [Michael Tran](http://dublue.com/plugins/toc/).
64
+
65
+ ### Screenshots
66
+
67
+ 1. The General section of the settings.
68
+ 2. The Appearance section of the settings.
69
+ 3. The Advanced section of the settings.
70
+
71
+ ### Installation
72
+
73
+ = Using the WordPress Plugin Search =
74
+
75
+ 1. Navigate to the `Add New` sub-page under the Plugins admin page.
76
+ 2. Search for `easy table of contents`.
77
+ 3. The plugin should be listed first in the search results.
78
+ 4. Click the `Install Now` link.
79
+ 5. Lastly click the `Activate Plugin` link to activate the plugin.
80
+
81
+ = Uploading in WordPress Admin =
82
+
83
+ 1. [Download the plugin zip file](http://wordpress.org/plugins/easy-table-of-contents/) and save it to your computer.
84
+ 2. Navigate to the `Add New` sub-page under the Plugins admin page.
85
+ 3. Click the `Upload` link.
86
+ 4. Select Easy Table of Contents zip file from where you saved the zip file on your computer.
87
+ 5. Click the `Install Now` button.
88
+ 6. Lastly click the `Activate Plugin` link to activate the plugin.
89
+
90
+ = Using FTP =
91
+
92
+ 1. [Download the plugin zip file](http://wordpress.org/plugins/easy-table-of-contents/) and save it to your computer.
93
+ 2. Extract the Easy Table of Contents zip file.
94
+ 3. Create a new directory named `easy-table-of-contents` directory in the `../wp-content/plugins/` directory.
95
+ 4. Upload the files from the folder extracted in Step 2.
96
+ 4. Activate the plugin on the Plugins admin page.
97
+
98
+ == Changelog ==
99
+
100
+ = 2.0.25/1 06/30/2022 =
101
+ * BUG: Reusable Block Headings are not rendering in TOC titles #215
102
+
103
+ = 2.0.25 06/27/2022 =
104
+ * TWEAK: Added Migration from Table of Contents Plus and LuckyWP Table of Contents #160
105
+ * TWEAK: Added Option to add inline CSS and JS #189
106
+ * TWEAK: Added Shortcode to show hidden view on particular posts #183
107
+ * TWEAK: Added Hyphen Counter to display the TOC heading #192
108
+ * TWEAK: Added Dot Counter to display the TOC heading #180
109
+ * TWEAK: Improved the Web Accessibility in TOC Toggle #190
110
+ * BUG: Shortcodes are not rendering in TOC titles #197
111
+ * BUG: TOC heading are getting hidden in sticky header #186
112
+ * BUG: No success or error message after support request is submitted #196
113
+ * BUG: Same font size appearing in headings and sub-headings #161
114
+ * BUG: Salient core plugin conflict with last update 2.0.24.1 #207
115
+
116
+ = 2.0.24.1 06/14/2022 =
117
+ * BUG: TOC not displaying properly when initial view option is disabled #195
118
+ * BUG: Initial View option not working with Pure CSS Loading Method #194
119
+
120
+ = 2.0.24 06/10/2022 =
121
+ * TWEAK: Added TOC in Infinite Scroll #138
122
+ * TWEAK: Improved the activation process #187
123
+ * BUG: TOC Toggle not working with Magnolia Theme #174
124
+ * BUG: Initial view not working with TOC Loading Method of CSS #179
125
+ * BUG: Toggle is not visible when Display Header option is disable #171
126
+ * BUG: CSS not loading when using shortcode in theme file #175
127
+ * BUG: the_content filter run twice #182
128
+ * BUG: Form UI looks ugly #169
129
+ * BUG: Debug Warnings in multibyte string functions #185
130
+
131
+ = 2.0.23 05/31/2022 =
132
+ * TWEAK: Added filter to modify anchor links #167
133
+ * TWEAK: Added filter to add TOC before or after the sidebar widget #166
134
+ * TWEAK: Added option to align TOC to center #158
135
+ * TWEAK: Design improvements in options panel #172
136
+
137
+ = 2.0.22 05/06/2022 =
138
+ * BUG: Double hyphens are getting removed from content issue fixed #163
139
+
140
+ = 2.0.21 05/06/2022 =
141
+ * BUG: Critical error fixed #147
142
+
143
+ = 2.0.20 05/05/2022 =
144
+ * TWEAK: Added Toggle with CSS for websites runs without jQuery #153
145
+ * TWEAK: Added telegram group join link for suggestions and feedback #159
146
+ * BUG: TOC links not jumping in some posts which have special characters #163
147
+ * BUG: Incorrect email ID updated in the plugin #165
148
+ * BUG: Proper documentation added for adding TOC with shortcodes & do_shortcode #152
149
+ * BUG: TOC links not working when do_shortcode added directly in the template #147
150
+ * BUG: TOC links not working with some specical character with Elementor #162
151
+
152
+ = 2.0.19 04/16/2022 =
153
+ * Bug Fixed : While Using Elementor Page builder TOC is not working when special characters are used in headings. #150
154
+ * Bug Fixed : Need to load CSS/JS files only on the selected post types. #154
155
+
156
+ = 2.0.18 03/29/2022 =
157
+ * TWEAK: Added Technical Support Tab in Settings Panel.
158
+
159
+ = 2.0.17 03/26/2021 =
160
+ * TWEAK: Add additional check to prevent `Uncaught Error: Call to undefined function is_woocommerce()`.
161
+ * TWEAK: Ensure an instance of `ezTOC_Post ` is returned before accessing methods/properties.
162
+
163
+ = 2.0.16 02/01/2021 =
164
+ * TWEAK: Remove special characters such as fancy quotes, en and, em dashes when generating in-page anchor IDs.
165
+
166
+ = 2.0.15 01/27/2021 =
167
+ * TWEAK: Remove additional reserved characters when generating in-page anchor IDs.
168
+
169
+ = 2.0.14 01/26/2021 =
170
+ * TWEAK: Refactor debug log as a Singleton.
171
+ * TWEAK: Add additional logging to aid in debugging.
172
+ * BUG: Correct logic for PHP where empty string no longer evaluates as integer `0`.
173
+
174
+ = 2.0.13 01/25/2021 =
175
+ * TWEAK: Restrict debug logging to when `WP_DEBUG` is enabled *and* current user capability of `manage_options`.
176
+ * TWEAK: Add logging to aid in support.
177
+ * DEV: phpDoc update.
178
+
179
+ = 2.0.12 01/22/2021 =
180
+ * TWEAK: Allow `_` and `-` in anchors.
181
+ * TWEAK: Minor CSS tweaks that prevent theme from breaking the layout.
182
+ * TWEAK: Minor tweak to class initialization.
183
+ * TWEAK: Do not display the view toggle if JavaScript is broken on the site.
184
+ * TWEAK: Add the ability to enable displaying of displaying debug information on the page.
185
+ * BUG: Check for array and keys before accessing values.
186
+ * BUG: Check for array key be fore access.
187
+ * BUG: Remove reserved characters when generating in-page anchor IDs.
188
+ * DEV: Remove unnecessary vendor library files.
189
+ * DEV: Deal with phpStorm showing a warning about path not found when including files.
190
+
191
+ = 2.0.11 05/01/2020 =
192
+ * COMPATIBILITY: Add support for the Uncode theme.
193
+ * COMPATIBILITY: Do not run on WooCommerce pages.
194
+ * DEV: Correct typo in phpDoc.
195
+
196
+ = 2.0.10 04/20/2020 =
197
+ * TWEAK: Add trailing `span` to heading, to prepare for `#` option and to fix duplicate heading title matching.
198
+ * TWEAK: Add second heading search/replace function to search for heading in content with heading html entities decoded. May help Beaver Builder users as it seems like it does not encode HTML entities as WP core does.
199
+
200
+
201
+ = 2.0.9 04/08/2020 =
202
+ * TWEAK: AMP/Caching plugins seems to break anchors with colons and periods even though they are valid characters for the id attribute in HTML5.
203
+ * TWEAK: Replace multiple underscores with a single underscore.
204
+ * DEV: Update the UWS library which fixes the deprecation notice for PHP 7.4.
205
+ * DEV: Add phpcs.xml.dist.
206
+ * DEV: Strict type checks.
207
+ * DEV: Inline doc updates.
208
+
209
+ = 2.0.8 04/03/2020 =
210
+ * TWEAK: Convert `<br />` tags in headings to a space.
211
+ * TWEAK: Add additional widget classes.
212
+ * TWEAK: Improve the sanitization of the excluded headings field post setting.
213
+ * TWEAK: Minor optimization of creating the matching pattern for excluding headings for improved performance.
214
+ * COMPATIBILITY: Exclude Create by Mediavine from heading eligibility.
215
+ * BUG: Ensure excluded headings are removed from the headings array.
216
+ * BUG: Ensure empty headings are removed from the headings array.
217
+
218
+ = 2.0.7 04/02/2020 =
219
+ * NEW: Exclude any HTML nodes with the class of `.ez-toc-exclude-headings`.
220
+ * TWEAK: Change smooth scroll selector from `'body a'` to `'a.ez-toc-link'`.
221
+ * TWEAK: Declare JS variables.
222
+ * TWEAK: Support unicode characters for the `id` attribute. Permitted by HTML5.
223
+ * TWEAK: Move the in-page anchor/span to before the heading text to account for long headings where it line wraps.
224
+ * TWEAK: Slight rework to ezTOC widget container classes logic.
225
+ * TWEAK: Cache bust the JS to make dev easier.
226
+ * TWEAK: JavaScript cleanup.
227
+ * TWEAK: URI Encode the id attribute to deal with reserved characters in JavaScript. Technically not necessary for the id attribute but needed to work with the jQuery smoothScroll library.
228
+ * COMPATIBILITY: Reintroduce filter to exclude Ultimate Addons for VC Composer Tabs from heading eligibility.
229
+ * BUG: Correct array iteration logic when processing headings.
230
+ * BUG: Tighten matching for headings in excluded HTML nodes. The loose matching was excluding far too many headings.
231
+ * BUG: Use `esc_attr()` instead of `esc_url()` for the anchor href because valid id attribute characters would cause it to return an empty href which cause a nonworking link.
232
+
233
+ = 2.0.6 03/30/2020 =
234
+ * BUG: Ensure minified files are current.
235
+
236
+ = 2.0.5 03/27/2020 =
237
+ * BUG: Prevent possible "strpos(): Empty needle in" warnings when excluding nodes from TOC eligibility.
238
+
239
+ = 2.0.4 03/16/2020 =
240
+ * NEW: Introduce the `ez_toc_container_class` filter.
241
+ * TWEAK: Slight rework to ezTOC container classes logic.
242
+ * BUG: `sprintf()` was eating `%` in the TOC heading item.
243
+ * BUG: Do not insert TOC at top of post if before first heading option is selected even if first heading can not be found. Some page builders cause the TOC to insert twice or on blog pages.
244
+
245
+ = 2.0.3 03/12/2020 =
246
+ * TWEAK: Slightly tighten heading matching, last update made it a little too loose.
247
+ * BUG: Correct logic required to place TOC before first heading which is required for the more lax heading matching required for page builders.
248
+
249
+ = 2.0.2 03/12/2020 =
250
+ * COMPATIBILITY: Remove filter to exclude Ultimate Addons for VC Composer Tabs from heading eligibility.
251
+ * COMPATIBILITY: Add additional filters to improve Elementor compatibility.
252
+ * TWEAK: Loosen heading matching when doing find/replace to insert in page links. Excluding the opening heading tag to allow matching heading where page builders dynamically add classes and id which break heading matching during find/replace.
253
+
254
+ = 2.0.1 03/09/2020 =
255
+ * COMPATIBILITY: Exclude the WordPress Related Posts plugin nodes.
256
+ * COMPATIBILITY: Exclude a couple Atomic Block plugin nodes.
257
+ * COMPATIBILITY: Exclude JetPack Related Posts from heading eligibility.
258
+ * COMPATIBILITY: Exclude Ultimate Addons for VC Composer Tabs from heading eligibility.
259
+ * COMPATIBILITY: Exclude WP Product Reviews from heading eligibility.
260
+ * TWEAK: Prevent possible "strpos(): Empty needle in" warnings when excluding nodes from TOC eligibility.
261
+
262
+ = 2.0 02/01/2020 =
263
+ * NEW: Major rewrite of all code and processing logic to make it faster and more reliable.
264
+ * NEW: Support for the <!--nextpage--> tag.
265
+ * NEW: Introduce helper functions for devs.
266
+ * NEW: Support WPML.
267
+ * NEW: Support Polylang.
268
+ * NEW: Add filter to support the Rank Math plugin.
269
+ * NEW: Introduce the `ez_toc_maybe_apply_the_content_filter` filter.
270
+ * TWEAK: Improve translation compatibility.
271
+ * TWEAK: Rework widget logic to allow multi-line TOC items, improve active item highlighting while removing the use of the jQuery Waypoints library.
272
+ * TWEAK Add additional classes to TOC list items.
273
+ * TWEAK: Add WOFF2 format for icon format and change font references in CSS.
274
+ * TWEAK: Add font-display: swap for toggle icon.
275
+ * TWEAK: Update JS Cookie to 2.2.1.
276
+ * TWEAK: Update jQuery Smooth Scroll to 2.2.0.
277
+ * TWEAK: Allow forward slash and angle brackets in headings and alternate headings.
278
+ * TWEAK: Allow forward slash in excluded headings.
279
+ * TWEAK: Remove new line/returns when matching excluded headings.
280
+ * TWEAK: Simple transient cache to ensure a post is only processed once per request for a TOC.
281
+ * TWEAK: Improve sanitization of alternate headings field value.
282
+ * TWEAK: Deal with non-breaking-spaces in alternate headings.
283
+ * TWEAK: Add the ability to exclude by selector content eligible to be included in the TOC.
284
+ * TWEAK: Change the shortcode priority to a higher value.
285
+ * TWEAK: Add filter to remove shortcodes from the content prior to the `the_content` filter being run to exclude shortcode content from being eligible as TOC items.
286
+ * TWEAK: Add compatibility filters to remove shortcodes for Connections and Striking theme to remove them from eligible TOC item content.
287
+ * TWEAK: Do not execute if root current filter is the `wp_head` or `get_the_excerpt` filters.
288
+ * TWEAK: Add filter to exclude content by selector.
289
+ * TWEAK: Move in-page anchor to after the heading instead of wrapping the heading to prevent conflicts with theme styling.
290
+ * TWEAK: Utilize the `ez_toc_exclude_by_selector` filter the exclude the JetPack share buttons from eligible headings.
291
+ * TWEAK: Remove the Elegant Themes Bloom plugin node from the post content before extracting headings.
292
+ * TWEAK: Add compatibility filter for the Visual Composer plugin.
293
+ * TWEAK: Utilize the `ez_toc_exclude_by_selector` filter the exclude the Starbox author heading from eligible headings.
294
+ * I18N: Add wpml-config.xml file.
295
+ * BUG: Correct option misspelling.
296
+ * BUG: Do not need to run values for alternate and exclude headings thru `wp_unslash()` because `update_post_meta()` already does.
297
+ * BUG: Do not need to run `stripslashes()` when escaping the alternate heading value.
298
+ * BUG: Sanitize the excluded heading string before saving post meta.
299
+ * DEV: Change PHP keywords to comply with PSR2.
300
+ * DEV:Bump minimum PHP version to 5.6.20 which matches WP core.
301
+
302
+ = 1.7 05/09/2018 =
303
+ * NEW: Introduce the `ez_toc_shortcode` filter.
304
+ * TWEAK: Fix notices due to late eligibility check. props unixtam
305
+ * TWEAK: Tweak eligibility check to support the TOC widget.
306
+ * TWEAK: Prefix a few CSS classes in order to prevent collisions with theme's and other plugins.
307
+ * TWEAK: Avoid potential PHP notice in admin when saving the post by checking for nonce before validating it.
308
+ * TWEAK: Using the shortcode now overrides global options.
309
+ * TWEAK: `the_content()` now caches result of `is_eligible()`.
310
+ * TWEAK: Refactor to pass the WP_Post object internally vs. accessing it via the `$wp_query->post` which may not in all cases exist.
311
+ * TWEAK: Use `pre_replace()` to replace one or more spaces with an underscore.
312
+ * TWEAK: Return original title in the `ez_toc_url_anchor_target` filter.
313
+ * TWEAK: Strip `&nbsp;`, replacing it with a space character.
314
+ * TWEAK: Minor tweaks to the in page URL creating.
315
+ * TWEAK: Wrap TOC list in a nav element.
316
+ * TWEAK: Init plugin on the `plugins_loaded` hook.
317
+ * TWEAK: Tweak the minimum number of headers to 1.
318
+ * BUG: The header options from the post meta should be used when building the TOC hierarchy, not the header options from the global settings.
319
+ * BUG: Do not double escape field values.
320
+ * BUG: Ensure Apostrophe / Single quote use in Exclude Headings work.
321
+ * OTHER: Update CSS to include the newly prefixed classes.
322
+ * DEV: Remove some commented out unused code.
323
+
324
+ = 1.6.1 03/16/2018 =
325
+ * TWEAK: Revert change made to allow HTML added via the `ez_toc_title` filter as it caused undesirable side effects.
326
+ * BUG: Ensure Smooth Scroll Offset is parsed as an integer.
327
+
328
+ = 1.6 03/15/2018 =
329
+ * NEW: Add `px` option for font size unit.
330
+ * NEW: Add title font size and weight settings options.
331
+ * NEW: Add the Mobile Smooth Scroll Offset option.
332
+ * TWEAK: Change default for font size unit from `px` to `%` to match the default options values.
333
+ * TWEAK: Correct CSS selector so margin is properly applied between the title and TOC items.
334
+ * TWEAK: Honor HTML added via `ez_toc_title` filter.
335
+ * TWEAK: Ensure the ezTOC content filter is not applied when running `the_content` filter.
336
+ * TWEAK: Only enqueue the javascript if the page is eligible for a TOC.
337
+ * TWEAK: Update icomoon CSS to remove unecessary CSS selectors to prevent possible conflicts.
338
+ * TWEAK: The smooth scroll offset needs to be taken into account when defining the offset_top property when affixing the widget.
339
+ * OTHER: Update frontend minified CSS file.
340
+ * OTHER: Update the frontend minified javascript file.
341
+ * DEV: phpDoc corrections.
342
+
343
+ = 1.5 02/20/2018 =
344
+ * BUG: Correct CSS selector to properly target the link color.
345
+ * OTHER: Update the WayPoints library.
346
+ * DEV: Add a couple @todo's.
347
+
348
+ = 1.4 01/29/2018 =
349
+ * TWEAK: Change text domain from ez_toc to easy-table-of-contents.
350
+ * TWEAK: Rename translation files with correct text domain.
351
+ * BUG: Ensure page headers are processed to add the in page header link when using the shortcodes.
352
+ * BUG: Add forward slash to domain path in the plugin header.
353
+ * I18N: Update POT file.
354
+ * I18N: Update Dutch (nl_NL) translation.
355
+
356
+ = 1.3 12/18/2017 =
357
+ * FEATURE: Add support for the `[ez-toc]` shortcode.
358
+ * NEW: For backwards compatibility with "Table of Content Plus", register the `[toc]` shortcode.
359
+ * NEW: Introduce the `ez_toc_extract_headings_content` filter.
360
+ * TWEAK: Update the tested to and required readme header text.
361
+ * TWEAK: Do not show the widget on the 404, archive, search and posts pages.
362
+ * I18N: Add the nl_NL translation.
363
+
364
+ = 1.2 04/29/2016 =
365
+ * TWEAK: Remove the font family from styling the TOC title header.
366
+ * TWEAK: Pass the raw title to the `ez_toc_title` filter.
367
+ * BUG: A jQuery 1.12 fix for WordPress 4.5.
368
+
369
+ = 1.1 02/24/2016 =
370
+ * FEATURE: Add option to replace header wither alternate header text in the table of content.
371
+ * NEW: Introduce the ez_toc_filter.
372
+ * NEW: Introduce ezTOC_Option::textarea() to render textareas.
373
+ * NEW: Introduce array_search_deep() to recursively search an array for a value.
374
+ * TWEAK: Run table of contents headers thru wp_kses_post().
375
+ * TWEAK: Escape URL.
376
+ * TWEAK: Count excluded headings only once instead of multiple times.
377
+ * TWEAK: Escape translated string before rendering.
378
+ * TWEAK: Use wp_unslash() instead of stripslashes().
379
+ * TWEAK: Escape translated string.
380
+ * BUG: Fix restrict path logic.
381
+ * OTHER: Readme tweaks.
382
+ * I18N: Add POT file.
383
+ * I18N: Add Dutch translation.
384
+ * DEV: Update .gitignore to allow PO files.
385
+ * DEV: phpDoc fix.
386
+
387
+ = 1.0 09/08/2015 =
388
+ * Initial release.
389
+ - Complete refactor and restructure of the original code for better design and separation of function to make code base much easier to maintain and extend.
390
+ - Update all third party libraries.
391
+ - Make much better use of the WordPress Settings API.
392
+ - Minified CSS and JS files are used by default. Using SCRIPT_DEBUG will use the un-minified versions.
393
+ - Add substantial amounts of phpDoc for developers.
394
+ - Add many hooks to permit third party integrations.
395
+ - Widget can be affixed/stuck to the page so it is always visible.
396
+ - Widget will highlight the table of content sections that are currently visible in the browser viewport.
397
+ - Widget will now generate table of contents using output from third party shortcodes.
398
+ - Use wpColorPicker instead of farbtastic.
399
+ - Remove all shortcodes.
400
+ - Per post options are saved in post meta instead of set by shortcode.
401
+
402
+ == Frequently Asked Questions ==
403
+
404
+ = Ok, I've installed this... what do I do next? =
405
+
406
+ You first stop should be the Table of Contents settings admin page. You can find this under the Settings menu item.
407
+
408
+ You first and only required decision is you need to decide which post types you want to enable Table of Contents support for. By default it is the Pages post type. If on Pages is the only place you plan on using Table of Contents, you have nothing to do on the Settings page. To keep things simple, I recommend not changing any of the other settings at this point. Many of the other settings control when and where the table of contents is inserted and changing these settings could cause it not to display making getting started a bit more difficult. After you get comfortable with how this works... then tweak away :)
409
+
410
+ With that out of the way make sure to read the **How are the tables of contents created?** FAQ so you know how the Table of Contents is automatically generated. After you have the page headers setup, or before, either way... Scroll down on the page you'll see a metabox named "*Table of Contents*", enable the *Insert table of contents.* option and Update and/or Publish you page. The table of contents should automatically be shown at the top of the page.
411
+
412
+ = How are the tables of contents created? =
413
+
414
+ The table of contents is generated by the headers found on a page. Headers are the [`<h1>,<h2>,<h3>,<h4>,<h5>,<h6>` HTML tags](http://www.w3schools.com/tags/tag_hn.asp). If you are using the WordPres Visual Post Editor, these header tags are used and inserted into the post when you select one of the [*Heading n* options from the formatting drop down](http://torquemag.io/wordpress-heading-tags/). Each header that is found on the page will create a table of content item. Here's an example which will create a table of contents containing the six items.
415
+
416
+ `<h1>Item 1</h1>
417
+ <h1>Item 2</h1>
418
+ <h1>Item 3</h1>
419
+ <h1>Item 4</h1>
420
+ <h1>Item 5</h1>
421
+ <h1>Item 6</h1>`
422
+
423
+ You can also create "nested" table of contents. This is difficult to explain so I'll illustrate building on the previous example. In this example a table of contents will be created with the same six items but now the first three will each an child item nested underneath it. The indentation is not necessary, it was only added for illustration purposes.
424
+
425
+ `<h1>Item 1</h1>
426
+ <h2>Item 1.1 -- Level 2</h2>
427
+ <h1>Item 2</h1>
428
+ <h2>Item 2.1 -- Level 2</h2>
429
+ <h1>Item 3</h1>
430
+ <h2>Item 3.1 -- Level 2</h2>
431
+ <h1>Item 4</h1>
432
+ <h1>Item 5</h1>
433
+ <h1>Item 6</h1>`
434
+
435
+ You are not limited to a single a single nested item either. You can add as many as you need. You can even create multiple nested levels...
436
+
437
+ `<h1>Item 1</h1>
438
+ <h2>Item 1.1 -- Level 2</h2>
439
+ <h3>Item 1.1.1 -- Level 3</h3>
440
+ <h3>Item 1.1.2 -- Level 3</h3>
441
+ <h3>Item 1.1.3 -- Level 3</h3>
442
+ <h2>Item 1.2 -- Level 2</h2>
443
+ <h3>Item 1.2.1 -- Level 3</h3>
444
+ <h3>Item 1.2.2 -- Level 3</h3>
445
+ <h3>Item 1.2.3 -- Level 3</h3>
446
+ <h2>Item 1.3 -- Level 2</h2>
447
+ <h1>Item 2</h1>
448
+ <h2>Item 2.1 -- Level 2</h2>
449
+ <h2>Item 2.2 -- Level 2</h2>
450
+ <h1>Item 3</h1>
451
+ <h2>Item 3.1 -- Level 2</h2>
452
+ <h2>Item 3.2 -- Level 2</h2>
453
+ <h1>Item 4</h1>
454
+ <h1>Item 5</h1>
455
+ <h1>Item 6</h1>`
456
+
457
+ You can nest up 6 levels deep if needed. I hope this helps you understand how to create and build your own auto generated table of contents on your sites!
458
+
459
+ = Is there any shortcode to add the table of content to anywhere I want ? =
460
+
461
+ Yes you can add the TOC with this shortcode – [ez-toc] and with the help of this you can easily add the TOC in the content or anywhere in the WordPress and if you want to add the shortcode on the theme file then you can add it with the help of this code – <?php echo do_shortcode( ‘[ez-toc]’ ); ?> and with this, you can add the TOC on any file according to your need.
462
+
463
+ == Upgrade Notice ==
464
+
465
+ = 1.0 =
466
+ Initial release.
467
+
468
+ = 1.3 =
469
+ Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
470
+
471
+ = 1.4 =
472
+ Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
473
+
474
+ = 1.5 =
475
+ Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
476
+
477
+ = 1.6 =
478
+ Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
479
+
480
+ = 1.6.1 =
481
+ Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
482
+
483
+ = 1.7 =
484
+ Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
485
+
486
+ = 2.0-rc4 =
487
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
488
+
489
+ = 2.0.1 =
490
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
491
+
492
+ = 2.0.2 =
493
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
494
+
495
+ = 2.0.3 =
496
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
497
+
498
+ = 2.0.4 =
499
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
500
+
501
+ = 2.0.5 =
502
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
503
+
504
+ = 2.0.6 =
505
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
506
+
507
+ = 2.0.7 =
508
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
509
+
510
+ = 2.0.8 =
511
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
512
+
513
+ = 2.0.9 =
514
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
515
+
516
+ = 2.0.10 =
517
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
518
+
519
+ = 2.0.11 =
520
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
521
+
522
+ = 2.0.12 =
523
+ Requires WordPress >= 5.3 and PHP version >= 5.6.20 (>= 7.4 is recommended).
524
+
525
+ = 2.0.13 =
526
+ Requires WordPress >= 5.3 and PHP version >= 5.6.20 (>= 7.4 is recommended).
527
+
528
+ = 2.0.14 =
529
+ Requires WordPress >= 5.3 and PHP version >= 5.6.20 (>= 7.4 is recommended).
530
+
531
+ = 2.0.15 =
532
+ Requires WordPress >= 5.3 and PHP version >= 5.6.20 (>= 7.4 is recommended).
533
+
534
+ = 2.0.16 =
535
+ Requires WordPress >= 5.3 and PHP version >= 5.6.20 (>= 7.4 is recommended).
536
+
537
+ = 2.0.17 =
538
+ Requires WordPress >= 5.3 and PHP version >= 5.6.20 (>= 7.4 is recommended).
assets/css/admin.css CHANGED
@@ -1,1235 +1,1235 @@
1
- div.tab_content table {
2
- margin-bottom: 1em;
3
- }
4
- table.more_toc_options_table th, table.more_toc_options_table td {
5
- padding: 0;
6
- margin: 0;
7
- }
8
- table.more_toc_options_table th {
9
- width: auto;
10
- padding-right: 4px;
11
- padding-top: 2px;
12
- }
13
- div.tab_content ul li {
14
- margin-left: 2em;
15
- list-style-type: disc;
16
- }
17
- div.tab_content ol li {
18
- list-style: inherit;
19
- }
20
- div.tab_content pre {
21
- margin-left: 2em;
22
- }
23
- ul#tabbed-nav {
24
- margin-top: 1em;
25
- }
26
- #tabbed-nav {
27
- margin: 0;
28
- padding: 0;
29
- float: left;
30
- list-style: none;
31
- height: 32px;
32
- border-bottom: 1px solid #DFDFDF;
33
- border-left: 1px solid #DFDFDF;
34
- width: 100%;
35
- }
36
- #tabbed-nav li {
37
- float: left;
38
- margin: 0;
39
- padding: 0;
40
- height: 31px;
41
- line-height: 31px;
42
- border: 1px solid #DFDFDF;
43
- border-left: none;
44
- margin-bottom: -1px;
45
- overflow: hidden;
46
- position: relative;
47
- background: #F5F5F5;
48
- background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#F5F5F5));
49
- background-image: -webkit-linear-gradient(center top, #fff, #F5F5F5);
50
- background-image: -moz-linear-gradient(center top, #fff, #F5F5F5);
51
- background-image: -ms-linear-gradient(center top, #fff, #F5F5F5);
52
- background-image: -o-linear-gradient(center top, #fff, #F5F5F5);
53
- background-image: linear-gradient(center top, #fff, #F5F5F5);
54
- }
55
- #tabbed-nav li a {
56
- text-decoration: none;
57
- color: #000;
58
- display: block;
59
- font-size: 1.2em;
60
- padding: 0 20px;
61
- border: 1px solid #fff;
62
- outline: none;
63
- }
64
- #tabbed-nav li a:hover {
65
- background: #ECECEC;
66
- }
67
- html #tabbed-nav li.active, html #tabbed-nav li.active a:hover {
68
- background: #fff;
69
- border-bottom: 1px solid #fff;
70
- }
71
- div.tab_container {
72
- border: 1px solid #DFDFDF;
73
- border-top: none;
74
- overflow: hidden;
75
- clear: both;
76
- float: left; width: 100%;
77
- background: #fff;
78
- margin-bottom: 2em;
79
- padding-bottom: 2em;
80
- }
81
- div.tab_content {
82
- padding: 10px;
83
- padding-bottom: 0;
84
- font-size: 1em;
85
- }
86
- h3 span.show_hide {
87
- font-size: 0.85em;
88
- font-weight: normal;
89
- }
90
- div.more_toc_options {
91
- margin-top: 4px;
92
- margin-left: 2em;
93
- }
94
- div.toc_theme_option {
95
- width: 200px;
96
- float: left;
97
- margin-right: 5px;
98
- }
99
- #wpcontent select optgroup option {
100
- padding-left: 15px;
101
- }
102
- input#width_custom,
103
- input#font_size,
104
- input#child_font_size,
105
- input#smooth_scroll_offset {
106
- width: 50px;
107
- text-align: center;
108
- }
109
- input.custom_colour_option {
110
- width: 75px;
111
- }
112
- table#theme_custom, div#farbtastic_colour_wheel {
113
- float: left;
114
- }
115
- table#theme_custom {
116
- margin-top: 30px;
117
- }
118
- table#theme_custom img {
119
- vertical-align: middle;
120
- opacity: 0.4;
121
- }
122
- table#theme_custom img:hover {
123
- cursor: pointer;
124
- opacity: 1;
125
- }
126
- div#farbtastic_colour_wheel {
127
- margin-left: 20px;
128
- }
129
- #tab3 h3:not(:first-child) {
130
- margin-top: 2em;
131
- }
132
-
133
- /* My styles */
134
- #toc input.small-text {
135
- width: 50px;
136
- padding: 2px;
137
- height: 28px;
138
- line-height: 28px;
139
- vertical-align: bottom;
140
- }
141
-
142
- #toc .form-table tr > th > strong {
143
- font-size: 18px;
144
- font-style: italic;
145
- }
146
- /* Tab panel styles */
147
- .postbox{
148
- padding: 10px;
149
- }
150
- html {
151
- scroll-behavior: smooth;
152
- }
153
- .toc-tab-panel {
154
- overflow: hidden;
155
- border: 1px solid #ccc;
156
- background-color: #fff;
157
- margin-top: 15px;}
158
- .toc-tab-panel a {
159
- background-color: inherit;
160
- text-decoration: none;
161
- float: left;
162
- border: none;
163
- outline: none;
164
- cursor: pointer;
165
- padding: 14px 16px;
166
- transition: 0s;
167
- font-size: 15px;
168
- color: #2271b1;
169
- font-weight: 500;
170
- }
171
- .toc-tab-panel a:hover {
172
- color: #0a4b78;
173
- }
174
- .toc-tab-panel a.active {
175
- box-shadow: none;
176
- border-bottom: 4px solid #646970;
177
- color: #1d2327;
178
- }
179
- .toc-tab-panel a:focus {
180
- box-shadow: none;
181
- outline: none;
182
- }
183
- .eztoc-tabcontent {
184
- display: none;
185
- border-top: none;
186
- animation: fadeEffect 1s;
187
- }
188
- #technical .eztoc-form-page-ui{
189
- display:flex;
190
- background: #fff;
191
- width: auto;
192
- height: auto;
193
- }
194
- #technical .eztoc-left-side{
195
- width: 70%;
196
-
197
- }
198
- .eztoc-right-side{
199
- width: 31%;
200
- margin-top: auto;
201
- margin-bottom: auto;
202
- text-align: center;
203
-
204
- }
205
- .eztoc-tabcontent {
206
- display: none;
207
- border-top: none;
208
- }
209
- #technical {
210
- background: #fff;
211
- margin-top: 10px;
212
- padding: 28px;
213
- padding: 15px 28px 28px 28px;
214
- min-width: 255px;
215
- box-shadow: 0 1px 1px rgb(0 0 0 / 4%);
216
- }
217
- /* #technical p{
218
- line-height: 0.5rem;
219
- } */
220
- #technical-form{
221
-
222
- width: 60%;
223
- }
224
- .support-label {
225
- margin-top: 4px;
226
- float: left;
227
- width: 70px;
228
-
229
- font-size: 14px;
230
- }
231
-
232
- .star-mark{
233
- color: red;
234
- margin-left: 4px;
235
- font-family: bold;
236
- }
237
- #technical li {
238
- margin:25px 0px 20px 0px;
239
- margin:10px 0px 10px 0px;
240
- list-style: none;
241
- }
242
- .eztoc_support_div_form{
243
- margin-top: 23px;
244
- }
245
- .eztoc-customer-type{
246
- display: block;
247
- }
248
- .support-input select{
249
- border-radius: 4px;
250
- margin-top: -7px;
251
- }
252
- .eztoc_dev-bio{
253
- display: block;
254
- }
255
- .ezoc-bio-wrap{
256
- float: left;
257
- text-align: center;
258
- width: 33.33%;
259
- text-transform: uppercase;
260
- }
261
- .ezoc-bio-wrap p{
262
- width: auto;
263
- font-size: 10px;
264
- color: #555;
265
- margin: 0px 0 20px 0;
266
- }
267
- .ezoc-bio-wrap img{
268
- margin: 25px 0 0 0;
269
- border-radius: 50%;
270
- }
271
- .eztoc-bio-box{
272
- background: #fff;
273
- border: 1px solid #ccc;
274
- padding: 15px 20px;
275
- border-radius: 4px;
276
- margin: 15px 15px 15px 0;
277
- /* height: 22rem; */
278
- padding: 0px 20px;
279
- }
280
- .eztoc-bio-box:hover{
281
- box-shadow: 5px 5px 8px #888888;
282
- }
283
- .eztoc-p{
284
- font-size: 15px;
285
- margin: 20px auto 0px auto;
286
- text-align: center;
287
- }
288
- .eztoc-p{
289
- line-height: 1.5rem;
290
- padding: 0 25px;
291
- margin-top: 10px;
292
- font-size: 16px;
293
- }
294
- .eztoc-bio-box h1{
295
- margin: 8px auto 0px auto;
296
- text-align: center;
297
- font-weight: bolder;
298
- }
299
- .eztoc_boxdesk{
300
- clear: left;
301
- font-size: 15px;
302
- text-align: center;
303
- margin: 20px 0 0 0;
304
-
305
- }
306
- .company-link{
307
- font-weight: 500;
308
- margin: 20px 0 0 0;
309
- }
310
- .company-link a{
311
-
312
- display: table;
313
- background: #e91e63;
314
- width: auto;
315
- margin: 0 auto;
316
- padding: 7px 25px;
317
- color: #fff;
318
- text-decoration: none;
319
- margin-top: 10px;
320
- margin-bottom: 15px;
321
- border-radius: 6px;
322
- border: 0;
323
- /* text-transform: uppercase; */
324
- font-size: 16px;
325
-
326
- }
327
- .eztoc-send-query{
328
- background: #2271b1;
329
- border-color: #2271b1;
330
- color:#fff;
331
- text-decoration: none;
332
- text-shadow: none;
333
- margin-left: 70px !important;;
334
- }
335
-
336
- @media screen and (min-width: 870px) and (max-width: 1300px ){
337
- .eztoc-bio-box{
338
- padding-top: 20px;
339
- height: 29.1rem;;
340
- }
341
- .eztoc-bio-box h1{
342
- font-size: 20px;
343
- }
344
- .eztoc-bio-box p{
345
- font-size: 13px;
346
- margin: 20px auto 0px auto;
347
- }
348
- .ezoc-bio-wrap img{
349
- width: 30px;
350
- height: 30px;
351
- }
352
- .ezoc-bio-wrap p{
353
- width: 55px;
354
- font-size: 12px;
355
- margin-bottom: 10px;
356
- }
357
-
358
- }
359
- @keyframes fadeEffect { from {opacity: 0;} to {opacity: 1;} }
360
-
361
-
362
- .eztoc-wrapper{
363
- max-width: 100%;
364
- width: 100%;
365
- display: flex;
366
- flex-wrap: wrap;
367
- margin: auto;
368
- }
369
-
370
- .eztoc-wrapper .table{
371
- margin: 0 auto;
372
- background: #fff;
373
- width: calc(30%);
374
- padding: 30px 20px;
375
- position: relative;
376
- box-shadow: 0 5px 10px rgb(0 0 0 / 10%);
377
- }
378
-
379
- .table .price-section{
380
- display: flex;
381
- justify-content: center;
382
- }
383
-
384
- .price-section .price-area{
385
- height: 120px;
386
- width: 120px;
387
- background: #ffd861;
388
- border-radius: 50%;
389
- padding: 2px;
390
- }
391
-
392
- .price-section .price-area .inner-area{
393
- height: 100%;
394
- width: 100%;
395
- border-radius: 50%;
396
- border: 3px solid #fff;
397
- color: #fff;
398
- line-height: 117px;
399
- text-align: center;
400
- position: relative;
401
- }
402
-
403
- .price-area .inner-area .text{
404
- font-size: 25px;
405
- font-weight: 400;
406
- position: absolute;
407
- top: -10px;
408
- left: 17px;
409
- }
410
-
411
- .price-area .inner-area .price{
412
- font-size: 55px;
413
- font-weight: 500;
414
- }
415
-
416
- .table .package-name{
417
- width: 100%;
418
- height: 2px;
419
- background: #ffecb3;
420
- margin: 35px 0;
421
- position: relative;
422
- }
423
-
424
- .table .package-name::before{
425
- position: absolute;
426
- content: "Basic";
427
- top: 50%;
428
- left: 50%;
429
- transform: translate(-50%, -50%);
430
- background: #fff;
431
- font-size: 25px;
432
- padding: 0 10px;
433
- font-weight: bolder;
434
- }
435
-
436
- .table .features li{
437
- list-style: none;
438
- display: flex;
439
- justify-content: space-between;
440
- margin-bottom: 15px;
441
- }
442
-
443
- .features li .list-name{
444
- font-size: 17px;
445
- font-weight: 400;
446
- }
447
-
448
- .features li .icon{
449
- font-size: 15px;
450
- }
451
-
452
- .features li .icon.check{
453
- color: #2db94d;
454
- }
455
-
456
- .features li .icon.cross{
457
- color: #cd3241;
458
- }
459
-
460
- .table .btn{
461
- display: flex;
462
- justify-content: center;
463
- margin-top: 35px;
464
- }
465
-
466
- .table .btn button{
467
- width: 80%;
468
- height: 50px;
469
- font-weight: 700;
470
- color: #fff;
471
- font-size: 20px;
472
- border: none;
473
- outline: none;
474
- border-radius: 25px;
475
- cursor: pointer;
476
- transition: all 0.3s ease;
477
- }
478
-
479
- .basic .price-area,
480
- .basic .inner-area{
481
- background: #ffd861;
482
- }
483
-
484
- .basic .btn button{
485
- background: #fff;
486
- color: #ffd861;
487
- border: 2px solid #ffd861;
488
- }
489
-
490
- .basic .btn button:hover{
491
- border-radius: 6px;
492
- background: #ffd861;
493
- color: #fff;
494
- }
495
-
496
- .Premium .price-area,
497
- .Premium .inner-area{
498
- background: #a26bfa;
499
- }
500
-
501
- .Premium .btn button{
502
- background: #fff;
503
- color: #a26bfa;
504
- border: 2px solid #a26bfa;
505
- }
506
-
507
- .Premium .btn button:hover{
508
- border-radius: 6px;
509
- background: #a26bfa;
510
- color: #fff;
511
- }
512
-
513
-
514
- .basic .package-name{
515
- background: #ffecb3;
516
- }
517
-
518
- .Premium .package-name{
519
- background: #a26bfa;
520
- }
521
-
522
-
523
-
524
- .basic .package-name::before{
525
- content: "Free";
526
- }
527
-
528
- .Premium .package-name::before{
529
- content: "PRO";
530
- }
531
-
532
-
533
-
534
- .basic ::selection,
535
- .basic .price-area,
536
- .basic .inner-area{
537
- background: #ffd861;
538
- }
539
-
540
- .Premium ::selection,
541
- .Premium .price-area,
542
- .Premium .inner-area{
543
- background: #a26bfa;
544
- }
545
-
546
- div#eztoc-tabs a {
547
- text-decoration: none;
548
- }
549
- div#eztoc-tabs a:first-child {
550
- color: #000;
551
- }
552
-
553
- #the-list{position: relative;}
554
- .eztoc-wr {
555
- width: 100%;
556
- margin: 0 auto;
557
- position: relative
558
- }
559
-
560
- .etoc-eztoc-img {
561
- width: 100%;
562
- margin: 0 auto;
563
- text-align: center;
564
- position: relative;
565
- line-height: 0;
566
- height: 300px;
567
- }
568
-
569
- .eztoc-img img {
570
- position: relative
571
- }
572
-
573
- .sp_ov {
574
- background: rgba(234, 76, 137, 1);
575
- bottom: 0;
576
- left: 0;
577
- position: absolute;
578
- right: 0;
579
- top: 0;
580
- }
581
-
582
- .etoc-eztoc-cnt {
583
- position: absolute;
584
- top: 40px;
585
- bottom: 0;
586
- left: 40px;
587
- right: 40px;
588
- margin: 0 auto;
589
- text-align: center
590
- }
591
-
592
- .etoc-eztoc-cnt h1 {
593
- font-size: 60px;
594
- color: #fff;
595
- font-weight: 600;
596
- }
597
-
598
- .etoc-eztoc-cnt p {
599
- margin-top: 0px;
600
- color: #371b24;
601
- font-size: 18px;
602
- padding: 0 100px;
603
- line-height: 1.4;
604
- font-weight: 500;
605
- }
606
-
607
- .etoc-eztoc-cnt .buy {
608
- border-width: 0px !important;
609
- font-size: 1.25rem;
610
- line-height: 2;
611
- text-decoration: none;
612
- background: white !important;
613
- border-radius: 8px !important;
614
- font-size: 16px !important;
615
- padding: 12px 18px;
616
- color: rgba(234, 76, 137, 1) !important;
617
- font-weight: 500;
618
- }
619
- .etoc-eztoc-cnt .buy:hover{
620
- box-shadow: 0px 2px 2px #999;
621
- background: linear-gradient(to left, #fdfc35, #ffe258) !important;
622
- }
623
- .pvf {
624
- position: relative;
625
- top: -16px;
626
- border: 1px solid #eee;
627
- padding-bottom: 40px
628
- }
629
-
630
- .ext {
631
- display: grid;
632
- grid-template-columns: 1fr 1fr 1fr;
633
- background: #f9f9f9;
634
- padding: 45px 0 45px 25px
635
- }
636
-
637
- .ex-1 {
638
- width: 80%;
639
- }
640
-
641
- .ex-1 h4 {
642
- margin: 15px 0 12px 0;
643
- font-weight: 600;
644
- font-size: 20px;
645
- color: rgba(234, 76, 137, 1);
646
- }
647
-
648
- .ex-1 p {
649
- font-size: 14px;
650
- font-weight: 400;
651
- margin: 0;
652
- color: #000;
653
- }
654
-
655
- .e-1 img {
656
- width: 65px!important
657
- }
658
-
659
- .e-2 img {
660
- width: 45px!important
661
- }
662
-
663
- .e-3 img {
664
- width: 49px!important
665
- }
666
-
667
- .pvf-cnt {
668
- width: 100%;
669
- display: inline-block
670
- }
671
-
672
- .pvf-tlt {
673
- text-align: center;
674
- width: 100%;
675
- margin: 70px 0 60px 0
676
- }
677
-
678
- .pvf-tlt h2 {
679
- font-size: 36px;
680
- line-height: 1.4;
681
- color: #000;
682
- font-weight: 500;
683
- margin: 0
684
- }
685
-
686
- .pvf-tlt span {
687
- font-size: 16px;
688
- color: #000;
689
- margin-top: 15px;
690
- display: inline-block;
691
- position: relative;
692
- top: 4px
693
- }
694
-
695
- .pvf-cmp {
696
- display: grid;
697
- grid-template-columns: 1fr 2fr
698
- }
699
-
700
- .fr {
701
- border-right: 1px solid #eee
702
- }
703
-
704
- .fr h1,
705
- .pr h1 {
706
- font-size: 36px;
707
- font-weight: 700;
708
- line-height: 1.5;
709
- border-bottom: 1px solid #efefef;
710
- padding: 0 0 20px 35px;
711
- }
712
-
713
- .pr h1 {
714
- padding-left: 50px;
715
- color: rgba(234, 76, 137, 1);
716
- }
717
-
718
- .fr-fe {
719
- color: #222;
720
- padding-top: 10px
721
- }
722
-
723
- .fe-1 {
724
- padding: 22px 35px 35px 35px
725
- }
726
-
727
- .fe-1 h4 {
728
- margin: 0 0 10px 0;
729
- font-size: 20px;
730
- line-height: 1.4;
731
- font-weight: 400;
732
- color: #000
733
- }
734
-
735
- .fe-1 p {
736
- font-size: 15px;
737
- line-height: 1.4;
738
- margin: 0;
739
- color: #333
740
- }
741
-
742
- .pr-fe {
743
- padding: 34px 35px 35px 35px
744
- }
745
-
746
- .pr-fe span {
747
- font-family: georgia;
748
- font-size: 16px;
749
- font-weight: 700;
750
- color: #000;
751
- font-style: italic;
752
- line-height: 1.3
753
- }
754
-
755
- .fet {
756
- width: 100%;
757
- display: grid;
758
- grid-template-columns: 1fr 1fr;
759
- grid-gap: 25px;
760
- margin-top: 40px
761
- }
762
-
763
- .fe-2 {
764
- color: #222
765
- }
766
-
767
- .fe-t img {
768
- width: 22px!important;
769
- display: inline-block;
770
- vertical-align: middle
771
- }
772
-
773
- .fe-t h4 {
774
- margin: 0;
775
- display: inline-block;
776
- vertical-align: middle;
777
- font-size: 19px;
778
- color: #000;
779
- font-weight: 400;
780
- line-height: 1.4;
781
- padding-left: 8px;
782
- margin-top: -5px;
783
- }
784
-
785
- .fe-2 p {
786
- font-size: 15px;
787
- line-height: 1.4;
788
- margin: 0;
789
- color: #555;
790
- padding-top: 8px
791
- }
792
-
793
- .pr-btn {
794
- width: 100%;
795
- display: inline-block;
796
- text-align: center;
797
- margin: 50px 0 25px 0
798
- }
799
-
800
- .pr-btn a {
801
- text-decoration: none;
802
- color: #fff;
803
- padding: 12px 35px 17px 35px;
804
- display: inline-block;
805
- border-radius: 5px;
806
- font-size: 28px;
807
- font-weight: 500;
808
- line-height: 1.2;
809
- background: -webkit-linear-gradient(to right, #e35796, #fc789f);
810
- font-weight: 600;
811
- background: linear-gradient(to right, #e35796, rgba(234, 76, 137, 1));
812
- margin-top: 0;
813
- box-shadow: 0 .15em .65em 0 rgba(0, 0, 0, .25);
814
- }
815
-
816
- .amp-upg {
817
- background: #f5f5f5;
818
- padding: 60px 10px 0 10px
819
- }
820
-
821
- .upg-t {
822
- text-align: center;
823
- color: #222
824
- }
825
-
826
- .upg-t h2 {
827
- margin: 0;
828
- font-size: 35px;
829
- color: #060606;
830
- line-height: 1.3;
831
- font-weight: 500
832
- }
833
-
834
- .upg-t>span {
835
- font-size: 14px;
836
- line-height: 1.2;
837
- margin-top: 15px;
838
- display: inline-block;
839
- color: #666
840
- }
841
-
842
- .etoc-pri-lst {
843
- width: 100%;
844
- display: grid;
845
- grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
846
- margin-top: 70px;
847
- grid-gap: 1px;
848
- box-shadow: 0 10px 15px 1px #ddd
849
- }
850
-
851
- .pri-tb {
852
- background: #fff;
853
- text-align: center;
854
- border: 1px solid #f9f9f9;
855
- position: relative
856
- }
857
-
858
- .pri-tb:hover {
859
- border: 1px solid #e04371;
860
- }
861
-
862
- .pri-tb a:hover .pri-by {
863
- background: #e04371;
864
- }
865
- .pri-tb a:hover .amt {
866
- color: #7241a7;
867
- }
868
-
869
- .pri-tb a {
870
- display: inline-block;
871
- text-decoration: none;
872
- color: #222;
873
- padding: 20px 12px;
874
- }
875
-
876
- .pri-tb h5 {
877
- margin: 0 0 20px 0;
878
- font-size: 13px;
879
- line-height: 1.2;
880
- letter-spacing: 2px;
881
- font-weight: 400;
882
- color: #000
883
- }
884
-
885
- .pri-tb span {
886
- display: inline-block
887
- }
888
-
889
- .pri-tb .amt {
890
- font-size: 40px;
891
- color: #e04371;
892
- font-weight: 500;
893
- margin-bottom: 20px;
894
- display: block;
895
- }
896
-
897
- .pri-tb .d-amt {
898
- font-size: 24px;
899
- color: #666;
900
- font-weight: 500;
901
- margin-bottom: 15px;
902
- display: none;
903
- text-decoration: line-through
904
- }
905
-
906
- .d-amt sup {
907
- line-height: 0;
908
- position: relative;
909
- top: 7px
910
- }
911
-
912
- .pri-tb .s-amt {
913
- font-size: 13px;
914
- color: #4caf50;
915
- font-weight: 500;
916
- margin-bottom: 10px;
917
- display: none
918
- }
919
-
920
- .pri-tb .amt sup {
921
- font-size: 22px;
922
- padding: 0 4px 0 0;
923
- position: relative;
924
- top: 7px
925
- }
926
-
927
- .pri-tb .bil {
928
- color: #aaa;
929
- font-size: 12px;
930
- margin-bottom: 20px
931
- }
932
-
933
- .pri-tb .e,
934
- .pri-tb .f,
935
- .pri-tb .s {
936
- font-size: 14px;
937
- margin-bottom: 15px;
938
- color: #3b4750;
939
- display: block;
940
- }
941
-
942
- .pri-tb .etoc-sv {
943
- display: none;
944
- font-size: 12px;
945
- color: #fff;
946
- background: #4caf50;
947
- margin: 0 auto;
948
- padding: 1px 7px 2px 7px;
949
- border-radius: 45px
950
- }
951
-
952
- .pri-by {
953
- font-size: 15px;
954
- line-height: 1.2;
955
- background: #333;
956
- border-radius: 2px;
957
- padding: 9px 18px 10px 18px;
958
- display: inline-block;
959
- color: #fff;
960
- margin-top: 29px;
961
- font-weight: 500
962
- }
963
-
964
- .etoc-pri-lst .rec {
965
- box-shadow: 0 1px 40px 0 #ccc;
966
- background: #fff;
967
- z-index: 9;
968
- margin-top: -20px;
969
- position: relative
970
- }
971
-
972
- .etoc-pri-lst .rec:hover .etoc-rcm {
973
- background: #000;
974
- color: #fff;
975
- }
976
-
977
- .etoc-pri-lst .rec .pri-by {
978
- background: #e04371;
979
- }
980
-
981
- .etoc-rcm {
982
- background: linear-gradient(to right, #e35796, #fc789f);
983
- color: #fff;
984
- position: absolute;
985
- top: -20px;
986
- left: 0;
987
- right: -1px;
988
- bottom: auto;
989
- padding: 2px 0;
990
- font-size: 11px;
991
- letter-spacing: 2px
992
- }
993
-
994
- .tru-us {
995
- text-align: center;
996
- padding: 60px 0;
997
- margin: 0 auto;
998
- font-size: 16px;
999
- color: #222
1000
- }
1001
-
1002
- .tru-us h2 {
1003
- margin: 20px 0 0 0;
1004
- font-size: 28px;
1005
- font-weight: 500
1006
- }
1007
-
1008
- .tru-us p {
1009
- font-size: 17px;
1010
- margin: 19px 15% 18px 15%;
1011
- color: #666;
1012
- line-height: 29px
1013
- }
1014
-
1015
- .tru-us a {
1016
- font-size: 18px;
1017
- color: #489bff;
1018
- text-decoration: none;
1019
- font-weight: 400
1020
- }
1021
-
1022
- .ampfaq {
1023
- width: 100%;
1024
- margin: 25px 0
1025
- }
1026
-
1027
- .ampfaq h4 {
1028
- margin: 0;
1029
- text-align: center;
1030
- font-size: 20px;
1031
- font-weight: 500;
1032
- color: #333
1033
- }
1034
-
1035
- .faq-lst {
1036
- margin-top: 50px;
1037
- display: grid;
1038
- grid-template-columns: 1fr 1fr
1039
- }
1040
-
1041
- .lt {
1042
- padding-left: 50px
1043
- }
1044
-
1045
- .lt,
1046
- .rt {
1047
- width: 70%
1048
- }
1049
-
1050
- .lt ul,
1051
- .rt ul {
1052
- margin: 0
1053
- }
1054
-
1055
- .lt ul li,
1056
- .rt ul li {
1057
- color: #222;
1058
- margin-bottom: 30px!important
1059
- }
1060
-
1061
- .lt span,
1062
- .rt span {
1063
- font-size: 17px;
1064
- font-weight: 500;
1065
- margin-bottom: 6px;
1066
- display: inline-block
1067
- }
1068
-
1069
- .lt p,
1070
- .rt p {
1071
- font-size: 15px;
1072
- margin: 0
1073
- }
1074
-
1075
- .f-cnt {
1076
- text-align: center;
1077
- margin-top: 20px;
1078
- color: #222
1079
- }
1080
-
1081
- .f-cnt span {
1082
- font-size: 17px;
1083
- margin: 8px 0;
1084
- font-weight: 500
1085
- }
1086
-
1087
- .f-cnt p {
1088
- font-size: 15px;
1089
- margin: 6px 0
1090
- }
1091
-
1092
- .f-cnt a {
1093
- background: #333;
1094
- color: #fff;
1095
- padding: 15px 30px;
1096
- text-decoration: none;
1097
- font-size: 18px;
1098
- font-weight: 500;
1099
- display: inline-block;
1100
- margin-top: 15px
1101
- }
1102
-
1103
- @media(max-width:1366px) {
1104
- .amp-upg {
1105
- padding: 60px 0 0 0
1106
- }
1107
- .etoc-eztoc-cnt p {
1108
-
1109
- line-height: 35px;
1110
- font-size: 18px;
1111
-
1112
- }
1113
- }
1114
-
1115
- @media(max-width:1280px) {
1116
- .etoc-eztoc-cnt {
1117
- top: 1.3%
1118
- }
1119
- }
1120
-
1121
- @media(max-width:768px) {
1122
- .ext {
1123
- grid-template-columns: 1fr;
1124
- grid-gap: 30px 0;
1125
- padding: 30px
1126
- }
1127
- .pvf-tlt h2 {
1128
- font-size: 26px
1129
- }
1130
- .pvf-cmp {
1131
- grid-template-columns: 1fr
1132
- }
1133
- .pr-btn a {
1134
- font-size: 22px
1135
- }
1136
- .etoc-pri-lst {
1137
- grid-template-columns: 1fr 1fr 1fr
1138
- }
1139
- .etoc-eztoc-cnt p {
1140
- line-height: 1.5;
1141
- font-size: 16px;
1142
- margin-top: 15px;
1143
- padding: 0 20px
1144
- }
1145
- .etoc-eztoc-cnt .buy {
1146
- font-size: 16px;
1147
- padding: 8px 30px
1148
- }
1149
- .etoc-eztoc-cnt {
1150
- top: 15px
1151
- }
1152
- .etoc-eztoc-cnt h1 {
1153
- font-size: 30px
1154
- }
1155
- .ex-1 {
1156
- width: 100%
1157
- }
1158
- .faq-lst {
1159
- grid-template-columns: 1fr
1160
- }
1161
- .rt {
1162
- padding-left: 50px
1163
- }
1164
- }
1165
- div#freevspro {
1166
- padding: 0;
1167
- }
1168
-
1169
- .ampfaq h2 {
1170
- margin: 40px 0 0 0;
1171
- font-size: 30px;
1172
- font-weight: 500;
1173
- text-align: center;
1174
- }
1175
- a#eztoc-upgrade {
1176
- color: #ffffff;
1177
- background: rgba(234, 76, 137, 1);
1178
- padding: 16px;
1179
- }
1180
- div#welcome {
1181
- text-align: center;
1182
- }
1183
- a#eztoc-welcome {
1184
- display: none;
1185
- }
1186
- .button-toc{
1187
- text-align: center;
1188
- cursor: pointer;
1189
- font-size: 16px;
1190
- margin: 20px;
1191
- color: #fff;
1192
- border-radius: 4px;
1193
- background-color: #ec407a;
1194
- border: none;
1195
- padding: 20px;
1196
- transition: all 0.5s;
1197
- font-weight: 600;
1198
- }
1199
- .button-toc span {
1200
- cursor: pointer;
1201
- display: inline-block;
1202
- position: relative;
1203
- transition: 0.5s;
1204
- }
1205
-
1206
- .button-toc span:after {
1207
- content: '»';
1208
- position: absolute;
1209
- opacity: 0;
1210
- top: 0;
1211
- right: -20px;
1212
- transition: 0.5s;
1213
- }
1214
-
1215
- .button-toc:hover span {
1216
- padding-right: 25px;
1217
- }
1218
-
1219
- .button-toc:hover span:after {
1220
- opacity: 1;
1221
- right: 0;
1222
- }
1223
-
1224
- .eztoc-query-success{
1225
- color: green;
1226
- }
1227
- .eztoc-query-error{
1228
- color: red;
1229
- }
1230
- .eztoc_hide{
1231
- display: none;
1232
- }
1233
- .eztoc-result{
1234
- margin-left: 70px;
1235
  }
1
+ div.tab_content table {
2
+ margin-bottom: 1em;
3
+ }
4
+ table.more_toc_options_table th, table.more_toc_options_table td {
5
+ padding: 0;
6
+ margin: 0;
7
+ }
8
+ table.more_toc_options_table th {
9
+ width: auto;
10
+ padding-right: 4px;
11
+ padding-top: 2px;
12
+ }
13
+ div.tab_content ul li {
14
+ margin-left: 2em;
15
+ list-style-type: disc;
16
+ }
17
+ div.tab_content ol li {
18
+ list-style: inherit;
19
+ }
20
+ div.tab_content pre {
21
+ margin-left: 2em;
22
+ }
23
+ ul#tabbed-nav {
24
+ margin-top: 1em;
25
+ }
26
+ #tabbed-nav {
27
+ margin: 0;
28
+ padding: 0;
29
+ float: left;
30
+ list-style: none;
31
+ height: 32px;
32
+ border-bottom: 1px solid #DFDFDF;
33
+ border-left: 1px solid #DFDFDF;
34
+ width: 100%;
35
+ }
36
+ #tabbed-nav li {
37
+ float: left;
38
+ margin: 0;
39
+ padding: 0;
40
+ height: 31px;
41
+ line-height: 31px;
42
+ border: 1px solid #DFDFDF;
43
+ border-left: none;
44
+ margin-bottom: -1px;
45
+ overflow: hidden;
46
+ position: relative;
47
+ background: #F5F5F5;
48
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#F5F5F5));
49
+ background-image: -webkit-linear-gradient(center top, #fff, #F5F5F5);
50
+ background-image: -moz-linear-gradient(center top, #fff, #F5F5F5);
51
+ background-image: -ms-linear-gradient(center top, #fff, #F5F5F5);
52
+ background-image: -o-linear-gradient(center top, #fff, #F5F5F5);
53
+ background-image: linear-gradient(center top, #fff, #F5F5F5);
54
+ }
55
+ #tabbed-nav li a {
56
+ text-decoration: none;
57
+ color: #000;
58
+ display: block;
59
+ font-size: 1.2em;
60
+ padding: 0 20px;
61
+ border: 1px solid #fff;
62
+ outline: none;
63
+ }
64
+ #tabbed-nav li a:hover {
65
+ background: #ECECEC;
66
+ }
67
+ html #tabbed-nav li.active, html #tabbed-nav li.active a:hover {
68
+ background: #fff;
69
+ border-bottom: 1px solid #fff;
70
+ }
71
+ div.tab_container {
72
+ border: 1px solid #DFDFDF;
73
+ border-top: none;
74
+ overflow: hidden;
75
+ clear: both;
76
+ float: left; width: 100%;
77
+ background: #fff;
78
+ margin-bottom: 2em;
79
+ padding-bottom: 2em;
80
+ }
81
+ div.tab_content {
82
+ padding: 10px;
83
+ padding-bottom: 0;
84
+ font-size: 1em;
85
+ }
86
+ h3 span.show_hide {
87
+ font-size: 0.85em;
88
+ font-weight: normal;
89
+ }
90
+ div.more_toc_options {
91
+ margin-top: 4px;
92
+ margin-left: 2em;
93
+ }
94
+ div.toc_theme_option {
95
+ width: 200px;
96
+ float: left;
97
+ margin-right: 5px;
98
+ }
99
+ #wpcontent select optgroup option {
100
+ padding-left: 15px;
101
+ }
102
+ input#width_custom,
103
+ input#font_size,
104
+ input#child_font_size,
105
+ input#smooth_scroll_offset {
106
+ width: 50px;
107
+ text-align: center;
108
+ }
109
+ input.custom_colour_option {
110
+ width: 75px;
111
+ }
112
+ table#theme_custom, div#farbtastic_colour_wheel {
113
+ float: left;
114
+ }
115
+ table#theme_custom {
116
+ margin-top: 30px;
117
+ }
118
+ table#theme_custom img {
119
+ vertical-align: middle;
120
+ opacity: 0.4;
121
+ }
122
+ table#theme_custom img:hover {
123
+ cursor: pointer;
124
+ opacity: 1;
125
+ }
126
+ div#farbtastic_colour_wheel {
127
+ margin-left: 20px;
128
+ }
129
+ #tab3 h3:not(:first-child) {
130
+ margin-top: 2em;
131
+ }
132
+
133
+ /* My styles */
134
+ #toc input.small-text {
135
+ width: 50px;
136
+ padding: 2px;
137
+ height: 28px;
138
+ line-height: 28px;
139
+ vertical-align: bottom;
140
+ }
141
+
142
+ #toc .form-table tr > th > strong {
143
+ font-size: 18px;
144
+ font-style: italic;
145
+ }
146
+ /* Tab panel styles */
147
+ .postbox{
148
+ padding: 10px;
149
+ }
150
+ html {
151
+ scroll-behavior: smooth;
152
+ }
153
+ .toc-tab-panel {
154
+ overflow: hidden;
155
+ border: 1px solid #ccc;
156
+ background-color: #fff;
157
+ margin-top: 15px;}
158
+ .toc-tab-panel a {
159
+ background-color: inherit;
160
+ text-decoration: none;
161
+ float: left;
162
+ border: none;
163
+ outline: none;
164
+ cursor: pointer;
165
+ padding: 14px 16px;
166
+ transition: 0s;
167
+ font-size: 15px;
168
+ color: #2271b1;
169
+ font-weight: 500;
170
+ }
171
+ .toc-tab-panel a:hover {
172
+ color: #0a4b78;
173
+ }
174
+ .toc-tab-panel a.active {
175
+ box-shadow: none;
176
+ border-bottom: 4px solid #646970;
177
+ color: #1d2327;
178
+ }
179
+ .toc-tab-panel a:focus {
180
+ box-shadow: none;
181
+ outline: none;
182
+ }
183
+ .eztoc-tabcontent {
184
+ display: none;
185
+ border-top: none;
186
+ animation: fadeEffect 1s;
187
+ }
188
+ #technical .eztoc-form-page-ui{
189
+ display:flex;
190
+ background: #fff;
191
+ width: auto;
192
+ height: auto;
193
+ }
194
+ #technical .eztoc-left-side{
195
+ width: 70%;
196
+
197
+ }
198
+ .eztoc-right-side{
199
+ width: 31%;
200
+ margin-top: auto;
201
+ margin-bottom: auto;
202
+ text-align: center;
203
+
204
+ }
205
+ .eztoc-tabcontent {
206
+ display: none;
207
+ border-top: none;
208
+ }
209
+ #technical {
210
+ background: #fff;
211
+ margin-top: 10px;
212
+ padding: 28px;
213
+ padding: 15px 28px 28px 28px;
214
+ min-width: 255px;
215
+ box-shadow: 0 1px 1px rgb(0 0 0 / 4%);
216
+ }
217
+ /* #technical p{
218
+ line-height: 0.5rem;
219
+ } */
220
+ #technical-form{
221
+
222
+ width: 60%;
223
+ }
224
+ .support-label {
225
+ margin-top: 4px;
226
+ float: left;
227
+ width: 70px;
228
+
229
+ font-size: 14px;
230
+ }
231
+
232
+ .star-mark{
233
+ color: red;
234
+ margin-left: 4px;
235
+ font-family: bold;
236
+ }
237
+ #technical li {
238
+ margin:25px 0px 20px 0px;
239
+ margin:10px 0px 10px 0px;
240
+ list-style: none;
241
+ }
242
+ .eztoc_support_div_form{
243
+ margin-top: 23px;
244
+ }
245
+ .eztoc-customer-type{
246
+ display: block;
247
+ }
248
+ .support-input select{
249
+ border-radius: 4px;
250
+ margin-top: -7px;
251
+ }
252
+ .eztoc_dev-bio{
253
+ display: block;
254
+ }
255
+ .ezoc-bio-wrap{
256
+ float: left;
257
+ text-align: center;
258
+ width: 33.33%;
259
+ text-transform: uppercase;
260
+ }
261
+ .ezoc-bio-wrap p{
262
+ width: auto;
263
+ font-size: 10px;
264
+ color: #555;
265
+ margin: 0px 0 20px 0;
266
+ }
267
+ .ezoc-bio-wrap img{
268
+ margin: 25px 0 0 0;
269
+ border-radius: 50%;
270
+ }
271
+ .eztoc-bio-box{
272
+ background: #fff;
273
+ border: 1px solid #ccc;
274
+ padding: 15px 20px;
275
+ border-radius: 4px;
276
+ margin: 15px 15px 15px 0;
277
+ /* height: 22rem; */
278
+ padding: 0px 20px;
279
+ }
280
+ .eztoc-bio-box:hover{
281
+ box-shadow: 5px 5px 8px #888888;
282
+ }
283
+ .eztoc-p{
284
+ font-size: 15px;
285
+ margin: 20px auto 0px auto;
286
+ text-align: center;
287
+ }
288
+ .eztoc-p{
289
+ line-height: 1.5rem;
290
+ padding: 0 25px;
291
+ margin-top: 10px;
292
+ font-size: 16px;
293
+ }
294
+ .eztoc-bio-box h1{
295
+ margin: 8px auto 0px auto;
296
+ text-align: center;
297
+ font-weight: bolder;
298
+ }
299
+ .eztoc_boxdesk{
300
+ clear: left;
301
+ font-size: 15px;
302
+ text-align: center;
303
+ margin: 20px 0 0 0;
304
+
305
+ }
306
+ .company-link{
307
+ font-weight: 500;
308
+ margin: 20px 0 0 0;
309
+ }
310
+ .company-link a{
311
+
312
+ display: table;
313
+ background: #e91e63;
314
+ width: auto;
315
+ margin: 0 auto;
316
+ padding: 7px 25px;
317
+ color: #fff;
318
+ text-decoration: none;
319
+ margin-top: 10px;
320
+ margin-bottom: 15px;
321
+ border-radius: 6px;
322
+ border: 0;
323
+ /* text-transform: uppercase; */
324
+ font-size: 16px;
325
+
326
+ }
327
+ .eztoc-send-query{
328
+ background: #2271b1;
329
+ border-color: #2271b1;
330
+ color:#fff;
331
+ text-decoration: none;
332
+ text-shadow: none;
333
+ margin-left: 70px !important;;
334
+ }
335
+
336
+ @media screen and (min-width: 870px) and (max-width: 1300px ){
337
+ .eztoc-bio-box{
338
+ padding-top: 20px;
339
+ height: 29.1rem;;
340
+ }
341
+ .eztoc-bio-box h1{
342
+ font-size: 20px;
343
+ }
344
+ .eztoc-bio-box p{
345
+ font-size: 13px;
346
+ margin: 20px auto 0px auto;
347
+ }
348
+ .ezoc-bio-wrap img{
349
+ width: 30px;
350
+ height: 30px;
351
+ }
352
+ .ezoc-bio-wrap p{
353
+ width: 55px;
354
+ font-size: 12px;
355
+ margin-bottom: 10px;
356
+ }
357
+
358
+ }
359
+ @keyframes fadeEffect { from {opacity: 0;} to {opacity: 1;} }
360
+
361
+
362
+ .eztoc-wrapper{
363
+ max-width: 100%;
364
+ width: 100%;
365
+ display: flex;
366
+ flex-wrap: wrap;
367
+ margin: auto;
368
+ }
369
+
370
+ .eztoc-wrapper .table{
371
+ margin: 0 auto;
372
+ background: #fff;
373
+ width: calc(30%);
374
+ padding: 30px 20px;
375
+ position: relative;
376
+ box-shadow: 0 5px 10px rgb(0 0 0 / 10%);
377
+ }
378
+
379
+ .table .price-section{
380
+ display: flex;
381
+ justify-content: center;
382
+ }
383
+
384
+ .price-section .price-area{
385
+ height: 120px;
386
+ width: 120px;
387
+ background: #ffd861;
388
+ border-radius: 50%;
389
+ padding: 2px;
390
+ }
391
+
392
+ .price-section .price-area .inner-area{
393
+ height: 100%;
394
+ width: 100%;
395
+ border-radius: 50%;
396
+ border: 3px solid #fff;
397
+ color: #fff;
398
+ line-height: 117px;
399
+ text-align: center;
400
+ position: relative;
401
+ }
402
+
403
+ .price-area .inner-area .text{
404
+ font-size: 25px;
405
+ font-weight: 400;
406
+ position: absolute;
407
+ top: -10px;
408
+ left: 17px;
409
+ }
410
+
411
+ .price-area .inner-area .price{
412
+ font-size: 55px;
413
+ font-weight: 500;
414
+ }
415
+
416
+ .table .package-name{
417
+ width: 100%;
418
+ height: 2px;
419
+ background: #ffecb3;
420
+ margin: 35px 0;
421
+ position: relative;
422
+ }
423
+
424
+ .table .package-name::before{
425
+ position: absolute;
426
+ content: "Basic";
427
+ top: 50%;
428
+ left: 50%;
429
+ transform: translate(-50%, -50%);
430
+ background: #fff;
431
+ font-size: 25px;
432
+ padding: 0 10px;
433
+ font-weight: bolder;
434
+ }
435
+
436
+ .table .features li{
437
+ list-style: none;
438
+ display: flex;
439
+ justify-content: space-between;
440
+ margin-bottom: 15px;
441
+ }
442
+
443
+ .features li .list-name{
444
+ font-size: 17px;
445
+ font-weight: 400;
446
+ }
447
+
448
+ .features li .icon{
449
+ font-size: 15px;
450
+ }
451
+
452
+ .features li .icon.check{
453
+ color: #2db94d;
454
+ }
455
+
456
+ .features li .icon.cross{
457
+ color: #cd3241;
458
+ }
459
+
460
+ .table .btn{
461
+ display: flex;
462
+ justify-content: center;
463
+ margin-top: 35px;
464
+ }
465
+
466
+ .table .btn button{
467
+ width: 80%;
468
+ height: 50px;
469
+ font-weight: 700;
470
+ color: #fff;
471
+ font-size: 20px;
472
+ border: none;
473
+ outline: none;
474
+ border-radius: 25px;
475
+ cursor: pointer;
476
+ transition: all 0.3s ease;
477
+ }
478
+
479
+ .basic .price-area,
480
+ .basic .inner-area{
481
+ background: #ffd861;
482
+ }
483
+
484
+ .basic .btn button{
485
+ background: #fff;
486
+ color: #ffd861;
487
+ border: 2px solid #ffd861;
488
+ }
489
+
490
+ .basic .btn button:hover{
491
+ border-radius: 6px;
492
+ background: #ffd861;
493
+ color: #fff;
494
+ }
495
+
496
+ .Premium .price-area,
497
+ .Premium .inner-area{
498
+ background: #a26bfa;
499
+ }
500
+
501
+ .Premium .btn button{
502
+ background: #fff;
503
+ color: #a26bfa;
504
+ border: 2px solid #a26bfa;
505
+ }
506
+
507
+ .Premium .btn button:hover{
508
+ border-radius: 6px;
509
+ background: #a26bfa;
510
+ color: #fff;
511
+ }
512
+
513
+
514
+ .basic .package-name{
515
+ background: #ffecb3;
516
+ }
517
+
518
+ .Premium .package-name{
519
+ background: #a26bfa;
520
+ }
521
+
522
+
523
+
524
+ .basic .package-name::before{
525
+ content: "Free";
526
+ }
527
+
528
+ .Premium .package-name::before{
529
+ content: "PRO";
530
+ }
531
+
532
+
533
+
534
+ .basic ::selection,
535
+ .basic .price-area,
536
+ .basic .inner-area{
537
+ background: #ffd861;
538
+ }
539
+
540
+ .Premium ::selection,
541
+ .Premium .price-area,
542
+ .Premium .inner-area{
543
+ background: #a26bfa;
544
+ }
545
+
546
+ div#eztoc-tabs a {
547
+ text-decoration: none;
548
+ }
549
+ div#eztoc-tabs a:first-child {
550
+ color: #000;
551
+ }
552
+
553
+ #the-list{position: relative;}
554
+ .eztoc-wr {
555
+ width: 100%;
556
+ margin: 0 auto;
557
+ position: relative
558
+ }
559
+
560
+ .etoc-eztoc-img {
561
+ width: 100%;
562
+ margin: 0 auto;
563
+ text-align: center;
564
+ position: relative;
565
+ line-height: 0;
566
+ height: 300px;
567
+ }
568
+
569
+ .eztoc-img img {
570
+ position: relative
571
+ }
572
+
573
+ .sp_ov {
574
+ background: rgba(234, 76, 137, 1);
575
+ bottom: 0;
576
+ left: 0;
577
+ position: absolute;
578
+ right: 0;
579
+ top: 0;
580
+ }
581
+
582
+ .etoc-eztoc-cnt {
583
+ position: absolute;
584
+ top: 40px;
585
+ bottom: 0;
586
+ left: 40px;
587
+ right: 40px;
588
+ margin: 0 auto;
589
+ text-align: center
590
+ }
591
+
592
+ .etoc-eztoc-cnt h1 {
593
+ font-size: 60px;
594
+ color: #fff;
595
+ font-weight: 600;
596
+ }
597
+
598
+ .etoc-eztoc-cnt p {
599
+ margin-top: 0px;
600
+ color: #371b24;
601
+ font-size: 18px;
602
+ padding: 0 100px;
603
+ line-height: 1.4;
604
+ font-weight: 500;
605
+ }
606
+
607
+ .etoc-eztoc-cnt .buy {
608
+ border-width: 0px !important;
609
+ font-size: 1.25rem;
610
+ line-height: 2;
611
+ text-decoration: none;
612
+ background: white !important;
613
+ border-radius: 8px !important;
614
+ font-size: 16px !important;
615
+ padding: 12px 18px;
616
+ color: rgba(234, 76, 137, 1) !important;
617
+ font-weight: 500;
618
+ }
619
+ .etoc-eztoc-cnt .buy:hover{
620
+ box-shadow: 0px 2px 2px #999;
621
+ background: linear-gradient(to left, #fdfc35, #ffe258) !important;
622
+ }
623
+ .pvf {
624
+ position: relative;
625
+ top: -16px;
626
+ border: 1px solid #eee;
627
+ padding-bottom: 40px
628
+ }
629
+
630
+ .ext {
631
+ display: grid;
632
+ grid-template-columns: 1fr 1fr 1fr;
633
+ background: #f9f9f9;
634
+ padding: 45px 0 45px 25px
635
+ }
636
+
637
+ .ex-1 {
638
+ width: 80%;
639
+ }
640
+
641
+ .ex-1 h4 {
642
+ margin: 15px 0 12px 0;
643
+ font-weight: 600;
644
+ font-size: 20px;
645
+ color: rgba(234, 76, 137, 1);
646
+ }
647
+
648
+ .ex-1 p {
649
+ font-size: 14px;
650
+ font-weight: 400;
651
+ margin: 0;
652
+ color: #000;
653
+ }
654
+
655
+ .e-1 img {
656
+ width: 65px!important
657
+ }
658
+
659
+ .e-2 img {
660
+ width: 45px!important
661
+ }
662
+
663
+ .e-3 img {
664
+ width: 49px!important
665
+ }
666
+
667
+ .pvf-cnt {
668
+ width: 100%;
669
+ display: inline-block
670
+ }
671
+
672
+ .pvf-tlt {
673
+ text-align: center;
674
+ width: 100%;
675
+ margin: 70px 0 60px 0
676
+ }
677
+
678
+ .pvf-tlt h2 {
679
+ font-size: 36px;
680
+ line-height: 1.4;
681
+ color: #000;
682
+ font-weight: 500;
683
+ margin: 0
684
+ }
685
+
686
+ .pvf-tlt span {
687
+ font-size: 16px;
688
+ color: #000;
689
+ margin-top: 15px;
690
+ display: inline-block;
691
+ position: relative;
692
+ top: 4px
693
+ }
694
+
695
+ .pvf-cmp {
696
+ display: grid;
697
+ grid-template-columns: 1fr 2fr
698
+ }
699
+
700
+ .fr {
701
+ border-right: 1px solid #eee
702
+ }
703
+
704
+ .fr h1,
705
+ .pr h1 {
706
+ font-size: 36px;
707
+ font-weight: 700;
708
+ line-height: 1.5;
709
+ border-bottom: 1px solid #efefef;
710
+ padding: 0 0 20px 35px;
711
+ }
712
+
713
+ .pr h1 {
714
+ padding-left: 50px;
715
+ color: rgba(234, 76, 137, 1);
716
+ }
717
+
718
+ .fr-fe {
719
+ color: #222;
720
+ padding-top: 10px
721
+ }
722
+
723
+ .fe-1 {
724
+ padding: 22px 35px 35px 35px
725
+ }
726
+
727
+ .fe-1 h4 {
728
+ margin: 0 0 10px 0;
729
+ font-size: 20px;
730
+ line-height: 1.4;
731
+ font-weight: 400;
732
+ color: #000
733
+ }
734
+
735
+ .fe-1 p {
736
+ font-size: 15px;
737
+ line-height: 1.4;
738
+ margin: 0;
739
+ color: #333
740
+ }
741
+
742
+ .pr-fe {
743
+ padding: 34px 35px 35px 35px
744
+ }
745
+
746
+ .pr-fe span {
747
+ font-family: georgia;
748
+ font-size: 16px;
749
+ font-weight: 700;
750
+ color: #000;
751
+ font-style: italic;
752
+ line-height: 1.3
753
+ }
754
+
755
+ .fet {
756
+ width: 100%;
757
+ display: grid;
758
+ grid-template-columns: 1fr 1fr;
759
+ grid-gap: 25px;
760
+ margin-top: 40px
761
+ }
762
+
763
+ .fe-2 {
764
+ color: #222
765
+ }
766
+
767
+ .fe-t img {
768
+ width: 22px!important;
769
+ display: inline-block;
770
+ vertical-align: middle
771
+ }
772
+
773
+ .fe-t h4 {
774
+ margin: 0;
775
+ display: inline-block;
776
+ vertical-align: middle;
777
+ font-size: 19px;
778
+ color: #000;
779
+ font-weight: 400;
780
+ line-height: 1.4;
781
+ padding-left: 8px;
782
+ margin-top: -5px;
783
+ }
784
+
785
+ .fe-2 p {
786
+ font-size: 15px;
787
+ line-height: 1.4;
788
+ margin: 0;
789
+ color: #555;
790
+ padding-top: 8px
791
+ }
792
+
793
+ .pr-btn {
794
+ width: 100%;
795
+ display: inline-block;
796
+ text-align: center;
797
+ margin: 50px 0 25px 0
798
+ }
799
+
800
+ .pr-btn a {
801
+ text-decoration: none;
802
+ color: #fff;
803
+ padding: 12px 35px 17px 35px;
804
+ display: inline-block;
805
+ border-radius: 5px;
806
+ font-size: 28px;
807
+ font-weight: 500;
808
+ line-height: 1.2;
809
+ background: -webkit-linear-gradient(to right, #e35796, #fc789f);
810
+ font-weight: 600;
811
+ background: linear-gradient(to right, #e35796, rgba(234, 76, 137, 1));
812
+ margin-top: 0;
813
+ box-shadow: 0 .15em .65em 0 rgba(0, 0, 0, .25);
814
+ }
815
+
816
+ .amp-upg {
817
+ background: #f5f5f5;
818
+ padding: 60px 10px 0 10px
819
+ }
820
+
821
+ .upg-t {
822
+ text-align: center;
823
+ color: #222
824
+ }
825
+
826
+ .upg-t h2 {
827
+ margin: 0;
828
+ font-size: 35px;
829
+ color: #060606;
830
+ line-height: 1.3;
831
+ font-weight: 500
832
+ }
833
+
834
+ .upg-t>span {
835
+ font-size: 14px;
836
+ line-height: 1.2;
837
+ margin-top: 15px;
838
+ display: inline-block;
839
+ color: #666
840
+ }
841
+
842
+ .etoc-pri-lst {
843
+ width: 100%;
844
+ display: grid;
845
+ grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
846
+ margin-top: 70px;
847
+ grid-gap: 1px;
848
+ box-shadow: 0 10px 15px 1px #ddd
849
+ }
850
+
851
+ .pri-tb {
852
+ background: #fff;
853
+ text-align: center;
854
+ border: 1px solid #f9f9f9;
855
+ position: relative
856
+ }
857
+
858
+ .pri-tb:hover {
859
+ border: 1px solid #e04371;
860
+ }
861
+
862
+ .pri-tb a:hover .pri-by {
863
+ background: #e04371;
864
+ }
865
+ .pri-tb a:hover .amt {
866
+ color: #7241a7;
867
+ }
868
+
869
+ .pri-tb a {
870
+ display: inline-block;
871
+ text-decoration: none;
872
+ color: #222;
873
+ padding: 20px 12px;
874
+ }
875
+
876
+ .pri-tb h5 {
877
+ margin: 0 0 20px 0;
878
+ font-size: 13px;
879
+ line-height: 1.2;
880
+ letter-spacing: 2px;
881
+ font-weight: 400;
882
+ color: #000
883
+ }
884
+
885
+ .pri-tb span {
886
+ display: inline-block
887
+ }
888
+
889
+ .pri-tb .amt {
890
+ font-size: 40px;
891
+ color: #e04371;
892
+ font-weight: 500;
893
+ margin-bottom: 20px;
894
+ display: block;
895
+ }
896
+
897
+ .pri-tb .d-amt {
898
+ font-size: 24px;
899
+ color: #666;
900
+ font-weight: 500;
901
+ margin-bottom: 15px;
902
+ display: none;
903
+ text-decoration: line-through
904
+ }
905
+
906
+ .d-amt sup {
907
+ line-height: 0;
908
+ position: relative;
909
+ top: 7px
910
+ }
911
+
912
+ .pri-tb .s-amt {
913
+ font-size: 13px;
914
+ color: #4caf50;
915
+ font-weight: 500;
916
+ margin-bottom: 10px;
917
+ display: none
918
+ }
919
+
920
+ .pri-tb .amt sup {
921
+ font-size: 22px;
922
+ padding: 0 4px 0 0;
923
+ position: relative;
924
+ top: 7px
925
+ }
926
+
927
+ .pri-tb .bil {
928
+ color: #aaa;
929
+ font-size: 12px;
930
+ margin-bottom: 20px
931
+ }
932
+
933
+ .pri-tb .e,
934
+ .pri-tb .f,
935
+ .pri-tb .s {
936
+ font-size: 14px;
937
+ margin-bottom: 15px;
938
+ color: #3b4750;
939
+ display: block;
940
+ }
941
+
942
+ .pri-tb .etoc-sv {
943
+ display: none;
944
+ font-size: 12px;
945
+ color: #fff;
946
+ background: #4caf50;
947
+ margin: 0 auto;
948
+ padding: 1px 7px 2px 7px;
949
+ border-radius: 45px
950
+ }
951
+
952
+ .pri-by {
953
+ font-size: 15px;
954
+ line-height: 1.2;
955
+ background: #333;
956
+ border-radius: 2px;
957
+ padding: 9px 18px 10px 18px;
958
+ display: inline-block;
959
+ color: #fff;
960
+ margin-top: 29px;
961
+ font-weight: 500
962
+ }
963
+
964
+ .etoc-pri-lst .rec {
965
+ box-shadow: 0 1px 40px 0 #ccc;
966
+ background: #fff;
967
+ z-index: 9;
968
+ margin-top: -20px;
969
+ position: relative
970
+ }
971
+
972
+ .etoc-pri-lst .rec:hover .etoc-rcm {
973
+ background: #000;
974
+ color: #fff;
975
+ }
976
+
977
+ .etoc-pri-lst .rec .pri-by {
978
+ background: #e04371;
979
+ }
980
+
981
+ .etoc-rcm {
982
+ background: linear-gradient(to right, #e35796, #fc789f);
983
+ color: #fff;
984
+ position: absolute;
985
+ top: -20px;
986
+ left: 0;
987
+ right: -1px;
988
+ bottom: auto;
989
+ padding: 2px 0;
990
+ font-size: 11px;
991
+ letter-spacing: 2px
992
+ }
993
+
994
+ .tru-us {
995
+ text-align: center;
996
+ padding: 60px 0;
997
+ margin: 0 auto;
998
+ font-size: 16px;
999
+ color: #222
1000
+ }
1001
+
1002
+ .tru-us h2 {
1003
+ margin: 20px 0 0 0;
1004
+ font-size: 28px;
1005
+ font-weight: 500
1006
+ }
1007
+
1008
+ .tru-us p {
1009
+ font-size: 17px;
1010
+ margin: 19px 15% 18px 15%;
1011
+ color: #666;
1012
+ line-height: 29px
1013
+ }
1014
+
1015
+ .tru-us a {
1016
+ font-size: 18px;
1017
+ color: #489bff;
1018
+ text-decoration: none;
1019
+ font-weight: 400
1020
+ }
1021
+
1022
+ .ampfaq {
1023
+ width: 100%;
1024
+ margin: 25px 0
1025
+ }
1026
+
1027
+ .ampfaq h4 {
1028
+ margin: 0;
1029
+ text-align: center;
1030
+ font-size: 20px;
1031
+ font-weight: 500;
1032
+ color: #333
1033
+ }
1034
+
1035
+ .faq-lst {
1036
+ margin-top: 50px;
1037
+ display: grid;
1038
+ grid-template-columns: 1fr 1fr
1039
+ }
1040
+
1041
+ .lt {
1042
+ padding-left: 50px
1043
+ }
1044
+
1045
+ .lt,
1046
+ .rt {
1047
+ width: 70%
1048
+ }
1049
+
1050
+ .lt ul,
1051
+ .rt ul {
1052
+ margin: 0
1053
+ }
1054
+
1055
+ .lt ul li,
1056
+ .rt ul li {
1057
+ color: #222;
1058
+ margin-bottom: 30px!important
1059
+ }
1060
+
1061
+ .lt span,
1062
+ .rt span {
1063
+ font-size: 17px;
1064
+ font-weight: 500;
1065
+ margin-bottom: 6px;
1066
+ display: inline-block
1067
+ }
1068
+
1069
+ .lt p,
1070
+ .rt p {
1071
+ font-size: 15px;
1072
+ margin: 0
1073
+ }
1074
+
1075
+ .f-cnt {
1076
+ text-align: center;
1077
+ margin-top: 20px;
1078
+ color: #222
1079
+ }
1080
+
1081
+ .f-cnt span {
1082
+ font-size: 17px;
1083
+ margin: 8px 0;
1084
+ font-weight: 500
1085
+ }
1086
+
1087
+ .f-cnt p {
1088
+ font-size: 15px;
1089
+ margin: 6px 0
1090
+ }
1091
+
1092
+ .f-cnt a {
1093
+ background: #333;
1094
+ color: #fff;
1095
+ padding: 15px 30px;
1096
+ text-decoration: none;
1097
+ font-size: 18px;
1098
+ font-weight: 500;
1099
+ display: inline-block;
1100
+ margin-top: 15px
1101
+ }
1102
+
1103
+ @media(max-width:1366px) {
1104
+ .amp-upg {
1105
+ padding: 60px 0 0 0
1106
+ }
1107
+ .etoc-eztoc-cnt p {
1108
+
1109
+ line-height: 35px;
1110
+ font-size: 18px;
1111
+
1112
+ }
1113
+ }
1114
+
1115
+ @media(max-width:1280px) {
1116
+ .etoc-eztoc-cnt {
1117
+ top: 1.3%
1118
+ }
1119
+ }
1120
+
1121
+ @media(max-width:768px) {
1122
+ .ext {
1123
+ grid-template-columns: 1fr;
1124
+ grid-gap: 30px 0;
1125
+ padding: 30px
1126
+ }
1127
+ .pvf-tlt h2 {
1128
+ font-size: 26px
1129
+ }
1130
+ .pvf-cmp {
1131
+ grid-template-columns: 1fr
1132
+ }
1133
+ .pr-btn a {
1134
+ font-size: 22px
1135
+ }
1136
+ .etoc-pri-lst {
1137
+ grid-template-columns: 1fr 1fr 1fr
1138
+ }
1139
+ .etoc-eztoc-cnt p {
1140
+ line-height: 1.5;
1141
+ font-size: 16px;
1142
+ margin-top: 15px;
1143
+ padding: 0 20px
1144
+ }
1145
+ .etoc-eztoc-cnt .buy {
1146
+ font-size: 16px;
1147
+ padding: 8px 30px
1148
+ }
1149
+ .etoc-eztoc-cnt {
1150
+ top: 15px
1151
+ }
1152
+ .etoc-eztoc-cnt h1 {
1153
+ font-size: 30px
1154
+ }
1155
+ .ex-1 {
1156
+ width: 100%
1157
+ }
1158
+ .faq-lst {
1159
+ grid-template-columns: 1fr
1160
+ }
1161
+ .rt {
1162
+ padding-left: 50px
1163
+ }
1164
+ }
1165
+ div#freevspro {
1166
+ padding: 0;
1167
+ }
1168
+
1169
+ .ampfaq h2 {
1170
+ margin: 40px 0 0 0;
1171
+ font-size: 30px;
1172
+ font-weight: 500;
1173
+ text-align: center;
1174
+ }
1175
+ a#eztoc-upgrade {
1176
+ color: #ffffff;
1177
+ background: rgba(234, 76, 137, 1);
1178
+ padding: 16px;
1179
+ }
1180
+ div#welcome {
1181
+ text-align: center;
1182
+ }
1183
+ a#eztoc-welcome {
1184
+ display: none;
1185
+ }
1186
+ .button-toc{
1187
+ text-align: center;
1188
+ cursor: pointer;
1189
+ font-size: 16px;
1190
+ margin: 20px;
1191
+ color: #fff;
1192
+ border-radius: 4px;
1193
+ background-color: #ec407a;
1194
+ border: none;
1195
+ padding: 20px;
1196
+ transition: all 0.5s;
1197
+ font-weight: 600;
1198
+ }
1199
+ .button-toc span {
1200
+ cursor: pointer;
1201
+ display: inline-block;
1202
+ position: relative;
1203
+ transition: 0.5s;
1204
+ }
1205
+
1206
+ .button-toc span:after {
1207
+ content: '»';
1208
+ position: absolute;
1209
+ opacity: 0;
1210
+ top: 0;
1211
+ right: -20px;
1212
+ transition: 0.5s;
1213
+ }
1214
+
1215
+ .button-toc:hover span {
1216
+ padding-right: 25px;
1217
+ }
1218
+
1219
+ .button-toc:hover span:after {
1220
+ opacity: 1;
1221
+ right: 0;
1222
+ }
1223
+
1224
+ .eztoc-query-success{
1225
+ color: green;
1226
+ }
1227
+ .eztoc-query-error{
1228
+ color: red;
1229
+ }
1230
+ .eztoc_hide{
1231
+ display: none;
1232
+ }
1233
+ .eztoc-result{
1234
+ margin-left: 70px;
1235
  }
assets/css/screen.css CHANGED
@@ -1,391 +1,391 @@
1
- #ez-toc-container {
2
- background: #F9F9F9;
3
- border: 1px solid #AAAAAA;
4
- border-radius: 4px;
5
- -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
6
- box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
7
- display: table;
8
- /*font-size: 95%;*/
9
- margin-bottom: 1em;
10
- padding: 10px;
11
- position: relative;
12
- width: auto;
13
- }
14
-
15
- div.ez-toc-widget-container {
16
- padding: 0;
17
- position: relative;
18
- }
19
-
20
- #ez-toc-container.ez-toc-light-blue {
21
- background: #EDF6FF;
22
- }
23
-
24
- #ez-toc-container.ez-toc-white {
25
- background: #FFFFFF;
26
- }
27
-
28
- #ez-toc-container.ez-toc-black {
29
- background: #000000;
30
- }
31
-
32
- #ez-toc-container.ez-toc-transparent {
33
- background: none transparent;
34
- }
35
-
36
- div.ez-toc-widget-container ul {
37
- display: block;
38
- }
39
-
40
- div.ez-toc-widget-container li {
41
- border: none;
42
- padding: 0;
43
- }
44
-
45
- div.ez-toc-widget-container ul.ez-toc-list {
46
- padding: 10px;
47
- }
48
-
49
- #ez-toc-container ul ul,
50
- .ez-toc div.ez-toc-widget-container ul ul {
51
- margin-left: 1.5em;
52
- }
53
-
54
- #ez-toc-container ul,
55
- #ez-toc-container li {
56
- margin: 0;
57
- padding: 0;
58
- }
59
-
60
- #ez-toc-container ul,
61
- #ez-toc-container li,
62
- #ez-toc-container ul li,
63
- div.ez-toc-widget-container,
64
- div.ez-toc-widget-container li {
65
- background: none;
66
- list-style: none none;
67
- line-height: 1.6;
68
- margin: 0;
69
- overflow: hidden;
70
- z-index: 1;
71
- }
72
-
73
- /*#ez-toc-container.have_bullets li {*/
74
- /*padding-left: 12px;*/
75
- /*}*/
76
-
77
- #ez-toc-container p.ez-toc-title {
78
- text-align: left;
79
- /*font-family: "Arial Narrow", sans-serif;*/
80
- /*font-size: 120%;*/
81
- /*font-weight: 500;*/
82
- line-height: 1.45;
83
- margin: 0;
84
- padding: 0;
85
- }
86
-
87
- .ez-toc-title-container {
88
- display: table;
89
- width: 100%;
90
- }
91
-
92
- .ez-toc-title,
93
- .ez-toc-title-toggle {
94
- display: table-cell;
95
- text-align: left;
96
- vertical-align: middle;
97
- }
98
-
99
- #ez-toc-container.ez-toc-black p.ez-toc-title {
100
- color: #FFF;
101
- }
102
-
103
- /*#ez-toc-container span.ez-toc-toggle {*/
104
- /*font-weight: 400;*/
105
- /*font-size: 90%;*/
106
- /*}*/
107
-
108
- #ez-toc-container div.ez-toc-title-container + ul.ez-toc-list {
109
- margin-top: 1em;
110
- }
111
-
112
- .ez-toc-wrap-left {
113
- float: left;
114
- margin-right: 10px;
115
- }
116
-
117
- .ez-toc-wrap-right {
118
- float: right;
119
- margin-left: 10px;
120
- }
121
- .ez-toc-wrap-center {
122
- margin: 0 auto;
123
- }
124
- #ez-toc-container a {
125
- color: #444444;
126
- box-shadow: none;
127
- text-decoration: none;
128
- text-shadow: none;
129
- }
130
-
131
- #ez-toc-container a:visited {
132
- color: #9f9f9f;
133
- }
134
-
135
- #ez-toc-container a:hover {
136
- text-decoration: underline;
137
- }
138
-
139
- #ez-toc-container.ez-toc-black a {
140
- color: #FFF;
141
- }
142
-
143
- #ez-toc-container.ez-toc-black a:visited {
144
- color: #FFF;
145
- }
146
-
147
- #ez-toc-container a.ez-toc-toggle {
148
- color: #444444;
149
- }
150
-
151
- #ez-toc-container.counter-hierarchy ul,
152
- .ez-toc-widget-container.counter-hierarchy ul,
153
- #ez-toc-container.counter-flat ul,
154
- .ez-toc-widget-container.counter-flat ul {
155
- counter-reset: item;
156
- }
157
-
158
- #ez-toc-container.counter-numeric li,
159
- .ez-toc-widget-container.counter-numeric li {
160
- list-style-type: decimal;
161
- list-style-position: inside;
162
- }
163
-
164
- #ez-toc-container.counter-disc li,
165
- .ez-toc-widget-container.counter-disc li {
166
- list-style-type: disc;
167
- list-style-position: inside;
168
- }
169
-
170
- #ez-toc-container.counter-hyphen li,
171
- .ez-toc-widget-container.counter-hyphen li {
172
- list-style-type: '-';
173
- list-style-position: inside;
174
- }
175
-
176
-
177
-
178
-
179
- #ez-toc-container.counter-decimal ul.ez-toc-list li a::before,
180
- .ez-toc-widget-container.counter-decimal ul.ez-toc-list li a::before {
181
- content: counters(item, ".") ". ";
182
- display: inline-block;
183
- counter-increment: item;
184
- margin-right: .2em;
185
- }
186
-
187
- #ez-toc-container.counter-roman li a::before,
188
- .ez-toc-widget-container.counter-roman ul.ez-toc-list li a::before {
189
- content: counters(item, ".", upper-roman) ". ";
190
- counter-increment: item;
191
- }
192
-
193
- .ez-toc-widget-container ul.ez-toc-list li::before {
194
- content: ' ';
195
- position: absolute;
196
- left: 0;
197
- right: 0;
198
- height: 30px;
199
- line-height: 30px;
200
- z-index: -1;
201
- }
202
-
203
- .ez-toc-widget-container ul.ez-toc-list li.active::before {
204
- background-color: #EDEDED;
205
- }
206
-
207
- .ez-toc-widget-container li.active > a {
208
- font-weight: 900;
209
- }
210
-
211
- .ez-toc-btn {
212
- display: inline-block;
213
- padding: 6px 12px;
214
- margin-bottom: 0;
215
- font-size: 14px;
216
- font-weight: normal;
217
- line-height: 1.428571429;
218
- text-align: center;
219
- white-space: nowrap;
220
- vertical-align: middle;
221
- cursor: pointer;
222
- background-image: none;
223
- border: 1px solid transparent;
224
- border-radius: 4px;
225
- -webkit-user-select: none;
226
- -moz-user-select: none;
227
- -ms-user-select: none;
228
- -o-user-select: none;
229
- user-select: none
230
- }
231
-
232
- .ez-toc-btn:focus {
233
- outline: thin dotted #333;
234
- outline: 5px auto -webkit-focus-ring-color;
235
- outline-offset: -2px
236
- }
237
-
238
- .ez-toc-btn:hover,.ez-toc-btn:focus {
239
- color: #333;
240
- text-decoration: none
241
- }
242
-
243
- .ez-toc-btn:active,.ez-toc-btn.active {
244
- background-image: none;
245
- outline: 0;
246
- -webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);
247
- box-shadow: inset 0 3px 5px rgba(0,0,0,0.125)
248
- }
249
-
250
- .ez-toc-btn-default {
251
- color: #333;
252
- background-color: #fff;
253
- border-color: #ccc
254
- }
255
-
256
- .ez-toc-btn-default:hover,.ez-toc-btn-default:focus,.ez-toc-btn-default:active,.ez-toc-btn-default.active {
257
- color: #333;
258
- background-color: #ebebeb;
259
- border-color: #adadad
260
- }
261
-
262
- .ez-toc-btn-default:active,.ez-toc-btn-default.active {
263
- background-image: none
264
- }
265
-
266
- /*.btn-lg {*/
267
- /*padding: 10px 16px;*/
268
- /*font-size: 18px;*/
269
- /*line-height: 1.33;*/
270
- /*border-radius: 6px*/
271
- /*}*/
272
-
273
- .ez-toc-btn-sm,.ez-toc-btn-xs {
274
- padding: 5px 10px;
275
- font-size: 12px;
276
- line-height: 1.5;
277
- border-radius: 3px
278
- }
279
-
280
- .ez-toc-btn-xs {
281
- padding: 1px 5px
282
- }
283
-
284
- .ez-toc-btn-default {
285
- text-shadow: 0 -1px 0 rgba(0,0,0,0.2);
286
- -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);
287
- box-shadow: inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075)
288
- }
289
-
290
- .ez-toc-btn-default:active {
291
- -webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);
292
- box-shadow: inset 0 3px 5px rgba(0,0,0,0.125)
293
- }
294
-
295
- .ez-toc-btn:active,.btn.active {
296
- background-image: none
297
- }
298
-
299
- .ez-toc-btn-default {
300
- text-shadow: 0 1px 0 #fff;
301
- background-image: -webkit-gradient(linear,left 0,left 100%,from(#fff),to(#e0e0e0));
302
- background-image: -webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);
303
- background-image: -moz-linear-gradient(top,#fff 0,#e0e0e0 100%);
304
- background-image: linear-gradient(to bottom,#fff 0,#e0e0e0 100%);
305
- background-repeat: repeat-x;
306
- border-color: #dbdbdb;
307
- border-color: #ccc;
308
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe0e0e0',GradientType=0);
309
- filter: progid:DXImageTransform.Microsoft.gradient(enabled=false)
310
- }
311
-
312
- .ez-toc-btn-default:hover,.ez-toc-btn-default:focus {
313
- background-color: #e0e0e0;
314
- background-position: 0 -15px
315
- }
316
-
317
- .ez-toc-btn-default:active,.ez-toc-btn-default.active {
318
- background-color: #e0e0e0;
319
- border-color: #dbdbdb
320
- }
321
-
322
- .ez-toc-pull-right {
323
- float: right !important;
324
- margin-left: 10px;
325
- }
326
-
327
- .ez-toc-glyphicon {
328
- position: relative;
329
- top: 1px;
330
- display: inline-block;
331
- font-family: 'Glyphicons Halflings';
332
- -webkit-font-smoothing: antialiased;
333
- font-style: normal;
334
- font-weight: normal;
335
- line-height: 1;
336
- -moz-osx-font-smoothing: grayscale
337
- }
338
-
339
- .ez-toc-glyphicon:empty {
340
- width: 1em
341
- }
342
-
343
- .ez-toc-toggle i.ez-toc-glyphicon {
344
- font-size: 16px;
345
- margin-left: 2px;
346
- }
347
-
348
- [class*="ez-toc-icon-"] {
349
- font-family: 'ez-toc-icomoon' !important; /* For better glyphicon compatibility */
350
- speak: none;
351
- font-style: normal;
352
- font-weight: normal;
353
- font-variant: normal;
354
- text-transform: none;
355
- line-height: 1;
356
-
357
- /* Better Font Rendering =========== */
358
- -webkit-font-smoothing: antialiased;
359
- -moz-osx-font-smoothing: grayscale;
360
- }
361
-
362
- .ez-toc-icon-toggle:before {
363
- content: "\e87a";
364
- }
365
- #ez-toc-container input {
366
- position: absolute;
367
- left: -999em;
368
- }
369
- #ez-toc-container input[type="checkbox"]:checked + nav {
370
- opacity: 0;
371
- max-height: 0;
372
- border: none;
373
- }
374
-
375
- #ez-toc-container label {
376
- float: right;
377
- position: relative;
378
- left: 10px;
379
- font-size: 16px;
380
- background: #f9efef;
381
- padding: 0px 4px 0px 5px;
382
- border: 1px solid #999191;
383
- border-radius: 5px;
384
- cursor: pointer;
385
- }
386
- div#ez-toc-container p.ez-toc-title {
387
- display: contents;
388
- }
389
- div#ez-toc-container {
390
- padding-right: 20px;
391
  }
1
+ #ez-toc-container {
2
+ background: #F9F9F9;
3
+ border: 1px solid #AAAAAA;
4
+ border-radius: 4px;
5
+ -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
6
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
7
+ display: table;
8
+ /*font-size: 95%;*/
9
+ margin-bottom: 1em;
10
+ padding: 10px;
11
+ position: relative;
12
+ width: auto;
13
+ }
14
+
15
+ div.ez-toc-widget-container {
16
+ padding: 0;
17
+ position: relative;
18
+ }
19
+
20
+ #ez-toc-container.ez-toc-light-blue {
21
+ background: #EDF6FF;
22
+ }
23
+
24
+ #ez-toc-container.ez-toc-white {
25
+ background: #FFFFFF;
26
+ }
27
+
28
+ #ez-toc-container.ez-toc-black {
29
+ background: #000000;
30
+ }
31
+
32
+ #ez-toc-container.ez-toc-transparent {
33
+ background: none transparent;
34
+ }
35
+
36
+ div.ez-toc-widget-container ul {
37
+ display: block;
38
+ }
39
+
40
+ div.ez-toc-widget-container li {
41
+ border: none;
42
+ padding: 0;
43
+ }
44
+
45
+ div.ez-toc-widget-container ul.ez-toc-list {
46
+ padding: 10px;
47
+ }
48
+
49
+ #ez-toc-container ul ul,
50
+ .ez-toc div.ez-toc-widget-container ul ul {
51
+ margin-left: 1.5em;
52
+ }
53
+
54
+ #ez-toc-container ul,
55
+ #ez-toc-container li {
56
+ margin: 0;
57
+ padding: 0;
58
+ }
59
+
60
+ #ez-toc-container ul,
61
+ #ez-toc-container li,
62
+ #ez-toc-container ul li,
63
+ div.ez-toc-widget-container,
64
+ div.ez-toc-widget-container li {
65
+ background: none;
66
+ list-style: none none;
67
+ line-height: 1.6;
68
+ margin: 0;
69
+ overflow: hidden;
70
+ z-index: 1;
71
+ }
72
+
73
+ /*#ez-toc-container.have_bullets li {*/
74
+ /*padding-left: 12px;*/
75
+ /*}*/
76
+
77
+ #ez-toc-container p.ez-toc-title {
78
+ text-align: left;
79
+ /*font-family: "Arial Narrow", sans-serif;*/
80
+ /*font-size: 120%;*/
81
+ /*font-weight: 500;*/
82
+ line-height: 1.45;
83
+ margin: 0;
84
+ padding: 0;
85
+ }
86
+
87
+ .ez-toc-title-container {
88
+ display: table;
89
+ width: 100%;
90
+ }
91
+
92
+ .ez-toc-title,
93
+ .ez-toc-title-toggle {
94
+ display: table-cell;
95
+ text-align: left;
96
+ vertical-align: middle;
97
+ }
98
+
99
+ #ez-toc-container.ez-toc-black p.ez-toc-title {
100
+ color: #FFF;
101
+ }
102
+
103
+ /*#ez-toc-container span.ez-toc-toggle {*/
104
+ /*font-weight: 400;*/
105
+ /*font-size: 90%;*/
106
+ /*}*/
107
+
108
+ #ez-toc-container div.ez-toc-title-container + ul.ez-toc-list {
109
+ margin-top: 1em;
110
+ }
111
+
112
+ .ez-toc-wrap-left {
113
+ float: left;
114
+ margin-right: 10px;
115
+ }
116
+
117
+ .ez-toc-wrap-right {
118
+ float: right;
119
+ margin-left: 10px;
120
+ }
121
+ .ez-toc-wrap-center {
122
+ margin: 0 auto;
123
+ }
124
+ #ez-toc-container a {
125
+ color: #444444;
126
+ box-shadow: none;
127
+ text-decoration: none;
128
+ text-shadow: none;
129
+ }
130
+
131
+ #ez-toc-container a:visited {
132
+ color: #9f9f9f;
133
+ }
134
+
135
+ #ez-toc-container a:hover {
136
+ text-decoration: underline;
137
+ }
138
+
139
+ #ez-toc-container.ez-toc-black a {
140
+ color: #FFF;
141
+ }
142
+
143
+ #ez-toc-container.ez-toc-black a:visited {
144
+ color: #FFF;
145
+ }
146
+
147
+ #ez-toc-container a.ez-toc-toggle {
148
+ color: #444444;
149
+ }
150
+
151
+ #ez-toc-container.counter-hierarchy ul,
152
+ .ez-toc-widget-container.counter-hierarchy ul,
153
+ #ez-toc-container.counter-flat ul,
154
+ .ez-toc-widget-container.counter-flat ul {
155
+ counter-reset: item;
156
+ }
157
+
158
+ #ez-toc-container.counter-numeric li,
159
+ .ez-toc-widget-container.counter-numeric li {
160
+ list-style-type: decimal;
161
+ list-style-position: inside;
162
+ }
163
+
164
+ #ez-toc-container.counter-disc li,
165
+ .ez-toc-widget-container.counter-disc li {
166
+ list-style-type: disc;
167
+ list-style-position: inside;
168
+ }
169
+
170
+ #ez-toc-container.counter-hyphen li,
171
+ .ez-toc-widget-container.counter-hyphen li {
172
+ list-style-type: '-';
173
+ list-style-position: inside;
174
+ }
175
+
176
+
177
+
178
+
179
+ #ez-toc-container.counter-decimal ul.ez-toc-list li a::before,
180
+ .ez-toc-widget-container.counter-decimal ul.ez-toc-list li a::before {
181
+ content: counters(item, ".") ". ";
182
+ display: inline-block;
183
+ counter-increment: item;
184
+ margin-right: .2em;
185
+ }
186
+
187
+ #ez-toc-container.counter-roman li a::before,
188
+ .ez-toc-widget-container.counter-roman ul.ez-toc-list li a::before {
189
+ content: counters(item, ".", upper-roman) ". ";
190
+ counter-increment: item;
191
+ }
192
+
193
+ .ez-toc-widget-container ul.ez-toc-list li::before {
194
+ content: ' ';
195
+ position: absolute;
196
+ left: 0;
197
+ right: 0;
198
+ height: 30px;
199
+ line-height: 30px;
200
+ z-index: -1;
201
+ }
202
+
203
+ .ez-toc-widget-container ul.ez-toc-list li.active::before {
204
+ background-color: #EDEDED;
205
+ }
206
+
207
+ .ez-toc-widget-container li.active > a {
208
+ font-weight: 900;
209
+ }
210
+
211
+ .ez-toc-btn {
212
+ display: inline-block;
213
+ padding: 6px 12px;
214
+ margin-bottom: 0;
215
+ font-size: 14px;
216
+ font-weight: normal;
217
+ line-height: 1.428571429;
218
+ text-align: center;
219
+ white-space: nowrap;
220
+ vertical-align: middle;
221
+ cursor: pointer;
222
+ background-image: none;
223
+ border: 1px solid transparent;
224
+ border-radius: 4px;
225
+ -webkit-user-select: none;
226
+ -moz-user-select: none;
227
+ -ms-user-select: none;
228
+ -o-user-select: none;
229
+ user-select: none
230
+ }
231
+
232
+ .ez-toc-btn:focus {
233
+ outline: thin dotted #333;
234
+ outline: 5px auto -webkit-focus-ring-color;
235
+ outline-offset: -2px
236
+ }
237
+
238
+ .ez-toc-btn:hover,.ez-toc-btn:focus {
239
+ color: #333;
240
+ text-decoration: none
241
+ }
242
+
243
+ .ez-toc-btn:active,.ez-toc-btn.active {
244
+ background-image: none;
245
+ outline: 0;
246
+ -webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);
247
+ box-shadow: inset 0 3px 5px rgba(0,0,0,0.125)
248
+ }
249
+
250
+ .ez-toc-btn-default {
251
+ color: #333;
252
+ background-color: #fff;
253
+ border-color: #ccc
254
+ }
255
+
256
+ .ez-toc-btn-default:hover,.ez-toc-btn-default:focus,.ez-toc-btn-default:active,.ez-toc-btn-default.active {
257
+ color: #333;
258
+ background-color: #ebebeb;
259
+ border-color: #adadad
260
+ }
261
+
262
+ .ez-toc-btn-default:active,.ez-toc-btn-default.active {
263
+ background-image: none
264
+ }
265
+
266
+ /*.btn-lg {*/
267
+ /*padding: 10px 16px;*/
268
+ /*font-size: 18px;*/
269
+ /*line-height: 1.33;*/
270
+ /*border-radius: 6px*/
271
+ /*}*/
272
+
273
+ .ez-toc-btn-sm,.ez-toc-btn-xs {
274
+ padding: 5px 10px;
275
+ font-size: 12px;
276
+ line-height: 1.5;
277
+ border-radius: 3px
278
+ }
279
+
280
+ .ez-toc-btn-xs {
281
+ padding: 1px 5px
282
+ }
283
+
284
+ .ez-toc-btn-default {
285
+ text-shadow: 0 -1px 0 rgba(0,0,0,0.2);
286
+ -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);
287
+ box-shadow: inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075)
288
+ }
289
+
290
+ .ez-toc-btn-default:active {
291
+ -webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);
292
+ box-shadow: inset 0 3px 5px rgba(0,0,0,0.125)
293
+ }
294
+
295
+ .ez-toc-btn:active,.btn.active {
296
+ background-image: none
297
+ }
298
+
299
+ .ez-toc-btn-default {
300
+ text-shadow: 0 1px 0 #fff;
301
+ background-image: -webkit-gradient(linear,left 0,left 100%,from(#fff),to(#e0e0e0));
302
+ background-image: -webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);
303
+ background-image: -moz-linear-gradient(top,#fff 0,#e0e0e0 100%);
304
+ background-image: linear-gradient(to bottom,#fff 0,#e0e0e0 100%);
305
+ background-repeat: repeat-x;
306
+ border-color: #dbdbdb;
307
+ border-color: #ccc;
308
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe0e0e0',GradientType=0);
309
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false)
310
+ }
311
+
312
+ .ez-toc-btn-default:hover,.ez-toc-btn-default:focus {
313
+ background-color: #e0e0e0;
314
+ background-position: 0 -15px
315
+ }
316
+
317
+ .ez-toc-btn-default:active,.ez-toc-btn-default.active {
318
+ background-color: #e0e0e0;
319
+ border-color: #dbdbdb
320
+ }
321
+
322
+ .ez-toc-pull-right {
323
+ float: right !important;
324
+ margin-left: 10px;
325
+ }
326
+
327
+ .ez-toc-glyphicon {
328
+ position: relative;
329
+ top: 1px;
330
+ display: inline-block;
331
+ font-family: 'Glyphicons Halflings';
332
+ -webkit-font-smoothing: antialiased;
333
+ font-style: normal;
334
+ font-weight: normal;
335
+ line-height: 1;
336
+ -moz-osx-font-smoothing: grayscale
337
+ }
338
+
339
+ .ez-toc-glyphicon:empty {
340
+ width: 1em
341
+ }
342
+
343
+ .ez-toc-toggle i.ez-toc-glyphicon {
344
+ font-size: 16px;
345
+ margin-left: 2px;
346
+ }
347
+
348
+ [class*="ez-toc-icon-"] {
349
+ font-family: 'ez-toc-icomoon' !important; /* For better glyphicon compatibility */
350
+ speak: none;
351
+ font-style: normal;
352
+ font-weight: normal;
353
+ font-variant: normal;
354
+ text-transform: none;
355
+ line-height: 1;
356
+
357
+ /* Better Font Rendering =========== */
358
+ -webkit-font-smoothing: antialiased;
359
+ -moz-osx-font-smoothing: grayscale;
360
+ }
361
+
362
+ .ez-toc-icon-toggle:before {
363
+ content: "\e87a";
364
+ }
365
+ #ez-toc-container input {
366
+ position: absolute;
367
+ left: -999em;
368
+ }
369
+ #ez-toc-container input[type="checkbox"]:checked + nav {
370
+ opacity: 0;
371
+ max-height: 0;
372
+ border: none;
373
+ }
374
+
375
+ #ez-toc-container label {
376
+ float: right;
377
+ position: relative;
378
+ left: 10px;
379
+ font-size: 16px;
380
+ background: #f9efef;
381
+ padding: 0px 4px 0px 5px;
382
+ border: 1px solid #999191;
383
+ border-radius: 5px;
384
+ cursor: pointer;
385
+ }
386
+ div#ez-toc-container p.ez-toc-title {
387
+ display: contents;
388
+ }
389
+ div#ez-toc-container {
390
+ padding-right: 20px;
391
  }
assets/css/screen.min.css CHANGED
@@ -1,23 +1,23 @@
1
- #ez-toc-container {background: #F9F9F9;border: 1px solid #AAAAAA;border-radius: 4px;-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);display: table;margin-bottom: 1em;padding: 10px;position: relative;width: auto;}div.ez-toc-widget-container {padding: 0;position: relative;}#ez-toc-container.ez-toc-light-blue {background: #EDF6FF;}#ez-toc-container.ez-toc-white {background: #FFFFFF;}#ez-toc-container.ez-toc-black {background: #000000;}#ez-toc-container.ez-toc-transparent {background: none transparent;}div.ez-toc-widget-container ul {display: block;}div.ez-toc-widget-container li {border: none;padding: 0;}div.ez-toc-widget-container ul.ez-toc-list {padding: 10px;}#ez-toc-container ul ul, .ez-toc div.ez-toc-widget-container ul ul {margin-left: 1.5em;}#ez-toc-container ul, #ez-toc-container li {margin: 0;padding: 0;}#ez-toc-container ul, #ez-toc-container li, #ez-toc-container ul li, div.ez-toc-widget-container, div.ez-toc-widget-container li {background: none;list-style: none none;line-height: 1.6;margin: 0;overflow: hidden;z-index: 1;}#ez-toc-container p.ez-toc-title {text-align: left;line-height: 1.45;margin: 0;padding: 0;}.ez-toc-title-container {display: table;width: 100%;}.ez-toc-title, .ez-toc-title-toggle {display: table-cell;text-align: left;vertical-align: middle;}#ez-toc-container.ez-toc-black p.ez-toc-title {color: #FFF;}#ez-toc-container div.ez-toc-title-container + ul.ez-toc-list {margin-top: 1em;}.ez-toc-wrap-left {float: left;margin-right: 10px;}.ez-toc-wrap-right {float: right;margin-left: 10px;}#ez-toc-container a {color: #444444;box-shadow: none;text-decoration: none;text-shadow: none;}#ez-toc-container a:visited {color: #9f9f9f;}#ez-toc-container a:hover {text-decoration: underline;}#ez-toc-container.ez-toc-black a {color: #FFF;}#ez-toc-container.ez-toc-black a:visited {color: #FFF;}#ez-toc-container a.ez-toc-toggle {color: #444444;}#ez-toc-container.counter-hierarchy ul, .ez-toc-widget-container.counter-hierarchy ul, #ez-toc-container.counter-flat ul, .ez-toc-widget-container.counter-flat ul {counter-reset: item;}#ez-toc-container.counter-numeric li, .ez-toc-widget-container.counter-numeric li {list-style-type: decimal;list-style-position: inside;}#ez-toc-container.counter-decimal ul.ez-toc-list li a::before, .ez-toc-widget-container.counter-decimal ul.ez-toc-list li a::before {content: counters(item, ".") ". ";display: inline-block;counter-increment: item;margin-right: .2em;}#ez-toc-container.counter-roman li a::before, .ez-toc-widget-container.counter-roman ul.ez-toc-list li a::before {content: counters(item, ".", upper-roman) ". ";counter-increment: item;}.ez-toc-widget-container ul.ez-toc-list li::before {content: ' ';position: absolute;left: 0;right: 0;height: 30px;line-height: 30px;z-index: -1;}.ez-toc-widget-container ul.ez-toc-list li.active::before {background-color: #EDEDED;}.ez-toc-widget-container li.active > a {font-weight: 900;}.ez-toc-btn {display: inline-block;padding: 6px 12px;margin-bottom: 0;font-size: 14px;font-weight: normal;line-height: 1.428571429;text-align: center;white-space: nowrap;vertical-align: middle;cursor: pointer;background-image: none;border: 1px solid transparent;border-radius: 4px;-webkit-user-select: none;-moz-user-select: none;-ms-user-select: none;-o-user-select: none;user-select: none }.ez-toc-btn:focus {outline: thin dotted #333;outline: 5px auto -webkit-focus-ring-color;outline-offset: -2px }.ez-toc-btn:hover,.ez-toc-btn:focus {color: #333;text-decoration: none }.ez-toc-btn:active,.ez-toc-btn.active {background-image: none;outline: 0;-webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);box-shadow: inset 0 3px 5px rgba(0,0,0,0.125) }.ez-toc-btn-default {color: #333;background-color: #fff;border-color: #ccc }.ez-toc-btn-default:hover,.ez-toc-btn-default:focus,.ez-toc-btn-default:active,.ez-toc-btn-default.active {color: #333;background-color: #ebebeb;border-color: #adadad }.ez-toc-btn-default:active,.ez-toc-btn-default.active {background-image: none }.ez-toc-btn-sm,.ez-toc-btn-xs {padding: 5px 10px;font-size: 12px;line-height: 1.5;border-radius: 3px }.ez-toc-btn-xs {padding: 1px 5px }.ez-toc-btn-default {text-shadow: 0 -1px 0 rgba(0,0,0,0.2);-webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);box-shadow: inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075) }.ez-toc-btn-default:active {-webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);box-shadow: inset 0 3px 5px rgba(0,0,0,0.125) }.ez-toc-btn:active,.btn.active {background-image: none }.ez-toc-btn-default {text-shadow: 0 1px 0 #fff;background-image: -webkit-gradient(linear,left 0,left 100%,from(#fff),to(#e0e0e0));background-image: -webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image: -moz-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image: linear-gradient(to bottom,#fff 0,#e0e0e0 100%);background-repeat: repeat-x;border-color: #dbdbdb;border-color: #ccc;filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe0e0e0',GradientType=0);filter: progid:DXImageTransform.Microsoft.gradient(enabled=false) }.ez-toc-btn-default:hover,.ez-toc-btn-default:focus {background-color: #e0e0e0;background-position: 0 -15px }.ez-toc-btn-default:active,.ez-toc-btn-default.active {background-color: #e0e0e0;border-color: #dbdbdb }.ez-toc-pull-right {float: right !important;margin-left: 10px;}.ez-toc-glyphicon {position: relative;top: 1px;display: inline-block;font-family: 'Glyphicons Halflings';-webkit-font-smoothing: antialiased;font-style: normal;font-weight: normal;line-height: 1;-moz-osx-font-smoothing: grayscale }.ez-toc-glyphicon:empty {width: 1em }.ez-toc-toggle i.ez-toc-glyphicon {font-size: 16px;margin-left: 2px;}[class*="ez-toc-icon-"] {font-family: 'ez-toc-icomoon' !important;speak: none;font-style: normal;font-weight: normal;font-variant: normal;text-transform: none;line-height: 1;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;}.ez-toc-icon-toggle:before {content: "\e87a";}#ez-toc-container input {position: absolute;left: -999em;}#ez-toc-container input[type="checkbox"]:checked + nav {opacity: 0;max-height: 0;border: none;}#ez-toc-container label {float: right;position: relative;left: 3px;font-size: 16px;/* background: #f9efef; */padding: 0px 4px 0px 5px;border: 1px solid #999191;border-radius: 5px;cursor: pointer;}div#ez-toc-container p.ez-toc-title {display: contents;}div#ez-toc-container {padding-right: 20px;}#ez-toc-container label {left: 10px;}.ez-toc-wrap-center {margin: 0 auto;}
2
- #ez-toc-container.counter-hyphen ul.ez-toc-list li a::before,
3
-
4
- #ez-toc-container.counter-disc li,
5
- .ez-toc-widget-container.counter-disc li {
6
- list-style-type: disc;
7
- list-style-position: inside;
8
- }
9
-
10
- #ez-toc-container.counter-hyphen li,
11
- .ez-toc-widget-container.counter-hyphen li {
12
- list-style-type: '- ';
13
- list-style-position: inside;
14
-
15
- }
16
-
17
- #ez-toc-container a.ez-toc-toggle {
18
- color: #444444;
19
- background: inherit;
20
- border: inherit;
21
- }
22
- .ez-toc-toggle #item{position: absolute;left: -999em;}
23
-
1
+ #ez-toc-container {background: #F9F9F9;border: 1px solid #AAAAAA;border-radius: 4px;-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);display: table;margin-bottom: 1em;padding: 10px;position: relative;width: auto;}div.ez-toc-widget-container {padding: 0;position: relative;}#ez-toc-container.ez-toc-light-blue {background: #EDF6FF;}#ez-toc-container.ez-toc-white {background: #FFFFFF;}#ez-toc-container.ez-toc-black {background: #000000;}#ez-toc-container.ez-toc-transparent {background: none transparent;}div.ez-toc-widget-container ul {display: block;}div.ez-toc-widget-container li {border: none;padding: 0;}div.ez-toc-widget-container ul.ez-toc-list {padding: 10px;}#ez-toc-container ul ul, .ez-toc div.ez-toc-widget-container ul ul {margin-left: 1.5em;}#ez-toc-container ul, #ez-toc-container li {margin: 0;padding: 0;}#ez-toc-container ul, #ez-toc-container li, #ez-toc-container ul li, div.ez-toc-widget-container, div.ez-toc-widget-container li {background: none;list-style: none none;line-height: 1.6;margin: 0;overflow: hidden;z-index: 1;}#ez-toc-container p.ez-toc-title {text-align: left;line-height: 1.45;margin: 0;padding: 0;}.ez-toc-title-container {display: table;width: 100%;}.ez-toc-title, .ez-toc-title-toggle {display: table-cell;text-align: left;vertical-align: middle;}#ez-toc-container.ez-toc-black p.ez-toc-title {color: #FFF;}#ez-toc-container div.ez-toc-title-container + ul.ez-toc-list {margin-top: 1em;}.ez-toc-wrap-left {float: left;margin-right: 10px;}.ez-toc-wrap-right {float: right;margin-left: 10px;}#ez-toc-container a {color: #444444;box-shadow: none;text-decoration: none;text-shadow: none;}#ez-toc-container a:visited {color: #9f9f9f;}#ez-toc-container a:hover {text-decoration: underline;}#ez-toc-container.ez-toc-black a {color: #FFF;}#ez-toc-container.ez-toc-black a:visited {color: #FFF;}#ez-toc-container a.ez-toc-toggle {color: #444444;}#ez-toc-container.counter-hierarchy ul, .ez-toc-widget-container.counter-hierarchy ul, #ez-toc-container.counter-flat ul, .ez-toc-widget-container.counter-flat ul {counter-reset: item;}#ez-toc-container.counter-numeric li, .ez-toc-widget-container.counter-numeric li {list-style-type: decimal;list-style-position: inside;}#ez-toc-container.counter-decimal ul.ez-toc-list li a::before, .ez-toc-widget-container.counter-decimal ul.ez-toc-list li a::before {content: counters(item, ".") ". ";display: inline-block;counter-increment: item;margin-right: .2em;}#ez-toc-container.counter-roman li a::before, .ez-toc-widget-container.counter-roman ul.ez-toc-list li a::before {content: counters(item, ".", upper-roman) ". ";counter-increment: item;}.ez-toc-widget-container ul.ez-toc-list li::before {content: ' ';position: absolute;left: 0;right: 0;height: 30px;line-height: 30px;z-index: -1;}.ez-toc-widget-container ul.ez-toc-list li.active::before {background-color: #EDEDED;}.ez-toc-widget-container li.active > a {font-weight: 900;}.ez-toc-btn {display: inline-block;padding: 6px 12px;margin-bottom: 0;font-size: 14px;font-weight: normal;line-height: 1.428571429;text-align: center;white-space: nowrap;vertical-align: middle;cursor: pointer;background-image: none;border: 1px solid transparent;border-radius: 4px;-webkit-user-select: none;-moz-user-select: none;-ms-user-select: none;-o-user-select: none;user-select: none }.ez-toc-btn:focus {outline: thin dotted #333;outline: 5px auto -webkit-focus-ring-color;outline-offset: -2px }.ez-toc-btn:hover,.ez-toc-btn:focus {color: #333;text-decoration: none }.ez-toc-btn:active,.ez-toc-btn.active {background-image: none;outline: 0;-webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);box-shadow: inset 0 3px 5px rgba(0,0,0,0.125) }.ez-toc-btn-default {color: #333;background-color: #fff;border-color: #ccc }.ez-toc-btn-default:hover,.ez-toc-btn-default:focus,.ez-toc-btn-default:active,.ez-toc-btn-default.active {color: #333;background-color: #ebebeb;border-color: #adadad }.ez-toc-btn-default:active,.ez-toc-btn-default.active {background-image: none }.ez-toc-btn-sm,.ez-toc-btn-xs {padding: 5px 10px;font-size: 12px;line-height: 1.5;border-radius: 3px }.ez-toc-btn-xs {padding: 1px 5px }.ez-toc-btn-default {text-shadow: 0 -1px 0 rgba(0,0,0,0.2);-webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);box-shadow: inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075) }.ez-toc-btn-default:active {-webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);box-shadow: inset 0 3px 5px rgba(0,0,0,0.125) }.ez-toc-btn:active,.btn.active {background-image: none }.ez-toc-btn-default {text-shadow: 0 1px 0 #fff;background-image: -webkit-gradient(linear,left 0,left 100%,from(#fff),to(#e0e0e0));background-image: -webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image: -moz-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image: linear-gradient(to bottom,#fff 0,#e0e0e0 100%);background-repeat: repeat-x;border-color: #dbdbdb;border-color: #ccc;filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe0e0e0',GradientType=0);filter: progid:DXImageTransform.Microsoft.gradient(enabled=false) }.ez-toc-btn-default:hover,.ez-toc-btn-default:focus {background-color: #e0e0e0;background-position: 0 -15px }.ez-toc-btn-default:active,.ez-toc-btn-default.active {background-color: #e0e0e0;border-color: #dbdbdb }.ez-toc-pull-right {float: right !important;margin-left: 10px;}.ez-toc-glyphicon {position: relative;top: 1px;display: inline-block;font-family: 'Glyphicons Halflings';-webkit-font-smoothing: antialiased;font-style: normal;font-weight: normal;line-height: 1;-moz-osx-font-smoothing: grayscale }.ez-toc-glyphicon:empty {width: 1em }.ez-toc-toggle i.ez-toc-glyphicon {font-size: 16px;margin-left: 2px;}[class*="ez-toc-icon-"] {font-family: 'ez-toc-icomoon' !important;speak: none;font-style: normal;font-weight: normal;font-variant: normal;text-transform: none;line-height: 1;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;}.ez-toc-icon-toggle:before {content: "\e87a";}#ez-toc-container input {position: absolute;left: -999em;}#ez-toc-container input[type="checkbox"]:checked + nav {opacity: 0;max-height: 0;border: none;}#ez-toc-container label {float: right;position: relative;left: 3px;font-size: 16px;/* background: #f9efef; */padding: 0px 4px 0px 5px;border: 1px solid #999191;border-radius: 5px;cursor: pointer;}div#ez-toc-container p.ez-toc-title {display: contents;}div#ez-toc-container {padding-right: 20px;}#ez-toc-container label {left: 10px;}.ez-toc-wrap-center {margin: 0 auto;}
2
+ #ez-toc-container.counter-hyphen ul.ez-toc-list li a::before,
3
+
4
+ #ez-toc-container.counter-disc li,
5
+ .ez-toc-widget-container.counter-disc li {
6
+ list-style-type: disc;
7
+ list-style-position: inside;
8
+ }
9
+
10
+ #ez-toc-container.counter-hyphen li,
11
+ .ez-toc-widget-container.counter-hyphen li {
12
+ list-style-type: '- ';
13
+ list-style-position: inside;
14
+
15
+ }
16
+
17
+ #ez-toc-container a.ez-toc-toggle {
18
+ color: #444444;
19
+ background: inherit;
20
+ border: inherit;
21
+ }
22
+ .ez-toc-toggle #item{position: absolute;left: -999em;}
23
+
assets/js/admin.js CHANGED
@@ -1,8 +1,8 @@
1
- jQuery(document).ready(function($) {
2
-
3
- var ez_toc_color_picker = $( '.ez-toc-color-picker' );
4
-
5
- if ( ez_toc_color_picker.length ) {
6
- ez_toc_color_picker.wpColorPicker();
7
- }
8
- });
1
+ jQuery(document).ready(function($) {
2
+
3
+ var ez_toc_color_picker = $( '.ez-toc-color-picker' );
4
+
5
+ if ( ez_toc_color_picker.length ) {
6
+ ez_toc_color_picker.wpColorPicker();
7
+ }
8
+ });
assets/js/eztoc-admin.js CHANGED
@@ -1,83 +1,83 @@
1
- function tabToggle(evt, idname) {
2
- var i, tabcontent, tablinks;tabcontent = document.getElementsByClassName("eztoc-tabcontent");
3
- for (i = 0; i < tabcontent.length; i++) {
4
- tabcontent[i].style.display = "none";
5
- }
6
- tablinks = document.getElementsByClassName("eztoc-tablinks");
7
- for (i = 0; i < tablinks.length; i++) {
8
- tablinks[i].className = tablinks[i].className.replace(" active", "");
9
- }
10
- document.getElementById(idname).style.display = "block";
11
-
12
- evt.target.className += " active";
13
- }
14
-
15
- function eztocIsEmail(email) {
16
- var regex = /^([a-zA-Z0-9_.+-])+\@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/;
17
- return regex.test(email);
18
- }
19
-
20
-
21
- //query form send starts here
22
- jQuery(document).ready(function($) {
23
-
24
- var url = window.location.href;
25
- if(url.indexOf('#technical-support') > -1){
26
- $("#eztoc-technical").click();
27
- }else if(url.indexOf('#freevspro-support') > -1){
28
- $("#eztoc-freevspro").click();
29
- }
30
- else if(url.indexOf('#welcome') > -1){
31
- $("#eztoc-welcome").click();
32
- }
33
- else{
34
- $("#eztoc-default").click();
35
- }
36
-
37
- $(".eztoc-send-query").on("click", function(e){
38
- e.preventDefault();
39
- var message = $("#eztoc_query_message").val();
40
- var email = $("#eztoc_query_email").val();
41
- var premium_cus = $("#saswp_query_premium_cus").val();
42
-
43
- if($.trim(message) !='' && $.trim(email) !='' && eztocIsEmail(email) == true){
44
- $.ajax({
45
- type: "POST",
46
- url:ajaxurl,
47
- dataType: "json",
48
- data:{action:"eztoc_send_query_message",message:message,email:email, eztoc_security_nonce:eztoc_admin_data.eztoc_security_nonce},
49
- success:function(response){
50
- if(response['status'] =='t'){
51
- $(".eztoc-query-success").show();
52
- $(".eztoc-query-error").hide();
53
- }else{
54
- $(".eztoc-query-success").hide();
55
- $(".eztoc-query-error").show();
56
- }
57
- },
58
- error: function(response){
59
- console.log(response);
60
- }
61
- });
62
- }else{
63
-
64
- if($.trim(message) =='' && $.trim(email) ==''){
65
- alert('Please enter the message, email and select customer type');
66
- }else{
67
-
68
- if($.trim(message) == ''){
69
- alert('Please enter the message');
70
- }
71
- if($.trim(email) == ''){
72
- alert('Please enter the email');
73
- }
74
- if(eztocIsEmail(email) == false){
75
- alert('Please enter a valid email');
76
- }
77
-
78
- }
79
-
80
- }
81
-
82
- });
83
  });
1
+ function tabToggle(evt, idname) {
2
+ var i, tabcontent, tablinks;tabcontent = document.getElementsByClassName("eztoc-tabcontent");
3
+ for (i = 0; i < tabcontent.length; i++) {
4
+ tabcontent[i].style.display = "none";
5
+ }
6
+ tablinks = document.getElementsByClassName("eztoc-tablinks");
7
+ for (i = 0; i < tablinks.length; i++) {
8
+ tablinks[i].className = tablinks[i].className.replace(" active", "");
9
+ }
10
+ document.getElementById(idname).style.display = "block";
11
+
12
+ evt.target.className += " active";
13
+ }
14
+
15
+ function eztocIsEmail(email) {
16
+ var regex = /^([a-zA-Z0-9_.+-])+\@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/;
17
+ return regex.test(email);
18
+ }
19
+
20
+
21
+ //query form send starts here
22
+ jQuery(document).ready(function($) {
23
+
24
+ var url = window.location.href;
25
+ if(url.indexOf('#technical-support') > -1){
26
+ $("#eztoc-technical").click();
27
+ }else if(url.indexOf('#freevspro-support') > -1){
28
+ $("#eztoc-freevspro").click();
29
+ }
30
+ else if(url.indexOf('#welcome') > -1){
31
+ $("#eztoc-welcome").click();
32
+ }
33
+ else{
34
+ $("#eztoc-default").click();
35
+ }
36
+
37
+ $(".eztoc-send-query").on("click", function(e){
38
+ e.preventDefault();
39
+ var message = $("#eztoc_query_message").val();
40
+ var email = $("#eztoc_query_email").val();
41
+ var premium_cus = $("#saswp_query_premium_cus").val();
42
+
43
+ if($.trim(message) !='' && $.trim(email) !='' && eztocIsEmail(email) == true){
44
+ $.ajax({
45
+ type: "POST",
46
+ url:ajaxurl,
47
+ dataType: "json",
48
+ data:{action:"eztoc_send_query_message",message:message,email:email, eztoc_security_nonce:eztoc_admin_data.eztoc_security_nonce},
49
+ success:function(response){
50
+ if(response['status'] =='t'){
51
+ $(".eztoc-query-success").show();
52
+ $(".eztoc-query-error").hide();
53
+ }else{
54
+ $(".eztoc-query-success").hide();
55
+ $(".eztoc-query-error").show();
56
+ }
57
+ },
58
+ error: function(response){
59
+ console.log(response);
60
+ }
61
+ });
62
+ }else{
63
+
64
+ if($.trim(message) =='' && $.trim(email) ==''){
65
+ alert('Please enter the message, email and select customer type');
66
+ }else{
67
+
68
+ if($.trim(message) == ''){
69
+ alert('Please enter the message');
70
+ }
71
+ if($.trim(email) == ''){
72
+ alert('Please enter the email');
73
+ }
74
+ if(eztocIsEmail(email) == false){
75
+ alert('Please enter a valid email');
76
+ }
77
+
78
+ }
79
+
80
+ }
81
+
82
+ });
83
  });
assets/js/front.js CHANGED
@@ -1,324 +1,324 @@
1
- jQuery( function( $ ) {
2
-
3
- /**
4
- * @typedef ezTOC
5
- * @type {Object} ezTOC
6
- * @property {string} affixSelector
7
- * @property {string} scroll_offset
8
- * @property {string} smooth_scroll
9
- * @property {string} visibility_hide_by_default
10
- */
11
-
12
- if ( typeof ezTOC != 'undefined' ) {
13
-
14
- /**
15
- * Init EZ TOC.
16
- */
17
- function ezTOCInit() {
18
-
19
- var affix = $( '.ez-toc-widget-container.ez-toc-affix' );
20
-
21
- if ( 0 !== affix.length ) {
22
-
23
- /**
24
- * The smooth scroll offset needs to be taken into account when defining the offset_top property.
25
- * @link https://github.com/shazahm1/Easy-Table-of-Contents/issues/19
26
- *
27
- * @type {number}
28
- */
29
- var affixOffset = 30;
30
-
31
- // check offset setting
32
- if ( typeof ezTOC.scroll_offset != 'undefined' ) {
33
-
34
- affixOffset = parseInt( ezTOC.scroll_offset );
35
- }
36
-
37
- $( ezTOC.affixSelector ).stick_in_parent( {
38
- inner_scrolling: false,
39
- offset_top: affixOffset
40
- } )
41
- }
42
-
43
- $.fn.shrinkTOCWidth = function() {
44
-
45
- $( this ).css( {
46
- width: 'auto',
47
- display: 'table'
48
- });
49
-
50
- if ( /MSIE 7\./.test( navigator.userAgent ) )
51
- $( this ).css( 'width', '' );
52
- };
53
-
54
- var smoothScroll = parseInt( ezTOC.smooth_scroll );
55
-
56
- if ( 1 === smoothScroll ) {
57
-
58
- $( 'a.ez-toc-link' ).on( 'click', function() {
59
-
60
- var self = $( this );
61
-
62
- var target = '';
63
- var hostname = self.prop( 'hostname' );
64
- var pathname = self.prop( 'pathname' );
65
- var qs = self.prop( 'search' );
66
- var hash = self.prop( 'hash' );
67
-
68
- // ie strips out the preceding / from pathname
69
- if ( pathname.length > 0 ) {
70
- if ( pathname.charAt( 0 ) !== '/' ) {
71
- pathname = '/' + pathname;
72
- }
73
- }
74
-
75
- if ( ( window.location.hostname === hostname ) &&
76
- ( window.location.pathname === pathname ) &&
77
- ( window.location.search === qs ) &&
78
- ( hash !== '' )
79
- ) {
80
-
81
- // var id = decodeURIComponent( hash.replace( '#', '' ) );
82
- target = '[id="' + hash.replace( '#', '' ) + '"]';
83
-
84
- // verify it exists
85
- if ( $( target ).length === 0 ) {
86
- console.log( 'ezTOC scrollTarget Not Found: ' + target );
87
- target = '';
88
- }
89
-
90
- // check offset setting
91
- if ( typeof ezTOC.scroll_offset != 'undefined' ) {
92
-
93
- var offset = -1 * ezTOC.scroll_offset;
94
-
95
- } else {
96
-
97
- var adminbar = $( '#wpadminbar' );
98
-
99
- if ( adminbar.length > 0 ) {
100
-
101
- if ( adminbar.is( ':visible' ) )
102
- offset = -30; // admin bar exists, give it the default
103
- else
104
- offset = 0; // there is an admin bar but it's hidden, so no offset!
105
-
106
- } else {
107
-
108
- // no admin bar, so no offset!
109
- offset = 0;
110
- }
111
- }
112
-
113
- if ( target ) {
114
- $.smoothScroll( {
115
- scrollTarget: target,
116
- offset: offset,
117
- beforeScroll: deactivateSetActiveEzTocListElement,
118
- afterScroll: function() { setActiveEzTocListElement(); activateSetActiveEzTocListElement(); }
119
- } );
120
-
121
- }
122
- }
123
- } );
124
- }
125
-
126
- if ( typeof ezTOC.visibility_hide_by_default != 'undefined' ) {
127
-
128
- var toc = $( 'ul.ez-toc-list' );
129
- var toggle = $( 'a.ez-toc-toggle' );
130
- var invert = ezTOC.visibility_hide_by_default;
131
-
132
- toggle.css( 'display', 'inline' );
133
-
134
- if ( Cookies ) {
135
-
136
- Cookies.get( 'ezTOC_hidetoc' ) == 1 ? toggle.data( 'visible', false ) : toggle.data( 'visible', true );
137
-
138
- } else {
139
-
140
- toggle.data( 'visible', true );
141
- }
142
-
143
- if ( invert ) {
144
-
145
- toggle.data( 'visible', false )
146
- }
147
-
148
- if ( ! toggle.data( 'visible' ) ) {
149
-
150
- toc.hide();
151
- }
152
-
153
- toggle.on( 'click', function( event ) {
154
-
155
- event.preventDefault();
156
-
157
- if ( $( this ).data( 'visible' ) ) {
158
-
159
- $( this ).data( 'visible', false );
160
-
161
- if ( Cookies ) {
162
-
163
- if ( invert )
164
- Cookies.set( 'ezTOC_hidetoc', null, { path: '/' } );
165
- else
166
- Cookies.set( 'ezTOC_hidetoc', '1', { expires: 30, path: '/' } );
167
- }
168
-
169
- toc.hide( 'fast' );
170
-
171
- } else {
172
-
173
- $( this ).data( 'visible', true );
174
-
175
- if ( Cookies ) {
176
-
177
- if ( invert )
178
- Cookies.set( 'ezTOC_hidetoc', '1', { expires: 30, path: '/' } );
179
- else
180
- Cookies.set( 'ezTOC_hidetoc', null, { path: '/' } );
181
- }
182
-
183
- toc.show( 'fast' );
184
-
185
- }
186
-
187
- } );
188
- }
189
-
190
-
191
- // ======================================
192
- // Set active heading in ez-toc-widget list
193
- // ======================================
194
-
195
- var headings = $( 'span.ez-toc-section' ).toArray();
196
- var headingToListElementLinkMap = getHeadingToListElementLinkMap( headings );
197
- var listElementLinks = $.map( headingToListElementLinkMap, function ( value, key ) {
198
- return value
199
- } );
200
- var scrollOffset = getScrollOffset();
201
-
202
- activateSetActiveEzTocListElement();
203
-
204
- function setActiveEzTocListElement() {
205
- var activeHeading = getActiveHeading( scrollOffset, headings );
206
- if ( activeHeading ) {
207
- var activeListElementLink = headingToListElementLinkMap[ activeHeading.id ];
208
- removeStyleFromNonActiveListElement( activeListElementLink, listElementLinks );
209
- setStyleForActiveListElementElement( activeListElementLink );
210
- }
211
- }
212
-
213
- function activateSetActiveEzTocListElement() {
214
- if ( headings.length > 0 && $('.ez-toc-widget-container').length) {
215
- $( window ).on( 'load resize scroll', setActiveEzTocListElement );
216
- }
217
- }
218
-
219
- function deactivateSetActiveEzTocListElement() {
220
- $( window ).off( 'load resize scroll', setActiveEzTocListElement );
221
- }
222
-
223
- function getEzTocListElementLinkByHeading( heading ) {
224
- return $( '.ez-toc-widget-container .ez-toc-list a[href="#' + $( heading ).attr( 'id' ) + '"]' );
225
- }
226
-
227
- function getHeadingToListElementLinkMap( headings ) {
228
- return headings.reduce( function ( map, heading ) {
229
- map[ heading.id ] = getEzTocListElementLinkByHeading( heading );
230
- return map;
231
- }, {} );
232
- }
233
-
234
- function getScrollOffset() {
235
- var scrollOffset = 5; // so if smooth offset is off, the correct title is set as active
236
- if ( typeof ezTOC.smooth_scroll != 'undefined' && parseInt( ezTOC.smooth_scroll ) === 1 ) {
237
- scrollOffset = ( typeof ezTOC.scroll_offset != 'undefined' ) ? parseInt( ezTOC.scroll_offset ) : 30;
238
- }
239
-
240
- var adminbar = $( '#wpadminbar' );
241
-
242
- if ( adminbar.length ) {
243
- scrollOffset += adminbar.height();
244
- }
245
- return scrollOffset;
246
- }
247
-
248
- function getActiveHeading( topOffset, headings ) {
249
- var scrollTop = $( window ).scrollTop();
250
- var relevantOffset = scrollTop + topOffset + 1;
251
- var activeHeading = headings[ 0 ];
252
- var closestHeadingAboveOffset = relevantOffset - $( activeHeading ).offset().top;
253
- headings.forEach( function ( section ) {
254
- var topOffset = relevantOffset - $( section ).offset().top;
255
- if ( topOffset > 0 && topOffset < closestHeadingAboveOffset ) {
256
- closestHeadingAboveOffset = topOffset;
257
- activeHeading = section;
258
- }
259
- } );
260
- return activeHeading;
261
- }
262
-
263
- function removeStyleFromNonActiveListElement( activeListElementLink, listElementLinks ) {
264
- listElementLinks.forEach( function ( listElementLink ) {
265
- if ( activeListElementLink !== listElementLink && listElementLink.parent().hasClass( 'active' ) ) {
266
- listElementLink.parent().removeClass( 'active' );
267
- }
268
- } );
269
- }
270
-
271
- function correctActiveListElementBackgroundColorHeight( activeListElement ) {
272
- var listElementHeight = getListElementHeightWithoutUlChildren( activeListElement );
273
- addListElementBackgroundColorHeightStyleToHead( listElementHeight );
274
- }
275
-
276
- function getListElementHeightWithoutUlChildren( listElement ) {
277
- var $listElement = $( listElement );
278
- var content = $listElement.html();
279
- // Adding list item with class '.active' to get the real height.
280
- // When adding a class to an existing element and using jQuery(..).height() directly afterwards,
281
- // the height is the 'old' height. The height might change due to text-wraps when setting the text-weight bold for example
282
- // When adding a new item, the height is calculated correctly.
283
- // But only when it might be visible (so display:none; is not possible...)
284
- // But because it get's directly removed afterwards it never will be rendered by the browser
285
- // (at least in my tests in FF, Chrome, IE11 and Edge)
286
- $listElement.parent().append( '<li id="ez-toc-height-test" class="active">' + content + '</li>' );
287
- var listItem = $( '#ez-toc-height-test' );
288
- var height = listItem.height();
289
- listItem.remove();
290
- return height - $listElement.children( 'ul' ).first().height();
291
- }
292
-
293
- function addListElementBackgroundColorHeightStyleToHead( listElementHeight ) {
294
- // Remove existing
295
- $( '#ez-toc-active-height' ).remove();
296
- // jQuery(..).css(..) doesn't work, because ::before is a pseudo element and not part of the DOM
297
- // Workaround is to add it to head
298
- $( '<style id="ez-toc-active-height">' +
299
- '.ez-toc-widget-container ul.ez-toc-list li.active::before {' +
300
- // 'line-heigh:' + listElementHeight + 'px; ' +
301
- 'height:' + listElementHeight + 'px;' +
302
- '} </style>' )
303
- .appendTo( 'head' );
304
- }
305
-
306
- function setStyleForActiveListElementElement( activeListElementLink ) {
307
- var activeListElement = activeListElementLink.parent();
308
- if ( !activeListElement.hasClass( 'active' ) ) {
309
- activeListElement.addClass( 'active' );
310
- }
311
- correctActiveListElementBackgroundColorHeight( activeListElement );
312
- }
313
- }
314
-
315
- /**
316
- * Attach global init handler to ezTOC window object.
317
- */
318
- ezTOC.init = function(){
319
- ezTOCInit();
320
- }
321
- // Start EZ TOC on page load.
322
- ezTOCInit();
323
- }
324
- } );
1
+ jQuery( function( $ ) {
2
+
3
+ /**
4
+ * @typedef ezTOC
5
+ * @type {Object} ezTOC
6
+ * @property {string} affixSelector
7
+ * @property {string} scroll_offset
8
+ * @property {string} smooth_scroll
9
+ * @property {string} visibility_hide_by_default
10
+ */
11
+
12
+ if ( typeof ezTOC != 'undefined' ) {
13
+
14
+ /**
15
+ * Init EZ TOC.
16
+ */
17
+ function ezTOCInit() {
18
+
19
+ var affix = $( '.ez-toc-widget-container.ez-toc-affix' );
20
+
21
+ if ( 0 !== affix.length ) {
22
+
23
+ /**
24
+ * The smooth scroll offset needs to be taken into account when defining the offset_top property.
25
+ * @link https://github.com/shazahm1/Easy-Table-of-Contents/issues/19
26
+ *
27
+ * @type {number}
28
+ */
29
+ var affixOffset = 30;
30
+
31
+ // check offset setting
32
+ if ( typeof ezTOC.scroll_offset != 'undefined' ) {
33
+
34
+ affixOffset = parseInt( ezTOC.scroll_offset );
35
+ }
36
+
37
+ $( ezTOC.affixSelector ).stick_in_parent( {
38
+ inner_scrolling: false,
39
+ offset_top: affixOffset
40
+ } )
41
+ }
42
+
43
+ $.fn.shrinkTOCWidth = function() {
44
+
45
+ $( this ).css( {
46
+ width: 'auto',
47
+ display: 'table'
48
+ });
49
+
50
+ if ( /MSIE 7\./.test( navigator.userAgent ) )
51
+ $( this ).css( 'width', '' );
52
+ };
53
+
54
+ var smoothScroll = parseInt( ezTOC.smooth_scroll );
55
+
56
+ if ( 1 === smoothScroll ) {
57
+
58
+ $( 'a.ez-toc-link' ).on( 'click', function() {
59
+
60
+ var self = $( this );
61
+
62
+ var target = '';
63
+ var hostname = self.prop( 'hostname' );
64
+ var pathname = self.prop( 'pathname' );
65
+ var qs = self.prop( 'search' );
66
+ var hash = self.prop( 'hash' );
67
+
68
+ // ie strips out the preceding / from pathname
69
+ if ( pathname.length > 0 ) {
70
+ if ( pathname.charAt( 0 ) !== '/' ) {
71
+ pathname = '/' + pathname;
72
+ }
73
+ }
74
+
75
+ if ( ( window.location.hostname === hostname ) &&
76
+ ( window.location.pathname === pathname ) &&
77
+ ( window.location.search === qs ) &&
78
+ ( hash !== '' )
79
+ ) {
80
+
81
+ // var id = decodeURIComponent( hash.replace( '#', '' ) );
82
+ target = '[id="' + hash.replace( '#', '' ) + '"]';
83
+
84
+ // verify it exists
85
+ if ( $( target ).length === 0 ) {
86
+ console.log( 'ezTOC scrollTarget Not Found: ' + target );
87
+ target = '';
88
+ }
89
+
90
+ // check offset setting
91
+ if ( typeof ezTOC.scroll_offset != 'undefined' ) {
92
+
93
+ var offset = -1 * ezTOC.scroll_offset;
94
+
95
+ } else {
96
+
97
+ var adminbar = $( '#wpadminbar' );
98
+
99
+ if ( adminbar.length > 0 ) {
100
+
101
+ if ( adminbar.is( ':visible' ) )
102
+ offset = -30; // admin bar exists, give it the default
103
+ else
104
+ offset = 0; // there is an admin bar but it's hidden, so no offset!
105
+
106
+ } else {
107
+
108
+ // no admin bar, so no offset!
109
+ offset = 0;
110
+ }
111
+ }
112
+
113
+ if ( target ) {
114
+ $.smoothScroll( {
115
+ scrollTarget: target,
116
+ offset: offset,
117
+ beforeScroll: deactivateSetActiveEzTocListElement,
118
+ afterScroll: function() { setActiveEzTocListElement(); activateSetActiveEzTocListElement(); }
119
+ } );
120
+
121
+ }
122
+ }
123
+ } );
124
+ }
125
+
126
+ if ( typeof ezTOC.visibility_hide_by_default != 'undefined' ) {
127
+
128
+ var toc = $( 'ul.ez-toc-list' );
129
+ var toggle = $( 'a.ez-toc-toggle' );
130
+ var invert = ezTOC.visibility_hide_by_default;
131
+
132
+ toggle.css( 'display', 'inline' );
133
+
134
+ if ( Cookies ) {
135
+
136
+ Cookies.get( 'ezTOC_hidetoc' ) == 1 ? toggle.data( 'visible', false ) : toggle.data( 'visible', true );
137
+
138
+ } else {
139
+
140
+ toggle.data( 'visible', true );
141
+ }
142
+
143
+ if ( invert ) {
144
+
145
+ toggle.data( 'visible', false )
146
+ }
147
+
148
+ if ( ! toggle.data( 'visible' ) ) {
149
+
150
+ toc.hide();
151
+ }
152
+
153
+ toggle.on( 'click', function( event ) {
154
+
155
+ event.preventDefault();
156
+
157
+ if ( $( this ).data( 'visible' ) ) {
158
+
159
+ $( this ).data( 'visible', false );
160
+
161
+ if ( Cookies ) {
162
+
163
+ if ( invert )
164
+ Cookies.set( 'ezTOC_hidetoc', null, { path: '/' } );
165
+ else
166
+ Cookies.set( 'ezTOC_hidetoc', '1', { expires: 30, path: '/' } );
167
+ }
168
+
169
+ toc.hide( 'fast' );
170
+
171
+ } else {
172
+
173
+ $( this ).data( 'visible', true );
174
+
175
+ if ( Cookies ) {
176
+
177
+ if ( invert )
178
+ Cookies.set( 'ezTOC_hidetoc', '1', { expires: 30, path: '/' } );
179
+ else
180
+ Cookies.set( 'ezTOC_hidetoc', null, { path: '/' } );
181
+ }
182
+
183
+ toc.show( 'fast' );
184
+
185
+ }
186
+
187
+ } );
188
+ }
189
+
190
+
191
+ // ======================================
192
+ // Set active heading in ez-toc-widget list
193
+ // ======================================
194
+
195
+ var headings = $( 'span.ez-toc-section' ).toArray();
196
+ var headingToListElementLinkMap = getHeadingToListElementLinkMap( headings );
197
+ var listElementLinks = $.map( headingToListElementLinkMap, function ( value, key ) {
198
+ return value
199
+ } );
200
+ var scrollOffset = getScrollOffset();
201
+
202
+ activateSetActiveEzTocListElement();
203
+
204
+ function setActiveEzTocListElement() {
205
+ var activeHeading = getActiveHeading( scrollOffset, headings );
206
+ if ( activeHeading ) {
207
+ var activeListElementLink = headingToListElementLinkMap[ activeHeading.id ];
208
+ removeStyleFromNonActiveListElement( activeListElementLink, listElementLinks );
209
+ setStyleForActiveListElementElement( activeListElementLink );
210
+ }
211
+ }
212
+
213
+ function activateSetActiveEzTocListElement() {
214
+ if ( headings.length > 0 && $('.ez-toc-widget-container').length) {
215
+ $( window ).on( 'load resize scroll', setActiveEzTocListElement );
216
+ }
217
+ }
218
+
219
+ function deactivateSetActiveEzTocListElement() {
220
+ $( window ).off( 'load resize scroll', setActiveEzTocListElement );
221
+ }
222
+
223
+ function getEzTocListElementLinkByHeading( heading ) {
224
+ return $( '.ez-toc-widget-container .ez-toc-list a[href="#' + $( heading ).attr( 'id' ) + '"]' );
225
+ }
226
+
227
+ function getHeadingToListElementLinkMap( headings ) {
228
+ return headings.reduce( function ( map, heading ) {
229
+ map[ heading.id ] = getEzTocListElementLinkByHeading( heading );
230
+ return map;
231
+ }, {} );
232
+ }
233
+
234
+ function getScrollOffset() {
235
+ var scrollOffset = 5; // so if smooth offset is off, the correct title is set as active
236
+ if ( typeof ezTOC.smooth_scroll != 'undefined' && parseInt( ezTOC.smooth_scroll ) === 1 ) {
237
+ scrollOffset = ( typeof ezTOC.scroll_offset != 'undefined' ) ? parseInt( ezTOC.scroll_offset ) : 30;
238
+ }
239
+
240
+ var adminbar = $( '#wpadminbar' );
241
+
242
+ if ( adminbar.length ) {
243
+ scrollOffset += adminbar.height();
244
+ }
245
+ return scrollOffset;
246
+ }
247
+
248
+ function getActiveHeading( topOffset, headings ) {
249
+ var scrollTop = $( window ).scrollTop();
250
+ var relevantOffset = scrollTop + topOffset + 1;
251
+ var activeHeading = headings[ 0 ];
252
+ var closestHeadingAboveOffset = relevantOffset - $( activeHeading ).offset().top;
253
+ headings.forEach( function ( section ) {
254
+ var topOffset = relevantOffset - $( section ).offset().top;
255
+ if ( topOffset > 0 && topOffset < closestHeadingAboveOffset ) {
256
+ closestHeadingAboveOffset = topOffset;
257
+ activeHeading = section;
258
+ }
259
+ } );
260
+ return activeHeading;
261
+ }
262
+
263
+ function removeStyleFromNonActiveListElement( activeListElementLink, listElementLinks ) {
264
+ listElementLinks.forEach( function ( listElementLink ) {
265
+ if ( activeListElementLink !== listElementLink && listElementLink.parent().hasClass( 'active' ) ) {
266
+ listElementLink.parent().removeClass( 'active' );
267
+ }
268
+ } );
269
+ }
270
+
271
+ function correctActiveListElementBackgroundColorHeight( activeListElement ) {
272
+ var listElementHeight = getListElementHeightWithoutUlChildren( activeListElement );
273
+ addListElementBackgroundColorHeightStyleToHead( listElementHeight );
274
+ }
275
+
276
+ function getListElementHeightWithoutUlChildren( listElement ) {
277
+ var $listElement = $( listElement );
278
+ var content = $listElement.html();
279
+ // Adding list item with class '.active' to get the real height.
280
+ // When adding a class to an existing element and using jQuery(..).height() directly afterwards,
281
+ // the height is the 'old' height. The height might change due to text-wraps when setting the text-weight bold for example
282
+ // When adding a new item, the height is calculated correctly.
283
+ // But only when it might be visible (so display:none; is not possible...)
284
+ // But because it get's directly removed afterwards it never will be rendered by the browser
285
+ // (at least in my tests in FF, Chrome, IE11 and Edge)
286
+ $listElement.parent().append( '<li id="ez-toc-height-test" class="active">' + content + '</li>' );
287
+ var listItem = $( '#ez-toc-height-test' );
288
+ var height = listItem.height();
289
+ listItem.remove();
290
+ return height - $listElement.children( 'ul' ).first().height();
291
+ }
292
+
293
+ function addListElementBackgroundColorHeightStyleToHead( listElementHeight ) {
294
+ // Remove existing
295
+ $( '#ez-toc-active-height' ).remove();
296
+ // jQuery(..).css(..) doesn't work, because ::before is a pseudo element and not part of the DOM
297
+ // Workaround is to add it to head
298
+ $( '<style id="ez-toc-active-height">' +
299
+ '.ez-toc-widget-container ul.ez-toc-list li.active::before {' +
300
+ // 'line-heigh:' + listElementHeight + 'px; ' +
301
+ 'height:' + listElementHeight + 'px;' +
302
+ '} </style>' )
303
+ .appendTo( 'head' );
304
+ }
305
+
306
+ function setStyleForActiveListElementElement( activeListElementLink ) {
307
+ var activeListElement = activeListElementLink.parent();
308
+ if ( !activeListElement.hasClass( 'active' ) ) {
309
+ activeListElement.addClass( 'active' );
310
+ }
311
+ correctActiveListElementBackgroundColorHeight( activeListElement );
312
+ }
313
+ }
314
+
315
+ /**
316
+ * Attach global init handler to ezTOC window object.
317
+ */
318
+ ezTOC.init = function(){
319
+ ezTOCInit();
320
+ }
321
+ // Start EZ TOC on page load.
322
+ ezTOCInit();
323
+ }
324
+ } );
easy-table-of-contents.php CHANGED
@@ -1,764 +1,764 @@
1
- <?php
2
- /**
3
- * Plugin Name: Easy Table of Contents
4
- * Plugin URI: https://magazine3.company/
5
- * Description: Adds a user friendly and fully automatic way to create and display a table of contents generated from the page content.
6
- * Version: 2.0.25
7
- * Author: Magazine3
8
- * Author URI: https://magazine3.company/
9
- * Text Domain: easy-table-of-contents
10
- * Domain Path: /languages
11
- *
12
- * Copyright 2022 Magazine3 ( email : team@magazine3.in )
13
- *
14
- * Easy Table of Contents is free software; you can redistribute it and/or modify
15
- * it under the terms of the GNU General Public License, version 2, as
16
- * published by the Free Software Foundation.
17
- *
18
- * This program is distributed in the hope that it will be useful,
19
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
- * GNU General Public License for more details.
22
- *
23
- * You should have received a copy of the GNU General Public License
24
- * along with Easy Table of Contents; if not, see <http://www.gnu.org/licenses/>.
25
- *
26
- * @package Easy Table of Contents
27
- * @category Plugin
28
- * @author Magazine3
29
- * @version 2.0.25
30
- */
31
-
32
- use Easy_Plugins\Table_Of_Contents\Debug;
33
- use function Easy_Plugins\Table_Of_Contents\String\mb_find_replace;
34
-
35
- // Exit if accessed directly
36
- if ( ! defined( 'ABSPATH' ) ) exit;
37
-
38
- if ( ! class_exists( 'ezTOC' ) ) {
39
-
40
- /**
41
- * Class ezTOC
42
- */
43
- final class ezTOC {
44
-
45
- /**
46
- * Current version.
47
- *
48
- * @since 1.0
49
- * @var string
50
- */
51
- const VERSION = '2.0.25';
52
-
53
- /**
54
- * Stores the instance of this class.
55
- *
56
- * @access private
57
- * @since 1.0
58
- * @static
59
- *
60
- * @var ezTOC
61
- */
62
- private static $instance;
63
-
64
- /**
65
- * @since 2.0
66
- * @var array
67
- */
68
- private static $store = array();
69
-
70
- /**
71
- * A dummy constructor to prevent the class from being loaded more than once.
72
- *
73
- * @access public
74
- * @since 1.0
75
- */
76
- public function __construct() { /* Do nothing here */ }
77
-
78
- /**
79
- * @access private
80
- * @since 1.0
81
- * @static
82
- *
83
- * @return ezTOC
84
- */
85
- public static function instance() {
86
-
87
- if ( ! isset( self::$instance ) && ! ( self::$instance instanceof self ) ) {
88
-
89
- self::$instance = new self;
90
-
91
- self::defineConstants();
92
- self::includes();
93
- self::hooks();
94
-
95
- self::loadTextdomain();
96
- }
97
-
98
- return self::$instance;
99
- }
100
-
101
- /**
102
- * Define the plugin constants.
103
- *
104
- * @access private
105
- * @since 1.0
106
- * @static
107
- */
108
- private static function defineConstants() {
109
-
110
- define( 'EZ_TOC_DIR_NAME', plugin_basename( dirname( __FILE__ ) ) );
111
- define( 'EZ_TOC_BASE_NAME', plugin_basename( __FILE__ ) );
112
- define( 'EZ_TOC_PATH', dirname( __FILE__ ) );
113
- define( 'EZ_TOC_URL', plugin_dir_url( __FILE__ ) );
114
- }
115
-
116
- /**
117
- * Includes the plugin dependency files.
118
- *
119
- * @access private
120
- * @since 1.0
121
- * @static
122
- */
123
- private static function includes() {
124
-
125
- require_once( EZ_TOC_PATH . '/includes/class.options.php' );
126
-
127
- if ( is_admin() ) {
128
-
129
- // This must be included after `class.options.php` because it depends on it methods.
130
- require_once( EZ_TOC_PATH . '/includes/class.admin.php' );
131
- }
132
-
133
- require_once( EZ_TOC_PATH . '/includes/class.post.php' );
134
- require_once( EZ_TOC_PATH . '/includes/class.widget-toc.php' );
135
- require_once( EZ_TOC_PATH . '/includes/Debug.php' );
136
- require_once( EZ_TOC_PATH . '/includes/inc.functions.php' );
137
- require_once( EZ_TOC_PATH . '/includes/inc.string-functions.php' );
138
-
139
- require_once( EZ_TOC_PATH . '/includes/inc.plugin-compatibility.php' );
140
- }
141
-
142
- /**
143
- * Add the core action filter hook.
144
- *
145
- * @access private
146
- * @since 1.0
147
- * @static
148
- */
149
- private static function hooks() {
150
-
151
- //add_action( 'plugins_loaded', array( __CLASS__, 'loadTextdomain' ) );
152
- add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueueScripts' ) );
153
-
154
- // Run after shortcodes are interpreted (priority 10).
155
- add_filter( 'the_content', array( __CLASS__, 'the_content' ), 100 );
156
- add_shortcode( 'ez-toc', array( __CLASS__, 'shortcode' ) );
157
- add_shortcode( 'lwptoc', array( __CLASS__, 'shortcode' ) );
158
- add_shortcode( apply_filters( 'ez_toc_shortcode', 'toc' ), array( __CLASS__, 'shortcode' ) );
159
- }
160
-
161
- /**
162
- * Load the plugin translation.
163
- *
164
- * Credit: Adapted from Ninja Forms / Easy Digital Downloads.
165
- *
166
- * @access private
167
- * @since 1.0
168
- * @static
169
- *
170
- * @uses apply_filters()
171
- * @uses get_locale()
172
- * @uses load_textdomain()
173
- * @uses load_plugin_textdomain()
174
- *
175
- * @return void
176
- */
177
- public static function loadTextdomain() {
178
-
179
- // Plugin textdomain. This should match the one set in the plugin header.
180
- $domain = 'easy-table-of-contents';
181
-
182
- // Set filter for plugin's languages directory
183
- $languagesDirectory = apply_filters( "ez_{$domain}_languages_directory", EZ_TOC_DIR_NAME . '/languages/' );
184
-
185
- // Traditional WordPress plugin locale filter
186
- $locale = apply_filters( 'plugin_locale', get_locale(), $domain );
187
- $fileName = sprintf( '%1$s-%2$s.mo', $domain, $locale );
188
-
189
- // Setup paths to current locale file
190
- $local = $languagesDirectory . $fileName;
191
- $global = WP_LANG_DIR . "/{$domain}/" . $fileName;
192
-
193
- if ( file_exists( $global ) ) {
194
-
195
- // Look in global `../wp-content/languages/{$domain}/` folder.
196
- load_textdomain( $domain, $global );
197
-
198
- } elseif ( file_exists( $local ) ) {
199
-
200
- // Look in local `../wp-content/plugins/{plugin-directory}/languages/` folder.
201
- load_textdomain( $domain, $local );
202
-
203
- } else {
204
-
205
- // Load the default language files
206
- load_plugin_textdomain( $domain, false, $languagesDirectory );
207
- }
208
- }
209
-
210
- /**
211
- * Call back for the `wp_enqueue_scripts` action.
212
- *
213
- * Register and enqueue CSS and javascript files for frontend.
214
- *
215
- * @access private
216
- * @since 1.0
217
- * @static
218
- */
219
- public static function enqueueScripts() {
220
-
221
- // If SCRIPT_DEBUG is set and TRUE load the non-minified JS files, otherwise, load the minified files.
222
- $min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
223
-
224
- $js_vars = array();
225
-
226
- $isEligible = self::is_eligible( get_post() );
227
-
228
- if ( ! $isEligible && ! is_active_widget( false, false, 'ezw_tco' ) ) {
229
- return false;
230
- }
231
-
232
- wp_register_style( 'ez-icomoon', EZ_TOC_URL . "vendor/icomoon/style$min.css", array(), ezTOC::VERSION );
233
- if (!ezTOC_Option::get( 'inline_css' )) {
234
- wp_register_style( 'ez-toc', EZ_TOC_URL . "assets/css/screen$min.css", array( 'ez-icomoon' ), ezTOC::VERSION );
235
- }
236
- wp_register_script( 'js-cookie', EZ_TOC_URL . "vendor/js-cookie/js.cookie$min.js", array(), '2.2.1', TRUE );
237
- wp_register_script( 'jquery-smooth-scroll', EZ_TOC_URL . "vendor/smooth-scroll/jquery.smooth-scroll$min.js", array( 'jquery' ), '2.2.0', TRUE );
238
- wp_register_script( 'jquery-sticky-kit', EZ_TOC_URL . "vendor/sticky-kit/jquery.sticky-kit$min.js", array( 'jquery' ), '1.9.2', TRUE );
239
-
240
- if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
241
- wp_register_script(
242
- 'ez-toc-js',
243
- EZ_TOC_URL . "assets/js/front{$min}.js",
244
- array( 'jquery-smooth-scroll', 'js-cookie', 'jquery-sticky-kit' ),
245
- ezTOC::VERSION . '-' . filemtime( EZ_TOC_PATH . "/assets/js/front{$min}.js" ),
246
- true
247
- );
248
- }
249
-
250
- if ( ! ezTOC_Option::get( 'exclude_css' ) ) {
251
-
252
- wp_enqueue_style( 'ez-toc' );
253
- self::inlineCSS();
254
- }
255
-
256
- if ( ezTOC_Option::get( 'smooth_scroll' ) ) {
257
-
258
- $js_vars['smooth_scroll'] = true;
259
- }
260
-
261
- //wp_enqueue_script( 'ez-toc-js' );
262
-
263
- if ( ezTOC_Option::get( 'show_heading_text' ) && ezTOC_Option::get( 'visibility' ) ) {
264
-
265
- $width = ezTOC_Option::get( 'width' ) !== 'custom' ? ezTOC_Option::get( 'width' ) : ezTOC_Option::get( 'width_custom' ) . ezTOC_Option::get( 'width_custom_units' );
266
-
267
- $js_vars['visibility_hide_by_default'] = ezTOC_Option::get( 'visibility_hide_by_default' ) ? true : false;
268
-
269
- $js_vars['width'] = esc_js( $width );
270
- }else{
271
- if(ezTOC_Option::get( 'visibility' )){
272
- $js_vars['visibility_hide_by_default'] = ezTOC_Option::get( 'visibility_hide_by_default' ) ? true : false;
273
- }
274
- }
275
-
276
- $offset = wp_is_mobile() ? ezTOC_Option::get( 'mobile_smooth_scroll_offset', 0 ) : ezTOC_Option::get( 'smooth_scroll_offset', 30 );
277
-
278
- $js_vars['scroll_offset'] = esc_js( $offset );
279
-
280
- if ( ezTOC_Option::get( 'widget_affix_selector' ) ) {
281
-
282
- $js_vars['affixSelector'] = ezTOC_Option::get( 'widget_affix_selector' );
283
- }
284
-
285
- if ( 0 < count( $js_vars ) ) {
286
-
287
- wp_localize_script( 'ez-toc-js', 'ezTOC', $js_vars );
288
- }
289
- }
290
-
291
- /**
292
- * Prints out inline CSS after the core CSS file to allow overriding core styles via options.
293
- *
294
- * @access private
295
- * @since 1.0
296
- * @static
297
- */
298
- public static function inlineCSS() {
299
-
300
- $css = '';
301
-
302
- if ( ! ezTOC_Option::get( 'exclude_css' ) ) {
303
-
304
- $css .= 'div#ez-toc-container p.ez-toc-title {font-size: ' . ezTOC_Option::get( 'title_font_size', 120 ) . ezTOC_Option::get( 'title_font_size_units', '%' ) . ';}';
305
- $css .= 'div#ez-toc-container p.ez-toc-title {font-weight: ' . ezTOC_Option::get( 'title_font_weight', 500 ) . ';}';
306
- $css .= 'div#ez-toc-container ul li {font-size: ' . ezTOC_Option::get( 'font_size' ) . ezTOC_Option::get( 'font_size_units' ) . ';}';
307
- $css .= 'div#ez-toc-container nav ul ul li ul li {font-size: ' . ezTOC_Option::get( 'child_font_size' ) . ezTOC_Option::get( 'font_size_units' ) . '!important;}';
308
-
309
- if ( ezTOC_Option::get( 'theme' ) === 'custom' || ezTOC_Option::get( 'width' ) != 'auto' ) {
310
-
311
- $css .= 'div#ez-toc-container {';
312
-
313
- if ( ezTOC_Option::get( 'theme' ) === 'custom' ) {
314
-
315
- $css .= 'background: ' . ezTOC_Option::get( 'custom_background_colour' ) . ';border: 1px solid ' . ezTOC_Option::get( 'custom_border_colour' ) . ';';
316
- }
317
-
318
- if ( 'auto' !== ezTOC_Option::get( 'width' ) ) {
319
-
320
- $css .= 'width: ';
321
-
322
- if ( 'custom' !== ezTOC_Option::get( 'width' ) ) {
323
-
324
- $css .= ezTOC_Option::get( 'width' );
325
-
326
- } else {
327
-
328
- $css .= ezTOC_Option::get( 'width_custom' ) . ezTOC_Option::get( 'width_custom_units' );
329
- }
330
-
331
- $css .= ';';
332
- }
333
-
334
- $css .= '}';
335
- }
336
-
337
- if ( 'custom' === ezTOC_Option::get( 'theme' ) ) {
338
-
339
- $css .= 'div#ez-toc-container p.ez-toc-title {color: ' . ezTOC_Option::get( 'custom_title_colour' ) . ';}';
340
- //$css .= 'div#ez-toc-container p.ez-toc-title a,div#ez-toc-container ul.ez-toc-list a {color: ' . ezTOC_Option::get( 'custom_link_colour' ) . ';}';
341
- $css .= 'div#ez-toc-container ul.ez-toc-list a {color: ' . ezTOC_Option::get( 'custom_link_colour' ) . ';}';
342
- $css .= 'div#ez-toc-container ul.ez-toc-list a:hover {color: ' . ezTOC_Option::get( 'custom_link_hover_colour' ) . ';}';
343
- $css .= 'div#ez-toc-container ul.ez-toc-list a:visited {color: ' . ezTOC_Option::get( 'custom_link_visited_colour' ) . ';}';
344
- }
345
- }
346
-
347
- if ( $css ) {
348
-
349
- wp_add_inline_style( 'ez-toc', $css );
350
- }
351
- }
352
-
353
- /**
354
- * Array search deep.
355
- *
356
- * Search an array recursively for a value.
357
- *
358
- * @link https://stackoverflow.com/a/5427665/5351316
359
- *
360
- * @param $search
361
- * @param array $array
362
- * @param string $mode
363
- *
364
- * @return bool
365
- */
366
- public static function array_search_deep( $search, array $array, $mode = 'value' ) {
367
-
368
- foreach ( new RecursiveIteratorIterator( new RecursiveArrayIterator( $array ) ) as $key => $value ) {
369
-
370
- if ( $search === ${${"mode"}} ) {
371
- return true;
372
- }
373
- }
374
-
375
- return false;
376
- }
377
-
378
- /**
379
- * Returns true if the table of contents is eligible to be printed, false otherwise.
380
- *
381
- * NOTE: Must bve use only within the loop.
382
- *
383
- * @access public
384
- * @since 1.0
385
- * @static
386
- *
387
- * @param WP_Post $post
388
- *
389
- * @return bool
390
- */
391
- public static function is_eligible( $post ) {
392
-
393
- //global $wp_current_filter;
394
-
395
- if ( empty( $post ) || ! $post instanceof WP_Post ) {
396
-
397
- Debug::log( 'not_instance_of_post', 'Not an instance if `WP_Post`.', $post );
398
- return false;
399
- }
400
-
401
- // This can likely be removed since it is checked in maybeApplyTheContentFilter().
402
- // Do not execute if root filter is one of those in the array.
403
- //if ( in_array( $wp_current_filter[0], array( 'get_the_excerpt', 'wp_head' ), true ) ) {
404
- //
405
- // return false;
406
- //}
407
-
408
- if ( has_shortcode( $post->post_content, apply_filters( 'ez_toc_shortcode', 'toc' ) ) ||
409
- has_shortcode( $post->post_content, 'ez-toc' ) ) {
410
-
411
- Debug::log( 'has_ez_toc_shortcode', 'Has instance of shortcode.', true );
412
- return true;
413
- }
414
-
415
- if ( is_front_page() && ! ezTOC_Option::get( 'include_homepage' ) ) {
416
-
417
- Debug::log( 'is_front_page', 'Is frontpage, TOC is not enabled.', false );
418
- return false;
419
- }
420
-
421
- $type = get_post_type( $post->ID );
422
-
423
- Debug::log( 'current_post_type', 'Post type is.', $type );
424
-
425
- $enabled = in_array( $type, ezTOC_Option::get( 'enabled_post_types', array() ), true );
426
- $insert = in_array( $type, ezTOC_Option::get( 'auto_insert_post_types', array() ), true );
427
-
428
- Debug::log( 'is_supported_post_type', 'Is supported post type?', $enabled );
429
- Debug::log( 'is_auto_insert_post_type', 'Is auto insert for post types?', $insert );
430
-
431
- if ( $insert || $enabled ) {
432
-
433
- if ( ezTOC_Option::get( 'restrict_path' ) ) {
434
-
435
- /**
436
- * @link https://wordpress.org/support/topic/restrict-path-logic-does-not-work-correctly?
437
- */
438
- if ( false !== strpos( ezTOC_Option::get( 'restrict_path' ), $_SERVER['REQUEST_URI'] ) ) {
439
-
440
- Debug::log( 'is_restricted_path', 'In restricted path, post not eligible.', ezTOC_Option::get( 'restrict_path' ) );
441
- return false;
442
-
443
- } else {
444
-
445
- Debug::log( 'is_not_restricted_path', 'Not in restricted path, post is eligible.', ezTOC_Option::get( 'restrict_path' ) );
446
- return true;
447
- }
448
-
449
- } else {
450
-
451
- if ( $insert && 1 === (int) get_post_meta( $post->ID, '_ez-toc-disabled', true ) ) {
452
-
453
- Debug::log( 'is_auto_insert_disable_post_meta', 'Auto insert enabled and disable TOC is enabled in post meta.', false );
454
- return false;
455
-
456
- } elseif ( $insert && 0 === (int) get_post_meta( $post->ID, '_ez-toc-disabled', true ) ) {
457
-
458
- Debug::log( 'is_auto_insert_enabled_post_meta', 'Auto insert enabled and disable TOC is not enabled in post meta.', true );
459
- return true;
460
-
461
- } elseif ( $enabled && 1 === (int) get_post_meta( $post->ID, '_ez-toc-insert', true ) ) {
462
-
463
- Debug::log( 'is_supported_post_type_disable_insert_post_meta', 'Supported post type and insert TOC is enabled in post meta.', true );
464
- return true;
465
-
466
- } elseif ( $enabled && $insert ) {
467
-
468
- Debug::log( 'supported_post_type_and_auto_insert', 'Supported post type and auto insert TOC is enabled.', true );
469
- return true;
470
- }
471
-
472
- Debug::log( 'not_auto_insert_or_not_supported_post_type', 'Not supported post type or insert TOC is disabled.', false );
473
- return false;
474
- }
475
-
476
- } else {
477
-
478
- Debug::log( 'not_auto_insert_and_not_supported post_type', 'Not supported post type and do not auto insert TOC.', false );
479
- return false;
480
- }
481
- }
482
-
483
- /**
484
- * Get TOC from store and if not in store process post and add it to the store.
485
- *
486
- * @since 2.0
487
- *
488
- * @param int $id
489
- *
490
- * @return ezTOC_Post|null
491
- */
492
- public static function get( $id ) {
493
-
494
- $post = null;
495
-
496
- if ( isset( self::$store[ $id ] ) && self::$store[ $id ] instanceof ezTOC_Post ) {
497
-
498
- $post = self::$store[ $id ];
499
-
500
- } else {
501
-
502
- $post = ezTOC_Post::get( get_the_ID() );
503
-
504
- if ( $post instanceof ezTOC_Post ) {
505
-
506
- self::$store[ $id ] = $post;
507
- }
508
- }
509
-
510
- return $post;
511
- }
512
-
513
- /**
514
- * Callback for the registered shortcode `[ez-toc]`
515
- *
516
- * NOTE: Shortcode is run before the callback @see ezTOC::the_content() for the `the_content` filter
517
- *
518
- * @access private
519
- * @since 1.3
520
- *
521
- * @param array|string $atts Shortcode attributes array or empty string.
522
- * @param string $content The enclosed content (if the shortcode is used in its enclosing form)
523
- * @param string $tag Shortcode name.
524
- *
525
- * @return string
526
- */
527
- public static function shortcode( $atts, $content, $tag ) {
528
-
529
- static $run = true;
530
- $html = '';
531
-
532
- if ( $run ) {
533
-
534
- $post = self::get( get_the_ID() );
535
-
536
- if ( ! $post instanceof ezTOC_Post ) {
537
-
538
- Debug::log( 'not_instance_of_post', 'Not an instance if `WP_Post`.', get_the_ID() );
539
-
540
- return Debug::log()->appendTo( $content );
541
- }
542
-
543
- $html = $post->getTOC();
544
- $run = false;
545
- }
546
- if (isset($atts["initial_view"]) && !empty($atts["initial_view"]) && $atts["initial_view"] == 'hide') {
547
- $html = preg_replace('/class="ez-toc-list ez-toc-list-level-1"/', 'class="ez-toc-list ez-toc-list-level-1" style="display:none"', $html);
548
- }
549
-
550
- return $html;
551
- }
552
-
553
- /**
554
- * Whether or not apply `the_content` filter.
555
- *
556
- * @since 2.0
557
- *
558
- * @return bool
559
- */
560
- private static function maybeApplyTheContentFilter() {
561
-
562
- $apply = true;
563
-
564
- global $wp_current_filter;
565
-
566
- // Do not execute if root current filter is one of those in the array.
567
- if ( in_array( $wp_current_filter[0], array( 'get_the_excerpt', 'init', 'wp_head' ), true ) ) {
568
-
569
- $apply = false;
570
- }
571
-
572
- // bail if feed, search or archive
573
- if ( is_feed() || is_search() || is_archive() ) {
574
-
575
- $apply = false;
576
- }
577
-
578
- /**
579
- * Whether or not to apply `the_content` filter callback.
580
- *
581
- * @see ezTOC::the_content()
582
- *
583
- * @since 2.0
584
- *
585
- * @param bool $apply
586
- */
587
- return apply_filters( 'ez_toc_maybe_apply_the_content_filter', $apply );
588
- }
589
-
590
- /**
591
- * Callback for the `the_content` filter.
592
- *
593
- * This will add the inline table of contents page anchors to the post content. It will also insert the
594
- * table of contents inline with the post content as defined by the user defined preference.
595
- *
596
- * @since 1.0
597
- *
598
- * @param string $content
599
- *
600
- * @return string
601
- */
602
- public static function the_content( $content ) {
603
- $maybeApplyFilter = self::maybeApplyTheContentFilter();
604
-
605
- Debug::log( 'the_content_filter', 'The `the_content` filter applied.', $maybeApplyFilter );
606
-
607
- if ( ! $maybeApplyFilter ) {
608
-
609
- return Debug::log()->appendTo( $content );
610
- }
611
-
612
- // Bail if post not eligible and widget is not active.
613
- $isEligible = self::is_eligible( get_post() );
614
- $isEligible = apply_filters('eztoc_do_shortcode',$isEligible);
615
- Debug::log( 'post_eligible', 'Post eligible.', $isEligible );
616
-
617
- if ( ! $isEligible && ! is_active_widget( false, false, 'ezw_tco' ) ) {
618
-
619
- return Debug::log()->appendTo( $content );
620
- }
621
-
622
- $post = self::get( get_the_ID() );
623
-
624
- if ( ! $post instanceof ezTOC_Post ) {
625
-
626
- Debug::log( 'not_instance_of_post', 'Not an instance if `WP_Post`.', get_the_ID() );
627
-
628
- return Debug::log()->appendTo( $content );
629
- }
630
-
631
- // Bail if no headings found.
632
- if ( ! $post->hasTOCItems() ) {
633
-
634
- return Debug::log()->appendTo( $content );
635
- }
636
-
637
- $find = $post->getHeadings();
638
- $replace = $post->getHeadingsWithAnchors();
639
- $toc = $post->getTOC();
640
- $headings = implode( PHP_EOL, $find );
641
- $anchors = implode( PHP_EOL, $replace );
642
-
643
- $headingRows = count( $find ) + 1;
644
- $anchorRows = count( $replace ) + 1;
645
-
646
- $style = "background-image: linear-gradient(#F1F1F1 50%, #F9F9F9 50%); background-size: 100% 4em; border: 1px solid #CCC; font-family: monospace; font-size: 1em; line-height: 2em; margin: 0 auto; overflow: auto; padding: 0 8px 4px; white-space: nowrap; width: 100%;";
647
-
648
- Debug::log(
649
- 'found_post_headings',
650
- 'Found headings:',
651
- "<textarea rows='{$headingRows}' style='{$style}' wrap='soft'>{$headings}</textarea>"
652
- );
653
-
654
- Debug::log(
655
- 'replace_post_headings',
656
- 'Replace found headings with:',
657
- "<textarea rows='{$anchorRows}' style='{$style}' wrap='soft'>{$anchors}</textarea>"
658
- );
659
-
660
- // If shortcode used or post not eligible, return content with anchored headings.
661
- if ( strpos( $content, 'ez-toc-container' ) || ! $isEligible ) {
662
-
663
- Debug::log( 'shortcode_found', 'Shortcode found, add links to content.', true );
664
-
665
- return mb_find_replace( $find, $replace, $content );
666
- }
667
-
668
- $position = ezTOC_Option::get( 'position' );
669
-
670
- Debug::log( 'toc_insert_position', 'Insert TOC at position', $position );
671
-
672
- // else also add toc to content
673
- switch ( $position ) {
674
-
675
- case 'top':
676
- $content = $toc . mb_find_replace( $find, $replace, $content );
677
- break;
678
-
679
- case 'bottom':
680
- $content = mb_find_replace( $find, $replace, $content ) . $toc;
681
- break;
682
-
683
- case 'after':
684
- $replace[0] = $replace[0] . $toc;
685
- $content = mb_find_replace( $find, $replace, $content );
686
- break;
687
-
688
- case 'before':
689
- default:
690
- //$replace[0] = $html . $replace[0];
691
- $content = mb_find_replace( $find, $replace, $content );
692
-
693
- /**
694
- * @link https://wordpress.org/support/topic/php-notice-undefined-offset-8/
695
- */
696
- if ( ! array_key_exists( 0, $replace ) ) {
697
- break;
698
- }
699
-
700
- $pattern = '`<h[1-6]{1}[^>]*' . preg_quote( $replace[0], '`' ) . '`msuU';
701
- $result = preg_match( $pattern, $content, $matches );
702
-
703
- /*
704
- * Try to place TOC before the first heading found in eligible heading, failing that,
705
- * insert TOC at top of content.
706
- */
707
- if ( 1 === $result ) {
708
-
709
- Debug::log( 'toc_insert_position_found', 'Insert TOC before first eligible heading.', $result );
710
-
711
- $start = strpos( $content, $matches[0] );
712
- $content = substr_replace( $content, $toc, $start, 0 );
713
-
714
- } else {
715
-
716
- Debug::log( 'toc_insert_position_not_found', 'Insert TOC before first eligible heading not found.', $result );
717
-
718
- // Somehow, there are scenarios where the processing get this far and
719
- // the TOC is being added to pages where it should not. Disable for now.
720
- //$content = $html . $content;
721
- }
722
- }
723
-
724
- return Debug::log()->appendTo( $content );
725
- }
726
-
727
- }
728
-
729
- /**
730
- * The main function responsible for returning the Easy Table of Contents instance to functions everywhere.
731
- *
732
- * Use this function like you would a global variable, except without needing to declare the global.
733
- *
734
- * Example: <?php $instance = ezTOC(); ?>
735
- *
736
- * @access public
737
- * @since 1.0
738
- *
739
- * @return ezTOC
740
- */
741
- function ezTOC() {
742
-
743
- return ezTOC::instance();
744
- }
745
-
746
- // Start Easy Table of Contents.
747
- add_action( 'plugins_loaded', 'ezTOC' );
748
- }
749
- register_activation_hook(__FILE__, 'ez_toc_activate');
750
- add_action('admin_init', 'ez_toc_redirect');
751
-
752
- function ez_toc_activate() {
753
- add_option('ez_toc_do_activation_redirect', true);
754
- }
755
-
756
- function ez_toc_redirect() {
757
- if (get_option('ez_toc_do_activation_redirect', false)) {
758
- delete_option('ez_toc_do_activation_redirect');
759
- if(!isset($_GET['activate-multi']))
760
- {
761
- wp_redirect("options-general.php?page=table-of-contents#welcome");
762
- }
763
- }
764
- }
1
+ <?php
2
+ /**
3
+ * Plugin Name: Easy Table of Contents
4
+ * Plugin URI: https://magazine3.company/
5
+ * Description: Adds a user friendly and fully automatic way to create and display a table of contents generated from the page content.
6
+ * Version: 2.0.25.1
7
+ * Author: Magazine3
8
+ * Author URI: https://magazine3.company/
9
+ * Text Domain: easy-table-of-contents
10
+ * Domain Path: /languages
11
+ *
12
+ * Copyright 2022 Magazine3 ( email : team@magazine3.in )
13
+ *
14
+ * Easy Table of Contents is free software; you can redistribute it and/or modify
15
+ * it under the terms of the GNU General Public License, version 2, as
16
+ * published by the Free Software Foundation.
17
+ *
18
+ * This program is distributed in the hope that it will be useful,
19
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
+ * GNU General Public License for more details.
22
+ *
23
+ * You should have received a copy of the GNU General Public License
24
+ * along with Easy Table of Contents; if not, see <http://www.gnu.org/licenses/>.
25
+ *
26
+ * @package Easy Table of Contents
27
+ * @category Plugin
28
+ * @author Magazine3
29
+ * @version 2.0.25.1
30
+ */
31
+
32
+ use Easy_Plugins\Table_Of_Contents\Debug;
33
+ use function Easy_Plugins\Table_Of_Contents\String\mb_find_replace;
34
+
35
+ // Exit if accessed directly
36
+ if ( ! defined( 'ABSPATH' ) ) exit;
37
+
38
+ if ( ! class_exists( 'ezTOC' ) ) {
39
+
40
+ /**
41
+ * Class ezTOC
42
+ */
43
+ final class ezTOC {
44
+
45
+ /**
46
+ * Current version.
47
+ *
48
+ * @since 1.0
49
+ * @var string
50
+ */
51
+ const VERSION = '2.0.25.1';
52
+
53
+ /**
54
+ * Stores the instance of this class.
55
+ *
56
+ * @access private
57
+ * @since 1.0
58
+ * @static
59
+ *
60
+ * @var ezTOC
61
+ */
62
+ private static $instance;
63
+
64
+ /**
65
+ * @since 2.0
66
+ * @var array
67
+ */
68
+ private static $store = array();
69
+
70
+ /**
71
+ * A dummy constructor to prevent the class from being loaded more than once.
72
+ *
73
+ * @access public
74
+ * @since 1.0
75
+ */
76
+ public function __construct() { /* Do nothing here */ }
77
+
78
+ /**
79
+ * @access private
80
+ * @since 1.0
81
+ * @static
82
+ *
83
+ * @return ezTOC
84
+ */
85
+ public static function instance() {
86
+
87
+ if ( ! isset( self::$instance ) && ! ( self::$instance instanceof self ) ) {
88
+
89
+ self::$instance = new self;
90
+
91
+ self::defineConstants();
92
+ self::includes();
93
+ self::hooks();
94
+
95
+ self::loadTextdomain();
96
+ }
97
+
98
+ return self::$instance;
99
+ }
100
+
101
+ /**
102
+ * Define the plugin constants.
103
+ *
104
+ * @access private
105
+ * @since 1.0
106
+ * @static
107
+ */
108
+ private static function defineConstants() {
109
+
110
+ define( 'EZ_TOC_DIR_NAME', plugin_basename( dirname( __FILE__ ) ) );
111
+ define( 'EZ_TOC_BASE_NAME', plugin_basename( __FILE__ ) );
112
+ define( 'EZ_TOC_PATH', dirname( __FILE__ ) );
113
+ define( 'EZ_TOC_URL', plugin_dir_url( __FILE__ ) );
114
+ }
115
+
116
+ /**
117
+ * Includes the plugin dependency files.
118
+ *
119
+ * @access private
120
+ * @since 1.0
121
+ * @static
122
+ */
123
+ private static function includes() {
124
+
125
+ require_once( EZ_TOC_PATH . '/includes/class.options.php' );
126
+
127
+ if ( is_admin() ) {
128
+
129
+ // This must be included after `class.options.php` because it depends on it methods.
130
+ require_once( EZ_TOC_PATH . '/includes/class.admin.php' );
131
+ }
132
+
133
+ require_once( EZ_TOC_PATH . '/includes/class.post.php' );
134
+ require_once( EZ_TOC_PATH . '/includes/class.widget-toc.php' );
135
+ require_once( EZ_TOC_PATH . '/includes/Debug.php' );
136
+ require_once( EZ_TOC_PATH . '/includes/inc.functions.php' );
137
+ require_once( EZ_TOC_PATH . '/includes/inc.string-functions.php' );
138
+
139
+ require_once( EZ_TOC_PATH . '/includes/inc.plugin-compatibility.php' );
140
+ }
141
+
142
+ /**
143
+ * Add the core action filter hook.
144
+ *
145
+ * @access private
146
+ * @since 1.0
147
+ * @static
148
+ */
149
+ private static function hooks() {
150
+
151
+ //add_action( 'plugins_loaded', array( __CLASS__, 'loadTextdomain' ) );
152
+ add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueueScripts' ) );
153
+
154
+ // Run after shortcodes are interpreted (priority 10).
155
+ add_filter( 'the_content', array( __CLASS__, 'the_content' ), 100 );
156
+ add_shortcode( 'ez-toc', array( __CLASS__, 'shortcode' ) );
157
+ add_shortcode( 'lwptoc', array( __CLASS__, 'shortcode' ) );
158
+ add_shortcode( apply_filters( 'ez_toc_shortcode', 'toc' ), array( __CLASS__, 'shortcode' ) );
159
+ }
160
+
161
+ /**
162
+ * Load the plugin translation.
163
+ *
164
+ * Credit: Adapted from Ninja Forms / Easy Digital Downloads.
165
+ *
166
+ * @access private
167
+ * @since 1.0
168
+ * @static
169
+ *
170
+ * @uses apply_filters()
171
+ * @uses get_locale()
172
+ * @uses load_textdomain()
173
+ * @uses load_plugin_textdomain()
174
+ *
175
+ * @return void
176
+ */
177
+ public static function loadTextdomain() {
178
+
179
+ // Plugin textdomain. This should match the one set in the plugin header.
180
+ $domain = 'easy-table-of-contents';
181
+
182
+ // Set filter for plugin's languages directory
183
+ $languagesDirectory = apply_filters( "ez_{$domain}_languages_directory", EZ_TOC_DIR_NAME . '/languages/' );
184
+
185
+ // Traditional WordPress plugin locale filter
186
+ $locale = apply_filters( 'plugin_locale', get_locale(), $domain );
187
+ $fileName = sprintf( '%1$s-%2$s.mo', $domain, $locale );
188
+
189
+ // Setup paths to current locale file
190
+ $local = $languagesDirectory . $fileName;
191
+ $global = WP_LANG_DIR . "/{$domain}/" . $fileName;
192
+
193
+ if ( file_exists( $global ) ) {
194
+
195
+ // Look in global `../wp-content/languages/{$domain}/` folder.
196
+ load_textdomain( $domain, $global );
197
+
198
+ } elseif ( file_exists( $local ) ) {
199
+
200
+ // Look in local `../wp-content/plugins/{plugin-directory}/languages/` folder.
201
+ load_textdomain( $domain, $local );
202
+
203
+ } else {
204
+
205
+ // Load the default language files
206
+ load_plugin_textdomain( $domain, false, $languagesDirectory );
207
+ }
208
+ }
209
+
210
+ /**
211
+ * Call back for the `wp_enqueue_scripts` action.
212
+ *
213
+ * Register and enqueue CSS and javascript files for frontend.
214
+ *
215
+ * @access private
216
+ * @since 1.0
217
+ * @static
218
+ */
219
+ public static function enqueueScripts() {
220
+
221
+ // If SCRIPT_DEBUG is set and TRUE load the non-minified JS files, otherwise, load the minified files.
222
+ $min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
223
+
224
+ $js_vars = array();
225
+
226
+ $isEligible = self::is_eligible( get_post() );
227
+
228
+ if ( ! $isEligible && ! is_active_widget( false, false, 'ezw_tco' ) ) {
229
+ return false;
230
+ }
231
+
232
+ wp_register_style( 'ez-icomoon', EZ_TOC_URL . "vendor/icomoon/style$min.css", array(), ezTOC::VERSION );
233
+ if (!ezTOC_Option::get( 'inline_css' )) {
234
+ wp_register_style( 'ez-toc', EZ_TOC_URL . "assets/css/screen$min.css", array( 'ez-icomoon' ), ezTOC::VERSION );
235
+ }
236
+ wp_register_script( 'js-cookie', EZ_TOC_URL . "vendor/js-cookie/js.cookie$min.js", array(), '2.2.1', TRUE );
237
+ wp_register_script( 'jquery-smooth-scroll', EZ_TOC_URL . "vendor/smooth-scroll/jquery.smooth-scroll$min.js", array( 'jquery' ), '2.2.0', TRUE );
238
+ wp_register_script( 'jquery-sticky-kit', EZ_TOC_URL . "vendor/sticky-kit/jquery.sticky-kit$min.js", array( 'jquery' ), '1.9.2', TRUE );
239
+
240
+ if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
241
+ wp_register_script(
242
+ 'ez-toc-js',
243
+ EZ_TOC_URL . "assets/js/front{$min}.js",
244
+ array( 'jquery-smooth-scroll', 'js-cookie', 'jquery-sticky-kit' ),
245
+ ezTOC::VERSION . '-' . filemtime( EZ_TOC_PATH . "/assets/js/front{$min}.js" ),
246
+ true
247
+ );
248
+ }
249
+
250
+ if ( ! ezTOC_Option::get( 'exclude_css' ) ) {
251
+
252
+ wp_enqueue_style( 'ez-toc' );
253
+ self::inlineCSS();
254
+ }
255
+
256
+ if ( ezTOC_Option::get( 'smooth_scroll' ) ) {
257
+
258
+ $js_vars['smooth_scroll'] = true;
259
+ }
260
+
261
+ //wp_enqueue_script( 'ez-toc-js' );
262
+
263
+ if ( ezTOC_Option::get( 'show_heading_text' ) && ezTOC_Option::get( 'visibility' ) ) {
264
+
265
+ $width = ezTOC_Option::get( 'width' ) !== 'custom' ? ezTOC_Option::get( 'width' ) : ezTOC_Option::get( 'width_custom' ) . ezTOC_Option::get( 'width_custom_units' );
266
+
267
+ $js_vars['visibility_hide_by_default'] = ezTOC_Option::get( 'visibility_hide_by_default' ) ? true : false;
268
+
269
+ $js_vars['width'] = esc_js( $width );
270
+ }else{
271
+ if(ezTOC_Option::get( 'visibility' )){
272
+ $js_vars['visibility_hide_by_default'] = ezTOC_Option::get( 'visibility_hide_by_default' ) ? true : false;
273
+ }
274
+ }
275
+
276
+ $offset = wp_is_mobile() ? ezTOC_Option::get( 'mobile_smooth_scroll_offset', 0 ) : ezTOC_Option::get( 'smooth_scroll_offset', 30 );
277
+
278
+ $js_vars['scroll_offset'] = esc_js( $offset );
279
+
280
+ if ( ezTOC_Option::get( 'widget_affix_selector' ) ) {
281
+
282
+ $js_vars['affixSelector'] = ezTOC_Option::get( 'widget_affix_selector' );
283
+ }
284
+
285
+ if ( 0 < count( $js_vars ) ) {
286
+
287
+ wp_localize_script( 'ez-toc-js', 'ezTOC', $js_vars );
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Prints out inline CSS after the core CSS file to allow overriding core styles via options.
293
+ *
294
+ * @access private
295
+ * @since 1.0
296
+ * @static
297
+ */
298
+ public static function inlineCSS() {
299
+
300
+ $css = '';
301
+
302
+ if ( ! ezTOC_Option::get( 'exclude_css' ) ) {
303
+
304
+ $css .= 'div#ez-toc-container p.ez-toc-title {font-size: ' . ezTOC_Option::get( 'title_font_size', 120 ) . ezTOC_Option::get( 'title_font_size_units', '%' ) . ';}';
305
+ $css .= 'div#ez-toc-container p.ez-toc-title {font-weight: ' . ezTOC_Option::get( 'title_font_weight', 500 ) . ';}';
306
+ $css .= 'div#ez-toc-container ul li {font-size: ' . ezTOC_Option::get( 'font_size' ) . ezTOC_Option::get( 'font_size_units' ) . ';}';
307
+ $css .= 'div#ez-toc-container nav ul ul li ul li {font-size: ' . ezTOC_Option::get( 'child_font_size' ) . ezTOC_Option::get( 'font_size_units' ) . '!important;}';
308
+
309
+ if ( ezTOC_Option::get( 'theme' ) === 'custom' || ezTOC_Option::get( 'width' ) != 'auto' ) {
310
+
311
+ $css .= 'div#ez-toc-container {';
312
+
313
+ if ( ezTOC_Option::get( 'theme' ) === 'custom' ) {
314
+
315
+ $css .= 'background: ' . ezTOC_Option::get( 'custom_background_colour' ) . ';border: 1px solid ' . ezTOC_Option::get( 'custom_border_colour' ) . ';';
316
+ }
317
+
318
+ if ( 'auto' !== ezTOC_Option::get( 'width' ) ) {
319
+
320
+ $css .= 'width: ';
321
+
322
+ if ( 'custom' !== ezTOC_Option::get( 'width' ) ) {
323
+
324
+ $css .= ezTOC_Option::get( 'width' );
325
+
326
+ } else {
327
+
328
+ $css .= ezTOC_Option::get( 'width_custom' ) . ezTOC_Option::get( 'width_custom_units' );
329
+ }
330
+
331
+ $css .= ';';
332
+ }
333
+
334
+ $css .= '}';
335
+ }
336
+
337
+ if ( 'custom' === ezTOC_Option::get( 'theme' ) ) {
338
+
339
+ $css .= 'div#ez-toc-container p.ez-toc-title {color: ' . ezTOC_Option::get( 'custom_title_colour' ) . ';}';
340
+ //$css .= 'div#ez-toc-container p.ez-toc-title a,div#ez-toc-container ul.ez-toc-list a {color: ' . ezTOC_Option::get( 'custom_link_colour' ) . ';}';
341
+ $css .= 'div#ez-toc-container ul.ez-toc-list a {color: ' . ezTOC_Option::get( 'custom_link_colour' ) . ';}';
342
+ $css .= 'div#ez-toc-container ul.ez-toc-list a:hover {color: ' . ezTOC_Option::get( 'custom_link_hover_colour' ) . ';}';
343
+ $css .= 'div#ez-toc-container ul.ez-toc-list a:visited {color: ' . ezTOC_Option::get( 'custom_link_visited_colour' ) . ';}';
344
+ }
345
+ }
346
+
347
+ if ( $css ) {
348
+
349
+ wp_add_inline_style( 'ez-toc', $css );
350
+ }
351
+ }
352
+
353
+ /**
354
+ * Array search deep.
355
+ *
356
+ * Search an array recursively for a value.
357
+ *
358
+ * @link https://stackoverflow.com/a/5427665/5351316
359
+ *
360
+ * @param $search
361
+ * @param array $array
362
+ * @param string $mode
363
+ *
364
+ * @return bool
365
+ */
366
+ public static function array_search_deep( $search, array $array, $mode = 'value' ) {
367
+
368
+ foreach ( new RecursiveIteratorIterator( new RecursiveArrayIterator( $array ) ) as $key => $value ) {
369
+
370
+ if ( $search === ${${"mode"}} ) {
371
+ return true;
372
+ }
373
+ }
374
+
375
+ return false;
376
+ }
377
+
378
+ /**
379
+ * Returns true if the table of contents is eligible to be printed, false otherwise.
380
+ *
381
+ * NOTE: Must bve use only within the loop.
382
+ *
383
+ * @access public
384
+ * @since 1.0
385
+ * @static
386
+ *
387
+ * @param WP_Post $post
388
+ *
389
+ * @return bool
390
+ */
391
+ public static function is_eligible( $post ) {
392
+
393
+ //global $wp_current_filter;
394
+
395
+ if ( empty( $post ) || ! $post instanceof WP_Post ) {
396
+
397
+ Debug::log( 'not_instance_of_post', 'Not an instance if `WP_Post`.', $post );
398
+ return false;
399
+ }
400
+
401
+ // This can likely be removed since it is checked in maybeApplyTheContentFilter().
402
+ // Do not execute if root filter is one of those in the array.
403
+ //if ( in_array( $wp_current_filter[0], array( 'get_the_excerpt', 'wp_head' ), true ) ) {
404
+ //
405
+ // return false;
406
+ //}
407
+
408
+ if ( has_shortcode( $post->post_content, apply_filters( 'ez_toc_shortcode', 'toc' ) ) ||
409
+ has_shortcode( $post->post_content, 'ez-toc' ) ) {
410
+
411
+ Debug::log( 'has_ez_toc_shortcode', 'Has instance of shortcode.', true );
412
+ return true;
413
+ }
414
+
415
+ if ( is_front_page() && ! ezTOC_Option::get( 'include_homepage' ) ) {
416
+
417
+ Debug::log( 'is_front_page', 'Is frontpage, TOC is not enabled.', false );
418
+ return false;
419
+ }
420
+
421
+ $type = get_post_type( $post->ID );
422
+
423
+ Debug::log( 'current_post_type', 'Post type is.', $type );
424
+
425
+ $enabled = in_array( $type, ezTOC_Option::get( 'enabled_post_types', array() ), true );
426
+ $insert = in_array( $type, ezTOC_Option::get( 'auto_insert_post_types', array() ), true );
427
+
428
+ Debug::log( 'is_supported_post_type', 'Is supported post type?', $enabled );
429
+ Debug::log( 'is_auto_insert_post_type', 'Is auto insert for post types?', $insert );
430
+
431
+ if ( $insert || $enabled ) {
432
+
433
+ if ( ezTOC_Option::get( 'restrict_path' ) ) {
434
+
435
+ /**
436
+ * @link https://wordpress.org/support/topic/restrict-path-logic-does-not-work-correctly?
437
+ */
438
+ if ( false !== strpos( ezTOC_Option::get( 'restrict_path' ), $_SERVER['REQUEST_URI'] ) ) {
439
+
440
+ Debug::log( 'is_restricted_path', 'In restricted path, post not eligible.', ezTOC_Option::get( 'restrict_path' ) );
441
+ return false;
442
+
443
+ } else {
444
+
445
+ Debug::log( 'is_not_restricted_path', 'Not in restricted path, post is eligible.', ezTOC_Option::get( 'restrict_path' ) );
446
+ return true;
447
+ }
448
+
449
+ } else {
450
+
451
+ if ( $insert && 1 === (int) get_post_meta( $post->ID, '_ez-toc-disabled', true ) ) {
452
+
453
+ Debug::log( 'is_auto_insert_disable_post_meta', 'Auto insert enabled and disable TOC is enabled in post meta.', false );
454
+ return false;
455
+
456
+ } elseif ( $insert && 0 === (int) get_post_meta( $post->ID, '_ez-toc-disabled', true ) ) {
457
+
458
+ Debug::log( 'is_auto_insert_enabled_post_meta', 'Auto insert enabled and disable TOC is not enabled in post meta.', true );
459
+ return true;
460
+
461
+ } elseif ( $enabled && 1 === (int) get_post_meta( $post->ID, '_ez-toc-insert', true ) ) {
462
+
463
+ Debug::log( 'is_supported_post_type_disable_insert_post_meta', 'Supported post type and insert TOC is enabled in post meta.', true );
464
+ return true;
465
+
466
+ } elseif ( $enabled && $insert ) {
467
+
468
+ Debug::log( 'supported_post_type_and_auto_insert', 'Supported post type and auto insert TOC is enabled.', true );
469
+ return true;
470
+ }
471
+
472
+ Debug::log( 'not_auto_insert_or_not_supported_post_type', 'Not supported post type or insert TOC is disabled.', false );
473
+ return false;
474
+ }
475
+
476
+ } else {
477
+
478
+ Debug::log( 'not_auto_insert_and_not_supported post_type', 'Not supported post type and do not auto insert TOC.', false );
479
+ return false;
480
+ }
481
+ }
482
+
483
+ /**
484
+ * Get TOC from store and if not in store process post and add it to the store.
485
+ *
486
+ * @since 2.0
487
+ *
488
+ * @param int $id
489
+ *
490
+ * @return ezTOC_Post|null
491
+ */
492
+ public static function get( $id ) {
493
+
494
+ $post = null;
495
+
496
+ if ( isset( self::$store[ $id ] ) && self::$store[ $id ] instanceof ezTOC_Post ) {
497
+
498
+ $post = self::$store[ $id ];
499
+
500
+ } else {
501
+
502
+ $post = ezTOC_Post::get( get_the_ID() );
503
+
504
+ if ( $post instanceof ezTOC_Post ) {
505
+
506
+ self::$store[ $id ] = $post;
507
+ }
508
+ }
509
+
510
+ return $post;
511
+ }
512
+
513
+ /**
514
+ * Callback for the registered shortcode `[ez-toc]`
515
+ *
516
+ * NOTE: Shortcode is run before the callback @see ezTOC::the_content() for the `the_content` filter
517
+ *
518
+ * @access private
519
+ * @since 1.3
520
+ *
521
+ * @param array|string $atts Shortcode attributes array or empty string.
522
+ * @param string $content The enclosed content (if the shortcode is used in its enclosing form)
523
+ * @param string $tag Shortcode name.
524
+ *
525
+ * @return string
526
+ */
527
+ public static function shortcode( $atts, $content, $tag ) {
528
+
529
+ static $run = true;
530
+ $html = '';
531
+
532
+ if ( $run ) {
533
+
534
+ $post = self::get( get_the_ID() );
535
+
536
+ if ( ! $post instanceof ezTOC_Post ) {
537
+
538
+ Debug::log( 'not_instance_of_post', 'Not an instance if `WP_Post`.', get_the_ID() );
539
+
540
+ return Debug::log()->appendTo( $content );
541
+ }
542
+
543
+ $html = $post->getTOC();
544
+ $run = false;
545
+ }
546
+ if (isset($atts["initial_view"]) && !empty($atts["initial_view"]) && $atts["initial_view"] == 'hide') {
547
+ $html = preg_replace('/class="ez-toc-list ez-toc-list-level-1"/', 'class="ez-toc-list ez-toc-list-level-1" style="display:none"', $html);
548
+ }
549
+
550
+ return $html;
551
+ }
552
+
553
+ /**
554
+ * Whether or not apply `the_content` filter.
555
+ *
556
+ * @since 2.0
557
+ *
558
+ * @return bool
559
+ */
560
+ private static function maybeApplyTheContentFilter() {
561
+
562
+ $apply = true;
563
+
564
+ global $wp_current_filter;
565
+
566
+ // Do not execute if root current filter is one of those in the array.
567
+ if ( in_array( $wp_current_filter[0], array( 'get_the_excerpt', 'init', 'wp_head' ), true ) ) {
568
+
569
+ $apply = false;
570
+ }
571
+
572
+ // bail if feed, search or archive
573
+ if ( is_feed() || is_search() || is_archive() ) {
574
+
575
+ $apply = false;
576
+ }
577
+
578
+ /**
579
+ * Whether or not to apply `the_content` filter callback.
580
+ *
581
+ * @see ezTOC::the_content()
582
+ *
583
+ * @since 2.0
584
+ *
585
+ * @param bool $apply
586
+ */
587
+ return apply_filters( 'ez_toc_maybe_apply_the_content_filter', $apply );
588
+ }
589
+
590
+ /**
591
+ * Callback for the `the_content` filter.
592
+ *
593
+ * This will add the inline table of contents page anchors to the post content. It will also insert the
594
+ * table of contents inline with the post content as defined by the user defined preference.
595
+ *
596
+ * @since 1.0
597
+ *
598
+ * @param string $content
599
+ *
600
+ * @return string
601
+ */
602
+ public static function the_content( $content ) {
603
+ $maybeApplyFilter = self::maybeApplyTheContentFilter();
604
+
605
+ Debug::log( 'the_content_filter', 'The `the_content` filter applied.', $maybeApplyFilter );
606
+
607
+ if ( ! $maybeApplyFilter ) {
608
+
609
+ return Debug::log()->appendTo( $content );
610
+ }
611
+
612
+ // Bail if post not eligible and widget is not active.
613
+ $isEligible = self::is_eligible( get_post() );
614
+ $isEligible = apply_filters('eztoc_do_shortcode',$isEligible);
615
+ Debug::log( 'post_eligible', 'Post eligible.', $isEligible );
616
+
617
+ if ( ! $isEligible && ! is_active_widget( false, false, 'ezw_tco' ) ) {
618
+
619
+ return Debug::log()->appendTo( $content );
620
+ }
621
+
622
+ $post = self::get( get_the_ID() );
623
+
624
+ if ( ! $post instanceof ezTOC_Post ) {
625
+
626
+ Debug::log( 'not_instance_of_post', 'Not an instance if `WP_Post`.', get_the_ID() );
627
+
628
+ return Debug::log()->appendTo( $content );
629
+ }
630
+
631
+ // Bail if no headings found.
632
+ if ( ! $post->hasTOCItems() ) {
633
+
634
+ return Debug::log()->appendTo( $content );
635
+ }
636
+
637
+ $find = $post->getHeadings();
638
+ $replace = $post->getHeadingsWithAnchors();
639
+ $toc = $post->getTOC();
640
+ $headings = implode( PHP_EOL, $find );
641
+ $anchors = implode( PHP_EOL, $replace );
642
+
643
+ $headingRows = count( $find ) + 1;
644
+ $anchorRows = count( $replace ) + 1;
645
+
646
+ $style = "background-image: linear-gradient(#F1F1F1 50%, #F9F9F9 50%); background-size: 100% 4em; border: 1px solid #CCC; font-family: monospace; font-size: 1em; line-height: 2em; margin: 0 auto; overflow: auto; padding: 0 8px 4px; white-space: nowrap; width: 100%;";
647
+
648
+ Debug::log(
649
+ 'found_post_headings',
650
+ 'Found headings:',
651
+ "<textarea rows='{$headingRows}' style='{$style}' wrap='soft'>{$headings}</textarea>"
652
+ );
653
+
654
+ Debug::log(
655
+ 'replace_post_headings',
656
+ 'Replace found headings with:',
657
+ "<textarea rows='{$anchorRows}' style='{$style}' wrap='soft'>{$anchors}</textarea>"
658
+ );
659
+
660
+ // If shortcode used or post not eligible, return content with anchored headings.
661
+ if ( strpos( $content, 'ez-toc-container' ) || ! $isEligible ) {
662
+
663
+ Debug::log( 'shortcode_found', 'Shortcode found, add links to content.', true );
664
+
665
+ return mb_find_replace( $find, $replace, $content );
666
+ }
667
+
668
+ $position = ezTOC_Option::get( 'position' );
669
+
670
+ Debug::log( 'toc_insert_position', 'Insert TOC at position', $position );
671
+
672
+ // else also add toc to content
673
+ switch ( $position ) {
674
+
675
+ case 'top':
676
+ $content = $toc . mb_find_replace( $find, $replace, $content );
677
+ break;
678
+
679
+ case 'bottom':
680
+ $content = mb_find_replace( $find, $replace, $content ) . $toc;
681
+ break;
682
+
683
+ case 'after':
684
+ $replace[0] = $replace[0] . $toc;
685
+ $content = mb_find_replace( $find, $replace, $content );
686
+ break;
687
+
688
+ case 'before':
689
+ default:
690
+ //$replace[0] = $html . $replace[0];
691
+ $content = mb_find_replace( $find, $replace, $content );
692
+
693
+ /**
694
+ * @link https://wordpress.org/support/topic/php-notice-undefined-offset-8/
695
+ */
696
+ if ( ! array_key_exists( 0, $replace ) ) {
697
+ break;
698
+ }
699
+
700
+ $pattern = '`<h[1-6]{1}[^>]*' . preg_quote( $replace[0], '`' ) . '`msuU';
701
+ $result = preg_match( $pattern, $content, $matches );
702
+
703
+ /*
704
+ * Try to place TOC before the first heading found in eligible heading, failing that,
705
+ * insert TOC at top of content.
706
+ */
707
+ if ( 1 === $result ) {
708
+
709
+ Debug::log( 'toc_insert_position_found', 'Insert TOC before first eligible heading.', $result );
710
+
711
+ $start = strpos( $content, $matches[0] );
712
+ $content = substr_replace( $content, $toc, $start, 0 );
713
+
714
+ } else {
715
+
716
+ Debug::log( 'toc_insert_position_not_found', 'Insert TOC before first eligible heading not found.', $result );
717
+
718
+ // Somehow, there are scenarios where the processing get this far and
719
+ // the TOC is being added to pages where it should not. Disable for now.
720
+ //$content = $html . $content;
721
+ }
722
+ }
723
+
724
+ return Debug::log()->appendTo( $content );
725
+ }
726
+
727
+ }
728
+
729
+ /**
730
+ * The main function responsible for returning the Easy Table of Contents instance to functions everywhere.
731
+ *
732
+ * Use this function like you would a global variable, except without needing to declare the global.
733
+ *
734
+ * Example: <?php $instance = ezTOC(); ?>
735
+ *
736
+ * @access public
737
+ * @since 1.0
738
+ *
739
+ * @return ezTOC
740
+ */
741
+ function ezTOC() {
742
+
743
+ return ezTOC::instance();
744
+ }
745
+
746
+ // Start Easy Table of Contents.
747
+ add_action( 'plugins_loaded', 'ezTOC' );
748
+ }
749
+ register_activation_hook(__FILE__, 'ez_toc_activate');
750
+ add_action('admin_init', 'ez_toc_redirect');
751
+
752
+ function ez_toc_activate() {
753
+ add_option('ez_toc_do_activation_redirect', true);
754
+ }
755
+
756
+ function ez_toc_redirect() {
757
+ if (get_option('ez_toc_do_activation_redirect', false)) {
758
+ delete_option('ez_toc_do_activation_redirect');
759
+ if(!isset($_GET['activate-multi']))
760
+ {
761
+ wp_redirect("options-general.php?page=table-of-contents#welcome");
762
+ }
763
+ }
764
+ }
includes/Debug.php CHANGED
@@ -1,180 +1,180 @@
1
- <?php
2
-
3
- namespace Easy_Plugins\Table_Of_Contents;
4
-
5
- use WP_Error;
6
-
7
- /**
8
- * Class Debug
9
- *
10
- * @package Easy_Plugins\Table_Of_Contents
11
- */
12
- final class Debug extends WP_Error {
13
-
14
- /**
15
- * @since 2.0.13
16
- * @var bool
17
- */
18
- protected $display = false;
19
-
20
- /**
21
- * @since 2.0.13
22
- * @var bool
23
- */
24
- protected $enabled = false;
25
-
26
- /**
27
- * @var self
28
- */
29
- private static $instance;
30
-
31
- /**
32
- * Debug constructor.
33
- *
34
- * @since 2.0.13
35
- *
36
- * @param string $code
37
- * @param string $message
38
- * @param string $data
39
- */
40
- public function __construct( $code = '', $message = '', $data = '' ) {
41
-
42
- parent::__construct( $code, $message, $data );
43
- }
44
-
45
- /**
46
- * @since 2.0.14
47
- *
48
- * @param string $code
49
- * @param string $message
50
- * @param string $data
51
- *
52
- * @return Debug
53
- */
54
- public static function log( $code = '', $message = '', $data = '' ) {
55
-
56
- if ( ! isset( self::$instance ) && ! ( self::$instance instanceof self ) ) {
57
-
58
- self::$instance = new self( $code, $message, $data );
59
-
60
- self::$instance->display = apply_filters(
61
- 'Easy_Plugins/Table_Of_Contents/Debug/Display',
62
- defined( 'WP_DEBUG_DISPLAY' ) && WP_DEBUG_DISPLAY
63
- );
64
-
65
- self::$instance->enabled = apply_filters(
66
- 'Easy_Plugins/Table_Of_Contents/Debug/Enabled',
67
- ( defined( 'WP_DEBUG' ) && WP_DEBUG ) && current_user_can( 'manage_options' )
68
- );
69
-
70
- } else {
71
-
72
- if ( ! empty( $code ) && ! empty( $message ) ) {
73
-
74
- self::$instance->add( $code, $message, $data );
75
- }
76
- }
77
-
78
- return self::$instance;
79
- }
80
-
81
- /**
82
- * Adds an error or appends an additional message to an existing error.
83
- *
84
- * NOTE: Overrides WP_Error::add() to allow support of passing `false` as `$data`.
85
- *
86
- * @since 2.0.14
87
- *
88
- * @param string|int $code Error code.
89
- * @param string $message Error message.
90
- * @param mixed $data Optional. Error data.
91
- */
92
- public function add( $code, $message, $data = null ) {
93
- $this->errors[ $code ][] = $message;
94
-
95
- if ( ! is_null( $data ) ) {
96
- $this->add_data( $data, $code );
97
- }
98
-
99
- /**
100
- * Fires when an error is added to a WP_Error object.
101
- *
102
- * @since 5.6.0
103
- *
104
- * @param string|int $code Error code.
105
- * @param string $message Error message.
106
- * @param mixed $data Error data. Might be empty.
107
- * @param WP_Error $wp_error The WP_Error object.
108
- */
109
- do_action( 'wp_error_added', $code, $message, $data, $this );
110
- }
111
-
112
- /**
113
- * @since 2.0.13
114
- *
115
- * @param string $content
116
- *
117
- * @return string
118
- */
119
- public function appendTo( $content = '' ) {
120
-
121
- return $content . $this;
122
- }
123
-
124
- /**
125
- * @since 2.0.13
126
- *
127
- * @return string
128
- */
129
- public function dump() {
130
-
131
- $dump = array();
132
-
133
- foreach ( (array) $this->errors as $code => $messages ) {
134
-
135
- $data = $this->get_error_data( $code );
136
- $data = is_string( $data ) ? $data : '<code>' . var_export( $data, true ) . '</code>';
137
- $data = "\t\t<li class=\"ez-toc-debug-message-data\">{$data}</li>" . PHP_EOL;
138
-
139
- array_push(
140
- $dump,
141
- PHP_EOL . "\t<ul class=\"ez-toc-debug-message-{$code}\">" . PHP_EOL . "\t\t<li class=\"ez-toc-debug-message\">" . implode( '</li>' . PHP_EOL . '<li>' . PHP_EOL, $messages ) . '</li>' . PHP_EOL . "{$data}\t</ul>" . PHP_EOL
142
- );
143
- }
144
-
145
- return '<div class="ez-toc-debug-message">' . implode( '</div>' . PHP_EOL . '<div class="ez-toc-debug-message">', $dump ) . '</div>' . PHP_EOL;
146
- }
147
-
148
- /**
149
- * @since 2.0.13
150
- *
151
- * @return string
152
- */
153
- public function __toString() {
154
-
155
- if ( false === $this->enabled ) {
156
-
157
- return '';
158
- }
159
-
160
- if ( false === $this->display ) {
161
-
162
- return '';
163
- }
164
-
165
- if ( ! $this->has_errors() ) {
166
-
167
- return '';
168
- }
169
-
170
- $intro = sprintf(
171
- 'You see the following because <a href="%1$s"><code>WP_DEBUG</code></a> and <a href="%1$s"><code>WP_DEBUG_DISPLAY</code></a> are enabled on this site. Please disabled these to prevent the display of these developers\' debug messages.',
172
- 'https://codex.wordpress.org/WP_DEBUG'
173
- );
174
-
175
- $intro = PHP_EOL . "<p>{$intro}</p>" .PHP_EOL;
176
- $dump = $this->dump();
177
-
178
- return PHP_EOL . "<div class='ez-toc-debug-messages'>{$intro}{$dump}</div>" . PHP_EOL;
179
- }
180
- }
1
+ <?php
2
+
3
+ namespace Easy_Plugins\Table_Of_Contents;
4
+
5
+ use WP_Error;
6
+
7
+ /**
8
+ * Class Debug
9
+ *
10
+ * @package Easy_Plugins\Table_Of_Contents
11
+ */
12
+ final class Debug extends WP_Error {
13
+
14
+ /**
15
+ * @since 2.0.13
16
+ * @var bool
17
+ */
18
+ protected $display = false;
19
+
20
+ /**
21
+ * @since 2.0.13
22
+ * @var bool
23
+ */
24
+ protected $enabled = false;
25
+
26
+ /**
27
+ * @var self
28
+ */
29
+ private static $instance;
30
+
31
+ /**
32
+ * Debug constructor.
33
+ *
34
+ * @since 2.0.13
35
+ *
36
+ * @param string $code
37
+ * @param string $message
38
+ * @param string $data
39
+ */
40
+ public function __construct( $code = '', $message = '', $data = '' ) {
41
+
42
+ parent::__construct( $code, $message, $data );
43
+ }
44
+
45
+ /**
46
+ * @since 2.0.14
47
+ *
48
+ * @param string $code
49
+ * @param string $message
50
+ * @param string $data
51
+ *
52
+ * @return Debug
53
+ */
54
+ public static function log( $code = '', $message = '', $data = '' ) {
55
+
56
+ if ( ! isset( self::$instance ) && ! ( self::$instance instanceof self ) ) {
57
+
58
+ self::$instance = new self( $code, $message, $data );
59
+
60
+ self::$instance->display = apply_filters(
61
+ 'Easy_Plugins/Table_Of_Contents/Debug/Display',
62
+ defined( 'WP_DEBUG_DISPLAY' ) && WP_DEBUG_DISPLAY
63
+ );
64
+
65
+ self::$instance->enabled = apply_filters(
66
+ 'Easy_Plugins/Table_Of_Contents/Debug/Enabled',
67
+ ( defined( 'WP_DEBUG' ) && WP_DEBUG ) && current_user_can( 'manage_options' )
68
+ );
69
+
70
+ } else {
71
+
72
+ if ( ! empty( $code ) && ! empty( $message ) ) {
73
+
74
+ self::$instance->add( $code, $message, $data );
75
+ }
76
+ }
77
+
78
+ return self::$instance;
79
+ }
80
+
81
+ /**
82
+ * Adds an error or appends an additional message to an existing error.
83
+ *
84
+ * NOTE: Overrides WP_Error::add() to allow support of passing `false` as `$data`.
85
+ *
86
+ * @since 2.0.14
87
+ *
88
+ * @param string|int $code Error code.
89
+ * @param string $message Error message.
90
+ * @param mixed $data Optional. Error data.
91
+ */
92
+ public function add( $code, $message, $data = null ) {
93
+ $this->errors[ $code ][] = $message;
94
+
95
+ if ( ! is_null( $data ) ) {
96
+ $this->add_data( $data, $code );
97
+ }
98
+
99
+ /**
100
+ * Fires when an error is added to a WP_Error object.
101
+ *
102
+ * @since 5.6.0
103
+ *
104
+ * @param string|int $code Error code.
105
+ * @param string $message Error message.
106
+ * @param mixed $data Error data. Might be empty.
107
+ * @param WP_Error $wp_error The WP_Error object.
108
+ */
109
+ do_action( 'wp_error_added', $code, $message, $data, $this );
110
+ }
111
+
112
+ /**
113
+ * @since 2.0.13
114
+ *
115
+ * @param string $content
116
+ *
117
+ * @return string
118
+ */
119
+ public function appendTo( $content = '' ) {
120
+
121
+ return $content . $this;
122
+ }
123
+
124
+ /**
125
+ * @since 2.0.13
126
+ *
127
+ * @return string
128
+ */
129
+ public function dump() {
130
+
131
+ $dump = array();
132
+
133
+ foreach ( (array) $this->errors as $code => $messages ) {
134
+
135
+ $data = $this->get_error_data( $code );
136
+ $data = is_string( $data ) ? $data : '<code>' . var_export( $data, true ) . '</code>';
137
+ $data = "\t\t<li class=\"ez-toc-debug-message-data\">{$data}</li>" . PHP_EOL;
138
+
139
+ array_push(
140
+ $dump,
141
+ PHP_EOL . "\t<ul class=\"ez-toc-debug-message-{$code}\">" . PHP_EOL . "\t\t<li class=\"ez-toc-debug-message\">" . implode( '</li>' . PHP_EOL . '<li>' . PHP_EOL, $messages ) . '</li>' . PHP_EOL . "{$data}\t</ul>" . PHP_EOL
142
+ );
143
+ }
144
+
145
+ return '<div class="ez-toc-debug-message">' . implode( '</div>' . PHP_EOL . '<div class="ez-toc-debug-message">', $dump ) . '</div>' . PHP_EOL;
146
+ }
147
+
148
+ /**
149
+ * @since 2.0.13
150
+ *
151
+ * @return string
152
+ */
153
+ public function __toString() {
154
+
155
+ if ( false === $this->enabled ) {
156
+
157
+ return '';
158
+ }
159
+
160
+ if ( false === $this->display ) {
161
+
162
+ return '';
163
+ }
164
+
165
+ if ( ! $this->has_errors() ) {
166
+
167
+ return '';
168
+ }
169
+
170
+ $intro = sprintf(
171
+ 'You see the following because <a href="%1$s"><code>WP_DEBUG</code></a> and <a href="%1$s"><code>WP_DEBUG_DISPLAY</code></a> are enabled on this site. Please disabled these to prevent the display of these developers\' debug messages.',
172
+ 'https://codex.wordpress.org/WP_DEBUG'
173
+ );
174
+
175
+ $intro = PHP_EOL . "<p>{$intro}</p>" .PHP_EOL;
176
+ $dump = $this->dump();
177
+
178
+ return PHP_EOL . "<div class='ez-toc-debug-messages'>{$intro}{$dump}</div>" . PHP_EOL;
179
+ }
180
+ }
includes/class.admin.php CHANGED
@@ -1,567 +1,567 @@
1
- <?php
2
-
3
- // Exit if accessed directly
4
- if ( ! defined( 'ABSPATH' ) ) exit;
5
-
6
- if ( ! class_exists( 'ezTOC_Admin' ) ) {
7
-
8
- /**
9
- * Class ezTOC_Admin
10
- */
11
- final class ezTOC_Admin {
12
-
13
- /**
14
- * Setup plugin for admin use.
15
- *
16
- * @access private
17
- * @since 1.0
18
- * @static
19
- */
20
- public function __construct() {
21
-
22
- $this->hooks();
23
- //$this->registerMetaboxes();
24
- }
25
-
26
- /**
27
- * Add the core admin hooks.
28
- *
29
- * @access private
30
- * @since 1.0
31
- * @static
32
- */
33
- private function hooks() {
34
-
35
- add_action( 'admin_init', array( $this, 'registerScripts' ) );
36
- add_action( 'admin_menu', array( $this, 'menu' ) );
37
- add_action( 'init', array( $this, 'registerMetaboxes' ), 99 );
38
- add_filter( 'plugin_action_links_' . EZ_TOC_BASE_NAME, array( $this, 'pluginActionLinks' ), 10, 2 );
39
- add_action( 'admin_enqueue_scripts', array( $this, 'load_scripts' ) );
40
- add_action('wp_ajax_eztoc_send_query_message', array( $this, 'eztoc_send_query_message'));
41
- }
42
-
43
- /**
44
- * Callback to add the Settings link to the plugin action links.
45
- *
46
- * @access private
47
- * @since 1.0
48
- * @static
49
- *
50
- * @param $links
51
- * @param $file
52
- *
53
- * @return array
54
- */
55
- public function pluginActionLinks( $links, $file ) {
56
-
57
- $url = add_query_arg( 'page', 'table-of-contents', self_admin_url( 'options-general.php' ) );
58
- $setting_link = '<a href="' . esc_url( $url ) . '">' . __( 'Settings', 'easy-table-of-contents' ) . '</a> |';
59
- $setting_link .= '<a href="https://tocwp.com/contact/" target="_blank">' . __( ' Support', 'easy-table-of-contents' ) . '</a> |';
60
- $setting_link .= '<a href="https://tocwp.com/pricing/" target="_blank">' . __( ' Upgrade', 'easy-table-of-contents' ) . '</a> |';
61
- $setting_link .= '<a href="https://tocwp.com/" target="_blank">' . __( ' Website', 'easy-table-of-contents' ) . '</a>';
62
- array_push( $links, $setting_link );
63
- return $links;
64
- }
65
-
66
- /**
67
- * Register the scripts used in the admin.
68
- *
69
- * @access private
70
- * @since 1.0
71
- * @static
72
- */
73
- public function registerScripts() {
74
-
75
- wp_register_script( 'cn_toc_admin_script', EZ_TOC_URL . 'assets/js/admin.js', array( 'jquery', 'wp-color-picker' ), ezTOC::VERSION, true );
76
- wp_register_style( 'cn_toc_admin_style', EZ_TOC_URL . 'assets/css/admin.css', array( 'wp-color-picker' ), ezTOC::VERSION );
77
- }
78
-
79
- /**
80
- * Callback to add plugin as a submenu page of the Options page.
81
- *
82
- * This also adds the action to enqueue the scripts to be loaded on plugin's admin pages only.
83
- *
84
- * @access private
85
- * @since 1.0
86
- * @static
87
- */
88
- public function menu() {
89
-
90
- $page = add_submenu_page(
91
- 'options-general.php',
92
- esc_html__( 'Table of Contents', 'easy-table-of-contents' ),
93
- esc_html__( 'Table of Contents', 'easy-table-of-contents' ),
94
- 'manage_options',
95
- 'table-of-contents',
96
- array( $this, 'page' )
97
- );
98
-
99
- add_action( 'admin_print_styles-' . $page, array( $this, 'enqueueScripts' ) );
100
- }
101
-
102
- /**
103
- * Enqueue the scripts.
104
- *
105
- * @access private
106
- * @since 1.0
107
- * @static
108
- */
109
- public function enqueueScripts() {
110
-
111
- wp_enqueue_script( 'cn_toc_admin_script' );
112
- wp_enqueue_style( 'cn_toc_admin_style' );
113
- }
114
-
115
- /**
116
- * Callback to add the action which will register the table of contents post metaboxes.
117
- *
118
- * Metaboxes will only be registered for the post types per user preferences.
119
- *
120
- * @access private
121
- * @since 1.0
122
- * @static
123
- */
124
- public function registerMetaboxes() {
125
-
126
- foreach ( get_post_types() as $type ) {
127
-
128
- if ( in_array( $type, ezTOC_Option::get( 'enabled_post_types', array() ) ) ) {
129
-
130
- add_action( "add_meta_boxes_$type", array( $this, 'metabox' ) );
131
- add_action( "save_post_$type", array( $this, 'save' ), 10, 3 );
132
- }
133
- }
134
- }
135
-
136
- /**
137
- * Callback to register the table of contents metaboxes.
138
- *
139
- * @access private
140
- * @since 1.0
141
- * @static
142
- */
143
- public function metabox() {
144
-
145
- add_meta_box( 'ez-toc', esc_html__( 'Table of Contents', 'ez-toc' ), array( $this, 'displayMetabox' ) );
146
- }
147
-
148
- /**
149
- * Callback to render the content of the table of contents metaboxes.
150
- *
151
- * @access private
152
- * @since 1.0
153
- * @static
154
- *
155
- * @param object $post The post object.
156
- * @param $atts
157
- */
158
- public function displayMetabox( $post, $atts ) {
159
-
160
- // Add an nonce field so we can check for it on save.
161
- wp_nonce_field( 'ez_toc_save', '_ez_toc_nonce' );
162
-
163
- $suppress = get_post_meta( $post->ID, '_ez-toc-disabled', true ) == 1 ? true : false;
164
- $insert = get_post_meta( $post->ID, '_ez-toc-insert', true ) == 1 ? true : false;
165
- $headings = get_post_meta( $post->ID, '_ez-toc-heading-levels', true );
166
- $exclude = get_post_meta( $post->ID, '_ez-toc-exclude', true );
167
- $altText = get_post_meta( $post->ID, '_ez-toc-alttext', true );
168
-
169
- if ( ! is_array( $headings ) ) {
170
-
171
- $headings = array();
172
- }
173
- ?>
174
-
175
- <table class="form-table">
176
-
177
- <tbody>
178
-
179
- <tr>
180
- <th scope="row"></th>
181
- <td>
182
-
183
- <?php if ( in_array( get_post_type( $post ), ezTOC_Option::get( 'auto_insert_post_types', array() ) ) ) :
184
-
185
- ezTOC_Option::checkbox(
186
- array(
187
- 'id' => 'disabled-toc',
188
- 'desc' => esc_html__( 'Disable the automatic insertion of the table of contents.', 'easy-table-of-contents' ),
189
- 'default' => $suppress,
190
- ),
191
- $suppress
192
- );
193
-
194
- elseif( in_array( get_post_type( $post ), ezTOC_Option::get( 'enabled_post_types', array() ) ) ):
195
-
196
- ezTOC_Option::checkbox(
197
- array(
198
- 'id' => 'insert-toc',
199
- 'desc' => esc_html__( 'Insert table of contents.', 'easy-table-of-contents' ),
200
- 'default' => $insert,
201
- ),
202
- $insert
203
- );
204
-
205
- endif; ?>
206
-
207
- </td>
208
- </tr>
209
-
210
- <tr>
211
- <th scope="row"><?php esc_html_e( 'Advanced:', 'easy-table-of-contents' ); ?></th>
212
- <td>
213
- <?php
214
- ezTOC_Option::descriptive_text(
215
- array(
216
- 'id' => 'exclude-desc',
217
- 'name' => '',
218
- 'desc' => '<p><strong>' . esc_html__( 'NOTE:', 'easy-table-of-contents' ) . '</strong></p>' .
219
- '<ul>' .
220
- '<li>' . esc_html__( 'Using the advanced options below will override the global advanced settings.', 'easy-table-of-contents' ) . '</li>' .
221
- '</ul>',
222
- )
223
- );
224
- ?>
225
- </td>
226
- </tr>
227
-
228
- <tr>
229
- <th scope="row"><?php esc_html_e( 'Headings:', 'easy-table-of-contents' ); ?></th>
230
- <td>
231
- <?php
232
- ezTOC_Option::checkboxgroup(
233
- array(
234
- 'id' => 'heading-levels',
235
- 'desc' => esc_html__( 'Select the heading to consider when generating the table of contents. Deselecting a heading will exclude it.', 'easy-table-of-contents' ),
236
- 'options' => array(
237
- '1' => __( 'Heading 1 (h1)', 'easy-table-of-contents' ),
238
- '2' => __( 'Heading 2 (h2)', 'easy-table-of-contents' ),
239
- '3' => __( 'Heading 3 (h3)', 'easy-table-of-contents' ),
240
- '4' => __( 'Heading 4 (h4)', 'easy-table-of-contents' ),
241
- '5' => __( 'Heading 5 (h5)', 'easy-table-of-contents' ),
242
- '6' => __( 'Heading 6 (h6)', 'easy-table-of-contents' ),
243
- ),
244
- 'default' => array(),
245
- ),
246
- array_map( 'absint', $headings )
247
- );
248
- ?>
249
- </td>
250
- </tr>
251
- <tr>
252
- <th scope="row"><?php esc_html_e( 'Alternate Headings', 'easy-table-of-contents' ); ?></th>
253
- <td>
254
- <?php
255
- ezTOC_Option::textarea(
256
- array(
257
- 'id' => 'alttext',
258
- 'desc' => __( 'Specify alternate table of contents header string. Add the header to be replaced and the alternate header on a single line separated with a pipe <code>|</code>. Put each additional original and alternate header on its own line.', 'easy-table-of-contents' ),
259
- 'size' => 'large',
260
- 'default' => '',
261
- ),
262
- $altText
263
- );
264
- ?>
265
- </td>
266
- </tr>
267
- <tr>
268
- <th scope="row"></th>
269
- <td>
270
- <?php
271
- ezTOC_Option::descriptive_text(
272
- array(
273
- 'id' => 'alttext-desc',
274
- 'name' => '',
275
- 'desc' => '<p><strong>' . esc_html__( 'Examples:', 'easy-table-of-contents' ) . '</strong></p>' .
276
- '<ul>' .
277
- '<li>' . __( '<code>Level [1.1]|Alternate TOC Header</code> Replaces Level [1.1] in the table of contents with Alternate TOC Header.', 'easy-table-of-contents' ) . '</li>' .
278
- '</ul>' .
279
- '<p>' . __( '<strong>Note:</strong> This is case sensitive.', 'easy-table-of-contents' ) . '</p>',
280
- )
281
- );
282
- ?>
283
- </td>
284
- </tr>
285
- <tr>
286
- <th scope="row"><?php esc_html_e( 'Exclude Headings', 'easy-table-of-contents' ); ?></th>
287
- <td>
288
- <?php
289
- ezTOC_Option::text(
290
- array(
291
- 'id' => 'exclude',
292
- 'desc' => __( 'Specify headings to be excluded from appearing in the table of contents. Separate multiple headings with a pipe <code>|</code>. Use an asterisk <code>*</code> as a wildcard to match other text.', 'easy-table-of-contents' ),
293
- 'size' => 'large',
294
- 'default' => '',
295
- ),
296
- $exclude
297
- );
298
- ?>
299
- </td>
300
- </tr>
301
- <tr>
302
- <th scope="row"></th>
303
- <td>
304
- <?php
305
- ezTOC_Option::descriptive_text(
306
- array(
307
- 'id' => 'exclude-desc',
308
- 'name' => '',
309
- 'desc' => '<p><strong>' . esc_html__( 'Examples:', 'easy-table-of-contents' ) . '</strong></p>' .
310
- '<ul>' .
311
- '<li>' . __( '<code>Fruit*</code> Ignore headings starting with "Fruit".', 'easy-table-of-contents' ) . '</li>' .
312
- '<li>' . __( '<code>*Fruit Diet*</code> Ignore headings with "Fruit Diet" somewhere in the heading.', 'easy-table-of-contents' ) . '</li>' .
313
- '<li>' . __( '<code>Apple Tree|Oranges|Yellow Bananas</code> Ignore headings that are exactly "Apple Tree", "Oranges" or "Yellow Bananas".', 'easy-table-of-contents' ) . '</li>' .
314
- '</ul>' .
315
- '<p>' . __( '<strong>Note:</strong> This is not case sensitive.', 'easy-table-of-contents' ) . '</p>',
316
- )
317
- );
318
- ?>
319
- </td>
320
- </tr>
321
- </tbody>
322
- </table>
323
-
324
- <?php
325
- }
326
-
327
- /**
328
- * Callback which saves the user preferences from the table of contents metaboxes.
329
- *
330
- * @access private
331
- * @since 1.0
332
- * @static
333
- *
334
- * @param int $post_id The post ID.
335
- * @param object $post The post object.
336
- * @param bool $update Whether this is an existing post being updated or not.
337
- */
338
- public function save( $post_id, $post, $update ) {
339
-
340
- if ( current_user_can( 'edit_post', $post_id ) &&
341
- isset( $_REQUEST['_ez_toc_nonce'] ) &&
342
- wp_verify_nonce( $_REQUEST['_ez_toc_nonce'], 'ez_toc_save' )
343
- ) {
344
-
345
- // Checkboxes are present if checked, absent if not.
346
- if ( isset( $_REQUEST['ez-toc-settings']['disabled-toc'] ) ) {
347
-
348
- update_post_meta( $post_id, '_ez-toc-disabled', true );
349
-
350
- } else {
351
-
352
- update_post_meta( $post_id, '_ez-toc-disabled', false );
353
-
354
- }
355
-
356
- if ( isset( $_REQUEST['ez-toc-settings']['insert-toc'] ) ) {
357
-
358
- update_post_meta( $post_id, '_ez-toc-insert', true );
359
-
360
- } else {
361
-
362
- update_post_meta( $post_id, '_ez-toc-insert', false );
363
- }
364
-
365
- if ( isset( $_REQUEST['ez-toc-settings']['heading-levels'] ) && ! empty( $_REQUEST['ez-toc-settings']['heading-levels'] ) ) {
366
-
367
- if ( is_array( $_REQUEST['ez-toc-settings']['heading-levels'] ) ) {
368
-
369
- $headings = array_map( 'absint', $_REQUEST['ez-toc-settings']['heading-levels'] );
370
-
371
- } else {
372
-
373
- $headings = array();
374
- }
375
-
376
- update_post_meta( $post_id, '_ez-toc-heading-levels', $headings );
377
-
378
- } else {
379
-
380
- update_post_meta( $post_id, '_ez-toc-heading-levels', array() );
381
- }
382
-
383
- if ( isset( $_REQUEST['ez-toc-settings']['alttext'] ) && ! empty( $_REQUEST['ez-toc-settings']['alttext'] ) ) {
384
-
385
- if ( is_string( $_REQUEST['ez-toc-settings']['alttext'] ) ) {
386
-
387
- $alttext = trim( $_REQUEST['ez-toc-settings']['alttext'] );
388
-
389
- } else {
390
-
391
- $alttext = '';
392
- }
393
-
394
- /*
395
- * This is basically `esc_html()` but does not encode quotes.
396
- * This is to allow angle brackets and such which `wp_kses_post` would strip as "evil" scripts.
397
- */
398
- $alttext = wp_check_invalid_utf8( $alttext );
399
- $alttext = _wp_specialchars( $alttext, ENT_NOQUOTES );
400
-
401
- update_post_meta( $post_id, '_ez-toc-alttext', wp_kses_post( $alttext ) );
402
-
403
- } else {
404
-
405
- update_post_meta( $post_id, '_ez-toc-alttext', '' );
406
- }
407
-
408
- if ( isset( $_REQUEST['ez-toc-settings']['exclude'] ) && ! empty( $_REQUEST['ez-toc-settings']['exclude'] ) ) {
409
-
410
- if ( is_string( $_REQUEST['ez-toc-settings']['exclude'] ) ) {
411
-
412
- $exclude = trim( $_REQUEST['ez-toc-settings']['exclude'] );
413
-
414
- } else {
415
-
416
- $exclude = '';
417
- }
418
-
419
- /*
420
- * This is basically `esc_html()` but does not encode quotes.
421
- * This is to allow angle brackets and such which `wp_kses_post` would strip as "evil" scripts.
422
- */
423
- $exclude = wp_check_invalid_utf8( $exclude );
424
- $exclude = _wp_specialchars( $exclude, ENT_NOQUOTES );
425
-
426
- update_post_meta( $post_id, '_ez-toc-exclude', wp_kses_post( $exclude ) );
427
-
428
- } else {
429
-
430
- update_post_meta( $post_id, '_ez-toc-exclude', '' );
431
- }
432
-
433
- }
434
-
435
- }
436
-
437
-
438
- /**
439
- * Enqueue Admin js scripts
440
- *
441
- */
442
- public function load_scripts($pagenow){
443
-
444
- if (isset($pagenow) && $pagenow != 'settings_page_table-of-contents' && strpos($pagenow, 'table-of-contents') == false) {
445
-
446
- return false;
447
- }
448
-
449
- wp_enqueue_script( 'eztoc-admin-js', EZ_TOC_URL . 'assets/js/eztoc-admin.js',array('jquery'), ezTOC::VERSION,true );
450
-
451
- $data = array(
452
- 'ajax_url' => admin_url( 'admin-ajax.php' ),
453
- 'eztoc_security_nonce' => wp_create_nonce('eztoc_ajax_check_nonce'),
454
- );
455
-
456
- $data = apply_filters('eztoc_localize_filter',$data,'eztoc_admin_data');
457
-
458
- wp_localize_script( 'eztoc-admin-js', 'eztoc_admin_data', $data );
459
- }
460
-
461
- /**
462
- * This is a ajax handler function for sending email from user admin panel to us.
463
- * @return type json string
464
- */
465
-
466
- public function eztoc_send_query_message(){
467
-
468
- if ( ! isset( $_POST['eztoc_security_nonce'] ) ){
469
- return;
470
- }
471
- if ( !wp_verify_nonce( $_POST['eztoc_security_nonce'], 'eztoc_ajax_check_nonce' ) ){
472
- return;
473
- }
474
- $message = $this->eztoc_sanitize_textarea_field($_POST['message']);
475
- $email = $this->eztoc_sanitize_textarea_field($_POST['email']);
476
-
477
- if(function_exists('wp_get_current_user')){
478
-
479
- $user = wp_get_current_user();
480
-
481
-
482
- $message = '<p>'.$message.'</p><br><br>'.'Query from Easy Table of Content plugin support tab';
483
-
484
- $user_data = $user->data;
485
- $user_email = $user_data->user_email;
486
-
487
- if($email){
488
- $user_email = $email;
489
- }
490
- //php mailer variables
491
- $sendto = 'team@magazine3.in';
492
- $subject = "Easy Table of Content Query";
493
-
494
- $headers[] = 'Content-Type: text/html; charset=UTF-8';
495
- $headers[] = 'From: '. esc_attr($user_email);
496
- $headers[] = 'Reply-To: ' . esc_attr($user_email);
497
- // Load WP components, no themes.
498
-
499
- $sent = wp_mail($sendto, $subject, $message, $headers);
500
-
501
- if($sent){
502
-
503
- echo json_encode(array('status'=>'t'));
504
-
505
- }else{
506
-
507
- echo json_encode(array('status'=>'f'));
508
-
509
- }
510
-
511
- }
512
-
513
- wp_die();
514
- }
515
-
516
- public function eztoc_sanitize_textarea_field( $str ) {
517
-
518
- if ( is_object( $str ) || is_array( $str ) ) {
519
- return '';
520
- }
521
-
522
- $str = (string) $str;
523
-
524
- $filtered = wp_check_invalid_utf8( $str );
525
-
526
- if ( strpos( $filtered, '<' ) !== false ) {
527
- $filtered = wp_pre_kses_less_than( $filtered );
528
- // This will strip extra whitespace for us.
529
- $filtered = wp_strip_all_tags( $filtered, false );
530
-
531
- // Use HTML entities in a special case to make sure no later
532
- // newline stripping stage could lead to a functional tag.
533
- $filtered = str_replace( "<\n", "&lt;\n", $filtered );
534
- }
535
-
536
- $filtered = trim( $filtered );
537
-
538
- $found = false;
539
- while ( preg_match( '/%[a-f0-9]{2}/i', $filtered, $match ) ) {
540
- $filtered = str_replace( $match[0], '', $filtered );
541
- $found = true;
542
- }
543
-
544
- if ( $found ) {
545
- // Strip out the whitespace that may now exist after removing the octets.
546
- $filtered = trim( preg_replace( '/ +/', ' ', $filtered ) );
547
- }
548
-
549
- return $filtered;
550
- }
551
-
552
- /**
553
- * Callback used to render the admin options page.
554
- *
555
- * @access private
556
- * @since 1.0
557
- * @static
558
- */
559
- public function page() {
560
-
561
- include EZ_TOC_PATH . '/includes/inc.admin-options-page.php';
562
- }
563
- }
564
-
565
- new ezTOC_Admin();
566
-
567
- }
1
+ <?php
2
+
3
+ // Exit if accessed directly
4
+ if ( ! defined( 'ABSPATH' ) ) exit;
5
+
6
+ if ( ! class_exists( 'ezTOC_Admin' ) ) {
7
+
8
+ /**
9
+ * Class ezTOC_Admin
10
+ */
11
+ final class ezTOC_Admin {
12
+
13
+ /**
14
+ * Setup plugin for admin use.
15
+ *
16
+ * @access private
17
+ * @since 1.0
18
+ * @static
19
+ */
20
+ public function __construct() {
21
+
22
+ $this->hooks();
23
+ //$this->registerMetaboxes();
24
+ }
25
+
26
+ /**
27
+ * Add the core admin hooks.
28
+ *
29
+ * @access private
30
+ * @since 1.0
31
+ * @static
32
+ */
33
+ private function hooks() {
34
+
35
+ add_action( 'admin_init', array( $this, 'registerScripts' ) );
36
+ add_action( 'admin_menu', array( $this, 'menu' ) );
37
+ add_action( 'init', array( $this, 'registerMetaboxes' ), 99 );
38
+ add_filter( 'plugin_action_links_' . EZ_TOC_BASE_NAME, array( $this, 'pluginActionLinks' ), 10, 2 );
39
+ add_action( 'admin_enqueue_scripts', array( $this, 'load_scripts' ) );
40
+ add_action('wp_ajax_eztoc_send_query_message', array( $this, 'eztoc_send_query_message'));
41
+ }
42
+
43
+ /**
44
+ * Callback to add the Settings link to the plugin action links.
45
+ *
46
+ * @access private
47
+ * @since 1.0
48
+ * @static
49
+ *
50
+ * @param $links
51
+ * @param $file
52
+ *
53
+ * @return array
54
+ */
55
+ public function pluginActionLinks( $links, $file ) {
56
+
57
+ $url = add_query_arg( 'page', 'table-of-contents', self_admin_url( 'options-general.php' ) );
58
+ $setting_link = '<a href="' . esc_url( $url ) . '">' . __( 'Settings', 'easy-table-of-contents' ) . '</a> |';
59
+ $setting_link .= '<a href="https://tocwp.com/contact/" target="_blank">' . __( ' Support', 'easy-table-of-contents' ) . '</a> |';
60
+ $setting_link .= '<a href="https://tocwp.com/pricing/" target="_blank">' . __( ' Upgrade', 'easy-table-of-contents' ) . '</a> |';
61
+ $setting_link .= '<a href="https://tocwp.com/" target="_blank">' . __( ' Website', 'easy-table-of-contents' ) . '</a>';
62
+ array_push( $links, $setting_link );
63
+ return $links;
64
+ }
65
+
66
+ /**
67
+ * Register the scripts used in the admin.
68
+ *
69
+ * @access private
70
+ * @since 1.0
71
+ * @static
72
+ */
73
+ public function registerScripts() {
74
+
75
+ wp_register_script( 'cn_toc_admin_script', EZ_TOC_URL . 'assets/js/admin.js', array( 'jquery', 'wp-color-picker' ), ezTOC::VERSION, true );
76
+ wp_register_style( 'cn_toc_admin_style', EZ_TOC_URL . 'assets/css/admin.css', array( 'wp-color-picker' ), ezTOC::VERSION );
77
+ }
78
+
79
+ /**
80
+ * Callback to add plugin as a submenu page of the Options page.
81
+ *
82
+ * This also adds the action to enqueue the scripts to be loaded on plugin's admin pages only.
83
+ *
84
+ * @access private
85
+ * @since 1.0
86
+ * @static
87
+ */
88
+ public function menu() {
89
+
90
+ $page = add_submenu_page(
91
+ 'options-general.php',
92
+ esc_html__( 'Table of Contents', 'easy-table-of-contents' ),
93
+ esc_html__( 'Table of Contents', 'easy-table-of-contents' ),
94
+ 'manage_options',
95
+ 'table-of-contents',
96
+ array( $this, 'page' )
97
+ );
98
+
99
+ add_action( 'admin_print_styles-' . $page, array( $this, 'enqueueScripts' ) );
100
+ }
101
+
102
+ /**
103
+ * Enqueue the scripts.
104
+ *
105
+ * @access private
106
+ * @since 1.0
107
+ * @static
108
+ */
109
+ public function enqueueScripts() {
110
+
111
+ wp_enqueue_script( 'cn_toc_admin_script' );
112
+ wp_enqueue_style( 'cn_toc_admin_style' );
113
+ }
114
+
115
+ /**
116
+ * Callback to add the action which will register the table of contents post metaboxes.
117
+ *
118
+ * Metaboxes will only be registered for the post types per user preferences.
119
+ *
120
+ * @access private
121
+ * @since 1.0
122
+ * @static
123
+ */
124
+ public function registerMetaboxes() {
125
+
126
+ foreach ( get_post_types() as $type ) {
127
+
128
+ if ( in_array( $type, ezTOC_Option::get( 'enabled_post_types', array() ) ) ) {
129
+
130
+ add_action( "add_meta_boxes_$type", array( $this, 'metabox' ) );
131
+ add_action( "save_post_$type", array( $this, 'save' ), 10, 3 );
132
+ }
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Callback to register the table of contents metaboxes.
138
+ *
139
+ * @access private
140
+ * @since 1.0
141
+ * @static
142
+ */
143
+ public function metabox() {
144
+
145
+ add_meta_box( 'ez-toc', esc_html__( 'Table of Contents', 'ez-toc' ), array( $this, 'displayMetabox' ) );
146
+ }
147
+
148
+ /**
149
+ * Callback to render the content of the table of contents metaboxes.
150
+ *
151
+ * @access private
152
+ * @since 1.0
153
+ * @static
154
+ *
155
+ * @param object $post The post object.
156
+ * @param $atts
157
+ */
158
+ public function displayMetabox( $post, $atts ) {
159
+
160
+ // Add an nonce field so we can check for it on save.
161
+ wp_nonce_field( 'ez_toc_save', '_ez_toc_nonce' );
162
+
163
+ $suppress = get_post_meta( $post->ID, '_ez-toc-disabled', true ) == 1 ? true : false;
164
+ $insert = get_post_meta( $post->ID, '_ez-toc-insert', true ) == 1 ? true : false;
165
+ $headings = get_post_meta( $post->ID, '_ez-toc-heading-levels', true );
166
+ $exclude = get_post_meta( $post->ID, '_ez-toc-exclude', true );
167
+ $altText = get_post_meta( $post->ID, '_ez-toc-alttext', true );
168
+
169
+ if ( ! is_array( $headings ) ) {
170
+
171
+ $headings = array();
172
+ }
173
+ ?>
174
+
175
+ <table class="form-table">
176
+
177
+ <tbody>
178
+
179
+ <tr>
180
+ <th scope="row"></th>
181
+ <td>
182
+
183
+ <?php if ( in_array( get_post_type( $post ), ezTOC_Option::get( 'auto_insert_post_types', array() ) ) ) :
184
+
185
+ ezTOC_Option::checkbox(
186
+ array(
187
+ 'id' => 'disabled-toc',
188
+ 'desc' => esc_html__( 'Disable the automatic insertion of the table of contents.', 'easy-table-of-contents' ),
189
+ 'default' => $suppress,
190
+ ),
191
+ $suppress
192
+ );
193
+
194
+ elseif( in_array( get_post_type( $post ), ezTOC_Option::get( 'enabled_post_types', array() ) ) ):
195
+
196
+ ezTOC_Option::checkbox(
197
+ array(
198
+ 'id' => 'insert-toc',
199
+ 'desc' => esc_html__( 'Insert table of contents.', 'easy-table-of-contents' ),
200
+ 'default' => $insert,
201
+ ),
202
+ $insert
203
+ );
204
+
205
+ endif; ?>
206
+
207
+ </td>
208
+ </tr>
209
+
210
+ <tr>
211
+ <th scope="row"><?php esc_html_e( 'Advanced:', 'easy-table-of-contents' ); ?></th>
212
+ <td>
213
+ <?php
214
+ ezTOC_Option::descriptive_text(
215
+ array(
216
+ 'id' => 'exclude-desc',
217
+ 'name' => '',
218
+ 'desc' => '<p><strong>' . esc_html__( 'NOTE:', 'easy-table-of-contents' ) . '</strong></p>' .
219
+ '<ul>' .
220
+ '<li>' . esc_html__( 'Using the advanced options below will override the global advanced settings.', 'easy-table-of-contents' ) . '</li>' .
221
+ '</ul>',
222
+ )
223
+ );
224
+ ?>
225
+ </td>
226
+ </tr>
227
+
228
+ <tr>
229
+ <th scope="row"><?php esc_html_e( 'Headings:', 'easy-table-of-contents' ); ?></th>
230
+ <td>
231
+ <?php
232
+ ezTOC_Option::checkboxgroup(
233
+ array(
234
+ 'id' => 'heading-levels',
235
+ 'desc' => esc_html__( 'Select the heading to consider when generating the table of contents. Deselecting a heading will exclude it.', 'easy-table-of-contents' ),
236
+ 'options' => array(
237
+ '1' => __( 'Heading 1 (h1)', 'easy-table-of-contents' ),
238
+ '2' => __( 'Heading 2 (h2)', 'easy-table-of-contents' ),
239
+ '3' => __( 'Heading 3 (h3)', 'easy-table-of-contents' ),
240
+ '4' => __( 'Heading 4 (h4)', 'easy-table-of-contents' ),
241
+ '5' => __( 'Heading 5 (h5)', 'easy-table-of-contents' ),
242
+ '6' => __( 'Heading 6 (h6)', 'easy-table-of-contents' ),
243
+ ),
244
+ 'default' => array(),
245
+ ),
246
+ array_map( 'absint', $headings )
247
+ );
248
+ ?>
249
+ </td>
250
+ </tr>
251
+ <tr>
252
+ <th scope="row"><?php esc_html_e( 'Alternate Headings', 'easy-table-of-contents' ); ?></th>
253
+ <td>
254
+ <?php
255
+ ezTOC_Option::textarea(
256
+ array(
257
+ 'id' => 'alttext',
258
+ 'desc' => __( 'Specify alternate table of contents header string. Add the header to be replaced and the alternate header on a single line separated with a pipe <code>|</code>. Put each additional original and alternate header on its own line.', 'easy-table-of-contents' ),
259
+ 'size' => 'large',
260
+ 'default' => '',
261
+ ),
262
+ $altText
263
+ );
264
+ ?>
265
+ </td>
266
+ </tr>
267
+ <tr>
268
+ <th scope="row"></th>
269
+ <td>
270
+ <?php
271
+ ezTOC_Option::descriptive_text(
272
+ array(
273
+ 'id' => 'alttext-desc',
274
+ 'name' => '',
275
+ 'desc' => '<p><strong>' . esc_html__( 'Examples:', 'easy-table-of-contents' ) . '</strong></p>' .
276
+ '<ul>' .
277
+ '<li>' . __( '<code>Level [1.1]|Alternate TOC Header</code> Replaces Level [1.1] in the table of contents with Alternate TOC Header.', 'easy-table-of-contents' ) . '</li>' .
278
+ '</ul>' .
279
+ '<p>' . __( '<strong>Note:</strong> This is case sensitive.', 'easy-table-of-contents' ) . '</p>',
280
+ )
281
+ );
282
+ ?>
283
+ </td>
284
+ </tr>
285
+ <tr>
286
+ <th scope="row"><?php esc_html_e( 'Exclude Headings', 'easy-table-of-contents' ); ?></th>
287
+ <td>
288
+ <?php
289
+ ezTOC_Option::text(
290
+ array(
291
+ 'id' => 'exclude',
292
+ 'desc' => __( 'Specify headings to be excluded from appearing in the table of contents. Separate multiple headings with a pipe <code>|</code>. Use an asterisk <code>*</code> as a wildcard to match other text.', 'easy-table-of-contents' ),
293
+ 'size' => 'large',
294
+ 'default' => '',
295
+ ),
296
+ $exclude
297
+ );
298
+ ?>
299
+ </td>
300
+ </tr>
301
+ <tr>
302
+ <th scope="row"></th>
303
+ <td>
304
+ <?php
305
+ ezTOC_Option::descriptive_text(
306
+ array(
307
+ 'id' => 'exclude-desc',
308
+ 'name' => '',
309
+ 'desc' => '<p><strong>' . esc_html__( 'Examples:', 'easy-table-of-contents' ) . '</strong></p>' .
310
+ '<ul>' .
311
+ '<li>' . __( '<code>Fruit*</code> Ignore headings starting with "Fruit".', 'easy-table-of-contents' ) . '</li>' .
312
+ '<li>' . __( '<code>*Fruit Diet*</code> Ignore headings with "Fruit Diet" somewhere in the heading.', 'easy-table-of-contents' ) . '</li>' .
313
+ '<li>' . __( '<code>Apple Tree|Oranges|Yellow Bananas</code> Ignore headings that are exactly "Apple Tree", "Oranges" or "Yellow Bananas".', 'easy-table-of-contents' ) . '</li>' .
314
+ '</ul>' .
315
+ '<p>' . __( '<strong>Note:</strong> This is not case sensitive.', 'easy-table-of-contents' ) . '</p>',
316
+ )
317
+ );
318
+ ?>
319
+ </td>
320
+ </tr>
321
+ </tbody>
322
+ </table>
323
+
324
+ <?php
325
+ }
326
+
327
+ /**
328
+ * Callback which saves the user preferences from the table of contents metaboxes.
329
+ *
330
+ * @access private
331
+ * @since 1.0
332
+ * @static
333
+ *
334
+ * @param int $post_id The post ID.
335
+ * @param object $post The post object.
336
+ * @param bool $update Whether this is an existing post being updated or not.
337
+ */
338
+ public function save( $post_id, $post, $update ) {
339
+
340
+ if ( current_user_can( 'edit_post', $post_id ) &&
341
+ isset( $_REQUEST['_ez_toc_nonce'] ) &&
342
+ wp_verify_nonce( $_REQUEST['_ez_toc_nonce'], 'ez_toc_save' )
343
+ ) {
344
+
345
+ // Checkboxes are present if checked, absent if not.
346
+ if ( isset( $_REQUEST['ez-toc-settings']['disabled-toc'] ) ) {
347
+
348
+ update_post_meta( $post_id, '_ez-toc-disabled', true );
349
+
350
+ } else {
351
+
352
+ update_post_meta( $post_id, '_ez-toc-disabled', false );
353
+
354
+ }
355
+
356
+ if ( isset( $_REQUEST['ez-toc-settings']['insert-toc'] ) ) {
357
+
358
+ update_post_meta( $post_id, '_ez-toc-insert', true );
359
+
360
+ } else {
361
+
362
+ update_post_meta( $post_id, '_ez-toc-insert', false );
363
+ }
364
+
365
+ if ( isset( $_REQUEST['ez-toc-settings']['heading-levels'] ) && ! empty( $_REQUEST['ez-toc-settings']['heading-levels'] ) ) {
366
+
367
+ if ( is_array( $_REQUEST['ez-toc-settings']['heading-levels'] ) ) {
368
+
369
+ $headings = array_map( 'absint', $_REQUEST['ez-toc-settings']['heading-levels'] );
370
+
371
+ } else {
372
+
373
+ $headings = array();
374
+ }
375
+
376
+ update_post_meta( $post_id, '_ez-toc-heading-levels', $headings );
377
+
378
+ } else {
379
+
380
+ update_post_meta( $post_id, '_ez-toc-heading-levels', array() );
381
+ }
382
+
383
+ if ( isset( $_REQUEST['ez-toc-settings']['alttext'] ) && ! empty( $_REQUEST['ez-toc-settings']['alttext'] ) ) {
384
+
385
+ if ( is_string( $_REQUEST['ez-toc-settings']['alttext'] ) ) {
386
+
387
+ $alttext = trim( $_REQUEST['ez-toc-settings']['alttext'] );
388
+
389
+ } else {
390
+
391
+ $alttext = '';
392
+ }
393
+
394
+ /*
395
+ * This is basically `esc_html()` but does not encode quotes.
396
+ * This is to allow angle brackets and such which `wp_kses_post` would strip as "evil" scripts.
397
+ */
398
+ $alttext = wp_check_invalid_utf8( $alttext );
399
+ $alttext = _wp_specialchars( $alttext, ENT_NOQUOTES );
400
+
401
+ update_post_meta( $post_id, '_ez-toc-alttext', wp_kses_post( $alttext ) );
402
+
403
+ } else {
404
+
405
+ update_post_meta( $post_id, '_ez-toc-alttext', '' );
406
+ }
407
+
408
+ if ( isset( $_REQUEST['ez-toc-settings']['exclude'] ) && ! empty( $_REQUEST['ez-toc-settings']['exclude'] ) ) {
409
+
410
+ if ( is_string( $_REQUEST['ez-toc-settings']['exclude'] ) ) {
411
+
412
+ $exclude = trim( $_REQUEST['ez-toc-settings']['exclude'] );
413
+
414
+ } else {
415
+
416
+ $exclude = '';
417
+ }
418
+
419
+ /*
420
+ * This is basically `esc_html()` but does not encode quotes.
421
+ * This is to allow angle brackets and such which `wp_kses_post` would strip as "evil" scripts.
422
+ */
423
+ $exclude = wp_check_invalid_utf8( $exclude );
424
+ $exclude = _wp_specialchars( $exclude, ENT_NOQUOTES );
425
+
426
+ update_post_meta( $post_id, '_ez-toc-exclude', wp_kses_post( $exclude ) );
427
+
428
+ } else {
429
+
430
+ update_post_meta( $post_id, '_ez-toc-exclude', '' );
431
+ }
432
+
433
+ }
434
+
435
+ }
436
+
437
+
438
+ /**
439
+ * Enqueue Admin js scripts
440
+ *
441
+ */
442
+ public function load_scripts($pagenow){
443
+
444
+ if (isset($pagenow) && $pagenow != 'settings_page_table-of-contents' && strpos($pagenow, 'table-of-contents') == false) {
445
+
446
+ return false;
447
+ }
448
+
449
+ wp_enqueue_script( 'eztoc-admin-js', EZ_TOC_URL . 'assets/js/eztoc-admin.js',array('jquery'), ezTOC::VERSION,true );
450
+
451
+ $data = array(
452
+ 'ajax_url' => admin_url( 'admin-ajax.php' ),
453
+ 'eztoc_security_nonce' => wp_create_nonce('eztoc_ajax_check_nonce'),
454
+ );
455
+
456
+ $data = apply_filters('eztoc_localize_filter',$data,'eztoc_admin_data');
457
+
458
+ wp_localize_script( 'eztoc-admin-js', 'eztoc_admin_data', $data );
459
+ }
460
+
461
+ /**
462
+ * This is a ajax handler function for sending email from user admin panel to us.
463
+ * @return type json string
464
+ */
465
+
466
+ public function eztoc_send_query_message(){
467
+
468
+ if ( ! isset( $_POST['eztoc_security_nonce'] ) ){
469
+ return;
470
+ }
471
+ if ( !wp_verify_nonce( $_POST['eztoc_security_nonce'], 'eztoc_ajax_check_nonce' ) ){
472
+ return;
473
+ }
474
+ $message = $this->eztoc_sanitize_textarea_field($_POST['message']);
475
+ $email = $this->eztoc_sanitize_textarea_field($_POST['email']);
476
+
477
+ if(function_exists('wp_get_current_user')){
478
+
479
+ $user = wp_get_current_user();
480
+
481
+
482
+ $message = '<p>'.$message.'</p><br><br>'.'Query from Easy Table of Content plugin support tab';
483
+
484
+ $user_data = $user->data;
485
+ $user_email = $user_data->user_email;
486
+
487
+ if($email){
488
+ $user_email = $email;
489
+ }
490
+ //php mailer variables
491
+ $sendto = 'team@magazine3.in';
492
+ $subject = "Easy Table of Content Query";
493
+
494
+ $headers[] = 'Content-Type: text/html; charset=UTF-8';
495
+ $headers[] = 'From: '. esc_attr($user_email);
496
+ $headers[] = 'Reply-To: ' . esc_attr($user_email);
497
+ // Load WP components, no themes.
498
+
499
+ $sent = wp_mail($sendto, $subject, $message, $headers);
500
+
501
+ if($sent){
502
+
503
+ echo json_encode(array('status'=>'t'));
504
+
505
+ }else{
506
+
507
+ echo json_encode(array('status'=>'f'));
508
+
509
+ }
510
+
511
+ }
512
+
513
+ wp_die();
514
+ }
515
+
516
+ public function eztoc_sanitize_textarea_field( $str ) {
517
+
518
+ if ( is_object( $str ) || is_array( $str ) ) {
519
+ return '';
520
+ }
521
+
522
+ $str = (string) $str;
523
+
524
+ $filtered = wp_check_invalid_utf8( $str );
525
+
526
+ if ( strpos( $filtered, '<' ) !== false ) {
527
+ $filtered = wp_pre_kses_less_than( $filtered );
528
+ // This will strip extra whitespace for us.
529
+ $filtered = wp_strip_all_tags( $filtered, false );
530
+
531
+ // Use HTML entities in a special case to make sure no later
532
+ // newline stripping stage could lead to a functional tag.
533
+ $filtered = str_replace( "<\n", "&lt;\n", $filtered );
534
+ }
535
+
536
+ $filtered = trim( $filtered );
537
+
538
+ $found = false;
539
+ while ( preg_match( '/%[a-f0-9]{2}/i', $filtered, $match ) ) {
540
+ $filtered = str_replace( $match[0], '', $filtered );
541
+ $found = true;
542
+ }
543
+
544
+ if ( $found ) {
545
+ // Strip out the whitespace that may now exist after removing the octets.
546
+ $filtered = trim( preg_replace( '/ +/', ' ', $filtered ) );
547
+ }
548
+
549
+ return $filtered;
550
+ }
551
+
552
+ /**
553
+ * Callback used to render the admin options page.
554
+ *
555
+ * @access private
556
+ * @since 1.0
557
+ * @static
558
+ */
559
+ public function page() {
560
+
561
+ include EZ_TOC_PATH . '/includes/inc.admin-options-page.php';
562
+ }
563
+ }
564
+
565
+ new ezTOC_Admin();
566
+
567
+ }
includes/class.options.php CHANGED
@@ -1,1386 +1,1386 @@
1
- <?php
2
-
3
- // Exit if accessed directly
4
- if ( ! defined( 'ABSPATH' ) ) exit;
5
-
6
- if ( ! class_exists( 'ezTOC_Option' ) ) {
7
-
8
- /**
9
- * Class ezTOC_Option
10
- *
11
- * Credit: Adapted from Easy Digital Downloads.
12
- */
13
- final class ezTOC_Option {
14
-
15
- /**
16
- * Register the plugins core settings and options.
17
- *
18
- * @access private
19
- * @since 1.0
20
- * @static
21
- */
22
- public static function register() {
23
-
24
- if ( false === get_option( 'ez-toc-settings' ) ) {
25
-
26
- add_option( 'ez-toc-settings', self::getDefaults() );
27
- }
28
-
29
- foreach ( self::getRegistered() as $section => $settings ) {
30
-
31
- add_settings_section(
32
- 'ez_toc_settings_' . $section,
33
- __return_null(),
34
- '__return_false',
35
- 'ez_toc_settings_' . $section
36
- );
37
-
38
- foreach ( $settings as $option ) {
39
-
40
- $name = isset( $option['name'] ) ? $option['name'] : '';
41
-
42
- add_settings_field(
43
- 'ez-toc-settings[' . $option['id'] . ']',
44
- $name,
45
- method_exists( __CLASS__, $option['type'] ) ? array( __CLASS__, $option['type'] ) : array( __CLASS__, 'missingCallback' ),
46
- 'ez_toc_settings_' . $section,
47
- 'ez_toc_settings_' . $section,
48
- array(
49
- 'section' => $section,
50
- 'id' => isset( $option['id'] ) ? $option['id'] : null,
51
- 'desc' => ! empty( $option['desc'] ) ? $option['desc'] : '',
52
- 'name' => isset( $option['name'] ) ? $option['name'] : null,
53
- 'size' => isset( $option['size'] ) ? $option['size'] : null,
54
- 'options' => isset( $option['options'] ) ? $option['options'] : '',
55
- 'default' => isset( $option['default'] ) ? $option['default'] : '',
56
- 'min' => isset( $option['min'] ) ? $option['min'] : null,
57
- 'max' => isset( $option['max'] ) ? $option['max'] : null,
58
- 'step' => isset( $option['step'] ) ? $option['step'] : null,
59
- 'chosen' => isset( $option['chosen'] ) ? $option['chosen'] : null,
60
- 'placeholder' => isset( $option['placeholder'] ) ? $option['placeholder'] : null,
61
- 'allow_blank' => isset( $option['allow_blank'] ) ? $option['allow_blank'] : true,
62
- 'readonly' => isset( $option['readonly'] ) ? $option['readonly'] : false,
63
- 'faux' => isset( $option['faux'] ) ? $option['faux'] : false,
64
- )
65
- );
66
- }
67
-
68
- }
69
-
70
- // Creates our settings in the options table
71
- register_setting( 'ez-toc-settings', 'ez-toc-settings', array( __CLASS__, 'sanitize' ) );
72
- }
73
-
74
- /**
75
- * Callback for settings sanitization.
76
- *
77
- * @access private
78
- * @since 1.0
79
- * @static
80
- *
81
- * @param array $input The value inputted in the field.
82
- *
83
- * @return string $input Sanitized value.
84
- */
85
- public static function sanitize( $input = array() ) {
86
-
87
- $options = self::getOptions();
88
-
89
- if ( empty( $_POST['_wp_http_referer'] ) ) {
90
-
91
- return $input;
92
- }
93
-
94
- $registered = self::getRegistered();
95
-
96
- foreach ( $registered as $sectionID => $sectionOptions ) {
97
-
98
- $input = $input ? $input : array();
99
- $input = apply_filters( 'ez_toc_settings_' . $sectionID . '_sanitize', $input );
100
-
101
- // Loop through each setting being saved and pass it through a sanitization filter
102
- foreach ( $input as $key => $value ) {
103
-
104
- // Get the setting type (checkbox, select, etc)
105
- $type = isset( $registered[ $sectionID ][ $key ]['type'] ) ? $registered[ $sectionID ][ $key ]['type'] : false;
106
-
107
- if ( $type ) {
108
-
109
- // Field type specific filter
110
- $input[ $key ] = apply_filters( 'ez_toc_settings_sanitize_' . $type, $value, $key );
111
- }
112
-
113
- // General filter
114
- $input[ $key ] = apply_filters( 'ez_toc_settings_sanitize', $input[ $key ], $key );
115
- }
116
-
117
- // Loop through the registered options.
118
- foreach ( $sectionOptions as $optionID => $optionProperties ) {
119
-
120
- // Unset any that are empty for the section being saved.
121
- if ( empty( $input[ $optionID ] ) ) {
122
-
123
- unset( $options[ $optionID ] );
124
- }
125
-
126
- // Check for the checkbox option type.
127
- if ( array_key_exists( 'type', $optionProperties ) && 'checkbox' == $optionProperties['type'] ) {
128
-
129
- // If it does not exist in the options values being saved, add the option ID and set its value to `0`.
130
- // This matches WP core behavior for saving checkbox option values.
131
- if ( ! array_key_exists( $optionID, $input ) ) {
132
-
133
- $input[ $optionID ] = '0';
134
- }
135
- }
136
- }
137
-
138
- }
139
-
140
- // Merge our new settings with the existing
141
- $output = array_merge( $options, $input );
142
-
143
- return $output;
144
- }
145
-
146
- /**
147
- * The core registered settings and options.
148
- *
149
- * @access private
150
- * @since 1.0
151
- * @static
152
- *
153
- * @return array
154
- */
155
- private static function getRegistered() {
156
-
157
- $options = array(
158
- 'general' => apply_filters(
159
- 'ez_toc_settings_general',
160
- array(
161
- 'enabled_post_types' => array(
162
- 'id' => 'enabled_post_types',
163
- 'name' => __( 'Enable Support', 'easy-table-of-contents' ),
164
- 'desc' => __( 'Select the post types to enable the support for table of contents.', 'easy-table-of-contents' ),
165
- 'type' => 'checkboxgroup',
166
- 'options' => self::getPostTypes(),
167
- 'default' => array(),
168
- ),
169
- 'auto_insert_post_types' => array(
170
- 'id' => 'auto_insert_post_types',
171
- 'name' => __( 'Auto Insert', 'easy-table-of-contents' ),
172
- 'desc' => __( 'Select the post types which will have the table of contents automatically inserted.', 'easy-table-of-contents' ) .
173
- '<br><span class="description">' . __( 'NOTE: The table of contents will only be automatically inserted on post types for which it has been enabled.', 'easy-table-of-contents' ) . '<span>',
174
- 'type' => 'checkboxgroup',
175
- 'options' => self::getPostTypes(),
176
- 'default' => array(),
177
- ),
178
- 'position' => array(
179
- 'id' => 'position',
180
- 'name' => __( 'Position', 'easy-table-of-contents' ),
181
- 'desc' => __( 'Choose where where you want to display the table of contents.', 'easy-table-of-contents' ),
182
- 'type' => 'select',
183
- 'options' => array(
184
- 'before' => __( 'Before first heading (default)', 'easy-table-of-contents' ),
185
- 'after' => __( 'After first heading', 'easy-table-of-contents' ),
186
- 'top' => __( 'Top', 'easy-table-of-contents' ),
187
- 'bottom' => __( 'Bottom', 'easy-table-of-contents' ),
188
- //'placeholder' => __( 'Replace [toc] placeholder. For backwards compatibility with Table of Content Plus.', 'easy-table-of-contents' ),
189
- ),
190
- 'default' => 1,
191
- ),
192
- 'start' => array(
193
- 'id' => 'start',
194
- 'name' => __( 'Show when', 'easy-table-of-contents' ),
195
- 'desc' => __( 'or more headings are present', 'easy-table-of-contents' ),
196
- 'type' => 'select',
197
- 'options' => array_combine( range( 1, 10 ), range( 1, 10 ) ),
198
- 'default' => 4,
199
- ),
200
- 'show_heading_text' => array(
201
- 'id' => 'show_heading_text',
202
- 'name' => __( 'Display Header Label', 'easy-table-of-contents' ),
203
- 'desc' => __( 'Show header text above the table of contents.', 'easy-table-of-contents' ),
204
- 'type' => 'checkbox',
205
- 'default' => true,
206
- ),
207
- 'heading_text' => array(
208
- 'id' => 'heading_text',
209
- 'name' => __( 'Header Label', 'easy-table-of-contents' ),
210
- 'desc' => __( 'Eg: Contents, Table of Contents, Page Contents', 'easy-table-of-contents' ),
211
- 'type' => 'text',
212
- 'default' => __( 'Contents', 'easy-table-of-contents' ),
213
- ),
214
- 'visibility' => array(
215
- 'id' => 'visibility',
216
- 'name' => __( 'Toggle View', 'easy-table-of-contents' ),
217
- 'desc' => __( 'Allow the user to toggle the visibility of the table of contents.', 'easy-table-of-contents' ),
218
- 'type' => 'checkbox',
219
- 'default' => true,
220
- ),
221
- //'visibility_show' => array(
222
- // 'id' => 'visibility_show',
223
- // 'name' => __( 'Show Label', 'easy-table-of-contents' ),
224
- // 'desc' => __( 'Eg: show', 'easy-table-of-contents' ),
225
- // 'type' => 'text',
226
- // 'default' => __( 'show', 'easy-table-of-contents' ),
227
- //),
228
- //'visibility_hide' => array(
229
- // 'id' => 'visibility_hide',
230
- // 'name' => __( 'Hide Label', 'easy-table-of-contents' ),
231
- // 'desc' => __( 'Eg: hide', 'easy-table-of-contents' ),
232
- // 'type' => 'text',
233
- // 'default' => __( 'hide', 'easy-table-of-contents' ),
234
- //),
235
- 'visibility_hide_by_default' => array(
236
- 'id' => 'visibility_hide_by_default',
237
- 'name' => __( 'Initial View', 'easy-table-of-contents' ),
238
- 'desc' => __( 'Initially hide the table of contents.', 'easy-table-of-contents' ),
239
- 'type' => 'checkbox',
240
- 'default' => false,
241
- ),
242
- 'show_hierarchy' => array(
243
- 'id' => 'show_hierarchy',
244
- 'name' => __( 'Show as Hierarchy', 'easy-table-of-contents' ),
245
- 'desc' => '',
246
- 'type' => 'checkbox',
247
- 'default' => true,
248
- ),
249
- 'counter' => array(
250
- 'id' => 'counter',
251
- 'name' => __( 'Counter', 'easy-table-of-contents' ),
252
- 'desc' => '',
253
- 'type' => 'select',
254
- 'options' => array(
255
- 'decimal' => __( 'Decimal (default)', 'easy-table-of-contents' ),
256
- 'disc' => __( 'Disc', 'easy-table-of-contents' ),
257
- 'hyphen' => __( 'Hyphen', 'easy-table-of-contents' ),
258
- 'numeric' => __( 'Numeric', 'easy-table-of-contents' ),
259
- 'roman' => __( 'Roman', 'easy-table-of-contents' ),
260
- 'none' => __( 'None', 'easy-table-of-contents' ),
261
- ),
262
- 'default' => 'decimal',
263
- ),
264
- 'smooth_scroll' => array(
265
- 'id' => 'smooth_scroll',
266
- 'name' => __( 'Smooth Scroll', 'easy-table-of-contents' ),
267
- 'desc' => '',
268
- 'type' => 'checkbox',
269
- 'default' => true,
270
- ),
271
- 'toc_loading' => array(
272
- 'id' => 'toc_loading',
273
- 'name' => __( 'TOC Loading Method', 'easy-table-of-contents' ),
274
- 'desc' => '',
275
- 'type' => 'select',
276
- 'options' => array(
277
- 'js' => __( 'JavaScript (default)', 'easy-table-of-contents' ),
278
- 'css' => __( 'Pure CSS', 'easy-table-of-contents' ),
279
-
280
- ),
281
- 'default' => 'js',
282
- ),
283
- )
284
- ),
285
- 'appearance' => apply_filters(
286
- 'ez_toc_settings_appearance',
287
- array(
288
- 'width' => array(
289
- 'id' => 'width',
290
- 'name' => __( 'Width', 'easy-table-of-contents' ),
291
- 'desc' => '',
292
- 'type' => 'selectgroup',
293
- 'options' => array(
294
- 'fixed' => array(
295
- 'name' => __( 'Fixed', 'easy-table-of-contents' ),
296
- 'options' => array(
297
- '200px' => '200px',
298
- '225px' => '225px',
299
- '250px' => '250px',
300
- '275px' => '275px',
301
- '300px' => '300px',
302
- '325px' => '325px',
303
- '350px' => '350px',
304
- '375px' => '375px',
305
- '400px' => '400px',
306
- ),
307
- ),
308
- 'relative' => array(
309
- 'name' => __( 'Relative', 'easy-table-of-contents' ),
310
- 'options' => array(
311
- 'auto' => 'Auto',
312
- '25%' => '25%',
313
- '33%' => '33%',
314
- '50%' => '50%',
315
- '66%' => '66%',
316
- '75%' => '75%',
317
- '100%' => '100%',
318
- ),
319
- ),
320
- 'other' => array(
321
- 'name' => __( 'Custom', 'easy-table-of-contents' ),
322
- 'options' => array(
323
- 'custom' => __( 'User Defined', 'easy-table-of-contents' ),
324
- ),
325
- ),
326
- ),
327
- 'default' => 'auto',
328
- ),
329
- 'width_custom' => array(
330
- 'id' => 'width_custom',
331
- 'name' => __( 'Custom Width', 'easy-table-of-contents' ),
332
- 'desc' => __( 'Select the User Defined option from the Width option to utilitze the custom width.', 'easy-table-of-contents' ),
333
- 'type' => 'custom_width',
334
- 'default' => 275,
335
- ),
336
- 'wrapping' => array(
337
- 'id' => 'wrapping',
338
- 'name' => __( 'Alignment', 'easy-table-of-contents' ),
339
- 'desc' => '',
340
- 'type' => 'select',
341
- 'options' => array(
342
- 'none' => __( 'None (Default)', 'easy-table-of-contents' ),
343
- 'left' => __( 'Left', 'easy-table-of-contents' ),
344
- 'right' => __( 'Right', 'easy-table-of-contents' ),
345
- 'center' => __( 'Center', 'easy-table-of-contents' ),
346
- ),
347
- 'default' => 'none',
348
- ),
349
- 'font_options_header' => array(
350
- 'id' => 'font_options',
351
- 'name' => '<strong>' . __( 'Font Option', 'easy-table-of-contents' ) . '</strong>',
352
- //'desc' => __( 'For the following settings to apply, select the Custom Font option.', 'easy-table-of-contents' ),
353
- 'type' => 'header',
354
- ),
355
- 'title_font_size' => array(
356
- 'id' => 'title_font_size',
357
- 'name' => __( 'Title Font Size', 'easy-table-of-contents' ),
358
- 'desc' => '',
359
- 'type' => 'font_size',
360
- 'default' => 120,
361
- ),
362
- 'title_font_weight' => array(
363
- 'id' => 'title_font_weight',
364
- 'name' => __( 'Title Font Weight', 'easy-table-of-contents' ),
365
- 'desc' => '',
366
- 'type' => 'select',
367
- 'options' => array(
368
- '100' => __( 'Thin', 'easy-table-of-contents' ),
369
- '200' => __( 'Extra Light', 'easy-table-of-contents' ),
370
- '300' => __( 'Light', 'easy-table-of-contents' ),
371
- '400' => __( 'Normal', 'easy-table-of-contents' ),
372
- '500' => __( 'Medium', 'easy-table-of-contents' ),
373
- '600' => __( 'Semi Bold', 'easy-table-of-contents' ),
374
- '700' => __( 'Bold', 'easy-table-of-contents' ),
375
- '800' => __( 'Extra Bold', 'easy-table-of-contents' ),
376
- '900' => __( 'Heavy', 'easy-table-of-contents' ),
377
- ),
378
- 'default' => '500',
379
- ),
380
- 'font_size' => array(
381
- 'id' => 'font_size',
382
- 'name' => __( 'Font Size', 'easy-table-of-contents' ),
383
- 'desc' => '',
384
- 'type' => 'font_size',
385
- 'default' => 95,
386
- ),
387
- 'child_font_size' => array(
388
- 'id' => 'child_font_size',
389
- 'name' => __( 'Child Font Size', 'easy-table-of-contents' ),
390
- 'desc' => '',
391
- 'type' => 'child_font_size',
392
- 'default' => 90,
393
- ),
394
- 'theme_option_header' => array(
395
- 'id' => 'theme_option_header',
396
- 'name' => '<strong>' . __( 'Theme Options', 'easy-table-of-contents' ) . '</strong>',
397
- //'desc' => __( 'For the following settings to apply, select the Custom Theme option.', 'easy-table-of-contents' ),
398
- 'type' => 'header',
399
- ),
400
- 'theme' => array(
401
- 'id' => 'theme',
402
- 'name' => __( 'Theme', 'easy-table-of-contents' ),
403
- 'desc' => __( 'The theme is only applied to the table of contents which is auto inserted into the post. The Table of Contents widget will inherit the theme widget styles.', 'easy-table-of-contents' ),
404
- 'type' => 'radio',
405
- 'options' => array(
406
- 'grey' => __( 'Grey', 'easy-table-of-contents' ),
407
- 'light-blue' => __( 'Light Blue', 'easy-table-of-contents' ),
408
- 'white' => __( 'White', 'easy-table-of-contents' ),
409
- 'black' => __( 'Black', 'easy-table-of-contents' ),
410
- 'transparent' => __( 'Transparent', 'easy-table-of-contents' ),
411
- 'custom' => __( 'Custom', 'easy-table-of-contents' ),
412
- ),
413
- 'default' => 'grey',
414
- ),
415
- 'custom_theme_header' => array(
416
- 'id' => 'custom_theme_header',
417
- 'name' => '<strong>' . __( 'Custom Theme', 'easy-table-of-contents' ) . '</strong>',
418
- 'desc' => __( 'For the following settings to apply, select the Custom Theme option.', 'easy-table-of-contents' ),
419
- 'type' => 'header',
420
- ),
421
- 'custom_background_colour' => array(
422
- 'id' => 'custom_background_colour',
423
- 'name' => __( 'Background Color', 'easy-table-of-contents' ),
424
- 'desc' => '',
425
- 'type' => 'color',
426
- 'default' => '#fff',
427
- ),
428
- 'custom_border_colour' => array(
429
- 'id' => 'custom_border_colour',
430
- 'name' => __( 'Border Color', 'easy-table-of-contents' ),
431
- 'desc' => '',
432
- 'type' => 'color',
433
- 'default' => '#ddd',
434
- ),
435
- 'custom_title_colour' => array(
436
- 'id' => 'custom_title_colour',
437
- 'name' => __( 'Title Color', 'easy-table-of-contents' ),
438
- 'desc' => '',
439
- 'type' => 'color',
440
- 'default' => '#999',
441
- ),
442
- 'custom_link_colour' => array(
443
- 'id' => 'custom_link_colour',
444
- 'name' => __( 'Link Color', 'easy-table-of-contents' ),
445
- 'desc' => '',
446
- 'type' => 'color',
447
- 'default' => '#428bca',
448
- ),
449
- 'custom_link_hover_colour' => array(
450
- 'id' => 'custom_link_hover_colour',
451
- 'name' => __( 'Link Hover Color', 'easy-table-of-contents' ),
452
- 'desc' => '',
453
- 'type' => 'color',
454
- 'default' => '#2a6496',
455
- ),
456
- 'custom_link_visited_colour' => array(
457
- 'id' => 'custom_link_visited_colour',
458
- 'name' => __( 'Link Visited Color', 'easy-table-of-contents' ),
459
- 'desc' => '',
460
- 'type' => 'color',
461
- 'default' => '#428bca',
462
- ),
463
- )
464
- ),
465
- 'advanced' => apply_filters(
466
- 'ez_toc_settings_advanced',
467
- array(
468
- 'lowercase' => array(
469
- 'id' => 'lowercase',
470
- 'name' => __( 'Lowercase', 'easy-table-of-contents' ),
471
- 'desc' => __( 'Ensure anchors are in lowercase.', 'easy-table-of-contents' ),
472
- 'type' => 'checkbox',
473
- 'default' => false,
474
- ),
475
- 'hyphenate' => array(
476
- 'id' => 'hyphenate',
477
- 'name' => __( 'Hyphenate', 'easy-table-of-contents' ),
478
- 'desc' => __( 'Use - rather than _ in anchors.', 'easy-table-of-contents' ),
479
- 'type' => 'checkbox',
480
- 'default' => false,
481
- ),
482
- 'include_homepage' => array(
483
- 'id' => 'include_homepage',
484
- 'name' => __( 'Homepage', 'easy-table-of-contents' ),
485
- 'desc' => __( 'Show the table of contents for qualifying items on the homepage.', 'easy-table-of-contents' ),
486
- 'type' => 'checkbox',
487
- 'default' => false,
488
- ),
489
- 'exclude_css' => array(
490
- 'id' => 'exclude_css',
491
- 'name' => __( 'CSS', 'easy-table-of-contents' ),
492
- 'desc' => __( "Prevent the loading the core CSS styles. When selected, the appearance options from above will be ignored.", 'easy-table-of-contents' ),
493
- 'type' => 'checkbox',
494
- 'default' => false,
495
- ),
496
- 'inline_css' => array(
497
- 'id' => 'inline_css',
498
- 'name' => __( 'Inline CSS', 'easy-table-of-contents' ),
499
- 'desc' => __( "Improve your website performance by inlining your CSS.", 'easy-table-of-contents' ),
500
- 'type' => 'checkbox',
501
- 'default' => false,
502
- ),
503
- //'bullet_spacing' => array(
504
- // 'id' => 'bullet_spacing',
505
- // 'name' => __( 'Theme Bullets', 'easy-table-of-contents' ),
506
- // 'desc' => __( 'If your theme includes background images for unordered list elements, enable this option to support them.', 'easy-table-of-contents' ),
507
- // 'type' => 'checkbox',
508
- // 'default' => false,
509
- //),
510
- 'heading_levels' => array(
511
- 'id' => 'heading_levels',
512
- 'name' => __( 'Headings:', 'easy-table-of-contents' ),
513
- 'desc' => __( 'Select the heading to consider when generating the table of contents. Deselecting a heading will exclude it.', 'easy-table-of-contents' ),
514
- 'type' => 'checkboxgroup',
515
- 'options' => array(
516
- '1' => __( 'Heading 1 (h1)', 'easy-table-of-contents' ),
517
- '2' => __( 'Heading 2 (h2)', 'easy-table-of-contents' ),
518
- '3' => __( 'Heading 3 (h3)', 'easy-table-of-contents' ),
519
- '4' => __( 'Heading 4 (h4)', 'easy-table-of-contents' ),
520
- '5' => __( 'Heading 5 (h5)', 'easy-table-of-contents' ),
521
- '6' => __( 'Heading 6 (h6)', 'easy-table-of-contents' ),
522
- ),
523
- 'default' => array( '1', '2', '3', '4', '5', '6' ),
524
- ),
525
- 'exclude' => array(
526
- 'id' => 'exclude',
527
- 'name' => __( 'Exclude Headings', 'easy-table-of-contents' ),
528
- 'desc' => __( 'Specify headings to be excluded from appearing in the table of contents. Separate multiple headings with a pipe <code>|</code>. Use an asterisk <code>*</code> as a wildcard to match other text.', 'easy-table-of-contents' ),
529
- 'type' => 'text',
530
- 'size' => 'large',
531
- 'default' => '',
532
- ),
533
- 'exclude_desc' => array(
534
- 'id' => 'exclude_desc',
535
- 'name' => '',
536
- 'desc' => '<p><strong>' . __( 'Examples:', 'easy-table-of-contents' ) . '</strong></p>' .
537
- '<ul>' .
538
- '<li>' . __( '<code>Fruit*</code> Ignore headings starting with "Fruit".', 'easy-table-of-contents' ) . '</li>' .
539
- '<li>' . __( '<code>*Fruit Diet*</code> Ignore headings with "Fruit Diet" somewhere in the heading.', 'easy-table-of-contents' ) . '</li>' .
540
- '<li>' . __( '<code>Apple Tree|Oranges|Yellow Bananas</code> Ignore headings that are exactly "Apple Tree", "Oranges" or "Yellow Bananas".', 'easy-table-of-contents' ) . '</li>' .
541
- '</ul>' .
542
- '<p>' . __( '<strong>Note:</strong> This is not case sensitive.', 'easy-table-of-contents' ) . '</p>',
543
- 'type' => 'descriptive_text',
544
- ),
545
- 'smooth_scroll_offset' => array(
546
- 'id' => 'smooth_scroll_offset',
547
- 'name' => __( 'Smooth Scroll Offset', 'easy-table-of-contents' ),
548
- 'desc' => 'px<br/>' . __( 'If you have a consistent menu across the top of your site, you can adjust the top offset to stop the headings from appearing underneath the top menu. A setting of 30 accommodates the WordPress admin bar. This setting only has an effect after you have enabled Smooth Scroll option.', 'easy-table-of-contents' ),
549
- 'type' => 'number',
550
- 'size' => 'small',
551
- 'default' => 30
552
- ),
553
- 'mobile_smooth_scroll_offset' => array(
554
- 'id' => 'mobile_smooth_scroll_offset',
555
- 'name' => __( 'Mobile Smooth Scroll Offset', 'easy-table-of-contents' ),
556
- 'desc' => 'px<br/>' . __( 'This provides the same function as the Smooth Scroll Offset option above but applied when the user is visiting your site on a mobile device.', 'easy-table-of-contents' ),
557
- 'type' => 'number',
558
- 'size' => 'small',
559
- 'default' => 0
560
- ),
561
- 'restrict_path' => array(
562
- 'id' => 'restrict_path',
563
- 'name' => __( 'Limit Path', 'easy-table-of-contents' ),
564
- 'desc' => '<br/>' . __( 'Restrict generation of the table of contents to pages that match the required path. This path is from the root of your site and always begins with a forward slash.', 'easy-table-of-contents' ) .
565
- '<br/><span class="description">' . __( 'Eg: /wiki/, /corporate/annual-reports/', 'easy-table-of-contents' ) . '</span>',
566
- 'type' => 'text',
567
- ),
568
- 'fragment_prefix' => array(
569
- 'id' => 'fragment_prefix',
570
- 'name' => __( 'Default Anchor Prefix', 'easy-table-of-contents' ),
571
- 'desc' => '<br/>' . __( 'Anchor targets are restricted to alphanumeric characters as per HTML specification (see readme for more detail). The default anchor prefix will be used when no characters qualify. When left blank, a number will be used instead.', 'easy-table-of-contents' ) .
572
- '<br/>' . __( 'This option normally applies to content written in character sets other than ASCII.', 'easy-table-of-contents' ) .
573
- '<br/><span class="description">' . __( 'Eg: i, toc_index, index, _', 'easy-table-of-contents' ) . '</span>',
574
- 'type' => 'text',
575
- 'default' => 'i',
576
- ),
577
- 'widget_affix_selector' => array(
578
- 'id' => 'widget_affix_selector',
579
- 'name' => __( 'Widget Affix Selector', 'easy-table-of-contents' ),
580
- 'desc' => '<br/>' . __( 'To enable the option to affix or pin the Table of Contents widget enter the theme\'s sidebar class or id.', 'easy-table-of-contents' ) .
581
- '<br/>' . __( 'Since every theme is different, this can not be determined automatically. If you are unsure how to find the sidebar\'s class or id, please ask the theme\'s support persons.', 'easy-table-of-contents' ) .
582
- '<br/><span class="description">' . __( 'Eg: .widget-area or #sidebar', 'easy-table-of-contents' ) . '</span>',
583
- 'type' => 'text',
584
- 'default' => '',
585
- ),
586
-
587
- )
588
- ),
589
- 'prosettings' => apply_filters(
590
- 'ez_toc_settings_prosettings',
591
- array(
592
- 'exclude_by_class' => array(
593
- 'id' => 'exclude_by_class',
594
- 'name' => __( 'Exclude Headings by Class', 'easy-table-of-contents' ),
595
- 'desc' => '<br/>' . __( 'You can hide the TOC heading by its class and if you want to hide multiple headings then please saparate them with a comma (,)', 'easy-table-of-contents' ),
596
- 'type' => 'text',
597
- 'default' => '',
598
- ),
599
- 'fixedtoc' => array(
600
- 'id' => 'fixedtoc',
601
- 'name' => __( 'Fixed TOC', 'easy-table-of-contents' ),
602
- 'desc' => __( 'Fixed TOC in the page display so it can be easier to navigate', 'easy-table-of-contents' ),
603
- 'type' => 'checkbox',
604
- 'default' => false,
605
- ),
606
- )
607
- ),
608
- );
609
-
610
- return apply_filters( 'ez_toc_registered_settings', $options );
611
- }
612
-
613
- /**
614
- * The default values for the registered settings and options.
615
- *
616
- * @access private
617
- * @since 1.0
618
- * @static
619
- *
620
- * @return array
621
- */
622
- private static function getDefaults() {
623
-
624
- $defaults = array(
625
- 'fragment_prefix' => 'i',
626
- 'position' => 'before',
627
- 'start' => 4,
628
- 'show_heading_text' => true,
629
- 'heading_text' => 'Table of Contents',
630
- 'enabled_post_types' => array( 'page' ),
631
- 'auto_insert_post_types' => array(),
632
- 'show_hierarchy' => true,
633
- 'counter' => 'decimal',
634
- 'smooth_scroll' => true,
635
- 'smooth_scroll_offset' => 30,
636
- 'mobile_smooth_scroll_offset' => 0,
637
- 'visibility' => true,
638
- 'toc_loading' => 'js',
639
- //'visibility_show' => 'show',
640
- //'visibility_hide' => 'hide',
641
- 'visibility_hide_by_default' => false,
642
- 'width' => 'auto',
643
- 'width_custom' => 275,
644
- 'width_custom_units' => 'px',
645
- 'wrapping' => 'none',
646
- 'title_font_size' => 120,
647
- 'title_font_size_units' => '%',
648
- 'title_font_weight' => 500,
649
- 'font_size' => 95,
650
- 'child_font_size' => 90,
651
- 'font_size_units' => '%',
652
- 'theme' => 'grey',
653
- 'custom_background_colour' => '#fff',
654
- 'custom_border_colour' => '#ddd',
655
- 'custom_title_colour' => '#999',
656
- 'custom_link_colour' => '#428bca',
657
- 'custom_link_hover_colour' => '#2a6496',
658
- 'custom_link_visited_colour' => '#428bca',
659
- 'lowercase' => false,
660
- 'hyphenate' => false,
661
- //'bullet_spacing' => false,
662
- 'include_homepage' => false,
663
- 'exclude_css' => false,
664
- 'inline_css' => false,
665
- 'exclude' => '',
666
- 'heading_levels' => array( '1', '2', '3', '4', '5', '6' ),
667
- 'restrict_path' => '',
668
- 'css_container_class' => '',
669
- //'show_toc_in_widget_only' => false,
670
- //'show_toc_in_widget_only_post_types' => array(),
671
- 'widget_affix_selector' => '',
672
- );
673
-
674
- return apply_filters( 'ez_toc_get_default_options', $defaults );
675
- }
676
-
677
- /**
678
- * Get the default options array.
679
- *
680
- * @access private
681
- * @since 1.0
682
- * @static
683
- *
684
- * @return array
685
- */
686
- private static function getOptions() {
687
-
688
- $defaults = self::getDefaults();
689
- $options = get_option( 'ez-toc-settings', $defaults );
690
-
691
- //return apply_filters( 'ez_toc_get_options', wp_parse_args( $options, $defaults ) );
692
- return apply_filters( 'ez_toc_get_options', $options );
693
- }
694
-
695
- /**
696
- * Get option value by key name.
697
- *
698
- * @access public
699
- * @since 1.0
700
- * @static
701
- *
702
- * @param string $key
703
- * @param bool|false $default
704
- *
705
- * @return mixed
706
- */
707
- public static function get( $key, $default = false ) {
708
-
709
- $options = self::getOptions();
710
-
711
- $value = array_key_exists( $key, $options ) ? $options[ $key ] : $default;
712
- $value = apply_filters( 'ez_toc_get_option', $value, $key, $default );
713
-
714
- return apply_filters( 'ez_toc_get_option_' . $key, $value, $key, $default );
715
- }
716
-
717
- /**
718
- * Set an option value by key name.
719
- *
720
- * @access public
721
- * @since 1.0
722
- * @static
723
- *
724
- * @param string $key
725
- * @param bool|false $value
726
- *
727
- * @return bool
728
- */
729
- public static function set( $key, $value = false ) {
730
-
731
- if ( empty( $value ) ) {
732
-
733
- $remove_option = self::delete( $key );
734
-
735
- return $remove_option;
736
- }
737
-
738
- $options = self::getOptions();
739
-
740
- $options[ $key ] = apply_filters( 'ez_toc_update_option', $value, $key );
741
-
742
- return update_option( 'ez-toc-settings', $options );
743
- }
744
-
745
- /**
746
- * Delete an option from the options table by option key name.
747
- *
748
- * @access public
749
- * @since 1.0
750
- * @static
751
- *
752
- * @param string $key
753
- *
754
- * @return bool
755
- */
756
- public static function delete( $key ) {
757
-
758
- // First let's grab the current settings
759
- $options = get_option( 'ez-toc-settings' );
760
-
761
- // Next let's try to update the value
762
- if ( array_key_exists( $key, $options ) ) {
763
-
764
- unset( $options[ $key ] );
765
- }
766
-
767
- return update_option( 'ez-toc-settings', $options );
768
- }
769
-
770
- /**
771
- * Sanitize a hex color from user input.
772
- *
773
- * Tries to convert $string into a valid hex colour.
774
- * Returns $default if $string is not a hex value, otherwise returns verified hex.
775
- *
776
- * @access private
777
- * @since 1.0
778
- * @static
779
- *
780
- * @param string $string
781
- * @param string $default
782
- *
783
- * @return mixed|string
784
- */
785
- private static function hex_value( $string = '', $default = '#' ) {
786
-
787
- $return = $default;
788
-
789
- if ( $string ) {
790
- // strip out non hex chars
791
- $return = preg_replace( '/[^a-fA-F0-9]*/', '', $string );
792
-
793
- switch ( strlen( $return ) ) {
794
- case 3: // do next
795
- case 6:
796
- $return = '#' . $return;
797
- break;
798
-
799
- default:
800
- if ( strlen( $return ) > 6 ) {
801
- $return = '#' . substr( $return, 0, 6 );
802
- } // if > 6 chars, then take the first 6
803
- elseif ( strlen( $return ) > 3 && strlen( $return ) < 6 ) {
804
- $return = '#' . substr( $return, 0, 3 );
805
- } // if between 3 and 6, then take first 3
806
- else {
807
- $return = $default;
808
- } // not valid, return $default
809
- }
810
- }
811
-
812
- return $return;
813
- }
814
-
815
- /**
816
- * Get the registered post types minus excluded core types.
817
- *
818
- * @access public
819
- * @since 1.0
820
- * @static
821
- *
822
- * @return array
823
- */
824
- public static function getPostTypes() {
825
-
826
- $exclude = apply_filters( 'ez_toc_exclude_post_types', array( 'attachment', 'revision', 'nav_menu_item', 'safecss' ) );
827
- $registered = get_post_types( array(), 'objects' );
828
- $types = array();
829
-
830
- foreach ( $registered as $post ) {
831
-
832
- if ( in_array( $post->name, $exclude ) ) {
833
-
834
- continue;
835
- }
836
-
837
- $types[ $post->name ] = $post->label;
838
- }
839
-
840
- return $types;
841
- }
842
-
843
- /**
844
- * Missing Callback
845
- *
846
- * If a settings field type callback is not callable, alert the user.
847
- *
848
- * @access public
849
- * @since 1.0
850
- * @static
851
- *
852
- * @param array $args Arguments passed by the setting
853
- */
854
- public static function missingCallback( $args ) {
855
-
856
- printf(
857
- __( 'The callback function used for the <strong>%s</strong> setting is missing.', 'easy-table-of-contents' ),
858
- $args['id']
859
- );
860
- }
861
-
862
- /**
863
- * Text Callback
864
- *
865
- * Renders text fields.
866
- *
867
- * @access public
868
- * @since 1.0
869
- * @static
870
- *
871
- * @param array $args Arguments passed by the setting
872
- * @param null $value
873
- */
874
- public static function text( $args, $value = null ) {
875
-
876
- if ( is_null( $value ) ) {
877
-
878
- $value = self::get( $args['id'], $args['default'] );
879
- }
880
-
881
- if ( isset( $args['faux'] ) && true === $args['faux'] ) {
882
-
883
- $args['readonly'] = true;
884
- $value = isset( $args['default'] ) ? $args['default'] : '';
885
- $name = '';
886
-
887
- } else {
888
-
889
- $name = ' name="ez-toc-settings[' . $args['id'] . ']"';
890
- }
891
-
892
- $readonly = isset( $args['readonly'] ) && $args['readonly'] === true ? ' readonly="readonly"' : '';
893
- $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
894
-
895
- $html = '<input type="text" class="' . $size . '-text" id="ez-toc-settings[' . $args['id'] . ']"' . $name . ' value="' . esc_attr( stripslashes( $value ) ) . '"' . $readonly . '/>';
896
-
897
- if ( 0 < strlen( $args['desc'] ) ) {
898
-
899
- $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
900
- }
901
-
902
- echo $html;
903
- }
904
-
905
- /**
906
- * Textarea Callback.
907
- *
908
- * Renders a textarea.
909
- *
910
- * @access public
911
- * @since 1.1
912
- * @static
913
- *
914
- * @param array $args Arguments passed by the setting
915
- * @param null $value
916
- */
917
- public static function textarea( $args, $value = null ) {
918
-
919
- $html = '';
920
-
921
- if ( is_null( $value ) ) {
922
-
923
- $value = self::get( $args['id'], $args['default'] );
924
- }
925
-
926
- if ( isset( $args['faux'] ) && true === $args['faux'] ) {
927
-
928
- $args['readonly'] = true;
929
- $value = isset( $args['default'] ) ? $args['default'] : '';
930
- $name = '';
931
-
932
- } else {
933
-
934
- $name = ' name="ez-toc-settings[' . $args['id'] . ']"';
935
- }
936
-
937
- $readonly = isset( $args['readonly'] ) && $args['readonly'] === true ? ' readonly="readonly"' : '';
938
- $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
939
-
940
- if ( 0 < strlen( $args['desc'] ) ) {
941
-
942
- $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
943
- }
944
-
945
- $html .= '<textarea rows="10" cols="50" class="' . $size . '-text" id="ez-toc-settings[' . $args['id'] . ']"' . $name . $readonly . '/>' . esc_textarea( $value ) . '</textarea>';
946
-
947
- echo $html;
948
- }
949
-
950
- /**
951
- * Number Callback
952
- *
953
- * Renders number fields.
954
- *
955
- * @access public
956
- * @since 1.0
957
- * @static
958
- *
959
- * @param array $args Arguments passed by the setting
960
- */
961
- public static function number( $args ) {
962
-
963
- $value = self::get( $args['id'], $args['default'] );
964
-
965
- if ( isset( $args['faux'] ) && true === $args['faux'] ) {
966
-
967
- $args['readonly'] = true;
968
- $value = isset( $args['default'] ) ? $args['default'] : '';
969
- $name = '';
970
-
971
- } else {
972
-
973
- $name = ' name="ez-toc-settings[' . $args['id'] . ']"';
974
- }
975
-
976
- $readonly = isset( $args['readonly'] ) && $args['readonly'] === true ? ' readonly="readonly"' : '';
977
- $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
978
-
979
- $html = '<input type="number" class="' . $size . '-text" id="ez-toc-settings[' . $args['id'] . ']"' . $name . ' value="' . esc_attr( stripslashes( $value ) ) . '"' . $readonly . '/>';
980
-
981
- if ( 0 < strlen( $args['desc'] ) ) {
982
-
983
- $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
984
- }
985
-
986
- echo $html;
987
- }
988
-
989
- /**
990
- * Checkbox Callback
991
- *
992
- * Renders checkboxes.
993
- *
994
- * @access public
995
- * @since 1.0
996
- * @static
997
- *
998
- * @param array $args Arguments passed by the setting
999
- * @param null $value
1000
- */
1001
- public static function checkbox( $args, $value = null ) {
1002
-
1003
- if ( is_null( $value ) ) {
1004
-
1005
- $value = self::get( $args['id'], $args['default'] );
1006
- }
1007
-
1008
- if ( isset( $args['faux'] ) && true === $args['faux'] ) {
1009
-
1010
- $name = '';
1011
-
1012
- } else {
1013
-
1014
- $name = ' name="ez-toc-settings[' . $args['id'] . ']"';
1015
- }
1016
-
1017
- $checked = $value ? checked( 1, $value, false ) : '';
1018
-
1019
- $html = '<input type="checkbox" id="ez-toc-settings[' . $args['id'] . ']"' . $name . ' value="1" ' . $checked . '/>';
1020
-
1021
- if ( 0 < strlen( $args['desc'] ) ) {
1022
-
1023
- $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1024
- }
1025
-
1026
- echo $html;
1027
- }
1028
-
1029
- /**
1030
- * Multicheck Callback
1031
- *
1032
- * Renders multiple checkboxes.
1033
- *
1034
- * @access public
1035
- * @since 1.0
1036
- * @static
1037
- *
1038
- * @param array $args Arguments passed by the setting
1039
- * @param null $value
1040
- */
1041
- public static function checkboxgroup( $args, $value = null ) {
1042
-
1043
- if ( is_null( $value ) ) {
1044
-
1045
- $value = self::get( $args['id'], $args['default'] );
1046
- }
1047
-
1048
- if ( ! empty( $args['options'] ) ) {
1049
-
1050
- foreach ( $args['options'] as $key => $option ):
1051
-
1052
- if ( in_array( $key, $value ) ) {
1053
-
1054
- $enabled = $option;
1055
-
1056
- } else {
1057
-
1058
- $enabled = null;
1059
- }
1060
-
1061
- echo '<input name="ez-toc-settings[' . $args['id'] . '][' . $key . ']" id="ez-toc-settings[' . $args['id'] . '][' . $key . ']" type="checkbox" value="' . $key . '" ' . checked( $option, $enabled, false ) . '/>&nbsp;';
1062
- echo '<label for="ez-toc-settings[' . $args['id'] . '][' . $key . ']">' . $option . '</label><br/>';
1063
-
1064
- endforeach;
1065
-
1066
- if ( 0 < strlen( $args['desc'] ) ) {
1067
-
1068
- echo '<p class="description">' . $args['desc'] . '</p>';
1069
- }
1070
- }
1071
- }
1072
-
1073
- /**
1074
- * Radio Callback
1075
- *
1076
- * Renders radio groups.
1077
- *
1078
- * @access public
1079
- * @since 1.0
1080
- * @static
1081
- *
1082
- * @param array $args Arguments passed by the setting
1083
- */
1084
- public static function radio( $args ) {
1085
-
1086
- $value = self::get( $args['id'], $args['default'] );
1087
-
1088
- foreach ( $args['options'] as $key => $option ) {
1089
-
1090
- echo '<input name="ez-toc-settings[' . $args['id'] . ']"" id="ez-toc-settings[' . $args['id'] . '][' . $key . ']" type="radio" value="' . $key . '" ' . checked( $key, $value, false ) . '/>&nbsp;';
1091
- echo '<label for="ez-toc-settings[' . $args['id'] . '][' . $key . ']">' . $option . '</label><br/>';
1092
- }
1093
-
1094
- if ( 0 < strlen( $args['desc'] ) ) {
1095
-
1096
- echo '<p class="description">' . $args['desc'] . '</p>';
1097
- }
1098
- }
1099
-
1100
- /**
1101
- * Select Callback
1102
- *
1103
- * Renders select fields.
1104
- *
1105
- * @access public
1106
- * @since 1.0
1107
- * @static
1108
- *
1109
- * @param array $args Arguments passed by the setting.
1110
- */
1111
- public static function select( $args ) {
1112
-
1113
- $value = self::get( $args['id'], $args['default'] );
1114
-
1115
- if ( isset( $args['placeholder'] ) ) {
1116
- $placeholder = $args['placeholder'];
1117
- } else {
1118
- $placeholder = '';
1119
- }
1120
-
1121
- if ( isset( $args['chosen'] ) ) {
1122
- $chosen = 'class="enhanced"';
1123
- } else {
1124
- $chosen = '';
1125
- }
1126
-
1127
- $html = '<select id="ez-toc-settings[' . $args['id'] . ']" name="ez-toc-settings[' . $args['id'] . ']" ' . $chosen . 'data-placeholder="' . $placeholder . '" />';
1128
-
1129
- foreach ( $args['options'] as $option => $name ) {
1130
- $selected = selected( $option, $value, false );
1131
- $html .= '<option value="' . $option . '" ' . $selected . '>' . $name . '</option>';
1132
- }
1133
-
1134
- $html .= '</select>';
1135
-
1136
- if ( 0 < strlen( $args['desc'] ) ) {
1137
-
1138
- $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1139
- }
1140
-
1141
- echo $html;
1142
- }
1143
-
1144
- /**
1145
- * Select Drop Down Callback
1146
- *
1147
- * Renders select with option group fields.
1148
- *
1149
- * @access public
1150
- * @since 1.0
1151
- * @static
1152
- *
1153
- * @param array $args Arguments passed by the setting.
1154
- */
1155
- public static function selectgroup( $args ) {
1156
-
1157
- $value = self::get( $args['id'], $args['default'] );
1158
-
1159
- if ( isset( $args['placeholder'] ) ) {
1160
- $placeholder = $args['placeholder'];
1161
- } else {
1162
- $placeholder = '';
1163
- }
1164
-
1165
- if ( isset( $args['chosen'] ) ) {
1166
- $chosen = 'class="enhanced"';
1167
- } else {
1168
- $chosen = '';
1169
- }
1170
-
1171
- $html = '<select id="ez-toc-settings[' . $args['id'] . ']" name="ez-toc-settings[' . $args['id'] . ']" ' . $chosen . 'data-placeholder="' . $placeholder . '" />';
1172
-
1173
- foreach ( $args['options'] as $group ) {
1174
-
1175
- $html .= sprintf( '<optgroup label="%1$s">', $group['name'] );
1176
-
1177
- foreach ( $group['options'] as $option => $name ) {
1178
-
1179
- $selected = selected( $option, $value, false );
1180
- $html .= '<option value="' . $option . '" ' . $selected . '>' . $name . '</option>';
1181
- }
1182
-
1183
- $html .= '</optgroup>';
1184
- }
1185
-
1186
- $html .= '</select>';
1187
-
1188
- if ( 0 < strlen( $args['desc'] ) ) {
1189
-
1190
- $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1191
- }
1192
-
1193
- echo $html;
1194
- }
1195
-
1196
- /**
1197
- * Header Callback
1198
- *
1199
- * Renders the header.
1200
- *
1201
- * @access public
1202
- * @since 1.0
1203
- * @static
1204
- *
1205
- * @param array $args Arguments passed by the setting
1206
- */
1207
- public static function header( $args ) {
1208
-
1209
- echo '<hr/>';
1210
-
1211
- if ( 0 < strlen( $args['desc'] ) ) {
1212
-
1213
- echo '<p>' . wp_kses_post( $args['desc'] ) . '</p>';
1214
- }
1215
- }
1216
-
1217
- /**
1218
- * Descriptive text callback.
1219
- *
1220
- * Renders descriptive text onto the settings field.
1221
- *
1222
- * @access public
1223
- * @since 1.0
1224
- * @static
1225
- *
1226
- * @param array $args Arguments passed by the setting
1227
- */
1228
- public static function descriptive_text( $args ) {
1229
-
1230
- echo wp_kses_post( $args['desc'] );
1231
- }
1232
-
1233
- /**
1234
- * Color picker Callback
1235
- *
1236
- * Renders color picker fields.
1237
- *
1238
- * @access public
1239
- * @since 1.0
1240
- * @static
1241
- *
1242
- * @param array $args Arguments passed by the setting
1243
- */
1244
- public static function color( $args ) {
1245
-
1246
- $value = self::get( $args['id'], $args['default'] );
1247
-
1248
- $default = isset( $args['default'] ) ? $args['default'] : '';
1249
-
1250
- $html = '<input type="text" class="ez-toc-color-picker" id="ez-toc-settings[' . $args['id'] . ']" name="ez-toc-settings[' . $args['id'] . ']" value="' . esc_attr( $value ) . '" data-default-color="' . esc_attr( $default ) . '" />';
1251
-
1252
- if ( 0 < strlen( $args['desc'] ) ) {
1253
-
1254
- echo '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1255
- }
1256
-
1257
- echo $html;
1258
- }
1259
-
1260
- /**
1261
- * Custom table of contents width.
1262
- *
1263
- * @access public
1264
- * @since 1.0
1265
- * @static
1266
- *
1267
- * @param array $args
1268
- */
1269
- public static function custom_width( $args ) {
1270
-
1271
- //$value = self::get( $args['id'], $args['default'] );
1272
-
1273
- self::text(
1274
- array(
1275
- 'id' => $args['id'],
1276
- 'desc' => '',
1277
- 'size' => 'small',
1278
- 'default' => $args['default'],
1279
- )
1280
- );
1281
-
1282
- self::select(
1283
- array(
1284
- 'id' => $args['id'] . '_units',
1285
- 'desc' => '',
1286
- 'options' => array(
1287
- 'px' => 'px',
1288
- '%' => '%',
1289
- 'em' => 'em',
1290
- ),
1291
- 'default' => 'px',
1292
- )
1293
- );
1294
-
1295
- if ( 0 < strlen( $args['desc'] ) ) {
1296
-
1297
- echo '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1298
- }
1299
- }
1300
-
1301
- /**
1302
- * Custom font size callback.
1303
- *
1304
- * @access public
1305
- * @since 1.0
1306
- * @static
1307
- *
1308
- * @param array $args
1309
- */
1310
- public static function font_size( $args ) {
1311
-
1312
- //$value = self::get( $args['id'], $args['default'] );
1313
-
1314
- self::text(
1315
- array(
1316
- 'id' => $args['id'],
1317
- 'desc' => '',
1318
- 'size' => 'small',
1319
- 'default' => $args['default'],
1320
- )
1321
- );
1322
-
1323
- self::select(
1324
- array(
1325
- 'id' => $args['id'] . '_units',
1326
- 'desc' => '',
1327
- 'options' => array(
1328
- 'pt' => 'pt',
1329
- 'px' => 'px',
1330
- '%' => '%',
1331
- 'em' => 'em',
1332
- ),
1333
- 'default' => '%',
1334
- )
1335
- );
1336
-
1337
- if ( 0 < strlen( $args['desc'] ) ) {
1338
-
1339
- echo '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1340
- }
1341
- }
1342
- /**
1343
- * Custom font size callback.
1344
- *
1345
- * @access public
1346
- * @since 1.0
1347
- * @static
1348
- *
1349
- * @param array $args
1350
- */
1351
- public static function child_font_size( $args ) {
1352
-
1353
- //$value = self::get( $args['id'], $args['default'] );
1354
-
1355
- self::text(
1356
- array(
1357
- 'id' => $args['id'],
1358
- 'desc' => '',
1359
- 'size' => 'small',
1360
- 'default' => $args['default'],
1361
- )
1362
- );
1363
-
1364
- self::select(
1365
- array(
1366
- 'id' => $args['id'] . '_units',
1367
- 'desc' => '',
1368
- 'options' => array(
1369
- 'pt' => 'pt',
1370
- 'px' => 'px',
1371
- '%' => '%',
1372
- 'em' => 'em',
1373
- ),
1374
- 'default' => '%',
1375
- )
1376
- );
1377
-
1378
- if ( 0 < strlen( $args['desc'] ) ) {
1379
-
1380
- echo '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1381
- }
1382
- }
1383
- }
1384
-
1385
- add_action( 'admin_init', array( 'ezTOC_Option', 'register' ) );
1386
- }
1
+ <?php
2
+
3
+ // Exit if accessed directly
4
+ if ( ! defined( 'ABSPATH' ) ) exit;
5
+
6
+ if ( ! class_exists( 'ezTOC_Option' ) ) {
7
+
8
+ /**
9
+ * Class ezTOC_Option
10
+ *
11
+ * Credit: Adapted from Easy Digital Downloads.
12
+ */
13
+ final class ezTOC_Option {
14
+
15
+ /**
16
+ * Register the plugins core settings and options.
17
+ *
18
+ * @access private
19
+ * @since 1.0
20
+ * @static
21
+ */
22
+ public static function register() {
23
+
24
+ if ( false === get_option( 'ez-toc-settings' ) ) {
25
+
26
+ add_option( 'ez-toc-settings', self::getDefaults() );
27
+ }
28
+
29
+ foreach ( self::getRegistered() as $section => $settings ) {
30
+
31
+ add_settings_section(
32
+ 'ez_toc_settings_' . $section,
33
+ __return_null(),
34
+ '__return_false',
35
+ 'ez_toc_settings_' . $section
36
+ );
37
+
38
+ foreach ( $settings as $option ) {
39
+
40
+ $name = isset( $option['name'] ) ? $option['name'] : '';
41
+
42
+ add_settings_field(
43
+ 'ez-toc-settings[' . $option['id'] . ']',
44
+ $name,
45
+ method_exists( __CLASS__, $option['type'] ) ? array( __CLASS__, $option['type'] ) : array( __CLASS__, 'missingCallback' ),
46
+ 'ez_toc_settings_' . $section,
47
+ 'ez_toc_settings_' . $section,
48
+ array(
49
+ 'section' => $section,
50
+ 'id' => isset( $option['id'] ) ? $option['id'] : null,
51
+ 'desc' => ! empty( $option['desc'] ) ? $option['desc'] : '',
52
+ 'name' => isset( $option['name'] ) ? $option['name'] : null,
53
+ 'size' => isset( $option['size'] ) ? $option['size'] : null,
54
+ 'options' => isset( $option['options'] ) ? $option['options'] : '',
55
+ 'default' => isset( $option['default'] ) ? $option['default'] : '',
56
+ 'min' => isset( $option['min'] ) ? $option['min'] : null,
57
+ 'max' => isset( $option['max'] ) ? $option['max'] : null,
58
+ 'step' => isset( $option['step'] ) ? $option['step'] : null,
59
+ 'chosen' => isset( $option['chosen'] ) ? $option['chosen'] : null,
60
+ 'placeholder' => isset( $option['placeholder'] ) ? $option['placeholder'] : null,
61
+ 'allow_blank' => isset( $option['allow_blank'] ) ? $option['allow_blank'] : true,
62
+ 'readonly' => isset( $option['readonly'] ) ? $option['readonly'] : false,
63
+ 'faux' => isset( $option['faux'] ) ? $option['faux'] : false,
64
+ )
65
+ );
66
+ }
67
+
68
+ }
69
+
70
+ // Creates our settings in the options table
71
+ register_setting( 'ez-toc-settings', 'ez-toc-settings', array( __CLASS__, 'sanitize' ) );
72
+ }
73
+
74
+ /**
75
+ * Callback for settings sanitization.
76
+ *
77
+ * @access private
78
+ * @since 1.0
79
+ * @static
80
+ *
81
+ * @param array $input The value inputted in the field.
82
+ *
83
+ * @return string $input Sanitized value.
84
+ */
85
+ public static function sanitize( $input = array() ) {
86
+
87
+ $options = self::getOptions();
88
+
89
+ if ( empty( $_POST['_wp_http_referer'] ) ) {
90
+
91
+ return $input;
92
+ }
93
+
94
+ $registered = self::getRegistered();
95
+
96
+ foreach ( $registered as $sectionID => $sectionOptions ) {
97
+
98
+ $input = $input ? $input : array();
99
+ $input = apply_filters( 'ez_toc_settings_' . $sectionID . '_sanitize', $input );
100
+
101
+ // Loop through each setting being saved and pass it through a sanitization filter
102
+ foreach ( $input as $key => $value ) {
103
+
104
+ // Get the setting type (checkbox, select, etc)
105
+ $type = isset( $registered[ $sectionID ][ $key ]['type'] ) ? $registered[ $sectionID ][ $key ]['type'] : false;
106
+
107
+ if ( $type ) {
108
+
109
+ // Field type specific filter
110
+ $input[ $key ] = apply_filters( 'ez_toc_settings_sanitize_' . $type, $value, $key );
111
+ }
112
+
113
+ // General filter
114
+ $input[ $key ] = apply_filters( 'ez_toc_settings_sanitize', $input[ $key ], $key );
115
+ }
116
+
117
+ // Loop through the registered options.
118
+ foreach ( $sectionOptions as $optionID => $optionProperties ) {
119
+
120
+ // Unset any that are empty for the section being saved.
121
+ if ( empty( $input[ $optionID ] ) ) {
122
+
123
+ unset( $options[ $optionID ] );
124
+ }
125
+
126
+ // Check for the checkbox option type.
127
+ if ( array_key_exists( 'type', $optionProperties ) && 'checkbox' == $optionProperties['type'] ) {
128
+
129
+ // If it does not exist in the options values being saved, add the option ID and set its value to `0`.
130
+ // This matches WP core behavior for saving checkbox option values.
131
+ if ( ! array_key_exists( $optionID, $input ) ) {
132
+
133
+ $input[ $optionID ] = '0';
134
+ }
135
+ }
136
+ }
137
+
138
+ }
139
+
140
+ // Merge our new settings with the existing
141
+ $output = array_merge( $options, $input );
142
+
143
+ return $output;
144
+ }
145
+
146
+ /**
147
+ * The core registered settings and options.
148
+ *
149
+ * @access private
150
+ * @since 1.0
151
+ * @static
152
+ *
153
+ * @return array
154
+ */
155
+ private static function getRegistered() {
156
+
157
+ $options = array(
158
+ 'general' => apply_filters(
159
+ 'ez_toc_settings_general',
160
+ array(
161
+ 'enabled_post_types' => array(
162
+ 'id' => 'enabled_post_types',
163
+ 'name' => __( 'Enable Support', 'easy-table-of-contents' ),
164
+ 'desc' => __( 'Select the post types to enable the support for table of contents.', 'easy-table-of-contents' ),
165
+ 'type' => 'checkboxgroup',
166
+ 'options' => self::getPostTypes(),
167
+ 'default' => array(),
168
+ ),
169
+ 'auto_insert_post_types' => array(
170
+ 'id' => 'auto_insert_post_types',
171
+ 'name' => __( 'Auto Insert', 'easy-table-of-contents' ),
172
+ 'desc' => __( 'Select the post types which will have the table of contents automatically inserted.', 'easy-table-of-contents' ) .
173
+ '<br><span class="description">' . __( 'NOTE: The table of contents will only be automatically inserted on post types for which it has been enabled.', 'easy-table-of-contents' ) . '<span>',
174
+ 'type' => 'checkboxgroup',
175
+ 'options' => self::getPostTypes(),
176
+ 'default' => array(),
177
+ ),
178
+ 'position' => array(
179
+ 'id' => 'position',
180
+ 'name' => __( 'Position', 'easy-table-of-contents' ),
181
+ 'desc' => __( 'Choose where where you want to display the table of contents.', 'easy-table-of-contents' ),
182
+ 'type' => 'select',
183
+ 'options' => array(
184
+ 'before' => __( 'Before first heading (default)', 'easy-table-of-contents' ),
185
+ 'after' => __( 'After first heading', 'easy-table-of-contents' ),
186
+ 'top' => __( 'Top', 'easy-table-of-contents' ),
187
+ 'bottom' => __( 'Bottom', 'easy-table-of-contents' ),
188
+ //'placeholder' => __( 'Replace [toc] placeholder. For backwards compatibility with Table of Content Plus.', 'easy-table-of-contents' ),
189
+ ),
190
+ 'default' => 1,
191
+ ),
192
+ 'start' => array(
193
+ 'id' => 'start',
194
+ 'name' => __( 'Show when', 'easy-table-of-contents' ),
195
+ 'desc' => __( 'or more headings are present', 'easy-table-of-contents' ),
196
+ 'type' => 'select',
197
+ 'options' => array_combine( range( 1, 10 ), range( 1, 10 ) ),
198
+ 'default' => 4,
199
+ ),
200
+ 'show_heading_text' => array(
201
+ 'id' => 'show_heading_text',
202
+ 'name' => __( 'Display Header Label', 'easy-table-of-contents' ),
203
+ 'desc' => __( 'Show header text above the table of contents.', 'easy-table-of-contents' ),
204
+ 'type' => 'checkbox',
205
+ 'default' => true,
206
+ ),
207
+ 'heading_text' => array(
208
+ 'id' => 'heading_text',
209
+ 'name' => __( 'Header Label', 'easy-table-of-contents' ),
210
+ 'desc' => __( 'Eg: Contents, Table of Contents, Page Contents', 'easy-table-of-contents' ),
211
+ 'type' => 'text',
212
+ 'default' => __( 'Contents', 'easy-table-of-contents' ),
213
+ ),
214
+ 'visibility' => array(
215
+ 'id' => 'visibility',
216
+ 'name' => __( 'Toggle View', 'easy-table-of-contents' ),
217
+ 'desc' => __( 'Allow the user to toggle the visibility of the table of contents.', 'easy-table-of-contents' ),
218
+ 'type' => 'checkbox',
219
+ 'default' => true,
220
+ ),
221
+ //'visibility_show' => array(
222
+ // 'id' => 'visibility_show',
223
+ // 'name' => __( 'Show Label', 'easy-table-of-contents' ),
224
+ // 'desc' => __( 'Eg: show', 'easy-table-of-contents' ),
225
+ // 'type' => 'text',
226
+ // 'default' => __( 'show', 'easy-table-of-contents' ),
227
+ //),
228
+ //'visibility_hide' => array(
229
+ // 'id' => 'visibility_hide',
230
+ // 'name' => __( 'Hide Label', 'easy-table-of-contents' ),
231
+ // 'desc' => __( 'Eg: hide', 'easy-table-of-contents' ),
232
+ // 'type' => 'text',
233
+ // 'default' => __( 'hide', 'easy-table-of-contents' ),
234
+ //),
235
+ 'visibility_hide_by_default' => array(
236
+ 'id' => 'visibility_hide_by_default',
237
+ 'name' => __( 'Initial View', 'easy-table-of-contents' ),
238
+ 'desc' => __( 'Initially hide the table of contents.', 'easy-table-of-contents' ),
239
+ 'type' => 'checkbox',
240
+ 'default' => false,
241
+ ),
242
+ 'show_hierarchy' => array(
243
+ 'id' => 'show_hierarchy',
244
+ 'name' => __( 'Show as Hierarchy', 'easy-table-of-contents' ),
245
+ 'desc' => '',
246
+ 'type' => 'checkbox',
247
+ 'default' => true,
248
+ ),
249
+ 'counter' => array(
250
+ 'id' => 'counter',
251
+ 'name' => __( 'Counter', 'easy-table-of-contents' ),
252
+ 'desc' => '',
253
+ 'type' => 'select',
254
+ 'options' => array(
255
+ 'decimal' => __( 'Decimal (default)', 'easy-table-of-contents' ),
256
+ 'disc' => __( 'Disc', 'easy-table-of-contents' ),
257
+ 'hyphen' => __( 'Hyphen', 'easy-table-of-contents' ),
258
+ 'numeric' => __( 'Numeric', 'easy-table-of-contents' ),
259
+ 'roman' => __( 'Roman', 'easy-table-of-contents' ),
260
+ 'none' => __( 'None', 'easy-table-of-contents' ),
261
+ ),
262
+ 'default' => 'decimal',
263
+ ),
264
+ 'smooth_scroll' => array(
265
+ 'id' => 'smooth_scroll',
266
+ 'name' => __( 'Smooth Scroll', 'easy-table-of-contents' ),
267
+ 'desc' => '',
268
+ 'type' => 'checkbox',
269
+ 'default' => true,
270
+ ),
271
+ 'toc_loading' => array(
272
+ 'id' => 'toc_loading',
273
+ 'name' => __( 'TOC Loading Method', 'easy-table-of-contents' ),
274
+ 'desc' => '',
275
+ 'type' => 'select',
276
+ 'options' => array(
277
+ 'js' => __( 'JavaScript (default)', 'easy-table-of-contents' ),
278
+ 'css' => __( 'Pure CSS', 'easy-table-of-contents' ),
279
+
280
+ ),
281
+ 'default' => 'js',
282
+ ),
283
+ )
284
+ ),
285
+ 'appearance' => apply_filters(
286
+ 'ez_toc_settings_appearance',
287
+ array(
288
+ 'width' => array(
289
+ 'id' => 'width',
290
+ 'name' => __( 'Width', 'easy-table-of-contents' ),
291
+ 'desc' => '',
292
+ 'type' => 'selectgroup',
293
+ 'options' => array(
294
+ 'fixed' => array(
295
+ 'name' => __( 'Fixed', 'easy-table-of-contents' ),
296
+ 'options' => array(
297
+ '200px' => '200px',
298
+ '225px' => '225px',
299
+ '250px' => '250px',
300
+ '275px' => '275px',
301
+ '300px' => '300px',
302
+ '325px' => '325px',
303
+ '350px' => '350px',
304
+ '375px' => '375px',
305
+ '400px' => '400px',
306
+ ),
307
+ ),
308
+ 'relative' => array(
309
+ 'name' => __( 'Relative', 'easy-table-of-contents' ),
310
+ 'options' => array(
311
+ 'auto' => 'Auto',
312
+ '25%' => '25%',
313
+ '33%' => '33%',
314
+ '50%' => '50%',
315
+ '66%' => '66%',
316
+ '75%' => '75%',
317
+ '100%' => '100%',
318
+ ),
319
+ ),
320
+ 'other' => array(
321
+ 'name' => __( 'Custom', 'easy-table-of-contents' ),
322
+ 'options' => array(
323
+ 'custom' => __( 'User Defined', 'easy-table-of-contents' ),
324
+ ),
325
+ ),
326
+ ),
327
+ 'default' => 'auto',
328
+ ),
329
+ 'width_custom' => array(
330
+ 'id' => 'width_custom',
331
+ 'name' => __( 'Custom Width', 'easy-table-of-contents' ),
332
+ 'desc' => __( 'Select the User Defined option from the Width option to utilitze the custom width.', 'easy-table-of-contents' ),
333
+ 'type' => 'custom_width',
334
+ 'default' => 275,
335
+ ),
336
+ 'wrapping' => array(
337
+ 'id' => 'wrapping',
338
+ 'name' => __( 'Alignment', 'easy-table-of-contents' ),
339
+ 'desc' => '',
340
+ 'type' => 'select',
341
+ 'options' => array(
342
+ 'none' => __( 'None (Default)', 'easy-table-of-contents' ),
343
+ 'left' => __( 'Left', 'easy-table-of-contents' ),
344
+ 'right' => __( 'Right', 'easy-table-of-contents' ),
345
+ 'center' => __( 'Center', 'easy-table-of-contents' ),
346
+ ),
347
+ 'default' => 'none',
348
+ ),
349
+ 'font_options_header' => array(
350
+ 'id' => 'font_options',
351
+ 'name' => '<strong>' . __( 'Font Option', 'easy-table-of-contents' ) . '</strong>',
352
+ //'desc' => __( 'For the following settings to apply, select the Custom Font option.', 'easy-table-of-contents' ),
353
+ 'type' => 'header',
354
+ ),
355
+ 'title_font_size' => array(
356
+ 'id' => 'title_font_size',
357
+ 'name' => __( 'Title Font Size', 'easy-table-of-contents' ),
358
+ 'desc' => '',
359
+ 'type' => 'font_size',
360
+ 'default' => 120,
361
+ ),
362
+ 'title_font_weight' => array(
363
+ 'id' => 'title_font_weight',
364
+ 'name' => __( 'Title Font Weight', 'easy-table-of-contents' ),
365
+ 'desc' => '',
366
+ 'type' => 'select',
367
+ 'options' => array(
368
+ '100' => __( 'Thin', 'easy-table-of-contents' ),
369
+ '200' => __( 'Extra Light', 'easy-table-of-contents' ),
370
+ '300' => __( 'Light', 'easy-table-of-contents' ),
371
+ '400' => __( 'Normal', 'easy-table-of-contents' ),
372
+ '500' => __( 'Medium', 'easy-table-of-contents' ),
373
+ '600' => __( 'Semi Bold', 'easy-table-of-contents' ),
374
+ '700' => __( 'Bold', 'easy-table-of-contents' ),
375
+ '800' => __( 'Extra Bold', 'easy-table-of-contents' ),
376
+ '900' => __( 'Heavy', 'easy-table-of-contents' ),
377
+ ),
378
+ 'default' => '500',
379
+ ),
380
+ 'font_size' => array(
381
+ 'id' => 'font_size',
382
+ 'name' => __( 'Font Size', 'easy-table-of-contents' ),
383
+ 'desc' => '',
384
+ 'type' => 'font_size',
385
+ 'default' => 95,
386
+ ),
387
+ 'child_font_size' => array(
388
+ 'id' => 'child_font_size',
389
+ 'name' => __( 'Child Font Size', 'easy-table-of-contents' ),
390
+ 'desc' => '',
391
+ 'type' => 'child_font_size',
392
+ 'default' => 90,
393
+ ),
394
+ 'theme_option_header' => array(
395
+ 'id' => 'theme_option_header',
396
+ 'name' => '<strong>' . __( 'Theme Options', 'easy-table-of-contents' ) . '</strong>',
397
+ //'desc' => __( 'For the following settings to apply, select the Custom Theme option.', 'easy-table-of-contents' ),
398
+ 'type' => 'header',
399
+ ),
400
+ 'theme' => array(
401
+ 'id' => 'theme',
402
+ 'name' => __( 'Theme', 'easy-table-of-contents' ),
403
+ 'desc' => __( 'The theme is only applied to the table of contents which is auto inserted into the post. The Table of Contents widget will inherit the theme widget styles.', 'easy-table-of-contents' ),
404
+ 'type' => 'radio',
405
+ 'options' => array(
406
+ 'grey' => __( 'Grey', 'easy-table-of-contents' ),
407
+ 'light-blue' => __( 'Light Blue', 'easy-table-of-contents' ),
408
+ 'white' => __( 'White', 'easy-table-of-contents' ),
409
+ 'black' => __( 'Black', 'easy-table-of-contents' ),
410
+ 'transparent' => __( 'Transparent', 'easy-table-of-contents' ),
411
+ 'custom' => __( 'Custom', 'easy-table-of-contents' ),
412
+ ),
413
+ 'default' => 'grey',
414
+ ),
415
+ 'custom_theme_header' => array(
416
+ 'id' => 'custom_theme_header',
417
+ 'name' => '<strong>' . __( 'Custom Theme', 'easy-table-of-contents' ) . '</strong>',
418
+ 'desc' => __( 'For the following settings to apply, select the Custom Theme option.', 'easy-table-of-contents' ),
419
+ 'type' => 'header',
420
+ ),
421
+ 'custom_background_colour' => array(
422
+ 'id' => 'custom_background_colour',
423
+ 'name' => __( 'Background Color', 'easy-table-of-contents' ),
424
+ 'desc' => '',
425
+ 'type' => 'color',
426
+ 'default' => '#fff',
427
+ ),
428
+ 'custom_border_colour' => array(
429
+ 'id' => 'custom_border_colour',
430
+ 'name' => __( 'Border Color', 'easy-table-of-contents' ),
431
+ 'desc' => '',
432
+ 'type' => 'color',
433
+ 'default' => '#ddd',
434
+ ),
435
+ 'custom_title_colour' => array(
436
+ 'id' => 'custom_title_colour',
437
+ 'name' => __( 'Title Color', 'easy-table-of-contents' ),
438
+ 'desc' => '',
439
+ 'type' => 'color',
440
+ 'default' => '#999',
441
+ ),
442
+ 'custom_link_colour' => array(
443
+ 'id' => 'custom_link_colour',
444
+ 'name' => __( 'Link Color', 'easy-table-of-contents' ),
445
+ 'desc' => '',
446
+ 'type' => 'color',
447
+ 'default' => '#428bca',
448
+ ),
449
+ 'custom_link_hover_colour' => array(
450
+ 'id' => 'custom_link_hover_colour',
451
+ 'name' => __( 'Link Hover Color', 'easy-table-of-contents' ),
452
+ 'desc' => '',
453
+ 'type' => 'color',
454
+ 'default' => '#2a6496',
455
+ ),
456
+ 'custom_link_visited_colour' => array(
457
+ 'id' => 'custom_link_visited_colour',
458
+ 'name' => __( 'Link Visited Color', 'easy-table-of-contents' ),
459
+ 'desc' => '',
460
+ 'type' => 'color',
461
+ 'default' => '#428bca',
462
+ ),
463
+ )
464
+ ),
465
+ 'advanced' => apply_filters(
466
+ 'ez_toc_settings_advanced',
467
+ array(
468
+ 'lowercase' => array(
469
+ 'id' => 'lowercase',
470
+ 'name' => __( 'Lowercase', 'easy-table-of-contents' ),
471
+ 'desc' => __( 'Ensure anchors are in lowercase.', 'easy-table-of-contents' ),
472
+ 'type' => 'checkbox',
473
+ 'default' => false,
474
+ ),
475
+ 'hyphenate' => array(
476
+ 'id' => 'hyphenate',
477
+ 'name' => __( 'Hyphenate', 'easy-table-of-contents' ),
478
+ 'desc' => __( 'Use - rather than _ in anchors.', 'easy-table-of-contents' ),
479
+ 'type' => 'checkbox',
480
+ 'default' => false,
481
+ ),
482
+ 'include_homepage' => array(
483
+ 'id' => 'include_homepage',
484
+ 'name' => __( 'Homepage', 'easy-table-of-contents' ),
485
+ 'desc' => __( 'Show the table of contents for qualifying items on the homepage.', 'easy-table-of-contents' ),
486
+ 'type' => 'checkbox',
487
+ 'default' => false,
488
+ ),
489
+ 'exclude_css' => array(
490
+ 'id' => 'exclude_css',
491
+ 'name' => __( 'CSS', 'easy-table-of-contents' ),
492
+ 'desc' => __( "Prevent the loading the core CSS styles. When selected, the appearance options from above will be ignored.", 'easy-table-of-contents' ),
493
+ 'type' => 'checkbox',
494
+ 'default' => false,
495
+ ),
496
+ 'inline_css' => array(
497
+ 'id' => 'inline_css',
498
+ 'name' => __( 'Inline CSS', 'easy-table-of-contents' ),
499
+ 'desc' => __( "Improve your website performance by inlining your CSS.", 'easy-table-of-contents' ),
500
+ 'type' => 'checkbox',
501
+ 'default' => false,
502
+ ),
503
+ //'bullet_spacing' => array(
504
+ // 'id' => 'bullet_spacing',
505
+ // 'name' => __( 'Theme Bullets', 'easy-table-of-contents' ),
506
+ // 'desc' => __( 'If your theme includes background images for unordered list elements, enable this option to support them.', 'easy-table-of-contents' ),
507
+ // 'type' => 'checkbox',
508
+ // 'default' => false,
509
+ //),
510
+ 'heading_levels' => array(
511
+ 'id' => 'heading_levels',
512
+ 'name' => __( 'Headings:', 'easy-table-of-contents' ),
513
+ 'desc' => __( 'Select the heading to consider when generating the table of contents. Deselecting a heading will exclude it.', 'easy-table-of-contents' ),
514
+ 'type' => 'checkboxgroup',
515
+ 'options' => array(
516
+ '1' => __( 'Heading 1 (h1)', 'easy-table-of-contents' ),
517
+ '2' => __( 'Heading 2 (h2)', 'easy-table-of-contents' ),
518
+ '3' => __( 'Heading 3 (h3)', 'easy-table-of-contents' ),
519
+ '4' => __( 'Heading 4 (h4)', 'easy-table-of-contents' ),
520
+ '5' => __( 'Heading 5 (h5)', 'easy-table-of-contents' ),
521
+ '6' => __( 'Heading 6 (h6)', 'easy-table-of-contents' ),
522
+ ),
523
+ 'default' => array( '1', '2', '3', '4', '5', '6' ),
524
+ ),
525
+ 'exclude' => array(
526
+ 'id' => 'exclude',
527
+ 'name' => __( 'Exclude Headings', 'easy-table-of-contents' ),
528
+ 'desc' => __( 'Specify headings to be excluded from appearing in the table of contents. Separate multiple headings with a pipe <code>|</code>. Use an asterisk <code>*</code> as a wildcard to match other text.', 'easy-table-of-contents' ),
529
+ 'type' => 'text',
530
+ 'size' => 'large',
531
+ 'default' => '',
532
+ ),
533
+ 'exclude_desc' => array(
534
+ 'id' => 'exclude_desc',
535
+ 'name' => '',
536
+ 'desc' => '<p><strong>' . __( 'Examples:', 'easy-table-of-contents' ) . '</strong></p>' .
537
+ '<ul>' .
538
+ '<li>' . __( '<code>Fruit*</code> Ignore headings starting with "Fruit".', 'easy-table-of-contents' ) . '</li>' .
539
+ '<li>' . __( '<code>*Fruit Diet*</code> Ignore headings with "Fruit Diet" somewhere in the heading.', 'easy-table-of-contents' ) . '</li>' .
540
+ '<li>' . __( '<code>Apple Tree|Oranges|Yellow Bananas</code> Ignore headings that are exactly "Apple Tree", "Oranges" or "Yellow Bananas".', 'easy-table-of-contents' ) . '</li>' .
541
+ '</ul>' .
542
+ '<p>' . __( '<strong>Note:</strong> This is not case sensitive.', 'easy-table-of-contents' ) . '</p>',
543
+ 'type' => 'descriptive_text',
544
+ ),
545
+ 'smooth_scroll_offset' => array(
546
+ 'id' => 'smooth_scroll_offset',
547
+ 'name' => __( 'Smooth Scroll Offset', 'easy-table-of-contents' ),
548
+ 'desc' => 'px<br/>' . __( 'If you have a consistent menu across the top of your site, you can adjust the top offset to stop the headings from appearing underneath the top menu. A setting of 30 accommodates the WordPress admin bar. This setting only has an effect after you have enabled Smooth Scroll option.', 'easy-table-of-contents' ),
549
+ 'type' => 'number',
550
+ 'size' => 'small',
551
+ 'default' => 30
552
+ ),
553
+ 'mobile_smooth_scroll_offset' => array(
554
+ 'id' => 'mobile_smooth_scroll_offset',
555
+ 'name' => __( 'Mobile Smooth Scroll Offset', 'easy-table-of-contents' ),
556
+ 'desc' => 'px<br/>' . __( 'This provides the same function as the Smooth Scroll Offset option above but applied when the user is visiting your site on a mobile device.', 'easy-table-of-contents' ),
557
+ 'type' => 'number',
558
+ 'size' => 'small',
559
+ 'default' => 0
560
+ ),
561
+ 'restrict_path' => array(
562
+ 'id' => 'restrict_path',
563
+ 'name' => __( 'Limit Path', 'easy-table-of-contents' ),
564
+ 'desc' => '<br/>' . __( 'Restrict generation of the table of contents to pages that match the required path. This path is from the root of your site and always begins with a forward slash.', 'easy-table-of-contents' ) .
565
+ '<br/><span class="description">' . __( 'Eg: /wiki/, /corporate/annual-reports/', 'easy-table-of-contents' ) . '</span>',
566
+ 'type' => 'text',
567
+ ),
568
+ 'fragment_prefix' => array(
569
+ 'id' => 'fragment_prefix',
570
+ 'name' => __( 'Default Anchor Prefix', 'easy-table-of-contents' ),
571
+ 'desc' => '<br/>' . __( 'Anchor targets are restricted to alphanumeric characters as per HTML specification (see readme for more detail). The default anchor prefix will be used when no characters qualify. When left blank, a number will be used instead.', 'easy-table-of-contents' ) .
572
+ '<br/>' . __( 'This option normally applies to content written in character sets other than ASCII.', 'easy-table-of-contents' ) .
573
+ '<br/><span class="description">' . __( 'Eg: i, toc_index, index, _', 'easy-table-of-contents' ) . '</span>',
574
+ 'type' => 'text',
575
+ 'default' => 'i',
576
+ ),
577
+ 'widget_affix_selector' => array(
578
+ 'id' => 'widget_affix_selector',
579
+ 'name' => __( 'Widget Affix Selector', 'easy-table-of-contents' ),
580
+ 'desc' => '<br/>' . __( 'To enable the option to affix or pin the Table of Contents widget enter the theme\'s sidebar class or id.', 'easy-table-of-contents' ) .
581
+ '<br/>' . __( 'Since every theme is different, this can not be determined automatically. If you are unsure how to find the sidebar\'s class or id, please ask the theme\'s support persons.', 'easy-table-of-contents' ) .
582
+ '<br/><span class="description">' . __( 'Eg: .widget-area or #sidebar', 'easy-table-of-contents' ) . '</span>',
583
+ 'type' => 'text',
584
+ 'default' => '',
585
+ ),
586
+
587
+ )
588
+ ),
589
+ 'prosettings' => apply_filters(
590
+ 'ez_toc_settings_prosettings',
591
+ array(
592
+ 'exclude_by_class' => array(
593
+ 'id' => 'exclude_by_class',
594
+ 'name' => __( 'Exclude Headings by Class', 'easy-table-of-contents' ),
595
+ 'desc' => '<br/>' . __( 'You can hide the TOC heading by its class and if you want to hide multiple headings then please saparate them with a comma (,)', 'easy-table-of-contents' ),
596
+ 'type' => 'text',
597
+ 'default' => '',
598
+ ),
599
+ 'fixedtoc' => array(
600
+ 'id' => 'fixedtoc',
601
+ 'name' => __( 'Fixed TOC', 'easy-table-of-contents' ),
602
+ 'desc' => __( 'Fixed TOC in the page display so it can be easier to navigate', 'easy-table-of-contents' ),
603
+ 'type' => 'checkbox',
604
+ 'default' => false,
605
+ ),
606
+ )
607
+ ),
608
+ );
609
+
610
+ return apply_filters( 'ez_toc_registered_settings', $options );
611
+ }
612
+
613
+ /**
614
+ * The default values for the registered settings and options.
615
+ *
616
+ * @access private
617
+ * @since 1.0
618
+ * @static
619
+ *
620
+ * @return array
621
+ */
622
+ private static function getDefaults() {
623
+
624
+ $defaults = array(
625
+ 'fragment_prefix' => 'i',
626
+ 'position' => 'before',
627
+ 'start' => 4,
628
+ 'show_heading_text' => true,
629
+ 'heading_text' => 'Table of Contents',
630
+ 'enabled_post_types' => array( 'page' ),
631
+ 'auto_insert_post_types' => array(),
632
+ 'show_hierarchy' => true,
633
+ 'counter' => 'decimal',
634
+ 'smooth_scroll' => true,
635
+ 'smooth_scroll_offset' => 30,
636
+ 'mobile_smooth_scroll_offset' => 0,
637
+ 'visibility' => true,
638
+ 'toc_loading' => 'js',
639
+ //'visibility_show' => 'show',
640
+ //'visibility_hide' => 'hide',
641
+ 'visibility_hide_by_default' => false,
642
+ 'width' => 'auto',
643
+ 'width_custom' => 275,
644
+ 'width_custom_units' => 'px',
645
+ 'wrapping' => 'none',
646
+ 'title_font_size' => 120,
647
+ 'title_font_size_units' => '%',
648
+ 'title_font_weight' => 500,
649
+ 'font_size' => 95,
650
+ 'child_font_size' => 90,
651
+ 'font_size_units' => '%',
652
+ 'theme' => 'grey',
653
+ 'custom_background_colour' => '#fff',
654
+ 'custom_border_colour' => '#ddd',
655
+ 'custom_title_colour' => '#999',
656
+ 'custom_link_colour' => '#428bca',
657
+ 'custom_link_hover_colour' => '#2a6496',
658
+ 'custom_link_visited_colour' => '#428bca',
659
+ 'lowercase' => false,
660
+ 'hyphenate' => false,
661
+ //'bullet_spacing' => false,
662
+ 'include_homepage' => false,
663
+ 'exclude_css' => false,
664
+ 'inline_css' => false,
665
+ 'exclude' => '',
666
+ 'heading_levels' => array( '1', '2', '3', '4', '5', '6' ),
667
+ 'restrict_path' => '',
668
+ 'css_container_class' => '',
669
+ //'show_toc_in_widget_only' => false,
670
+ //'show_toc_in_widget_only_post_types' => array(),
671
+ 'widget_affix_selector' => '',
672
+ );
673
+
674
+ return apply_filters( 'ez_toc_get_default_options', $defaults );
675
+ }
676
+
677
+ /**
678
+ * Get the default options array.
679
+ *
680
+ * @access private
681
+ * @since 1.0
682
+ * @static
683
+ *
684
+ * @return array
685
+ */
686
+ private static function getOptions() {
687
+
688
+ $defaults = self::getDefaults();
689
+ $options = get_option( 'ez-toc-settings', $defaults );
690
+
691
+ //return apply_filters( 'ez_toc_get_options', wp_parse_args( $options, $defaults ) );
692
+ return apply_filters( 'ez_toc_get_options', $options );
693
+ }
694
+
695
+ /**
696
+ * Get option value by key name.
697
+ *
698
+ * @access public
699
+ * @since 1.0
700
+ * @static
701
+ *
702
+ * @param string $key
703
+ * @param bool|false $default
704
+ *
705
+ * @return mixed
706
+ */
707
+ public static function get( $key, $default = false ) {
708
+
709
+ $options = self::getOptions();
710
+
711
+ $value = array_key_exists( $key, $options ) ? $options[ $key ] : $default;
712
+ $value = apply_filters( 'ez_toc_get_option', $value, $key, $default );
713
+
714
+ return apply_filters( 'ez_toc_get_option_' . $key, $value, $key, $default );
715
+ }
716
+
717
+ /**
718
+ * Set an option value by key name.
719
+ *
720
+ * @access public
721
+ * @since 1.0
722
+ * @static
723
+ *
724
+ * @param string $key
725
+ * @param bool|false $value
726
+ *
727
+ * @return bool
728
+ */
729
+ public static function set( $key, $value = false ) {
730
+
731
+ if ( empty( $value ) ) {
732
+
733
+ $remove_option = self::delete( $key );
734
+
735
+ return $remove_option;
736
+ }
737
+
738
+ $options = self::getOptions();
739
+
740
+ $options[ $key ] = apply_filters( 'ez_toc_update_option', $value, $key );
741
+
742
+ return update_option( 'ez-toc-settings', $options );
743
+ }
744
+
745
+ /**
746
+ * Delete an option from the options table by option key name.
747
+ *
748
+ * @access public
749
+ * @since 1.0
750
+ * @static
751
+ *
752
+ * @param string $key
753
+ *
754
+ * @return bool
755
+ */
756
+ public static function delete( $key ) {
757
+
758
+ // First let's grab the current settings
759
+ $options = get_option( 'ez-toc-settings' );
760
+
761
+ // Next let's try to update the value
762
+ if ( array_key_exists( $key, $options ) ) {
763
+
764
+ unset( $options[ $key ] );
765
+ }
766
+
767
+ return update_option( 'ez-toc-settings', $options );
768
+ }
769
+
770
+ /**
771
+ * Sanitize a hex color from user input.
772
+ *
773
+ * Tries to convert $string into a valid hex colour.
774
+ * Returns $default if $string is not a hex value, otherwise returns verified hex.
775
+ *
776
+ * @access private
777
+ * @since 1.0
778
+ * @static
779
+ *
780
+ * @param string $string
781
+ * @param string $default
782
+ *
783
+ * @return mixed|string
784
+ */
785
+ private static function hex_value( $string = '', $default = '#' ) {
786
+
787
+ $return = $default;
788
+
789
+ if ( $string ) {
790
+ // strip out non hex chars
791
+ $return = preg_replace( '/[^a-fA-F0-9]*/', '', $string );
792
+
793
+ switch ( strlen( $return ) ) {
794
+ case 3: // do next
795
+ case 6:
796
+ $return = '#' . $return;
797
+ break;
798
+
799
+ default:
800
+ if ( strlen( $return ) > 6 ) {
801
+ $return = '#' . substr( $return, 0, 6 );
802
+ } // if > 6 chars, then take the first 6
803
+ elseif ( strlen( $return ) > 3 && strlen( $return ) < 6 ) {
804
+ $return = '#' . substr( $return, 0, 3 );
805
+ } // if between 3 and 6, then take first 3
806
+ else {
807
+ $return = $default;
808
+ } // not valid, return $default
809
+ }
810
+ }
811
+
812
+ return $return;
813
+ }
814
+
815
+ /**
816
+ * Get the registered post types minus excluded core types.
817
+ *
818
+ * @access public
819
+ * @since 1.0
820
+ * @static
821
+ *
822
+ * @return array
823
+ */
824
+ public static function getPostTypes() {
825
+
826
+ $exclude = apply_filters( 'ez_toc_exclude_post_types', array( 'attachment', 'revision', 'nav_menu_item', 'safecss' ) );
827
+ $registered = get_post_types( array(), 'objects' );
828
+ $types = array();
829
+
830
+ foreach ( $registered as $post ) {
831
+
832
+ if ( in_array( $post->name, $exclude ) ) {
833
+
834
+ continue;
835
+ }
836
+
837
+ $types[ $post->name ] = $post->label;
838
+ }
839
+
840
+ return $types;
841
+ }
842
+
843
+ /**
844
+ * Missing Callback
845
+ *
846
+ * If a settings field type callback is not callable, alert the user.
847
+ *
848
+ * @access public
849
+ * @since 1.0
850
+ * @static
851
+ *
852
+ * @param array $args Arguments passed by the setting
853
+ */
854
+ public static function missingCallback( $args ) {
855
+
856
+ printf(
857
+ __( 'The callback function used for the <strong>%s</strong> setting is missing.', 'easy-table-of-contents' ),
858
+ $args['id']
859
+ );
860
+ }
861
+
862
+ /**
863
+ * Text Callback
864
+ *
865
+ * Renders text fields.
866
+ *
867
+ * @access public
868
+ * @since 1.0
869
+ * @static
870
+ *
871
+ * @param array $args Arguments passed by the setting
872
+ * @param null $value
873
+ */
874
+ public static function text( $args, $value = null ) {
875
+
876
+ if ( is_null( $value ) ) {
877
+
878
+ $value = self::get( $args['id'], $args['default'] );
879
+ }
880
+
881
+ if ( isset( $args['faux'] ) && true === $args['faux'] ) {
882
+
883
+ $args['readonly'] = true;
884
+ $value = isset( $args['default'] ) ? $args['default'] : '';
885
+ $name = '';
886
+
887
+ } else {
888
+
889
+ $name = ' name="ez-toc-settings[' . $args['id'] . ']"';
890
+ }
891
+
892
+ $readonly = isset( $args['readonly'] ) && $args['readonly'] === true ? ' readonly="readonly"' : '';
893
+ $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
894
+
895
+ $html = '<input type="text" class="' . $size . '-text" id="ez-toc-settings[' . $args['id'] . ']"' . $name . ' value="' . esc_attr( stripslashes( $value ) ) . '"' . $readonly . '/>';
896
+
897
+ if ( 0 < strlen( $args['desc'] ) ) {
898
+
899
+ $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
900
+ }
901
+
902
+ echo $html;
903
+ }
904
+
905
+ /**
906
+ * Textarea Callback.
907
+ *
908
+ * Renders a textarea.
909
+ *
910
+ * @access public
911
+ * @since 1.1
912
+ * @static
913
+ *
914
+ * @param array $args Arguments passed by the setting
915
+ * @param null $value
916
+ */
917
+ public static function textarea( $args, $value = null ) {
918
+
919
+ $html = '';
920
+
921
+ if ( is_null( $value ) ) {
922
+
923
+ $value = self::get( $args['id'], $args['default'] );
924
+ }
925
+
926
+ if ( isset( $args['faux'] ) && true === $args['faux'] ) {
927
+
928
+ $args['readonly'] = true;
929
+ $value = isset( $args['default'] ) ? $args['default'] : '';
930
+ $name = '';
931
+
932
+ } else {
933
+
934
+ $name = ' name="ez-toc-settings[' . $args['id'] . ']"';
935
+ }
936
+
937
+ $readonly = isset( $args['readonly'] ) && $args['readonly'] === true ? ' readonly="readonly"' : '';
938
+ $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
939
+
940
+ if ( 0 < strlen( $args['desc'] ) ) {
941
+
942
+ $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
943
+ }
944
+
945
+ $html .= '<textarea rows="10" cols="50" class="' . $size . '-text" id="ez-toc-settings[' . $args['id'] . ']"' . $name . $readonly . '/>' . esc_textarea( $value ) . '</textarea>';
946
+
947
+ echo $html;
948
+ }
949
+
950
+ /**
951
+ * Number Callback
952
+ *
953
+ * Renders number fields.
954
+ *
955
+ * @access public
956
+ * @since 1.0
957
+ * @static
958
+ *
959
+ * @param array $args Arguments passed by the setting
960
+ */
961
+ public static function number( $args ) {
962
+
963
+ $value = self::get( $args['id'], $args['default'] );
964
+
965
+ if ( isset( $args['faux'] ) && true === $args['faux'] ) {
966
+
967
+ $args['readonly'] = true;
968
+ $value = isset( $args['default'] ) ? $args['default'] : '';
969
+ $name = '';
970
+
971
+ } else {
972
+
973
+ $name = ' name="ez-toc-settings[' . $args['id'] . ']"';
974
+ }
975
+
976
+ $readonly = isset( $args['readonly'] ) && $args['readonly'] === true ? ' readonly="readonly"' : '';
977
+ $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
978
+
979
+ $html = '<input type="number" class="' . $size . '-text" id="ez-toc-settings[' . $args['id'] . ']"' . $name . ' value="' . esc_attr( stripslashes( $value ) ) . '"' . $readonly . '/>';
980
+
981
+ if ( 0 < strlen( $args['desc'] ) ) {
982
+
983
+ $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
984
+ }
985
+
986
+ echo $html;
987
+ }
988
+
989
+ /**
990
+ * Checkbox Callback
991
+ *
992
+ * Renders checkboxes.
993
+ *
994
+ * @access public
995
+ * @since 1.0
996
+ * @static
997
+ *
998
+ * @param array $args Arguments passed by the setting
999
+ * @param null $value
1000
+ */
1001
+ public static function checkbox( $args, $value = null ) {
1002
+
1003
+ if ( is_null( $value ) ) {
1004
+
1005
+ $value = self::get( $args['id'], $args['default'] );
1006
+ }
1007
+
1008
+ if ( isset( $args['faux'] ) && true === $args['faux'] ) {
1009
+
1010
+ $name = '';
1011
+
1012
+ } else {
1013
+
1014
+ $name = ' name="ez-toc-settings[' . $args['id'] . ']"';
1015
+ }
1016
+
1017
+ $checked = $value ? checked( 1, $value, false ) : '';
1018
+
1019
+ $html = '<input type="checkbox" id="ez-toc-settings[' . $args['id'] . ']"' . $name . ' value="1" ' . $checked . '/>';
1020
+
1021
+ if ( 0 < strlen( $args['desc'] ) ) {
1022
+
1023
+ $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1024
+ }
1025
+
1026
+ echo $html;
1027
+ }
1028
+
1029
+ /**
1030
+ * Multicheck Callback
1031
+ *
1032
+ * Renders multiple checkboxes.
1033
+ *
1034
+ * @access public
1035
+ * @since 1.0
1036
+ * @static
1037
+ *
1038
+ * @param array $args Arguments passed by the setting
1039
+ * @param null $value
1040
+ */
1041
+ public static function checkboxgroup( $args, $value = null ) {
1042
+
1043
+ if ( is_null( $value ) ) {
1044
+
1045
+ $value = self::get( $args['id'], $args['default'] );
1046
+ }
1047
+
1048
+ if ( ! empty( $args['options'] ) ) {
1049
+
1050
+ foreach ( $args['options'] as $key => $option ):
1051
+
1052
+ if ( in_array( $key, $value ) ) {
1053
+
1054
+ $enabled = $option;
1055
+
1056
+ } else {
1057
+
1058
+ $enabled = null;
1059
+ }
1060
+
1061
+ echo '<input name="ez-toc-settings[' . $args['id'] . '][' . $key . ']" id="ez-toc-settings[' . $args['id'] . '][' . $key . ']" type="checkbox" value="' . $key . '" ' . checked( $option, $enabled, false ) . '/>&nbsp;';
1062
+ echo '<label for="ez-toc-settings[' . $args['id'] . '][' . $key . ']">' . $option . '</label><br/>';
1063
+
1064
+ endforeach;
1065
+
1066
+ if ( 0 < strlen( $args['desc'] ) ) {
1067
+
1068
+ echo '<p class="description">' . $args['desc'] . '</p>';
1069
+ }
1070
+ }
1071
+ }
1072
+
1073
+ /**
1074
+ * Radio Callback
1075
+ *
1076
+ * Renders radio groups.
1077
+ *
1078
+ * @access public
1079
+ * @since 1.0
1080
+ * @static
1081
+ *
1082
+ * @param array $args Arguments passed by the setting
1083
+ */
1084
+ public static function radio( $args ) {
1085
+
1086
+ $value = self::get( $args['id'], $args['default'] );
1087
+
1088
+ foreach ( $args['options'] as $key => $option ) {
1089
+
1090
+ echo '<input name="ez-toc-settings[' . $args['id'] . ']"" id="ez-toc-settings[' . $args['id'] . '][' . $key . ']" type="radio" value="' . $key . '" ' . checked( $key, $value, false ) . '/>&nbsp;';
1091
+ echo '<label for="ez-toc-settings[' . $args['id'] . '][' . $key . ']">' . $option . '</label><br/>';
1092
+ }
1093
+
1094
+ if ( 0 < strlen( $args['desc'] ) ) {
1095
+
1096
+ echo '<p class="description">' . $args['desc'] . '</p>';
1097
+ }
1098
+ }
1099
+
1100
+ /**
1101
+ * Select Callback
1102
+ *
1103
+ * Renders select fields.
1104
+ *
1105
+ * @access public
1106
+ * @since 1.0
1107
+ * @static
1108
+ *
1109
+ * @param array $args Arguments passed by the setting.
1110
+ */
1111
+ public static function select( $args ) {
1112
+
1113
+ $value = self::get( $args['id'], $args['default'] );
1114
+
1115
+ if ( isset( $args['placeholder'] ) ) {
1116
+ $placeholder = $args['placeholder'];
1117
+ } else {
1118
+ $placeholder = '';
1119
+ }
1120
+
1121
+ if ( isset( $args['chosen'] ) ) {
1122
+ $chosen = 'class="enhanced"';
1123
+ } else {
1124
+ $chosen = '';
1125
+ }
1126
+
1127
+ $html = '<select id="ez-toc-settings[' . $args['id'] . ']" name="ez-toc-settings[' . $args['id'] . ']" ' . $chosen . 'data-placeholder="' . $placeholder . '" />';
1128
+
1129
+ foreach ( $args['options'] as $option => $name ) {
1130
+ $selected = selected( $option, $value, false );
1131
+ $html .= '<option value="' . $option . '" ' . $selected . '>' . $name . '</option>';
1132
+ }
1133
+
1134
+ $html .= '</select>';
1135
+
1136
+ if ( 0 < strlen( $args['desc'] ) ) {
1137
+
1138
+ $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1139
+ }
1140
+
1141
+ echo $html;
1142
+ }
1143
+
1144
+ /**
1145
+ * Select Drop Down Callback
1146
+ *
1147
+ * Renders select with option group fields.
1148
+ *
1149
+ * @access public
1150
+ * @since 1.0
1151
+ * @static
1152
+ *
1153
+ * @param array $args Arguments passed by the setting.
1154
+ */
1155
+ public static function selectgroup( $args ) {
1156
+
1157
+ $value = self::get( $args['id'], $args['default'] );
1158
+
1159
+ if ( isset( $args['placeholder'] ) ) {
1160
+ $placeholder = $args['placeholder'];
1161
+ } else {
1162
+ $placeholder = '';
1163
+ }
1164
+
1165
+ if ( isset( $args['chosen'] ) ) {
1166
+ $chosen = 'class="enhanced"';
1167
+ } else {
1168
+ $chosen = '';
1169
+ }
1170
+
1171
+ $html = '<select id="ez-toc-settings[' . $args['id'] . ']" name="ez-toc-settings[' . $args['id'] . ']" ' . $chosen . 'data-placeholder="' . $placeholder . '" />';
1172
+
1173
+ foreach ( $args['options'] as $group ) {
1174
+
1175
+ $html .= sprintf( '<optgroup label="%1$s">', $group['name'] );
1176
+
1177
+ foreach ( $group['options'] as $option => $name ) {
1178
+
1179
+ $selected = selected( $option, $value, false );
1180
+ $html .= '<option value="' . $option . '" ' . $selected . '>' . $name . '</option>';
1181
+ }
1182
+
1183
+ $html .= '</optgroup>';
1184
+ }
1185
+
1186
+ $html .= '</select>';
1187
+
1188
+ if ( 0 < strlen( $args['desc'] ) ) {
1189
+
1190
+ $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1191
+ }
1192
+
1193
+ echo $html;
1194
+ }
1195
+
1196
+ /**
1197
+ * Header Callback
1198
+ *
1199
+ * Renders the header.
1200
+ *
1201
+ * @access public
1202
+ * @since 1.0
1203
+ * @static
1204
+ *
1205
+ * @param array $args Arguments passed by the setting
1206
+ */
1207
+ public static function header( $args ) {
1208
+
1209
+ echo '<hr/>';
1210
+
1211
+ if ( 0 < strlen( $args['desc'] ) ) {
1212
+
1213
+ echo '<p>' . wp_kses_post( $args['desc'] ) . '</p>';
1214
+ }
1215
+ }
1216
+
1217
+ /**
1218
+ * Descriptive text callback.
1219
+ *
1220
+ * Renders descriptive text onto the settings field.
1221
+ *
1222
+ * @access public
1223
+ * @since 1.0
1224
+ * @static
1225
+ *
1226
+ * @param array $args Arguments passed by the setting
1227
+ */
1228
+ public static function descriptive_text( $args ) {
1229
+
1230
+ echo wp_kses_post( $args['desc'] );
1231
+ }
1232
+
1233
+ /**
1234
+ * Color picker Callback
1235
+ *
1236
+ * Renders color picker fields.
1237
+ *
1238
+ * @access public
1239
+ * @since 1.0
1240
+ * @static
1241
+ *
1242
+ * @param array $args Arguments passed by the setting
1243
+ */
1244
+ public static function color( $args ) {
1245
+
1246
+ $value = self::get( $args['id'], $args['default'] );
1247
+
1248
+ $default = isset( $args['default'] ) ? $args['default'] : '';
1249
+
1250
+ $html = '<input type="text" class="ez-toc-color-picker" id="ez-toc-settings[' . $args['id'] . ']" name="ez-toc-settings[' . $args['id'] . ']" value="' . esc_attr( $value ) . '" data-default-color="' . esc_attr( $default ) . '" />';
1251
+
1252
+ if ( 0 < strlen( $args['desc'] ) ) {
1253
+
1254
+ echo '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1255
+ }
1256
+
1257
+ echo $html;
1258
+ }
1259
+
1260
+ /**
1261
+ * Custom table of contents width.
1262
+ *
1263
+ * @access public
1264
+ * @since 1.0
1265
+ * @static
1266
+ *
1267
+ * @param array $args
1268
+ */
1269
+ public static function custom_width( $args ) {
1270
+
1271
+ //$value = self::get( $args['id'], $args['default'] );
1272
+
1273
+ self::text(
1274
+ array(
1275
+ 'id' => $args['id'],
1276
+ 'desc' => '',
1277
+ 'size' => 'small',
1278
+ 'default' => $args['default'],
1279
+ )
1280
+ );
1281
+
1282
+ self::select(
1283
+ array(
1284
+ 'id' => $args['id'] . '_units',
1285
+ 'desc' => '',
1286
+ 'options' => array(
1287
+ 'px' => 'px',
1288
+ '%' => '%',
1289
+ 'em' => 'em',
1290
+ ),
1291
+ 'default' => 'px',
1292
+ )
1293
+ );
1294
+
1295
+ if ( 0 < strlen( $args['desc'] ) ) {
1296
+
1297
+ echo '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1298
+ }
1299
+ }
1300
+
1301
+ /**
1302
+ * Custom font size callback.
1303
+ *
1304
+ * @access public
1305
+ * @since 1.0
1306
+ * @static
1307
+ *
1308
+ * @param array $args
1309
+ */
1310
+ public static function font_size( $args ) {
1311
+
1312
+ //$value = self::get( $args['id'], $args['default'] );
1313
+
1314
+ self::text(
1315
+ array(
1316
+ 'id' => $args['id'],
1317
+ 'desc' => '',
1318
+ 'size' => 'small',
1319
+ 'default' => $args['default'],
1320
+ )
1321
+ );
1322
+
1323
+ self::select(
1324
+ array(
1325
+ 'id' => $args['id'] . '_units',
1326
+ 'desc' => '',
1327
+ 'options' => array(
1328
+ 'pt' => 'pt',
1329
+ 'px' => 'px',
1330
+ '%' => '%',
1331
+ 'em' => 'em',
1332
+ ),
1333
+ 'default' => '%',
1334
+ )
1335
+ );
1336
+
1337
+ if ( 0 < strlen( $args['desc'] ) ) {
1338
+
1339
+ echo '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1340
+ }
1341
+ }
1342
+ /**
1343
+ * Custom font size callback.
1344
+ *
1345
+ * @access public
1346
+ * @since 1.0
1347
+ * @static
1348
+ *
1349
+ * @param array $args
1350
+ */
1351
+ public static function child_font_size( $args ) {
1352
+
1353
+ //$value = self::get( $args['id'], $args['default'] );
1354
+
1355
+ self::text(
1356
+ array(
1357
+ 'id' => $args['id'],
1358
+ 'desc' => '',
1359
+ 'size' => 'small',
1360
+ 'default' => $args['default'],
1361
+ )
1362
+ );
1363
+
1364
+ self::select(
1365
+ array(
1366
+ 'id' => $args['id'] . '_units',
1367
+ 'desc' => '',
1368
+ 'options' => array(
1369
+ 'pt' => 'pt',
1370
+ 'px' => 'px',
1371
+ '%' => '%',
1372
+ 'em' => 'em',
1373
+ ),
1374
+ 'default' => '%',
1375
+ )
1376
+ );
1377
+
1378
+ if ( 0 < strlen( $args['desc'] ) ) {
1379
+
1380
+ echo '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1381
+ }
1382
+ }
1383
+ }
1384
+
1385
+ add_action( 'admin_init', array( 'ezTOC_Option', 'register' ) );
1386
+ }
includes/class.post.php CHANGED
@@ -1,1440 +1,1436 @@
1
- <?php
2
-
3
- use function Easy_Plugins\Table_Of_Contents\String\br2;
4
-
5
- class ezTOC_Post {
6
-
7
- /**
8
- * @since 2.0
9
- * @var int
10
- */
11
- private $queriedObjectID;
12
-
13
- /**
14
- * @since 2.0
15
- * @var WP_Post
16
- */
17
- private $post;
18
-
19
- /**
20
- * @since 2.0
21
- * @var false|string
22
- */
23
- private $permalink;
24
-
25
- /**
26
- * The post content broken into pages by user inserting `<!--nextpage-->` into the post content.
27
- * @see ezTOC_Post::extractPages()
28
- * @since 2.0
29
- * @var array
30
- */
31
- private $pages = array();
32
-
33
- /**
34
- * The user defined heading levels to be included in the TOC.
35
- * @see ezTOC_Post::getHeadingLevels()
36
- * @since 2.0
37
- * @var array
38
- */
39
- private $headingLevels = array();
40
-
41
- /**
42
- * Array of nodes that are excluded by class/id selector.
43
- * @since 2.0
44
- * @var string[]
45
- */
46
- private $excludedNodes = array();
47
-
48
- /**
49
- * Keeps a track of used anchors for collision detecting.
50
- * @see ezTOC_Post::generateHeadingIDFromTitle()
51
- * @since 2.0
52
- * @var array
53
- */
54
- private $collision_collector = array();
55
-
56
- /**
57
- * @var bool
58
- */
59
- private $hasTOCItems = false;
60
-
61
- /**
62
- * ezTOC_Post constructor.
63
- *
64
- * @since 2.0
65
- *
66
- * @param WP_Post $post
67
- * @param bool $apply_content_filter Whether or not to apply the `the_content` filter on the post content.
68
- */
69
- public function __construct( WP_Post $post, $apply_content_filter = true ) {
70
-
71
- $this->post = $post;
72
- $this->permalink = get_permalink( $post );
73
- $this->queriedObjectID = get_queried_object_id();
74
-
75
- if ( $apply_content_filter ) {
76
-
77
- $this->applyContentFilter()->process();
78
-
79
- } else {
80
-
81
- $this->process();
82
- }
83
- }
84
-
85
- /**
86
- * @access public
87
- * @since 2.0
88
- *
89
- * @param $id
90
- *
91
- * @return ezTOC_Post|null
92
- */
93
- public static function get( $id ) {
94
-
95
- $post = get_post( $id );
96
-
97
- if ( ! $post instanceof WP_Post ) {
98
-
99
- return null;
100
- }
101
-
102
- return new static( $post );
103
- }
104
-
105
- /**
106
- * Process post content for headings.
107
- *
108
- * This must be run after object init or after @see ezTOC_Post::applyContentFilter().
109
- *
110
- * @since 2.0
111
- *
112
- * @return static
113
- */
114
- private function process() {
115
-
116
- $this->processPages();
117
-
118
- return $this;
119
- }
120
-
121
- /**
122
- * Apply `the_content` filter to the post content.
123
- *
124
- * @since 2.0
125
- *
126
- * @return static
127
- */
128
- private function applyContentFilter() {
129
-
130
- add_filter( 'strip_shortcodes_tagnames', array( __CLASS__, 'stripShortcodes' ), 10, 2 );
131
-
132
- /*
133
- * Ensure the ezTOC content filter is not applied when running `the_content` filter.
134
- */
135
- remove_filter( 'the_content', array( 'ezTOC', 'the_content' ), 100 );
136
-
137
- $this->post->post_content = apply_filters( 'ez_toc_the_content', strip_shortcodes( $this->post->post_content ) );
138
-
139
- if( class_exists( 'Salient_Core' ) ) {
140
- $this->post->post_content = apply_filters( 'the_content', strip_shortcodes( $this->post->post_content ) );
141
- }
142
-
143
- add_filter( 'the_content', array( 'ezTOC', 'the_content' ), 100 );
144
-
145
- remove_filter( 'strip_shortcodes_tagnames', array( __CLASS__, 'stripShortcodes' ) );
146
-
147
- return $this;
148
- }
149
-
150
- /**
151
- * Callback for the `strip_shortcodes_tagnames` filter.
152
- *
153
- * Strip the shortcodes so their content is no processed for headings.
154
- *
155
- * @see ezTOC_Post::applyContentFilter()
156
- *
157
- * @since 2.0
158
- *
159
- * @param array $tags_to_remove Array of shortcode tags to remove.
160
- * @param string $content Content shortcodes are being removed from.
161
- *
162
- * @return array
163
- */
164
- public static function stripShortcodes( $tags_to_remove, $content ) {
165
-
166
- //error_log( var_export( $tags_to_remove, true ) );
167
-
168
- /*
169
- * Ensure the ezTOC shortcodes are not processed when applying `the_content` filter
170
- * otherwise an infinite loop may occur.
171
- */
172
- $tags_to_remove = apply_filters(
173
- 'ez_toc_strip_shortcodes_tagnames',
174
- array(
175
- 'ez-toc',
176
- apply_filters( 'ez_toc_shortcode', 'toc' ),
177
- ),
178
- $content
179
- );
180
-
181
- //error_log( var_export( $tags_to_remove, true ) );
182
-
183
- return $tags_to_remove;
184
- }
185
-
186
- /**
187
- * This is a work around for theme's and plugins
188
- * which break the WordPress global $wp_query var by unsetting it
189
- * or overwriting it which breaks the method call
190
- * that `get_query_var()` uses to return the query variable.
191
- *
192
- * @access protected
193
- * @since 2.0
194
- *
195
- * @return int
196
- */
197
- protected function getCurrentPage() {
198
-
199
- global $wp_query;
200
-
201
- // Check to see if the global `$wp_query` var is an instance of WP_Query and that the get() method is callable.
202
- // If it is then when can simply use the get_query_var() function.
203
- if ( $wp_query instanceof WP_Query && is_callable( array( $wp_query, 'get' ) ) ) {
204
-
205
- $page = get_query_var( 'page', 1 );
206
-
207
- return 1 > $page ? 1 : $page;
208
-
209
- // If a theme or plugin broke the global `$wp_query` var, check to see if the $var was parsed and saved in $GLOBALS['wp_query']->query_vars.
210
- } elseif ( isset( $GLOBALS['wp_query']->query_vars[ 'page' ] ) ) {
211
-
212
- return $GLOBALS['wp_query']->query_vars[ 'page' ];
213
-
214
- // We should not reach this, but if we do, lets check the original parsed query vars in $GLOBALS['wp_the_query']->query_vars.
215
- } elseif ( isset( $GLOBALS['wp_the_query']->query_vars[ 'page' ] ) ) {
216
-
217
- return $GLOBALS['wp_the_query']->query_vars[ 'page' ];
218
-
219
- // Ok, if all else fails, check the $_REQUEST super global.
220
- } elseif ( isset( $_REQUEST[ 'page' ] ) ) {
221
-
222
- return $_REQUEST[ 'page' ];
223
- }
224
-
225
- // Finally, return the $default if it was supplied.
226
- return 1;
227
- }
228
-
229
- /**
230
- * Get the number of page the post has.
231
- *
232
- * @access protected
233
- * @since 2.0
234
- *
235
- * @return int
236
- */
237
- protected function getNumberOfPages() {
238
-
239
- return count( $this->pages );
240
- }
241
-
242
- /**
243
- * Whether or not the post has multiple pages.
244
- *
245
- * @access protected
246
- * @since 2.0
247
- *
248
- * @return bool
249
- */
250
- protected function isMultipage() {
251
-
252
- return 1 < $this->getNumberOfPages();
253
- }
254
-
255
- /**
256
- * Parse the post content and headings.
257
- *
258
- * @access private
259
- * @since 2.0
260
- */
261
- private function processPages() {
262
-
263
- //if ( ! class_exists( 'TagFilter' ) ) {
264
- //
265
- // require_once( EZ_TOC_PATH . '/includes/vendor/ultimate-web-scraper/tag_filter.php' );
266
- //}
267
-
268
- $split = preg_split( '/<!--nextpage-->/msuU', $this->post->post_content );
269
- $pages = array();
270
-
271
- if ( is_array( $split ) ) {
272
-
273
- $page = 1;
274
-
275
- //$tagFilterOptions = TagFilter::GetHTMLOptions();
276
-
277
- //// Set custom TagFilter options.
278
- //$tagFilterOptions['charset'] = get_option( 'blog_charset' );
279
- ////$tagFilterOptions['output_mode'] = 'xml';
280
-
281
- foreach ( $split as $content ) {
282
-
283
- //$html = TagFilter::Explode( $content, $tagFilterOptions );
284
- //
285
- ///**
286
- // * @since 2.0
287
- // *
288
- // * @param $selectors array Array of classes/id selector to exclude from TOC.
289
- // * @param $content string Post content.
290
- // */
291
- //$selectors = apply_filters( 'ez_toc_exclude_by_selector', array(), $content );
292
- //
293
- //$nodes = $html->Find( implode( ',', $selectors ) );
294
- //
295
- //foreach ( $nodes['ids'] as $id ) {
296
- //
297
- // $html->Remove( $id );
298
- //}
299
- //
300
- //$eligibleContent = $html->Implode( 0, $tagFilterOptions );
301
- //
302
- ///**
303
- // * TagFilter::Implode() writes br tags as `<br>` while WP normalizes to `<br />`.
304
- // * Normalize `$eligibleContent` to match WP.
305
- // *
306
- // * @see wpautop()
307
- // */
308
- ////$eligibleContent = str_replace( array( '<br>', '<br/>' ), array( '<br />' ), $eligibleContent );
309
- //$eligibleContent = \Easy_Plugins\Table_Of_Contents\String\force_balance_tags( $eligibleContent );
310
-
311
- $this->extractExcludedNodes( $page, $content );
312
-
313
- $pages[ $page ] = array(
314
- 'headings' => $this->extractHeadings( $content ),
315
- 'content' => $content,
316
- );
317
-
318
- $page++;
319
- }
320
-
321
- }
322
-
323
- $this->pages = $pages;
324
- }
325
-
326
- /**
327
- * Get the post's parse content and headings.
328
- *
329
- * @access public
330
- * @since 2.0
331
- *
332
- * @return array
333
- */
334
- public function getPages() {
335
-
336
- return $this->pages;
337
- }
338
-
339
- /**
340
- * Extract nodes that heading are to be excluded.
341
- *
342
- * @since 2.0
343
- *
344
- * @param int $page
345
- * @param string $content
346
- */
347
- private function extractExcludedNodes( $page, $content ) {
348
-
349
- if ( ! class_exists( 'TagFilter' ) ) {
350
-
351
- require_once( EZ_TOC_PATH . '/includes/vendor/ultimate-web-scraper/tag_filter.php' );
352
- }
353
-
354
- $tagFilterOptions = TagFilter::GetHTMLOptions();
355
-
356
- // Set custom TagFilter options.
357
- $tagFilterOptions['charset'] = get_option( 'blog_charset' );
358
- //$tagFilterOptions['output_mode'] = 'xml';
359
-
360
- $html = TagFilter::Explode( $content, $tagFilterOptions );
361
-
362
- /**
363
- * @since 2.0
364
- *
365
- * @param $selectors array Array of classes/id selector to exclude from TOC.
366
- * @param $content string Post content.
367
- */
368
- $selectors = apply_filters( 'ez_toc_exclude_by_selector', array( '.ez-toc-exclude-headings' ), $content );
369
-
370
- $nodes = $html->Find( implode( ',', $selectors ) );
371
-
372
- foreach ( $nodes['ids'] as $id ) {
373
-
374
- //$this->excludedNodes[ $page ][ $id ] = $html->Implode( $id, $tagFilterOptions );
375
- array_push( $this->excludedNodes, $html->Implode( $id, $tagFilterOptions ) );
376
- }
377
-
378
- //$eligibleContent = $html->Implode( 0, $tagFilterOptions );
379
-
380
- /**
381
- * TagFilter::Implode() writes br tags as `<br>` while WP normalizes to `<br />`.
382
- * Normalize `$eligibleContent` to match WP.
383
- *
384
- * @see wpautop()
385
- */
386
- //$eligibleContent = \Easy_Plugins\Table_Of_Contents\String\force_balance_tags( $eligibleContent );
387
- }
388
-
389
- /**
390
- * Extract the posts content for headings.
391
- *
392
- * @access private
393
- * @since 2.0
394
- *
395
- * @param string $content
396
- *
397
- * @return array
398
- */
399
- private function extractHeadings( $content ) {
400
-
401
- $matches = array();
402
-
403
- // reset the internal collision collection as the_content may have been triggered elsewhere
404
- // eg by themes or other plugins that need to read in content such as metadata fields in
405
- // the head html tag, or to provide descriptions to twitter/facebook
406
- /** @todo does this need to be used??? */
407
- //self::$collision_collector = array();
408
-
409
- $content = apply_filters( 'ez_toc_extract_headings_content', wptexturize( $content ) );
410
-
411
- // get all headings
412
- // the html spec allows for a maximum of 6 heading depths
413
- if ( preg_match_all( '/(<h([1-6]{1})[^>]*>)(.*)<\/h\2>/msuU', $content, $matches, PREG_SET_ORDER ) ) {
414
-
415
- $minimum = absint( ezTOC_Option::get( 'start' ) );
416
-
417
- $this->removeHeadingsFromExcludedNodes( $matches );
418
- $this->removeHeadings( $matches );
419
- $this->excludeHeadings( $matches );
420
- $this->removeEmptyHeadings( $matches );
421
-
422
- if ( count( $matches ) >= $minimum ) {
423
-
424
- $this->alternateHeadings( $matches );
425
- $this->headingIDs( $matches );
426
- $this->hasTOCItems = true;
427
-
428
- } else {
429
-
430
- return array();
431
- }
432
-
433
- }
434
-
435
- return array_values( $matches ); // Rest the array index.
436
- }
437
-
438
- /**
439
- * Whether or not the string is in one of the excluded nodes.
440
- *
441
- * @since 2.0
442
- *
443
- * @param string $string
444
- *
445
- * @return bool
446
- */
447
- private function inExcludedNode( $string ) {
448
-
449
- foreach ( $this->excludedNodes as $node ) {
450
-
451
- if ( empty( $node ) || empty( $string ) ) {
452
-
453
- return false;
454
- }
455
-
456
- if ( false !== strpos( $node, $string ) ) {
457
-
458
- return true;
459
- }
460
- }
461
-
462
- return false;
463
- }
464
-
465
- /**
466
- * Remove headings that are in excluded nodes.
467
- *
468
- * @since 2.0
469
- *
470
- * @param array $matches
471
- *
472
- * @return array
473
- */
474
- private function removeHeadingsFromExcludedNodes( &$matches ) {
475
-
476
- foreach ( $matches as $i => $match ) {
477
-
478
- if ( $this->inExcludedNode( "{$match[3]}</h$match[2]>" ) ) {
479
-
480
- unset( $matches[ $i ] );
481
- }
482
- }
483
-
484
- return $matches;
485
- }
486
-
487
- /**
488
- * Get the heading levels to be included in the TOC.
489
- *
490
- * @access private
491
- * @since 2.0
492
- *
493
- * @return array
494
- */
495
- private function getHeadingLevels() {
496
-
497
- $levels = get_post_meta( $this->post->ID, '_ez-toc-heading-levels', true );
498
-
499
- if ( ! is_array( $levels ) ) {
500
-
501
- $levels = array();
502
- }
503
-
504
- if ( empty( $levels ) ) {
505
-
506
- $levels = ezTOC_Option::get( 'heading_levels', array() );
507
- }
508
-
509
- $this->headingLevels = $levels;
510
-
511
- return $this->headingLevels;
512
- }
513
-
514
- /**
515
- * Remove the heading levels as defined by user settings from the TOC heading matches.
516
- *
517
- * @see ezTOC_Post::extractHeadings()
518
- *
519
- * @access private
520
- * @since 2.0
521
- *
522
- * @param array $matches The heading from the post content extracted with preg_match_all().
523
- *
524
- * @return array
525
- */
526
- private function removeHeadings( &$matches ) {
527
-
528
- $levels = $this->getHeadingLevels();
529
-
530
- if ( count( $levels ) != 6 ) {
531
-
532
- $new_matches = array();
533
- //$count = count( $matches );
534
-
535
- //for ( $i = 0; $i < $count; $i++ ) {
536
- foreach ( $matches as $i => $match ) {
537
-
538
- if ( in_array( $matches[ $i ][2], $levels ) ) {
539
-
540
- $new_matches[ $i ] = $matches[ $i ];
541
- }
542
- }
543
-
544
- $matches = $new_matches;
545
- }
546
-
547
- return $matches;
548
- }
549
-
550
- /**
551
- * Exclude the heading, by title, as defined by the user settings from the TOC matches.
552
- *
553
- * @see ezTOC_Post::extractHeadings()
554
- *
555
- * @access private
556
- * @since 2.0
557
- *
558
- * @param array $matches The headings from the post content extracted with preg_match_all().
559
- *
560
- * @return array
561
- */
562
- private function excludeHeadings( &$matches ) {
563
-
564
- $exclude = get_post_meta( $this->post->ID, '_ez-toc-exclude', true );
565
-
566
- if ( empty( $exclude ) ) {
567
-
568
- $exclude = ezTOC_Option::get( 'exclude' );
569
- }
570
-
571
- if ( $exclude ) {
572
-
573
- $excluded_headings = explode( '|', $exclude );
574
- $excluded_count = count( $excluded_headings );
575
-
576
- if ( $excluded_count > 0 ) {
577
-
578
- for ( $j = 0; $j < $excluded_count; $j++ ) {
579
-
580
- $excluded_headings[ $j ] = preg_quote( $excluded_headings[ $j ] );
581
-
582
- // escape some regular expression characters
583
- // others: http://www.php.net/manual/en/regexp.reference.meta.php
584
- $excluded_headings[ $j ] = str_replace(
585
- array( '\*', '/', '%' ),
586
- array( '.*', '\/', '\%' ),
587
- trim( $excluded_headings[ $j ] )
588
- );
589
- }
590
-
591
- $new_matches = array();
592
- //$count = count( $matches );
593
-
594
- //for ( $i = 0; $i < $count; $i++ ) {
595
- foreach ( $matches as $i => $match ) {
596
-
597
- $found = false;
598
-
599
- $against = html_entity_decode(
600
- wptexturize( strip_tags( str_replace( array( "\r", "\n" ), ' ', $matches[ $i ][0] ) ) ),
601
- ENT_NOQUOTES,
602
- get_option( 'blog_charset' )
603
- );
604
-
605
- for ( $j = 0; $j < $excluded_count; $j++ ) {
606
-
607
- // Since WP manipulates the post content it is required that the excluded header and
608
- // the actual header be manipulated similarly so a match can be made.
609
- $pattern = html_entity_decode(
610
- wptexturize( $excluded_headings[ $j ] ),
611
- ENT_NOQUOTES,
612
- get_option( 'blog_charset' )
613
- );
614
-
615
- if ( @preg_match( '/^' . $pattern . '$/imU', $against ) ) {
616
-
617
- $found = true;
618
- break;
619
- }
620
- }
621
-
622
- if ( ! $found ) {
623
-
624
- $new_matches[ $i ] = $matches[ $i ];
625
- }
626
- }
627
-
628
- //if ( count( $matches ) != count( $new_matches ) ) {
629
-
630
- $matches = $new_matches;
631
- //}
632
- }
633
- }
634
-
635
- return $matches;
636
- }
637
-
638
- /**
639
- * Return the alternate headings added by the user, saved in the post meta.
640
- *
641
- * The result is an associative array where the `key` is the original post heading
642
- * and the `value` is the alternate heading.
643
- *
644
- * @access private
645
- * @since 2.0
646
- *
647
- * @return array
648
- */
649
- private function getAlternateHeadings() {
650
-
651
- $alternates = array();
652
- $value = get_post_meta( $this->post->ID, '_ez-toc-alttext', true );
653
-
654
- if ( $value ) {
655
-
656
- $headings = preg_split( '/\r\n|[\r\n]/', $value );
657
- $count = count( $headings );
658
-
659
- if ( $headings ) {
660
-
661
- for ( $k = 0; $k < $count; $k++ ) {
662
-
663
- $heading = explode( '|', $headings[ $k ] );
664
-
665
- /**
666
- * @link https://wordpress.org/support/topic/undefined-offset-1-home-blog-public-wp-content-plugins-easy-table-of-contents/
667
- */
668
- if ( ! is_array( $heading) ||
669
- ! array_key_exists( 0, $heading ) ||
670
- ! array_key_exists( 1, $heading )
671
- ) {
672
- continue;
673
- }
674
-
675
- if ( 0 < strlen( $heading[0] ) && 0 < strlen( $heading[1] ) ) {
676
-
677
- $alternates[ $heading[0] ] = $heading[1];
678
- }
679
- }
680
-
681
- }
682
-
683
- }
684
-
685
- return $alternates;
686
- }
687
-
688
- /**
689
- * Add the alternate headings to the array.
690
- *
691
- * @see ezTOC_Post::extractHeadings()
692
- *
693
- * @access private
694
- * @since 2.0
695
- *
696
- * @param array $matches The heading from the post content extracted with preg_match_all().
697
- *
698
- * @return array
699
- */
700
- private function alternateHeadings( &$matches ) {
701
-
702
- $alt_headings = $this->getAlternateHeadings();
703
- //$count = count( $matches );
704
-
705
- if ( 0 < count( $alt_headings ) ) {
706
-
707
- //for ( $i = 0; $i < $count; $i++ ) {
708
- foreach ( $matches as $i => $match ) {
709
-
710
- foreach ( $alt_headings as $original_heading => $alt_heading ) {
711
-
712
- // Cleanup and texturize so alt heading can match heading in post content.
713
- $original_heading = wptexturize( trim( $original_heading ) );
714
-
715
- // Deal with special characters such as non-breakable space.
716
- $original_heading = str_replace(
717
- array( "\xc2\xa0" ),
718
- array( ' ' ),
719
- $original_heading
720
- );
721
-
722
- // Escape for regular expression.
723
- $original_heading = preg_quote( $original_heading );
724
-
725
- // Escape for regular expression some other characters: http://www.php.net/manual/en/regexp.reference.meta.php
726
- $original_heading = str_replace(
727
- array( '\*', '/', '%' ),
728
- array( '.*', '\/', '\%' ),
729
- $original_heading
730
- );
731
-
732
- // Cleanup subject so alt heading can match heading in post content.
733
- $subject = strip_tags( $matches[ $i ][0] );
734
-
735
- // Deal with special characters such as non-breakable space.
736
- $subject = str_replace(
737
- array( "\xc2\xa0" ),
738
- array( ' ' ),
739
- $subject
740
- );
741
-
742
- if ( @preg_match( '/^' . $original_heading . '$/imU', $subject ) ) {
743
-
744
- $matches[ $i ]['alternate'] = $alt_heading;
745
- }
746
- }
747
- }
748
- }
749
-
750
- return $matches;
751
- }
752
-
753
- /**
754
- * Add the heading `id` to the array.
755
- *
756
- * @see ezTOC_Post::extractHeadings()
757
- *
758
- * @access private
759
- * @since 2.0
760
- *
761
- * @param array $matches The heading from the post content extracted with preg_match_all().
762
- *
763
- * @return mixed
764
- */
765
- private function headingIDs( &$matches ) {
766
-
767
- //$count = count( $matches );
768
-
769
- //for ( $i = 0; $i < $count; $i++ ) {
770
- foreach ( $matches as $i => $match ) {
771
-
772
- $matches[ $i ]['id'] = $this->generateHeadingIDFromTitle( $matches[ $i ][0] );
773
- }
774
-
775
- return $matches;
776
- }
777
-
778
- /**
779
- * Create unique heading ID from heading string.
780
- *
781
- * @access private
782
- * @since 2.0
783
- *
784
- * @param string $heading
785
- *
786
- * @return bool|string
787
- */
788
- private function generateHeadingIDFromTitle( $heading ) {
789
-
790
- $return = false;
791
-
792
- if ( $heading ) {
793
- $heading = apply_filters( 'ez_toc_url_anchor_target_before', $heading );
794
- // WP entity encodes the post content.
795
- $return = html_entity_decode( $heading, ENT_QUOTES, get_option( 'blog_charset' ) );
796
- $return = br2( $return, ' ' );
797
- $return = trim( strip_tags( $return ) );
798
-
799
- // Convert accented characters to ASCII.
800
- $return = remove_accents( $return );
801
-
802
- // replace newlines with spaces (eg when headings are split over multiple lines)
803
- $return = str_replace( array( "\r", "\n", "\n\r", "\r\n" ), ' ', $return );
804
-
805
- // Remove `&amp;` and `&nbsp;` NOTE: in order to strip "hidden" `&nbsp;`,
806
- // title needs to be converted to HTML entities.
807
- // @link https://stackoverflow.com/a/21801444/5351316
808
- $return = htmlentities2( $return );
809
- $return = str_replace( array( '&amp;', '&nbsp;' ), ' ', $return );
810
- $return = html_entity_decode( $return, ENT_QUOTES, get_option( 'blog_charset' ) );
811
-
812
- // remove non alphanumeric chars
813
- //$return = preg_replace( '/[^a-zA-Z0-9 \-_]*/', '', $return );
814
- $return = preg_replace( '/[\x00-\x1F\x7F]*/u', '', $return );
815
-
816
- // Reserved Characters.
817
- // * ' ( ) ; : @ & = + $ , / ? # [ ]
818
- $return = str_replace(
819
- array( '*', '\'', '(', ')', ';', '@', '&', '=', '+', '$', ',', '/', '?', '#', '[', ']' ),
820
- '',
821
- $return
822
- );
823
-
824
- // Unsafe Characters.
825
- // % { } | \ ^ ~ [ ] `
826
- $return = str_replace(
827
- array( '%', '{', '}', '|', '\\', '^', '~', '[', ']', '`' ),
828
- '',
829
- $return
830
- );
831
-
832
- // Special Characters.
833
- // $ - _ . + ! * ' ( ) ,
834
- $return = str_replace(
835
- array( '$', '.', '+', '!', '*', '\'', '(', ')', ',' ),
836
- '',
837
- $return
838
- );
839
-
840
- // Dashes
841
- // Special Characters.
842
- // - (minus) - (dash) – (en dash) — (em dash)
843
- $return = str_replace(
844
- array( '-', '-', '–', '—' ),
845
- '-',
846
- $return
847
- );
848
-
849
- // Curley quotes.
850
- // ‘ (curly single open quote) ’ (curly single close quote) “ (curly double open quote) ” (curly double close quote)
851
- $return = str_replace(
852
- array( '‘', '’', '“', '”' ),
853
- '',
854
- $return
855
- );
856
-
857
- // AMP/Caching plugins seems to break URL with the following characters, so lets replace them.
858
- $return = str_replace( array( ':' ), '_', $return );
859
-
860
- // Convert space characters to an `_` (underscore).
861
- $return = preg_replace( '/\s+/', '_', $return );
862
-
863
- // Replace multiple `-` (hyphen) with a single `-` (hyphen).
864
- $return = preg_replace( '/-+/', '-', $return );
865
-
866
- // Replace multiple `_` (underscore) with a single `_` (underscore).
867
- $return = preg_replace( '/_+/', '_', $return );
868
-
869
- // Remove trailing `-` (hyphen) and `_` (underscore).
870
- $return = rtrim( $return, '-_' );
871
-
872
- /*
873
- * Encode URI based on ECMA-262.
874
- *
875
- * Only required to support the jQuery smoothScroll library.
876
- *
877
- * @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI#Description
878
- * @link https://stackoverflow.com/a/19858404/5351316
879
- */
880
- $return = preg_replace_callback(
881
- "{[^0-9a-z_.!~*'();,/?:@&=+$#-]}i",
882
- function( $m ) {
883
-
884
- return sprintf( '%%%02X', ord( $m[0] ) );
885
- },
886
- $return
887
- );
888
-
889
- // lowercase everything?
890
- if ( ezTOC_Option::get( 'lowercase' ) ) {
891
-
892
- $return = strtolower( $return );
893
- }
894
-
895
- // if blank, then prepend with the fragment prefix
896
- // blank anchors normally appear on sites that don't use the latin charset
897
- if ( ! $return ) {
898
-
899
- $return = ( ezTOC_Option::get( 'fragment_prefix' ) ) ? ezTOC_Option::get( 'fragment_prefix' ) : '_';
900
- }
901
-
902
- // hyphenate?
903
- if ( ezTOC_Option::get( 'hyphenate' ) ) {
904
-
905
- $return = str_replace( '_', '-', $return );
906
- $return = preg_replace( '/-+/', '-', $return );
907
- }
908
- }
909
-
910
- if ( array_key_exists( $return, $this->collision_collector ) ) {
911
-
912
- $this->collision_collector[ $return ]++;
913
- $return .= '-' . $this->collision_collector[ $return ];
914
-
915
- } else {
916
-
917
- $this->collision_collector[ $return ] = 1;
918
- }
919
-
920
- return apply_filters( 'ez_toc_url_anchor_target', $return, $heading );
921
- }
922
-
923
- /**
924
- * Remove any empty headings from the TOC.
925
- *
926
- * @access private
927
- * @since 2.0
928
- *
929
- * @param array $matches The heading from the post content extracted with preg_match_all().
930
- *
931
- * @return array
932
- */
933
- private function removeEmptyHeadings( &$matches ) {
934
-
935
- $new_matches = array();
936
- //$count = count( $matches );
937
-
938
- //for ( $i = 0; $i < $count; $i ++ ) {
939
- foreach ( $matches as $i => $match ) {
940
-
941
- if ( trim( strip_tags( $matches[ $i ][0] ) ) != false ) {
942
-
943
- $new_matches[ $i ] = $matches[ $i ];
944
- }
945
- }
946
-
947
- //if ( count( $matches ) != count( $new_matches ) ) {
948
-
949
- $matches = $new_matches;
950
- //}
951
-
952
- return $matches;
953
- }
954
-
955
- /**
956
- * Whether or not the post has TOC items.
957
- *
958
- * @see ezTOC_Post::extractHeadings()
959
- *
960
- * @access public
961
- * @since 2.0
962
- *
963
- * @return bool
964
- */
965
- public function hasTOCItems() {
966
-
967
- return $this->hasTOCItems;
968
- }
969
-
970
- /**
971
- * Get the headings of the current page of the post.
972
- *
973
- * @access public
974
- * @since 2.0
975
- *
976
- * @param int|null $page
977
- *
978
- * @return array
979
- */
980
- public function getHeadings( $page = null ) {
981
-
982
- $headings = array();
983
-
984
- if ( is_null( $page ) ) {
985
-
986
- $page = $this->getCurrentPage();
987
- }
988
-
989
- if ( isset( $this->pages[ $page ] ) ) {
990
-
991
- //$headings = wp_list_pluck( $this->pages[ $page ]['headings'], 0 );
992
-
993
- $matches = $this->pages[ $page ]['headings'];
994
- //$count = count( $matches );
995
-
996
- //for ( $i = 0; $i < $count; $i++ ) {
997
- foreach ( $matches as $i => $match ) {
998
-
999
- //$anchor = $matches[ $i ]['id'];
1000
- $headings[] = str_replace(
1001
- array(
1002
- $matches[ $i ][1], // start of heading
1003
- '</h' . $matches[ $i ][2] . '>' // end of heading
1004
- ),
1005
- array(
1006
- '>',
1007
- '</h' . $matches[ $i ][2] . '>'
1008
- ),
1009
- $matches[ $i ][0]
1010
- );
1011
- }
1012
- }
1013
-
1014
- return $headings;
1015
- }
1016
-
1017
- /**
1018
- * Get the heading with in page anchors of the current page of the post.
1019
- *
1020
- * @access public
1021
- * @since 2.0
1022
- *
1023
- * @param int|null $page
1024
- *
1025
- * @return array
1026
- */
1027
- public function getHeadingsWithAnchors( $page = null ) {
1028
-
1029
- $headings = array();
1030
-
1031
- if ( is_null( $page ) ) {
1032
-
1033
- $page = $this->getCurrentPage();
1034
- }
1035
-
1036
- if ( isset( $this->pages[ $page ] ) ) {
1037
-
1038
- $matches = $this->pages[ $page ]['headings'];
1039
- //$count = count( $matches );
1040
-
1041
- //for ( $i = 0; $i < $count; $i++ ) {
1042
- foreach ( $matches as $i => $match ) {
1043
-
1044
- $anchor = $matches[ $i ]['id'];
1045
- $headings[] = str_replace(
1046
- array(
1047
- $matches[ $i ][1], // start of heading
1048
- '</h' . $matches[ $i ][2] . '>' // end of heading
1049
- ),
1050
- array(
1051
- '><span class="ez-toc-section" id="' . $anchor . '"></span>',
1052
- '<span class="ez-toc-section-end"></span></h' . $matches[ $i ][2] . '>'
1053
- ),
1054
- $matches[ $i ][0]
1055
- );
1056
- }
1057
- }
1058
-
1059
- return $headings;
1060
- }
1061
-
1062
- /**
1063
- * Get the post TOC list.
1064
- *
1065
- * @access public
1066
- * @since 2.0
1067
- *
1068
- * @return string
1069
- */
1070
- public function getTOCList() {
1071
-
1072
- $html = '';
1073
-
1074
- if ( $this->hasTOCItems ) {
1075
-
1076
- foreach ( $this->pages as $page => $attribute ) {
1077
-
1078
- $html .= $this->createTOC( $page, $attribute['headings'] );
1079
- }
1080
-
1081
- $html = '<ul class="ez-toc-list ez-toc-list-level-1">' . $html . '</ul>';
1082
- }
1083
-
1084
- return $html;
1085
- }
1086
-
1087
- /**
1088
- * Get the post TOC content block.
1089
- *
1090
- * @access public
1091
- * @since 2.0
1092
- *
1093
- * @return string
1094
- */
1095
- public function getTOC() {
1096
-
1097
- $class = array( 'ez-toc-v' . str_replace( '.', '_', ezTOC::VERSION ) );
1098
- $html = '';
1099
-
1100
- if ( $this->hasTOCItems() ) {
1101
-
1102
- // wrapping css classes
1103
- switch ( ezTOC_Option::get( 'wrapping' ) ) {
1104
-
1105
- case 'left':
1106
- $class[] = 'ez-toc-wrap-left';
1107
- break;
1108
-
1109
- case 'right':
1110
- $class[] = 'ez-toc-wrap-right';
1111
- break;
1112
- case 'center':
1113
- $class[] = 'ez-toc-wrap-center';
1114
- break;
1115
-
1116
- case 'none':
1117
- default:
1118
- // do nothing
1119
- }
1120
-
1121
- if ( ezTOC_Option::get( 'show_hierarchy' ) ) {
1122
-
1123
- $class[] = 'counter-hierarchy';
1124
-
1125
- } else {
1126
-
1127
- $class[] .= 'counter-flat';
1128
- }
1129
-
1130
- switch ( ezTOC_Option::get( 'counter' ) ) {
1131
-
1132
- case 'numeric':
1133
- $class[] .= 'counter-numeric';
1134
- break;
1135
-
1136
- case 'roman':
1137
- $class[] = 'counter-roman';
1138
- break;
1139
-
1140
- case 'decimal':
1141
- $class[] = 'counter-decimal';
1142
- break;
1143
-
1144
- case 'hyphen':
1145
- $class[] = 'counter-hyphen';
1146
- break;
1147
-
1148
- case 'disc':
1149
- $class[] = 'counter-disc';
1150
- break;
1151
- }
1152
-
1153
- // colour themes
1154
- switch ( ezTOC_Option::get( 'theme' ) ) {
1155
-
1156
- case 'light-blue':
1157
- $class[] = 'ez-toc-light-blue';
1158
- break;
1159
-
1160
- case 'white':
1161
- $class[] = 'ez-toc-white';
1162
- break;
1163
-
1164
- case 'black':
1165
- $class[] = 'ez-toc-black';
1166
- break;
1167
-
1168
- case 'transparent':
1169
- $class[] .= 'ez-toc-transparent';
1170
- break;
1171
-
1172
- case 'grey':
1173
- $class[] = 'ez-toc-grey';
1174
- break;
1175
- }
1176
-
1177
- $custom_classes = ezTOC_Option::get( 'css_container_class', '' );
1178
-
1179
- if ( 0 < strlen( $custom_classes ) ) {
1180
-
1181
- $custom_classes = explode( ' ', $custom_classes );
1182
- $custom_classes = apply_filters( 'ez_toc_container_class', $custom_classes, $this );
1183
-
1184
- if ( is_array( $custom_classes ) ) {
1185
-
1186
- $class = array_merge( $class, $custom_classes );
1187
- }
1188
- }
1189
-
1190
- $class = array_filter( $class );
1191
- $class = array_map( 'trim', $class );
1192
- $class = array_map( 'sanitize_html_class', $class );
1193
-
1194
- $html .= '<div id="ez-toc-container" class="' . implode( ' ', $class ) . '">' . PHP_EOL;
1195
-
1196
- if ( ezTOC_Option::get( 'show_heading_text' ) ) {
1197
-
1198
- $toc_title = ezTOC_Option::get( 'heading_text' );
1199
-
1200
- if ( strpos( $toc_title, '%PAGE_TITLE%' ) !== false ) {
1201
-
1202
- $toc_title = str_replace( '%PAGE_TITLE%', get_the_title(), $toc_title );
1203
- }
1204
-
1205
- if ( strpos( $toc_title, '%PAGE_NAME%' ) !== false ) {
1206
-
1207
- $toc_title = str_replace( '%PAGE_NAME%', get_the_title(), $toc_title );
1208
- }
1209
-
1210
- if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
1211
- $html .= '<div class="ez-toc-title-container">' . PHP_EOL;
1212
- }
1213
-
1214
- $html .= '<p class="ez-toc-title">' . esc_html__( htmlentities( $toc_title, ENT_COMPAT, 'UTF-8' ), 'easy-table-of-contents' ). '</p>' . PHP_EOL;
1215
-
1216
- if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
1217
- $html .= '<span class="ez-toc-title-toggle">';
1218
- }
1219
-
1220
- if ( ezTOC_Option::get( 'visibility' ) ) {
1221
- if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
1222
- $html .= '<a class="ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle" style="display: none;"><label for="item" aria-label="'.__( 'Table of Content', 'easy-table-of-contents' ).'"><i class="ez-toc-glyphicon ez-toc-icon-toggle"></i></label><input type="checkbox" id="item"></a>';
1223
- }else{
1224
- $toggle_view='';
1225
- if(ezTOC_Option::get('visibility_hide_by_default')==true){
1226
- $toggle_view= "checked";
1227
- }
1228
- $html .= '<label for="item"><i class="ez-toc-glyphicon ez-toc-icon-toggle"></i></label><input type="checkbox" id="item" '.$toggle_view.'>';
1229
- }
1230
- }
1231
-
1232
- if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
1233
- $html .= '</span>';
1234
- }
1235
- if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
1236
- $html .= '</div>' . PHP_EOL;
1237
- }
1238
- }else{
1239
- $html .= '<div class="ez-toc-title-container">' . PHP_EOL;
1240
- $html .= '<span class="ez-toc-title-toggle">';
1241
- $html .= '<a class="ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle" style="display: none;"><i class="ez-toc-glyphicon ez-toc-icon-toggle"></i></a>';
1242
- $html .= '</span>';
1243
- $html .= '</div>' . PHP_EOL;
1244
- }
1245
-
1246
- ob_start();
1247
- do_action( 'ez_toc_before' );
1248
- $html .= ob_get_clean();
1249
-
1250
- $html .= '<nav>' . $this->getTOCList() . '</nav>';
1251
-
1252
- ob_start();
1253
- do_action( 'ez_toc_after' );
1254
- $html .= ob_get_clean();
1255
-
1256
- $html .= '</div>' . PHP_EOL;
1257
-
1258
- // Enqueue the script.
1259
- wp_enqueue_script( 'ez-toc-js' );
1260
- }
1261
-
1262
- return $html;
1263
- }
1264
-
1265
- /**
1266
- * Displays the post's TOC.
1267
- *
1268
- * @access public
1269
- * @since 2.0
1270
- */
1271
- public function toc() {
1272
-
1273
- echo $this->getTOC();
1274
- }
1275
-
1276
- /**
1277
- * Generate the TOC list items for a given page within a post.
1278
- *
1279
- * @access private
1280
- * @since 2.0
1281
- *
1282
- * @param int $page The page of the post to create the TOC items for.
1283
- * @param array $matches The heading from the post content extracted with preg_match_all().
1284
- *
1285
- * @return string The HTML list of TOC items.
1286
- */
1287
- private function createTOC( $page, $matches ) {
1288
-
1289
- // Whether or not the TOC should be built flat or hierarchical.
1290
- $hierarchical = ezTOC_Option::get( 'show_hierarchy' );
1291
- $html = '';
1292
-
1293
- if ( $hierarchical ) {
1294
-
1295
- $current_depth = 100; // headings can't be larger than h6 but 100 as a default to be sure
1296
- $numbered_items = array();
1297
- $numbered_items_min = null;
1298
-
1299
- // reset the internal collision collection
1300
- /** @todo does this need to be used??? */
1301
- //self::$collision_collector = array();
1302
-
1303
- // find the minimum heading to establish our baseline
1304
- //for ( $i = 0; $i < count( $matches ); $i ++ ) {
1305
- foreach ( $matches as $i => $match ) {
1306
- if ( $current_depth > $matches[ $i ][2] ) {
1307
- $current_depth = (int) $matches[ $i ][2];
1308
- }
1309
- }
1310
-
1311
- $numbered_items[ $current_depth ] = 0;
1312
- $numbered_items_min = $current_depth;
1313
-
1314
- //for ( $i = 0; $i < count( $matches ); $i ++ ) {
1315
- foreach ( $matches as $i => $match ) {
1316
-
1317
- $level = $matches[ $i ][2];
1318
- $count = $i + 1;
1319
-
1320
- if ( $current_depth == (int) $matches[ $i ][2] ) {
1321
-
1322
- $html .= '<li class="ez-toc-page-' . $page . ' ez-toc-heading-level-' . $current_depth . '">';
1323
- }
1324
-
1325
- // start lists
1326
- if ( $current_depth != (int) $matches[ $i ][2] ) {
1327
-
1328
- for ( $current_depth; $current_depth < (int) $matches[ $i ][2]; $current_depth++ ) {
1329
-
1330
- $numbered_items[ $current_depth + 1 ] = 0;
1331
- $html .= '<ul class="ez-toc-list-level-' . $level . '"><li class="ez-toc-heading-level-' . $level . '">';
1332
- }
1333
- }
1334
-
1335
- $title = isset( $matches[ $i ]['alternate'] ) ? $matches[ $i ]['alternate'] : $matches[ $i ][0];
1336
- $title = br2( $title, ' ' );
1337
- $title = strip_tags( apply_filters( 'ez_toc_title', $title ), apply_filters( 'ez_toc_title_allowable_tags', '' ) );
1338
-
1339
- $html .= $this->createTOCItemAnchor( $page, $matches[ $i ]['id'], $title, $count );
1340
-
1341
- // end lists
1342
- if ( $i != count( $matches ) - 1 ) {
1343
-
1344
- if ( $current_depth > (int) $matches[ $i + 1 ][2] ) {
1345
-
1346
- for ( $current_depth; $current_depth > (int) $matches[ $i + 1 ][2]; $current_depth-- ) {
1347
-
1348
- $html .= '</li></ul>';
1349
- $numbered_items[ $current_depth ] = 0;
1350
- }
1351
- }
1352
-
1353
- if ( $current_depth == (int) @$matches[ $i + 1 ][2] ) {
1354
-
1355
- $html .= '</li>';
1356
- }
1357
-
1358
- } else {
1359
-
1360
- // this is the last item, make sure we close off all tags
1361
- for ( $current_depth; $current_depth >= $numbered_items_min; $current_depth-- ) {
1362
-
1363
- $html .= '</li>';
1364
-
1365
- if ( $current_depth != $numbered_items_min ) {
1366
- $html .= '</ul>';
1367
- }
1368
- }
1369
- }
1370
- }
1371
-
1372
- } else {
1373
-
1374
- //for ( $i = 0; $i < count( $matches ); $i++ ) {
1375
- foreach ( $matches as $i => $match ) {
1376
-
1377
- $count = $i + 1;
1378
-
1379
- $title = isset( $matches[ $i ]['alternate'] ) ? $matches[ $i ]['alternate'] : $matches[ $i ][0];
1380
- $title = strip_tags( apply_filters( 'ez_toc_title', $title ), apply_filters( 'ez_toc_title_allowable_tags', '' ) );
1381
-
1382
- $html .= '<li class="ez-toc-page-' . $page . '">';
1383
-
1384
- $html .= $this->createTOCItemAnchor( $page, $matches[ $i ]['id'], $title, $count );
1385
-
1386
- $html .= '</li>';
1387
- }
1388
- }
1389
-
1390
- return do_shortcode($html);
1391
- }
1392
-
1393
- /**
1394
- * @access private
1395
- * @since 2.0
1396
- *
1397
- * @param int $page
1398
- * @param string $id
1399
- * @param string $title
1400
- * @param int $count
1401
- *
1402
- * @return string
1403
- */
1404
- private function createTOCItemAnchor( $page, $id, $title, $count ) {
1405
-
1406
- return sprintf(
1407
- '<a class="ez-toc-link ez-toc-heading-' . $count . '" href="%1$s" title="%2$s">%3$s</a>',
1408
- esc_attr( $this->createTOCItemURL( $id, $page ) ),
1409
- esc_attr( strip_tags( $title ) ),
1410
- $title
1411
- );
1412
- }
1413
-
1414
- /**
1415
- * @access private
1416
- * @since 2.0
1417
- *
1418
- * @param string $id
1419
- * @param int $page
1420
- *
1421
- * @return string
1422
- */
1423
- private function createTOCItemURL( $id, $page ) {
1424
-
1425
- $current_post = $this->post->ID === $this->queriedObjectID;
1426
- $current_page = $this->getCurrentPage();
1427
-
1428
- if ( $page === $current_page && $current_post ) {
1429
-
1430
- return '#' . $id;
1431
-
1432
- } elseif ( 1 === $page ) {
1433
-
1434
- return trailingslashit( $this->permalink ) . '#' . $id;
1435
-
1436
- }
1437
-
1438
- return trailingslashit( $this->permalink ) . $page . '/#' . $id;
1439
- }
1440
- }
1
+ <?php
2
+
3
+ use function Easy_Plugins\Table_Of_Contents\String\br2;
4
+
5
+ class ezTOC_Post {
6
+
7
+ /**
8
+ * @since 2.0
9
+ * @var int
10
+ */
11
+ private $queriedObjectID;
12
+
13
+ /**
14
+ * @since 2.0
15
+ * @var WP_Post
16
+ */
17
+ private $post;
18
+
19
+ /**
20
+ * @since 2.0
21
+ * @var false|string
22
+ */
23
+ private $permalink;
24
+
25
+ /**
26
+ * The post content broken into pages by user inserting `<!--nextpage-->` into the post content.
27
+ * @see ezTOC_Post::extractPages()
28
+ * @since 2.0
29
+ * @var array
30
+ */
31
+ private $pages = array();
32
+
33
+ /**
34
+ * The user defined heading levels to be included in the TOC.
35
+ * @see ezTOC_Post::getHeadingLevels()
36
+ * @since 2.0
37
+ * @var array
38
+ */
39
+ private $headingLevels = array();
40
+
41
+ /**
42
+ * Array of nodes that are excluded by class/id selector.
43
+ * @since 2.0
44
+ * @var string[]
45
+ */
46
+ private $excludedNodes = array();
47
+
48
+ /**
49
+ * Keeps a track of used anchors for collision detecting.
50
+ * @see ezTOC_Post::generateHeadingIDFromTitle()
51
+ * @since 2.0
52
+ * @var array
53
+ */
54
+ private $collision_collector = array();
55
+
56
+ /**
57
+ * @var bool
58
+ */
59
+ private $hasTOCItems = false;
60
+
61
+ /**
62
+ * ezTOC_Post constructor.
63
+ *
64
+ * @since 2.0
65
+ *
66
+ * @param WP_Post $post
67
+ * @param bool $apply_content_filter Whether or not to apply the `the_content` filter on the post content.
68
+ */
69
+ public function __construct( WP_Post $post, $apply_content_filter = true ) {
70
+
71
+ $this->post = $post;
72
+ $this->permalink = get_permalink( $post );
73
+ $this->queriedObjectID = get_queried_object_id();
74
+
75
+ if ( $apply_content_filter ) {
76
+
77
+ $this->applyContentFilter()->process();
78
+
79
+ } else {
80
+
81
+ $this->process();
82
+ }
83
+ }
84
+
85
+ /**
86
+ * @access public
87
+ * @since 2.0
88
+ *
89
+ * @param $id
90
+ *
91
+ * @return ezTOC_Post|null
92
+ */
93
+ public static function get( $id ) {
94
+
95
+ $post = get_post( $id );
96
+
97
+ if ( ! $post instanceof WP_Post ) {
98
+
99
+ return null;
100
+ }
101
+
102
+ return new static( $post );
103
+ }
104
+
105
+ /**
106
+ * Process post content for headings.
107
+ *
108
+ * This must be run after object init or after @see ezTOC_Post::applyContentFilter().
109
+ *
110
+ * @since 2.0
111
+ *
112
+ * @return static
113
+ */
114
+ private function process() {
115
+
116
+ $this->processPages();
117
+
118
+ return $this;
119
+ }
120
+
121
+ /**
122
+ * Apply `the_content` filter to the post content.
123
+ *
124
+ * @since 2.0
125
+ *
126
+ * @return static
127
+ */
128
+ private function applyContentFilter() {
129
+
130
+ add_filter( 'strip_shortcodes_tagnames', array( __CLASS__, 'stripShortcodes' ), 10, 2 );
131
+
132
+ /*
133
+ * Ensure the ezTOC content filter is not applied when running `the_content` filter.
134
+ */
135
+ remove_filter( 'the_content', array( 'ezTOC', 'the_content' ), 100 );
136
+
137
+ $this->post->post_content = apply_filters( 'the_content', strip_shortcodes( $this->post->post_content ) );
138
+
139
+ add_filter( 'the_content', array( 'ezTOC', 'the_content' ), 100 );
140
+
141
+ remove_filter( 'strip_shortcodes_tagnames', array( __CLASS__, 'stripShortcodes' ) );
142
+
143
+ return $this;
144
+ }
145
+
146
+ /**
147
+ * Callback for the `strip_shortcodes_tagnames` filter.
148
+ *
149
+ * Strip the shortcodes so their content is no processed for headings.
150
+ *
151
+ * @see ezTOC_Post::applyContentFilter()
152
+ *
153
+ * @since 2.0
154
+ *
155
+ * @param array $tags_to_remove Array of shortcode tags to remove.
156
+ * @param string $content Content shortcodes are being removed from.
157
+ *
158
+ * @return array
159
+ */
160
+ public static function stripShortcodes( $tags_to_remove, $content ) {
161
+
162
+ //error_log( var_export( $tags_to_remove, true ) );
163
+
164
+ /*
165
+ * Ensure the ezTOC shortcodes are not processed when applying `the_content` filter
166
+ * otherwise an infinite loop may occur.
167
+ */
168
+ $tags_to_remove = apply_filters(
169
+ 'ez_toc_strip_shortcodes_tagnames',
170
+ array(
171
+ 'ez-toc',
172
+ apply_filters( 'ez_toc_shortcode', 'toc' ),
173
+ ),
174
+ $content
175
+ );
176
+
177
+ //error_log( var_export( $tags_to_remove, true ) );
178
+
179
+ return $tags_to_remove;
180
+ }
181
+
182
+ /**
183
+ * This is a work around for theme's and plugins
184
+ * which break the WordPress global $wp_query var by unsetting it
185
+ * or overwriting it which breaks the method call
186
+ * that `get_query_var()` uses to return the query variable.
187
+ *
188
+ * @access protected
189
+ * @since 2.0
190
+ *
191
+ * @return int
192
+ */
193
+ protected function getCurrentPage() {
194
+
195
+ global $wp_query;
196
+
197
+ // Check to see if the global `$wp_query` var is an instance of WP_Query and that the get() method is callable.
198
+ // If it is then when can simply use the get_query_var() function.
199
+ if ( $wp_query instanceof WP_Query && is_callable( array( $wp_query, 'get' ) ) ) {
200
+
201
+ $page = get_query_var( 'page', 1 );
202
+
203
+ return 1 > $page ? 1 : $page;
204
+
205
+ // If a theme or plugin broke the global `$wp_query` var, check to see if the $var was parsed and saved in $GLOBALS['wp_query']->query_vars.
206
+ } elseif ( isset( $GLOBALS['wp_query']->query_vars[ 'page' ] ) ) {
207
+
208
+ return $GLOBALS['wp_query']->query_vars[ 'page' ];
209
+
210
+ // We should not reach this, but if we do, lets check the original parsed query vars in $GLOBALS['wp_the_query']->query_vars.
211
+ } elseif ( isset( $GLOBALS['wp_the_query']->query_vars[ 'page' ] ) ) {
212
+
213
+ return $GLOBALS['wp_the_query']->query_vars[ 'page' ];
214
+
215
+ // Ok, if all else fails, check the $_REQUEST super global.
216
+ } elseif ( isset( $_REQUEST[ 'page' ] ) ) {
217
+
218
+ return $_REQUEST[ 'page' ];
219
+ }
220
+
221
+ // Finally, return the $default if it was supplied.
222
+ return 1;
223
+ }
224
+
225
+ /**
226
+ * Get the number of page the post has.
227
+ *
228
+ * @access protected
229
+ * @since 2.0
230
+ *
231
+ * @return int
232
+ */
233
+ protected function getNumberOfPages() {
234
+
235
+ return count( $this->pages );
236
+ }
237
+
238
+ /**
239
+ * Whether or not the post has multiple pages.
240
+ *
241
+ * @access protected
242
+ * @since 2.0
243
+ *
244
+ * @return bool
245
+ */
246
+ protected function isMultipage() {
247
+
248
+ return 1 < $this->getNumberOfPages();
249
+ }
250
+
251
+ /**
252
+ * Parse the post content and headings.
253
+ *
254
+ * @access private
255
+ * @since 2.0
256
+ */
257
+ private function processPages() {
258
+
259
+ //if ( ! class_exists( 'TagFilter' ) ) {
260
+ //
261
+ // require_once( EZ_TOC_PATH . '/includes/vendor/ultimate-web-scraper/tag_filter.php' );
262
+ //}
263
+
264
+ $split = preg_split( '/<!--nextpage-->/msuU', $this->post->post_content );
265
+ $pages = array();
266
+
267
+ if ( is_array( $split ) ) {
268
+
269
+ $page = 1;
270
+
271
+ //$tagFilterOptions = TagFilter::GetHTMLOptions();
272
+
273
+ //// Set custom TagFilter options.
274
+ //$tagFilterOptions['charset'] = get_option( 'blog_charset' );
275
+ ////$tagFilterOptions['output_mode'] = 'xml';
276
+
277
+ foreach ( $split as $content ) {
278
+
279
+ //$html = TagFilter::Explode( $content, $tagFilterOptions );
280
+ //
281
+ ///**
282
+ // * @since 2.0
283
+ // *
284
+ // * @param $selectors array Array of classes/id selector to exclude from TOC.
285
+ // * @param $content string Post content.
286
+ // */
287
+ //$selectors = apply_filters( 'ez_toc_exclude_by_selector', array(), $content );
288
+ //
289
+ //$nodes = $html->Find( implode( ',', $selectors ) );
290
+ //
291
+ //foreach ( $nodes['ids'] as $id ) {
292
+ //
293
+ // $html->Remove( $id );
294
+ //}
295
+ //
296
+ //$eligibleContent = $html->Implode( 0, $tagFilterOptions );
297
+ //
298
+ ///**
299
+ // * TagFilter::Implode() writes br tags as `<br>` while WP normalizes to `<br />`.
300
+ // * Normalize `$eligibleContent` to match WP.
301
+ // *
302
+ // * @see wpautop()
303
+ // */
304
+ ////$eligibleContent = str_replace( array( '<br>', '<br/>' ), array( '<br />' ), $eligibleContent );
305
+ //$eligibleContent = \Easy_Plugins\Table_Of_Contents\String\force_balance_tags( $eligibleContent );
306
+
307
+ $this->extractExcludedNodes( $page, $content );
308
+
309
+ $pages[ $page ] = array(
310
+ 'headings' => $this->extractHeadings( $content ),
311
+ 'content' => $content,
312
+ );
313
+
314
+ $page++;
315
+ }
316
+
317
+ }
318
+
319
+ $this->pages = $pages;
320
+ }
321
+
322
+ /**
323
+ * Get the post's parse content and headings.
324
+ *
325
+ * @access public
326
+ * @since 2.0
327
+ *
328
+ * @return array
329
+ */
330
+ public function getPages() {
331
+
332
+ return $this->pages;
333
+ }
334
+
335
+ /**
336
+ * Extract nodes that heading are to be excluded.
337
+ *
338
+ * @since 2.0
339
+ *
340
+ * @param int $page
341
+ * @param string $content
342
+ */
343
+ private function extractExcludedNodes( $page, $content ) {
344
+
345
+ if ( ! class_exists( 'TagFilter' ) ) {
346
+
347
+ require_once( EZ_TOC_PATH . '/includes/vendor/ultimate-web-scraper/tag_filter.php' );
348
+ }
349
+
350
+ $tagFilterOptions = TagFilter::GetHTMLOptions();
351
+
352
+ // Set custom TagFilter options.
353
+ $tagFilterOptions['charset'] = get_option( 'blog_charset' );
354
+ //$tagFilterOptions['output_mode'] = 'xml';
355
+
356
+ $html = TagFilter::Explode( $content, $tagFilterOptions );
357
+
358
+ /**
359
+ * @since 2.0
360
+ *
361
+ * @param $selectors array Array of classes/id selector to exclude from TOC.
362
+ * @param $content string Post content.
363
+ */
364
+ $selectors = apply_filters( 'ez_toc_exclude_by_selector', array( '.ez-toc-exclude-headings' ), $content );
365
+
366
+ $nodes = $html->Find( implode( ',', $selectors ) );
367
+
368
+ foreach ( $nodes['ids'] as $id ) {
369
+
370
+ //$this->excludedNodes[ $page ][ $id ] = $html->Implode( $id, $tagFilterOptions );
371
+ array_push( $this->excludedNodes, $html->Implode( $id, $tagFilterOptions ) );
372
+ }
373
+
374
+ //$eligibleContent = $html->Implode( 0, $tagFilterOptions );
375
+
376
+ /**
377
+ * TagFilter::Implode() writes br tags as `<br>` while WP normalizes to `<br />`.
378
+ * Normalize `$eligibleContent` to match WP.
379
+ *
380
+ * @see wpautop()
381
+ */
382
+ //$eligibleContent = \Easy_Plugins\Table_Of_Contents\String\force_balance_tags( $eligibleContent );
383
+ }
384
+
385
+ /**
386
+ * Extract the posts content for headings.
387
+ *
388
+ * @access private
389
+ * @since 2.0
390
+ *
391
+ * @param string $content
392
+ *
393
+ * @return array
394
+ */
395
+ private function extractHeadings( $content ) {
396
+
397
+ $matches = array();
398
+
399
+ // reset the internal collision collection as the_content may have been triggered elsewhere
400
+ // eg by themes or other plugins that need to read in content such as metadata fields in
401
+ // the head html tag, or to provide descriptions to twitter/facebook
402
+ /** @todo does this need to be used??? */
403
+ //self::$collision_collector = array();
404
+
405
+ $content = apply_filters( 'ez_toc_extract_headings_content', wptexturize( $content ) );
406
+
407
+ // get all headings
408
+ // the html spec allows for a maximum of 6 heading depths
409
+ if ( preg_match_all( '/(<h([1-6]{1})[^>]*>)(.*)<\/h\2>/msuU', $content, $matches, PREG_SET_ORDER ) ) {
410
+
411
+ $minimum = absint( ezTOC_Option::get( 'start' ) );
412
+
413
+ $this->removeHeadingsFromExcludedNodes( $matches );
414
+ $this->removeHeadings( $matches );
415
+ $this->excludeHeadings( $matches );
416
+ $this->removeEmptyHeadings( $matches );
417
+
418
+ if ( count( $matches ) >= $minimum ) {
419
+
420
+ $this->alternateHeadings( $matches );
421
+ $this->headingIDs( $matches );
422
+ $this->hasTOCItems = true;
423
+
424
+ } else {
425
+
426
+ return array();
427
+ }
428
+
429
+ }
430
+
431
+ return array_values( $matches ); // Rest the array index.
432
+ }
433
+
434
+ /**
435
+ * Whether or not the string is in one of the excluded nodes.
436
+ *
437
+ * @since 2.0
438
+ *
439
+ * @param string $string
440
+ *
441
+ * @return bool
442
+ */
443
+ private function inExcludedNode( $string ) {
444
+
445
+ foreach ( $this->excludedNodes as $node ) {
446
+
447
+ if ( empty( $node ) || empty( $string ) ) {
448
+
449
+ return false;
450
+ }
451
+
452
+ if ( false !== strpos( $node, $string ) ) {
453
+
454
+ return true;
455
+ }
456
+ }
457
+
458
+ return false;
459
+ }
460
+
461
+ /**
462
+ * Remove headings that are in excluded nodes.
463
+ *
464
+ * @since 2.0
465
+ *
466
+ * @param array $matches
467
+ *
468
+ * @return array
469
+ */
470
+ private function removeHeadingsFromExcludedNodes( &$matches ) {
471
+
472
+ foreach ( $matches as $i => $match ) {
473
+
474
+ if ( $this->inExcludedNode( "{$match[3]}</h$match[2]>" ) ) {
475
+
476
+ unset( $matches[ $i ] );
477
+ }
478
+ }
479
+
480
+ return $matches;
481
+ }
482
+
483
+ /**
484
+ * Get the heading levels to be included in the TOC.
485
+ *
486
+ * @access private
487
+ * @since 2.0
488
+ *
489
+ * @return array
490
+ */
491
+ private function getHeadingLevels() {
492
+
493
+ $levels = get_post_meta( $this->post->ID, '_ez-toc-heading-levels', true );
494
+
495
+ if ( ! is_array( $levels ) ) {
496
+
497
+ $levels = array();
498
+ }
499
+
500
+ if ( empty( $levels ) ) {
501
+
502
+ $levels = ezTOC_Option::get( 'heading_levels', array() );
503
+ }
504
+
505
+ $this->headingLevels = $levels;
506
+
507
+ return $this->headingLevels;
508
+ }
509
+
510
+ /**
511
+ * Remove the heading levels as defined by user settings from the TOC heading matches.
512
+ *
513
+ * @see ezTOC_Post::extractHeadings()
514
+ *
515
+ * @access private
516
+ * @since 2.0
517
+ *
518
+ * @param array $matches The heading from the post content extracted with preg_match_all().
519
+ *
520
+ * @return array
521
+ */
522
+ private function removeHeadings( &$matches ) {
523
+
524
+ $levels = $this->getHeadingLevels();
525
+
526
+ if ( count( $levels ) != 6 ) {
527
+
528
+ $new_matches = array();
529
+ //$count = count( $matches );
530
+
531
+ //for ( $i = 0; $i < $count; $i++ ) {
532
+ foreach ( $matches as $i => $match ) {
533
+
534
+ if ( in_array( $matches[ $i ][2], $levels ) ) {
535
+
536
+ $new_matches[ $i ] = $matches[ $i ];
537
+ }
538
+ }
539
+
540
+ $matches = $new_matches;
541
+ }
542
+
543
+ return $matches;
544
+ }
545
+
546
+ /**
547
+ * Exclude the heading, by title, as defined by the user settings from the TOC matches.
548
+ *
549
+ * @see ezTOC_Post::extractHeadings()
550
+ *
551
+ * @access private
552
+ * @since 2.0
553
+ *
554
+ * @param array $matches The headings from the post content extracted with preg_match_all().
555
+ *
556
+ * @return array
557
+ */
558
+ private function excludeHeadings( &$matches ) {
559
+
560
+ $exclude = get_post_meta( $this->post->ID, '_ez-toc-exclude', true );
561
+
562
+ if ( empty( $exclude ) ) {
563
+
564
+ $exclude = ezTOC_Option::get( 'exclude' );
565
+ }
566
+
567
+ if ( $exclude ) {
568
+
569
+ $excluded_headings = explode( '|', $exclude );
570
+ $excluded_count = count( $excluded_headings );
571
+
572
+ if ( $excluded_count > 0 ) {
573
+
574
+ for ( $j = 0; $j < $excluded_count; $j++ ) {
575
+
576
+ $excluded_headings[ $j ] = preg_quote( $excluded_headings[ $j ] );
577
+
578
+ // escape some regular expression characters
579
+ // others: http://www.php.net/manual/en/regexp.reference.meta.php
580
+ $excluded_headings[ $j ] = str_replace(
581
+ array( '\*', '/', '%' ),
582
+ array( '.*', '\/', '\%' ),
583
+ trim( $excluded_headings[ $j ] )
584
+ );
585
+ }
586
+
587
+ $new_matches = array();
588
+ //$count = count( $matches );
589
+
590
+ //for ( $i = 0; $i < $count; $i++ ) {
591
+ foreach ( $matches as $i => $match ) {
592
+
593
+ $found = false;
594
+
595
+ $against = html_entity_decode(
596
+ wptexturize( strip_tags( str_replace( array( "\r", "\n" ), ' ', $matches[ $i ][0] ) ) ),
597
+ ENT_NOQUOTES,
598
+ get_option( 'blog_charset' )
599
+ );
600
+
601
+ for ( $j = 0; $j < $excluded_count; $j++ ) {
602
+
603
+ // Since WP manipulates the post content it is required that the excluded header and
604
+ // the actual header be manipulated similarly so a match can be made.
605
+ $pattern = html_entity_decode(
606
+ wptexturize( $excluded_headings[ $j ] ),
607
+ ENT_NOQUOTES,
608
+ get_option( 'blog_charset' )
609
+ );
610
+
611
+ if ( @preg_match( '/^' . $pattern . '$/imU', $against ) ) {
612
+
613
+ $found = true;
614
+ break;
615
+ }
616
+ }
617
+
618
+ if ( ! $found ) {
619
+
620
+ $new_matches[ $i ] = $matches[ $i ];
621
+ }
622
+ }
623
+
624
+ //if ( count( $matches ) != count( $new_matches ) ) {
625
+
626
+ $matches = $new_matches;
627
+ //}
628
+ }
629
+ }
630
+
631
+ return $matches;
632
+ }
633
+
634
+ /**
635
+ * Return the alternate headings added by the user, saved in the post meta.
636
+ *
637
+ * The result is an associative array where the `key` is the original post heading
638
+ * and the `value` is the alternate heading.
639
+ *
640
+ * @access private
641
+ * @since 2.0
642
+ *
643
+ * @return array
644
+ */
645
+ private function getAlternateHeadings() {
646
+
647
+ $alternates = array();
648
+ $value = get_post_meta( $this->post->ID, '_ez-toc-alttext', true );
649
+
650
+ if ( $value ) {
651
+
652
+ $headings = preg_split( '/\r\n|[\r\n]/', $value );
653
+ $count = count( $headings );
654
+
655
+ if ( $headings ) {
656
+
657
+ for ( $k = 0; $k < $count; $k++ ) {
658
+
659
+ $heading = explode( '|', $headings[ $k ] );
660
+
661
+ /**
662
+ * @link https://wordpress.org/support/topic/undefined-offset-1-home-blog-public-wp-content-plugins-easy-table-of-contents/
663
+ */
664
+ if ( ! is_array( $heading) ||
665
+ ! array_key_exists( 0, $heading ) ||
666
+ ! array_key_exists( 1, $heading )
667
+ ) {
668
+ continue;
669
+ }
670
+
671
+ if ( 0 < strlen( $heading[0] ) && 0 < strlen( $heading[1] ) ) {
672
+
673
+ $alternates[ $heading[0] ] = $heading[1];
674
+ }
675
+ }
676
+
677
+ }
678
+
679
+ }
680
+
681
+ return $alternates;
682
+ }
683
+
684
+ /**
685
+ * Add the alternate headings to the array.
686
+ *
687
+ * @see ezTOC_Post::extractHeadings()
688
+ *
689
+ * @access private
690
+ * @since 2.0
691
+ *
692
+ * @param array $matches The heading from the post content extracted with preg_match_all().
693
+ *
694
+ * @return array
695
+ */
696
+ private function alternateHeadings( &$matches ) {
697
+
698
+ $alt_headings = $this->getAlternateHeadings();
699
+ //$count = count( $matches );
700
+
701
+ if ( 0 < count( $alt_headings ) ) {
702
+
703
+ //for ( $i = 0; $i < $count; $i++ ) {
704
+ foreach ( $matches as $i => $match ) {
705
+
706
+ foreach ( $alt_headings as $original_heading => $alt_heading ) {
707
+
708
+ // Cleanup and texturize so alt heading can match heading in post content.
709
+ $original_heading = wptexturize( trim( $original_heading ) );
710
+
711
+ // Deal with special characters such as non-breakable space.
712
+ $original_heading = str_replace(
713
+ array( "\xc2\xa0" ),
714
+ array( ' ' ),
715
+ $original_heading
716
+ );
717
+
718
+ // Escape for regular expression.
719
+ $original_heading = preg_quote( $original_heading );
720
+
721
+ // Escape for regular expression some other characters: http://www.php.net/manual/en/regexp.reference.meta.php
722
+ $original_heading = str_replace(
723
+ array( '\*', '/', '%' ),
724
+ array( '.*', '\/', '\%' ),
725
+ $original_heading
726
+ );
727
+
728
+ // Cleanup subject so alt heading can match heading in post content.
729
+ $subject = strip_tags( $matches[ $i ][0] );
730
+
731
+ // Deal with special characters such as non-breakable space.
732
+ $subject = str_replace(
733
+ array( "\xc2\xa0" ),
734
+ array( ' ' ),
735
+ $subject
736
+ );
737
+
738
+ if ( @preg_match( '/^' . $original_heading . '$/imU', $subject ) ) {
739
+
740
+ $matches[ $i ]['alternate'] = $alt_heading;
741
+ }
742
+ }
743
+ }
744
+ }
745
+
746
+ return $matches;
747
+ }
748
+
749
+ /**
750
+ * Add the heading `id` to the array.
751
+ *
752
+ * @see ezTOC_Post::extractHeadings()
753
+ *
754
+ * @access private
755
+ * @since 2.0
756
+ *
757
+ * @param array $matches The heading from the post content extracted with preg_match_all().
758
+ *
759
+ * @return mixed
760
+ */
761
+ private function headingIDs( &$matches ) {
762
+
763
+ //$count = count( $matches );
764
+
765
+ //for ( $i = 0; $i < $count; $i++ ) {
766
+ foreach ( $matches as $i => $match ) {
767
+
768
+ $matches[ $i ]['id'] = $this->generateHeadingIDFromTitle( $matches[ $i ][0] );
769
+ }
770
+
771
+ return $matches;
772
+ }
773
+
774
+ /**
775
+ * Create unique heading ID from heading string.
776
+ *
777
+ * @access private
778
+ * @since 2.0
779
+ *
780
+ * @param string $heading
781
+ *
782
+ * @return bool|string
783
+ */
784
+ private function generateHeadingIDFromTitle( $heading ) {
785
+
786
+ $return = false;
787
+
788
+ if ( $heading ) {
789
+ $heading = apply_filters( 'ez_toc_url_anchor_target_before', $heading );
790
+ // WP entity encodes the post content.
791
+ $return = html_entity_decode( $heading, ENT_QUOTES, get_option( 'blog_charset' ) );
792
+ $return = br2( $return, ' ' );
793
+ $return = trim( strip_tags( $return ) );
794
+
795
+ // Convert accented characters to ASCII.
796
+ $return = remove_accents( $return );
797
+
798
+ // replace newlines with spaces (eg when headings are split over multiple lines)
799
+ $return = str_replace( array( "\r", "\n", "\n\r", "\r\n" ), ' ', $return );
800
+
801
+ // Remove `&amp;` and `&nbsp;` NOTE: in order to strip "hidden" `&nbsp;`,
802
+ // title needs to be converted to HTML entities.
803
+ // @link https://stackoverflow.com/a/21801444/5351316
804
+ $return = htmlentities2( $return );
805
+ $return = str_replace( array( '&amp;', '&nbsp;' ), ' ', $return );
806
+ $return = html_entity_decode( $return, ENT_QUOTES, get_option( 'blog_charset' ) );
807
+
808
+ // remove non alphanumeric chars
809
+ //$return = preg_replace( '/[^a-zA-Z0-9 \-_]*/', '', $return );
810
+ $return = preg_replace( '/[\x00-\x1F\x7F]*/u', '', $return );
811
+
812
+ // Reserved Characters.
813
+ // * ' ( ) ; : @ & = + $ , / ? # [ ]
814
+ $return = str_replace(
815
+ array( '*', '\'', '(', ')', ';', '@', '&', '=', '+', '$', ',', '/', '?', '#', '[', ']' ),
816
+ '',
817
+ $return
818
+ );
819
+
820
+ // Unsafe Characters.
821
+ // % { } | \ ^ ~ [ ] `
822
+ $return = str_replace(
823
+ array( '%', '{', '}', '|', '\\', '^', '~', '[', ']', '`' ),
824
+ '',
825
+ $return
826
+ );
827
+
828
+ // Special Characters.
829
+ // $ - _ . + ! * ' ( ) ,
830
+ $return = str_replace(
831
+ array( '$', '.', '+', '!', '*', '\'', '(', ')', ',' ),
832
+ '',
833
+ $return
834
+ );
835
+
836
+ // Dashes
837
+ // Special Characters.
838
+ // - (minus) - (dash) – (en dash) — (em dash)
839
+ $return = str_replace(
840
+ array( '-', '-', '–', '—' ),
841
+ '-',
842
+ $return
843
+ );
844
+
845
+ // Curley quotes.
846
+ // ‘ (curly single open quote) ’ (curly single close quote) “ (curly double open quote) ” (curly double close quote)
847
+ $return = str_replace(
848
+ array( '‘', '’', '“', '”' ),
849
+ '',
850
+ $return
851
+ );
852
+
853
+ // AMP/Caching plugins seems to break URL with the following characters, so lets replace them.
854
+ $return = str_replace( array( ':' ), '_', $return );
855
+
856
+ // Convert space characters to an `_` (underscore).
857
+ $return = preg_replace( '/\s+/', '_', $return );
858
+
859
+ // Replace multiple `-` (hyphen) with a single `-` (hyphen).
860
+ $return = preg_replace( '/-+/', '-', $return );
861
+
862
+ // Replace multiple `_` (underscore) with a single `_` (underscore).
863
+ $return = preg_replace( '/_+/', '_', $return );
864
+
865
+ // Remove trailing `-` (hyphen) and `_` (underscore).
866
+ $return = rtrim( $return, '-_' );
867
+
868
+ /*
869
+ * Encode URI based on ECMA-262.
870
+ *
871
+ * Only required to support the jQuery smoothScroll library.
872
+ *
873
+ * @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI#Description
874
+ * @link https://stackoverflow.com/a/19858404/5351316
875
+ */
876
+ $return = preg_replace_callback(
877
+ "{[^0-9a-z_.!~*'();,/?:@&=+$#-]}i",
878
+ function( $m ) {
879
+
880
+ return sprintf( '%%%02X', ord( $m[0] ) );
881
+ },
882
+ $return
883
+ );
884
+
885
+ // lowercase everything?
886
+ if ( ezTOC_Option::get( 'lowercase' ) ) {
887
+
888
+ $return = strtolower( $return );
889
+ }
890
+
891
+ // if blank, then prepend with the fragment prefix
892
+ // blank anchors normally appear on sites that don't use the latin charset
893
+ if ( ! $return ) {
894
+
895
+ $return = ( ezTOC_Option::get( 'fragment_prefix' ) ) ? ezTOC_Option::get( 'fragment_prefix' ) : '_';
896
+ }
897
+
898
+ // hyphenate?
899
+ if ( ezTOC_Option::get( 'hyphenate' ) ) {
900
+
901
+ $return = str_replace( '_', '-', $return );
902
+ $return = preg_replace( '/-+/', '-', $return );
903
+ }
904
+ }
905
+
906
+ if ( array_key_exists( $return, $this->collision_collector ) ) {
907
+
908
+ $this->collision_collector[ $return ]++;
909
+ $return .= '-' . $this->collision_collector[ $return ];
910
+
911
+ } else {
912
+
913
+ $this->collision_collector[ $return ] = 1;
914
+ }
915
+
916
+ return apply_filters( 'ez_toc_url_anchor_target', $return, $heading );
917
+ }
918
+
919
+ /**
920
+ * Remove any empty headings from the TOC.
921
+ *
922
+ * @access private
923
+ * @since 2.0
924
+ *
925
+ * @param array $matches The heading from the post content extracted with preg_match_all().
926
+ *
927
+ * @return array
928
+ */
929
+ private function removeEmptyHeadings( &$matches ) {
930
+
931
+ $new_matches = array();
932
+ //$count = count( $matches );
933
+
934
+ //for ( $i = 0; $i < $count; $i ++ ) {
935
+ foreach ( $matches as $i => $match ) {
936
+
937
+ if ( trim( strip_tags( $matches[ $i ][0] ) ) != false ) {
938
+
939
+ $new_matches[ $i ] = $matches[ $i ];
940
+ }
941
+ }
942
+
943
+ //if ( count( $matches ) != count( $new_matches ) ) {
944
+
945
+ $matches = $new_matches;
946
+ //}
947
+
948
+ return $matches;
949
+ }
950
+
951
+ /**
952
+ * Whether or not the post has TOC items.
953
+ *
954
+ * @see ezTOC_Post::extractHeadings()
955
+ *
956
+ * @access public
957
+ * @since 2.0
958
+ *
959
+ * @return bool
960
+ */
961
+ public function hasTOCItems() {
962
+
963
+ return $this->hasTOCItems;
964
+ }
965
+
966
+ /**
967
+ * Get the headings of the current page of the post.
968
+ *
969
+ * @access public
970
+ * @since 2.0
971
+ *
972
+ * @param int|null $page
973
+ *
974
+ * @return array
975
+ */
976
+ public function getHeadings( $page = null ) {
977
+
978
+ $headings = array();
979
+
980
+ if ( is_null( $page ) ) {
981
+
982
+ $page = $this->getCurrentPage();
983
+ }
984
+
985
+ if ( isset( $this->pages[ $page ] ) ) {
986
+
987
+ //$headings = wp_list_pluck( $this->pages[ $page ]['headings'], 0 );
988
+
989
+ $matches = $this->pages[ $page ]['headings'];
990
+ //$count = count( $matches );
991
+
992
+ //for ( $i = 0; $i < $count; $i++ ) {
993
+ foreach ( $matches as $i => $match ) {
994
+
995
+ //$anchor = $matches[ $i ]['id'];
996
+ $headings[] = str_replace(
997
+ array(
998
+ $matches[ $i ][1], // start of heading
999
+ '</h' . $matches[ $i ][2] . '>' // end of heading
1000
+ ),
1001
+ array(
1002
+ '>',
1003
+ '</h' . $matches[ $i ][2] . '>'
1004
+ ),
1005
+ $matches[ $i ][0]
1006
+ );
1007
+ }
1008
+ }
1009
+
1010
+ return $headings;
1011
+ }
1012
+
1013
+ /**
1014
+ * Get the heading with in page anchors of the current page of the post.
1015
+ *
1016
+ * @access public
1017
+ * @since 2.0
1018
+ *
1019
+ * @param int|null $page
1020
+ *
1021
+ * @return array
1022
+ */
1023
+ public function getHeadingsWithAnchors( $page = null ) {
1024
+
1025
+ $headings = array();
1026
+
1027
+ if ( is_null( $page ) ) {
1028
+
1029
+ $page = $this->getCurrentPage();
1030
+ }
1031
+
1032
+ if ( isset( $this->pages[ $page ] ) ) {
1033
+
1034
+ $matches = $this->pages[ $page ]['headings'];
1035
+ //$count = count( $matches );
1036
+
1037
+ //for ( $i = 0; $i < $count; $i++ ) {
1038
+ foreach ( $matches as $i => $match ) {
1039
+
1040
+ $anchor = $matches[ $i ]['id'];
1041
+ $headings[] = str_replace(
1042
+ array(
1043
+ $matches[ $i ][1], // start of heading
1044
+ '</h' . $matches[ $i ][2] . '>' // end of heading
1045
+ ),
1046
+ array(
1047
+ '><span class="ez-toc-section" id="' . $anchor . '"></span>',
1048
+ '<span class="ez-toc-section-end"></span></h' . $matches[ $i ][2] . '>'
1049
+ ),
1050
+ $matches[ $i ][0]
1051
+ );
1052
+ }
1053
+ }
1054
+
1055
+ return $headings;
1056
+ }
1057
+
1058
+ /**
1059
+ * Get the post TOC list.
1060
+ *
1061
+ * @access public
1062
+ * @since 2.0
1063
+ *
1064
+ * @return string
1065
+ */
1066
+ public function getTOCList() {
1067
+
1068
+ $html = '';
1069
+
1070
+ if ( $this->hasTOCItems ) {
1071
+
1072
+ foreach ( $this->pages as $page => $attribute ) {
1073
+
1074
+ $html .= $this->createTOC( $page, $attribute['headings'] );
1075
+ }
1076
+
1077
+ $html = '<ul class="ez-toc-list ez-toc-list-level-1">' . $html . '</ul>';
1078
+ }
1079
+
1080
+ return $html;
1081
+ }
1082
+
1083
+ /**
1084
+ * Get the post TOC content block.
1085
+ *
1086
+ * @access public
1087
+ * @since 2.0
1088
+ *
1089
+ * @return string
1090
+ */
1091
+ public function getTOC() {
1092
+
1093
+ $class = array( 'ez-toc-v' . str_replace( '.', '_', ezTOC::VERSION ) );
1094
+ $html = '';
1095
+
1096
+ if ( $this->hasTOCItems() ) {
1097
+
1098
+ // wrapping css classes
1099
+ switch ( ezTOC_Option::get( 'wrapping' ) ) {
1100
+
1101
+ case 'left':
1102
+ $class[] = 'ez-toc-wrap-left';
1103
+ break;
1104
+
1105
+ case 'right':
1106
+ $class[] = 'ez-toc-wrap-right';
1107
+ break;
1108
+ case 'center':
1109
+ $class[] = 'ez-toc-wrap-center';
1110
+ break;
1111
+
1112
+ case 'none':
1113
+ default:
1114
+ // do nothing
1115
+ }
1116
+
1117
+ if ( ezTOC_Option::get( 'show_hierarchy' ) ) {
1118
+
1119
+ $class[] = 'counter-hierarchy';
1120
+
1121
+ } else {
1122
+
1123
+ $class[] .= 'counter-flat';
1124
+ }
1125
+
1126
+ switch ( ezTOC_Option::get( 'counter' ) ) {
1127
+
1128
+ case 'numeric':
1129
+ $class[] .= 'counter-numeric';
1130
+ break;
1131
+
1132
+ case 'roman':
1133
+ $class[] = 'counter-roman';
1134
+ break;
1135
+
1136
+ case 'decimal':
1137
+ $class[] = 'counter-decimal';
1138
+ break;
1139
+
1140
+ case 'hyphen':
1141
+ $class[] = 'counter-hyphen';
1142
+ break;
1143
+
1144
+ case 'disc':
1145
+ $class[] = 'counter-disc';
1146
+ break;
1147
+ }
1148
+
1149
+ // colour themes
1150
+ switch ( ezTOC_Option::get( 'theme' ) ) {
1151
+
1152
+ case 'light-blue':
1153
+ $class[] = 'ez-toc-light-blue';
1154
+ break;
1155
+
1156
+ case 'white':
1157
+ $class[] = 'ez-toc-white';
1158
+ break;
1159
+
1160
+ case 'black':
1161
+ $class[] = 'ez-toc-black';
1162
+ break;
1163
+
1164
+ case 'transparent':
1165
+ $class[] .= 'ez-toc-transparent';
1166
+ break;
1167
+
1168
+ case 'grey':
1169
+ $class[] = 'ez-toc-grey';
1170
+ break;
1171
+ }
1172
+
1173
+ $custom_classes = ezTOC_Option::get( 'css_container_class', '' );
1174
+
1175
+ if ( 0 < strlen( $custom_classes ) ) {
1176
+
1177
+ $custom_classes = explode( ' ', $custom_classes );
1178
+ $custom_classes = apply_filters( 'ez_toc_container_class', $custom_classes, $this );
1179
+
1180
+ if ( is_array( $custom_classes ) ) {
1181
+
1182
+ $class = array_merge( $class, $custom_classes );
1183
+ }
1184
+ }
1185
+
1186
+ $class = array_filter( $class );
1187
+ $class = array_map( 'trim', $class );
1188
+ $class = array_map( 'sanitize_html_class', $class );
1189
+
1190
+ $html .= '<div id="ez-toc-container" class="' . implode( ' ', $class ) . '">' . PHP_EOL;
1191
+
1192
+ if ( ezTOC_Option::get( 'show_heading_text' ) ) {
1193
+
1194
+ $toc_title = ezTOC_Option::get( 'heading_text' );
1195
+
1196
+ if ( strpos( $toc_title, '%PAGE_TITLE%' ) !== false ) {
1197
+
1198
+ $toc_title = str_replace( '%PAGE_TITLE%', get_the_title(), $toc_title );
1199
+ }
1200
+
1201
+ if ( strpos( $toc_title, '%PAGE_NAME%' ) !== false ) {
1202
+
1203
+ $toc_title = str_replace( '%PAGE_NAME%', get_the_title(), $toc_title );
1204
+ }
1205
+
1206
+ if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
1207
+ $html .= '<div class="ez-toc-title-container">' . PHP_EOL;
1208
+ }
1209
+
1210
+ $html .= '<p class="ez-toc-title">' . esc_html__( htmlentities( $toc_title, ENT_COMPAT, 'UTF-8' ), 'easy-table-of-contents' ). '</p>' . PHP_EOL;
1211
+
1212
+ if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
1213
+ $html .= '<span class="ez-toc-title-toggle">';
1214
+ }
1215
+
1216
+ if ( ezTOC_Option::get( 'visibility' ) ) {
1217
+ if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
1218
+ $html .= '<a class="ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle" style="display: none;"><label for="item" aria-label="'.__( 'Table of Content', 'easy-table-of-contents' ).'"><i class="ez-toc-glyphicon ez-toc-icon-toggle"></i></label><input type="checkbox" id="item"></a>';
1219
+ }else{
1220
+ $toggle_view='';
1221
+ if(ezTOC_Option::get('visibility_hide_by_default')==true){
1222
+ $toggle_view= "checked";
1223
+ }
1224
+ $html .= '<label for="item"><i class="ez-toc-glyphicon ez-toc-icon-toggle"></i></label><input type="checkbox" id="item" '.$toggle_view.'>';
1225
+ }
1226
+ }
1227
+
1228
+ if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
1229
+ $html .= '</span>';
1230
+ }
1231
+ if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
1232
+ $html .= '</div>' . PHP_EOL;
1233
+ }
1234
+ }else{
1235
+ $html .= '<div class="ez-toc-title-container">' . PHP_EOL;
1236
+ $html .= '<span class="ez-toc-title-toggle">';
1237
+ $html .= '<a class="ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle" style="display: none;"><i class="ez-toc-glyphicon ez-toc-icon-toggle"></i></a>';
1238
+ $html .= '</span>';
1239
+ $html .= '</div>' . PHP_EOL;
1240
+ }
1241
+
1242
+ ob_start();
1243
+ do_action( 'ez_toc_before' );
1244
+ $html .= ob_get_clean();
1245
+
1246
+ $html .= '<nav>' . $this->getTOCList() . '</nav>';
1247
+
1248
+ ob_start();
1249
+ do_action( 'ez_toc_after' );
1250
+ $html .= ob_get_clean();
1251
+
1252
+ $html .= '</div>' . PHP_EOL;
1253
+
1254
+ // Enqueue the script.
1255
+ wp_enqueue_script( 'ez-toc-js' );
1256
+ }
1257
+
1258
+ return $html;
1259
+ }
1260
+
1261
+ /**
1262
+ * Displays the post's TOC.
1263
+ *
1264
+ * @access public
1265
+ * @since 2.0
1266
+ */
1267
+ public function toc() {
1268
+
1269
+ echo $this->getTOC();
1270
+ }
1271
+
1272
+ /**
1273
+ * Generate the TOC list items for a given page within a post.
1274
+ *
1275
+ * @access private
1276
+ * @since 2.0
1277
+ *
1278
+ * @param int $page The page of the post to create the TOC items for.
1279
+ * @param array $matches The heading from the post content extracted with preg_match_all().
1280
+ *
1281
+ * @return string The HTML list of TOC items.
1282
+ */
1283
+ private function createTOC( $page, $matches ) {
1284
+
1285
+ // Whether or not the TOC should be built flat or hierarchical.
1286
+ $hierarchical = ezTOC_Option::get( 'show_hierarchy' );
1287
+ $html = '';
1288
+
1289
+ if ( $hierarchical ) {
1290
+
1291
+ $current_depth = 100; // headings can't be larger than h6 but 100 as a default to be sure
1292
+ $numbered_items = array();
1293
+ $numbered_items_min = null;
1294
+
1295
+ // reset the internal collision collection
1296
+ /** @todo does this need to be used??? */
1297
+ //self::$collision_collector = array();
1298
+
1299
+ // find the minimum heading to establish our baseline
1300
+ //for ( $i = 0; $i < count( $matches ); $i ++ ) {
1301
+ foreach ( $matches as $i => $match ) {
1302
+ if ( $current_depth > $matches[ $i ][2] ) {
1303
+ $current_depth = (int) $matches[ $i ][2];
1304
+ }
1305
+ }
1306
+
1307
+ $numbered_items[ $current_depth ] = 0;
1308
+ $numbered_items_min = $current_depth;
1309
+
1310
+ //for ( $i = 0; $i < count( $matches ); $i ++ ) {
1311
+ foreach ( $matches as $i => $match ) {
1312
+
1313
+ $level = $matches[ $i ][2];
1314
+ $count = $i + 1;
1315
+
1316
+ if ( $current_depth == (int) $matches[ $i ][2] ) {
1317
+
1318
+ $html .= '<li class="ez-toc-page-' . $page . ' ez-toc-heading-level-' . $current_depth . '">';
1319
+ }
1320
+
1321
+ // start lists
1322
+ if ( $current_depth != (int) $matches[ $i ][2] ) {
1323
+
1324
+ for ( $current_depth; $current_depth < (int) $matches[ $i ][2]; $current_depth++ ) {
1325
+
1326
+ $numbered_items[ $current_depth + 1 ] = 0;
1327
+ $html .= '<ul class="ez-toc-list-level-' . $level . '"><li class="ez-toc-heading-level-' . $level . '">';
1328
+ }
1329
+ }
1330
+
1331
+ $title = isset( $matches[ $i ]['alternate'] ) ? $matches[ $i ]['alternate'] : $matches[ $i ][0];
1332
+ $title = br2( $title, ' ' );
1333
+ $title = strip_tags( apply_filters( 'ez_toc_title', $title ), apply_filters( 'ez_toc_title_allowable_tags', '' ) );
1334
+
1335
+ $html .= $this->createTOCItemAnchor( $page, $matches[ $i ]['id'], $title, $count );
1336
+
1337
+ // end lists
1338
+ if ( $i != count( $matches ) - 1 ) {
1339
+
1340
+ if ( $current_depth > (int) $matches[ $i + 1 ][2] ) {
1341
+
1342
+ for ( $current_depth; $current_depth > (int) $matches[ $i + 1 ][2]; $current_depth-- ) {
1343
+
1344
+ $html .= '</li></ul>';
1345
+ $numbered_items[ $current_depth ] = 0;
1346
+ }
1347
+ }
1348
+
1349
+ if ( $current_depth == (int) @$matches[ $i + 1 ][2] ) {
1350
+
1351
+ $html .= '</li>';
1352
+ }
1353
+
1354
+ } else {
1355
+
1356
+ // this is the last item, make sure we close off all tags
1357
+ for ( $current_depth; $current_depth >= $numbered_items_min; $current_depth-- ) {
1358
+
1359
+ $html .= '</li>';
1360
+
1361
+ if ( $current_depth != $numbered_items_min ) {
1362
+ $html .= '</ul>';
1363
+ }
1364
+ }
1365
+ }
1366
+ }
1367
+
1368
+ } else {
1369
+
1370
+ //for ( $i = 0; $i < count( $matches ); $i++ ) {
1371
+ foreach ( $matches as $i => $match ) {
1372
+
1373
+ $count = $i + 1;
1374
+
1375
+ $title = isset( $matches[ $i ]['alternate'] ) ? $matches[ $i ]['alternate'] : $matches[ $i ][0];
1376
+ $title = strip_tags( apply_filters( 'ez_toc_title', $title ), apply_filters( 'ez_toc_title_allowable_tags', '' ) );
1377
+
1378
+ $html .= '<li class="ez-toc-page-' . $page . '">';
1379
+
1380
+ $html .= $this->createTOCItemAnchor( $page, $matches[ $i ]['id'], $title, $count );
1381
+
1382
+ $html .= '</li>';
1383
+ }
1384
+ }
1385
+
1386
+ return do_shortcode($html);
1387
+ }
1388
+
1389
+ /**
1390
+ * @access private
1391
+ * @since 2.0
1392
+ *
1393
+ * @param int $page
1394
+ * @param string $id
1395
+ * @param string $title
1396
+ * @param int $count
1397
+ *
1398
+ * @return string
1399
+ */
1400
+ private function createTOCItemAnchor( $page, $id, $title, $count ) {
1401
+
1402
+ return sprintf(
1403
+ '<a class="ez-toc-link ez-toc-heading-' . $count . '" href="%1$s" title="%2$s">%3$s</a>',
1404
+ esc_attr( $this->createTOCItemURL( $id, $page ) ),
1405
+ esc_attr( strip_tags( $title ) ),
1406
+ $title
1407
+ );
1408
+ }
1409
+
1410
+ /**
1411
+ * @access private
1412
+ * @since 2.0
1413
+ *
1414
+ * @param string $id
1415
+ * @param int $page
1416
+ *
1417
+ * @return string
1418
+ */
1419
+ private function createTOCItemURL( $id, $page ) {
1420
+
1421
+ $current_post = $this->post->ID === $this->queriedObjectID;
1422
+ $current_page = $this->getCurrentPage();
1423
+
1424
+ if ( $page === $current_page && $current_post ) {
1425
+
1426
+ return '#' . $id;
1427
+
1428
+ } elseif ( 1 === $page ) {
1429
+
1430
+ return trailingslashit( $this->permalink ) . '#' . $id;
1431
+
1432
+ }
1433
+
1434
+ return trailingslashit( $this->permalink ) . $page . '/#' . $id;
1435
+ }
1436
+ }
 
 
 
 
includes/class.widget-toc.php CHANGED
@@ -1,379 +1,379 @@
1
- <?php
2
- // Exit if accessed directly
3
- if ( ! defined( 'ABSPATH' ) ) exit;
4
-
5
- if ( ! class_exists( 'ezTOC_Widget' ) ) {
6
-
7
- /**
8
- * Class ezTOC_Widget
9
- */
10
- class ezTOC_Widget extends WP_Widget {
11
-
12
- /**
13
- * Setup and register the table of contents widget.
14
- *
15
- * @access public
16
- * @since 1.0
17
- */
18
- public function __construct() {
19
-
20
- $options = array(
21
- 'classname' => 'ez-toc',
22
- 'description' => __( 'Display the table of contents.', 'easy-table-of-contents' )
23
- );
24
-
25
- parent::__construct(
26
- 'ezw_tco',
27
- __( 'Table of Contents', 'easy-table-of-contents' ),
28
- $options
29
- );
30
-
31
- add_action( 'admin_enqueue_scripts', array( $this, 'enqueueScripts' ) );
32
- add_action( 'admin_footer-widgets.php', array( $this, 'printScripts' ), 9999 );
33
- }
34
-
35
- /**
36
- * Callback which registers the widget with the Widget API.
37
- *
38
- * @access public
39
- * @since 1.0
40
- * @static
41
- *
42
- * @return void
43
- */
44
- public static function register() {
45
-
46
- register_widget( __CLASS__ );
47
- }
48
-
49
- /**
50
- * Callback to enqueue scripts on the Widgets admin page.
51
- *
52
- * @access private
53
- * @since 1.0
54
- *
55
- * @param string $hook_suffix
56
- */
57
- public function enqueueScripts( $hook_suffix ) {
58
-
59
- if ( 'widgets.php' !== $hook_suffix ) {
60
- return;
61
- }
62
-
63
- wp_enqueue_style( 'wp-color-picker' );
64
- wp_enqueue_script( 'wp-color-picker' );
65
- wp_enqueue_script( 'underscore' );
66
- }
67
-
68
- /**
69
- * Callback to print the scripts to the Widgets admin page footer.
70
- *
71
- * @access private
72
- * @since 1.0
73
- */
74
- public function printScripts() {
75
- ?>
76
- <script>
77
- ( function( $ ){
78
- function initColorPicker( widget ) {
79
- widget.find( '.color-picker' ).wpColorPicker( {
80
- change: _.throttle( function() { // For Customizer
81
- $(this).trigger( 'change' );
82
- }, 3000 )
83
- });
84
- }
85
-
86
- function onFormUpdate( event, widget ) {
87
- initColorPicker( widget );
88
- }
89
-
90
- $( document ).on( 'widget-added widget-updated', onFormUpdate );
91
-
92
- $( document ).ready( function() {
93
- $( '#widgets-right .widget:has(.color-picker)' ).each( function () {
94
- initColorPicker( $( this ) );
95
- } );
96
- } );
97
- }( jQuery ) );
98
- </script>
99
- <?php
100
- }
101
-
102
- /**
103
- * Display the post content. Optionally allows post ID to be passed
104
- *
105
- * @link http://stephenharris.info/get-post-content-by-id/
106
- * @link http://wordpress.stackexchange.com/a/143316
107
- *
108
- * @access public
109
- * @since 1.0
110
- *
111
- * @param int $post_id Optional. Post ID.
112
- *
113
- * @return string
114
- */
115
- public function the_content( $post_id = 0 ) {
116
-
117
- global $post;
118
- $post = get_post( $post_id );
119
- setup_postdata( $post );
120
- ob_start();
121
- the_content();
122
- $content = ob_get_clean();
123
- wp_reset_postdata();
124
-
125
- return $content;
126
- }
127
-
128
- /**
129
- * Renders the widgets.
130
- *
131
- * @access private
132
- * @since 1.0
133
- *
134
- * @param array $args
135
- * @param array $instance
136
- */
137
- public function widget( $args, $instance ) {
138
-
139
- if ( is_404() || is_archive() || is_search() || ( ! is_front_page() && is_home() ) ) return;
140
-
141
- //global $wp_query;
142
-
143
- //$find = $replace = array();
144
- //$post = get_post( $wp_query->post->ID );
145
- //$post = ezTOC_Post::get( get_the_ID() );//->applyContentFilter()->process();
146
- $post = ezTOC::get( get_the_ID() );
147
-
148
- /**
149
- * @link https://wordpress.org/support/topic/fatal-error-when-trying-to-access-widget-area/
150
- */
151
- if ( ! $post instanceof ezTOC_Post ) return;
152
-
153
- /*
154
- * Ensure the ezTOC content filter is not applied when running `the_content` filter.
155
- */
156
- //remove_filter( 'the_content', array( 'ezTOC', 'the_content' ), 100 );
157
- //$post->post_content = apply_filters( 'the_content', $post->post_content );
158
- //add_filter( 'the_content', array( 'ezTOC', 'the_content' ), 100 );
159
-
160
- if ( $post->hasTOCItems() ) {
161
-
162
- /**
163
- * @var string $before_widget
164
- * @var string $after_widget
165
- * @var string $before_title
166
- * @var string $after_title
167
- */
168
- extract( $args );
169
-
170
- $class = array(
171
- 'ez-toc-v' . str_replace( '.', '_', ezTOC::VERSION ),
172
- 'ez-toc-widget',
173
- );
174
-
175
- $title = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );
176
- //$items = ezTOC::extract_headings( $find, $replace, $post );
177
-
178
- if ( false !== strpos( $title, '%PAGE_TITLE%' ) || false !== strpos( $title, '%PAGE_NAME%' ) ) {
179
-
180
- $title = str_replace( '%PAGE_TITLE%', get_the_title(), $title );
181
- }
182
-
183
- if ( ezTOC_Option::get( 'show_hierarchy' ) ) {
184
-
185
- $class[] = 'counter-hierarchy';
186
-
187
- } else {
188
-
189
- $class[] = 'counter-flat';
190
- }
191
-
192
- switch ( ezTOC_Option::get( 'counter' ) ) {
193
-
194
- case 'numeric':
195
- $class[] = 'counter-numeric';
196
- break;
197
-
198
- case 'roman':
199
- $class[] = 'counter-roman';
200
- break;
201
-
202
- case 'decimal':
203
- $class[] = 'counter-decimal';
204
- break;
205
-
206
- case 'hyphen':
207
- $class[] = 'counter-hyphen';
208
- break;
209
-
210
- case 'disc':
211
- $class[] = 'counter-disc';
212
- break;
213
-
214
- }
215
-
216
- if ( $instance['affix'] ) {
217
-
218
- $class[] = 'ez-toc-affix';
219
- }
220
-
221
- $custom_classes = ezTOC_Option::get( 'css_container_class', '' );
222
-
223
- if ( 0 < strlen( $custom_classes ) ) {
224
-
225
- $custom_classes = explode( ' ', $custom_classes );
226
- $custom_classes = apply_filters( 'ez_toc_container_class', $custom_classes, $this );
227
-
228
- if ( is_array( $custom_classes ) ) {
229
-
230
- $class = array_merge( $class, $custom_classes );
231
- }
232
- }
233
-
234
- $class = array_filter( $class );
235
- $class = array_map( 'trim', $class );
236
- $class = array_map( 'sanitize_html_class', $class );
237
-
238
- echo $before_widget;
239
-
240
- echo '<div class="ez-toc-widget-container ' . implode( ' ', $class ) . '">' . PHP_EOL;
241
-
242
- do_action( 'ez_toc_before_widget' );
243
-
244
- /**
245
- * @todo Instead of inline style, use the shadow DOM.
246
- * @link https://css-tricks.com/playing-shadow-dom/
247
- *
248
- * @todo Consider not outputting the style if CSS is disabled.
249
- * @link https://wordpress.org/support/topic/inline-styling-triggers-html-validation-error/
250
- */
251
-
252
- if ( 0 < strlen( $title ) ) {
253
-
254
- ?>
255
-
256
- <?php echo $before_title; ?>
257
-
258
- <span class="ez-toc-title-container">
259
-
260
- <style type="text/css">
261
- #<?php echo $this->id ?> .ez-toc-widget-container ul.ez-toc-list li.active::before {
262
- background-color: <?php echo esc_attr( $instance['highlight_color'] ); ?>;
263
- }
264
- </style>
265
-
266
- <span class="ez-toc-title"><?php echo $title; ?></span>
267
-
268
- <span class="ez-toc-title-toggle">
269
-
270
- <?php
271
- if ( ezTOC_Option::get( 'visibility' ) ) {
272
-
273
- echo '<a class="ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle"><i class="ez-toc-glyphicon ez-toc-icon-toggle"></i></a>';
274
- }
275
- ?>
276
-
277
- </span>
278
-
279
- </span>
280
-
281
- <?php echo $after_title; ?>
282
-
283
- <?php
284
- }
285
- do_action( 'ez_toc_before' );
286
- echo '<nav>'. PHP_EOL . $post->getTOCList() . '</nav>' . PHP_EOL;
287
- do_action( 'ez_toc_after' );
288
- do_action( 'ez_toc_after_widget' );
289
-
290
- echo '</div>' . PHP_EOL;
291
-
292
- echo $after_widget;
293
-
294
- // Enqueue the script.
295
- wp_enqueue_script( 'ez-toc-js' );
296
- }
297
- }
298
-
299
- /**
300
- * Update the widget settings.
301
- *
302
- * @access private
303
- * @since 1.0
304
- *
305
- * @param array $new_instance
306
- * @param array $old_instance
307
- *
308
- * @return array
309
- */
310
- public function update( $new_instance, $old_instance ) {
311
-
312
- $instance = $old_instance;
313
-
314
- $instance['title'] = strip_tags( $new_instance['title'] );
315
-
316
- $instance['affix'] = array_key_exists( 'affix', $new_instance ) ? $new_instance['affix'] : '0';
317
-
318
- $instance['highlight_color'] = strip_tags( $new_instance['highlight_color'] );
319
-
320
- $instance['hide_inline'] = array_key_exists( 'hide_inline', $new_instance ) ? $new_instance['hide_inline'] : '0';
321
-
322
- //ezTOC_Option::set( 'show_toc_in_widget_only', $instance['hide_inline'] );
323
- //ezTOC_Option::set( 'show_toc_in_widget_only_post_types', $new_instance['show_toc_in_widget_only_post_types'] );
324
-
325
- return $instance;
326
- }
327
-
328
- /**
329
- * Displays the widget settings on the Widgets admin page.
330
- *
331
- * @access private
332
- * @since 1.0
333
- *
334
- * @param array $instance
335
- *
336
- * @return string|void
337
- */
338
- public function form( $instance ) {
339
-
340
- $defaults = array(
341
- 'affix' => '0',
342
- 'highlight_color' => '#ededed',
343
- 'title' => '',
344
- );
345
-
346
- $instance = wp_parse_args( (array) $instance, $defaults );
347
-
348
- $highlight_color = esc_attr( $instance[ 'highlight_color' ] );
349
-
350
- ?>
351
- <p>
352
- <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title', 'easy-table-of-contents' ); ?>:</label>
353
- <input type="text" id="<?php echo $this->get_field_id( 'title' ); ?>"
354
- name="<?php echo $this->get_field_name( 'title' ); ?>" value="<?php echo $instance['title']; ?>"
355
- style="width:100%;"/>
356
- </p>
357
-
358
- <p>
359
- <label for="<?php echo $this->get_field_id( 'highlight_color' ); ?>"><?php _e( 'Active Section Highlight Color:', 'easy-table-of-contents' ); ?></label><br>
360
- <input type="text" name="<?php echo $this->get_field_name( 'highlight_color' ); ?>" class="color-picker" id="<?php echo $this->get_field_id( 'highlight_color' ); ?>" value="<?php echo $highlight_color; ?>" data-default-color="<?php echo $defaults['highlight_color']; ?>" />
361
- </p>
362
-
363
- <p style="display: <?php echo ezTOC_Option::get( 'widget_affix_selector' ) ? 'block' : 'none'; ?>;">
364
- <input class="checkbox" type="checkbox" <?php checked( $instance['affix'], 1 ); ?>
365
- id="<?php echo $this->get_field_id( 'affix' ); ?>"
366
- name="<?php echo $this->get_field_name( 'affix' ); ?>" value="1"/>
367
- <label for="<?php echo $this->get_field_id( 'affix' ); ?>"> <?php _e( 'Affix or pin the widget.', 'easy-table-of-contents' ); ?></label>
368
- </p>
369
-
370
- <p class="description" style="display: <?php echo ezTOC_Option::get( 'widget_affix_selector' ) ? 'block' : 'none'; ?>;">
371
- <?php _e( 'If you choose to affix the widget, do not add any other widgets on the sidebar. Also, make sure you have only one instance Table of Contents widget on the page.', 'easy-table-of-contents' ); ?>
372
- </p>
373
- <?php
374
- }
375
-
376
- } // end class
377
-
378
- add_action( 'widgets_init', array( 'ezTOC_Widget', 'register' ) );
379
- }
1
+ <?php
2
+ // Exit if accessed directly
3
+ if ( ! defined( 'ABSPATH' ) ) exit;
4
+
5
+ if ( ! class_exists( 'ezTOC_Widget' ) ) {
6
+
7
+ /**
8
+ * Class ezTOC_Widget
9
+ */
10
+ class ezTOC_Widget extends WP_Widget {
11
+
12
+ /**
13
+ * Setup and register the table of contents widget.
14
+ *
15
+ * @access public
16
+ * @since 1.0
17
+ */
18
+ public function __construct() {
19
+
20
+ $options = array(
21
+ 'classname' => 'ez-toc',
22
+ 'description' => __( 'Display the table of contents.', 'easy-table-of-contents' )
23
+ );
24
+
25
+ parent::__construct(
26
+ 'ezw_tco',
27
+ __( 'Table of Contents', 'easy-table-of-contents' ),
28
+ $options
29
+ );
30
+
31
+ add_action( 'admin_enqueue_scripts', array( $this, 'enqueueScripts' ) );
32
+ add_action( 'admin_footer-widgets.php', array( $this, 'printScripts' ), 9999 );
33
+ }
34
+
35
+ /**
36
+ * Callback which registers the widget with the Widget API.
37
+ *
38
+ * @access public
39
+ * @since 1.0
40
+ * @static
41
+ *
42
+ * @return void
43
+ */
44
+ public static function register() {
45
+
46
+ register_widget( __CLASS__ );
47
+ }
48
+
49
+ /**
50
+ * Callback to enqueue scripts on the Widgets admin page.
51
+ *
52
+ * @access private
53
+ * @since 1.0
54
+ *
55
+ * @param string $hook_suffix
56
+ */
57
+ public function enqueueScripts( $hook_suffix ) {
58
+
59
+ if ( 'widgets.php' !== $hook_suffix ) {
60
+ return;
61
+ }
62
+
63
+ wp_enqueue_style( 'wp-color-picker' );
64
+ wp_enqueue_script( 'wp-color-picker' );
65
+ wp_enqueue_script( 'underscore' );
66
+ }
67
+
68
+ /**
69
+ * Callback to print the scripts to the Widgets admin page footer.
70
+ *
71
+ * @access private
72
+ * @since 1.0
73
+ */
74
+ public function printScripts() {
75
+ ?>
76
+ <script>
77
+ ( function( $ ){
78
+ function initColorPicker( widget ) {
79
+ widget.find( '.color-picker' ).wpColorPicker( {
80
+ change: _.throttle( function() { // For Customizer
81
+ $(this).trigger( 'change' );
82
+ }, 3000 )
83
+ });
84
+ }
85
+
86
+ function onFormUpdate( event, widget ) {
87
+ initColorPicker( widget );
88
+ }
89
+
90
+ $( document ).on( 'widget-added widget-updated', onFormUpdate );
91
+
92
+ $( document ).ready( function() {
93
+ $( '#widgets-right .widget:has(.color-picker)' ).each( function () {
94
+ initColorPicker( $( this ) );
95
+ } );
96
+ } );
97
+ }( jQuery ) );
98
+ </script>
99
+ <?php
100
+ }
101
+
102
+ /**
103
+ * Display the post content. Optionally allows post ID to be passed
104
+ *
105
+ * @link http://stephenharris.info/get-post-content-by-id/
106
+ * @link http://wordpress.stackexchange.com/a/143316
107
+ *
108
+ * @access public
109
+ * @since 1.0
110
+ *
111
+ * @param int $post_id Optional. Post ID.
112
+ *
113
+ * @return string
114
+ */
115
+ public function the_content( $post_id = 0 ) {
116
+
117
+ global $post;
118
+ $post = get_post( $post_id );
119
+ setup_postdata( $post );
120
+ ob_start();
121
+ the_content();
122
+ $content = ob_get_clean();
123
+ wp_reset_postdata();
124
+
125
+ return $content;
126
+ }
127
+
128
+ /**
129
+ * Renders the widgets.
130
+ *
131
+ * @access private
132
+ * @since 1.0
133
+ *
134
+ * @param array $args
135
+ * @param array $instance
136
+ */
137
+ public function widget( $args, $instance ) {
138
+
139
+ if ( is_404() || is_archive() || is_search() || ( ! is_front_page() && is_home() ) ) return;
140
+
141
+ //global $wp_query;
142
+
143
+ //$find = $replace = array();
144
+ //$post = get_post( $wp_query->post->ID );
145
+ //$post = ezTOC_Post::get( get_the_ID() );//->applyContentFilter()->process();
146
+ $post = ezTOC::get( get_the_ID() );
147
+
148
+ /**
149
+ * @link https://wordpress.org/support/topic/fatal-error-when-trying-to-access-widget-area/
150
+ */
151
+ if ( ! $post instanceof ezTOC_Post ) return;
152
+
153
+ /*
154
+ * Ensure the ezTOC content filter is not applied when running `the_content` filter.
155
+ */
156
+ //remove_filter( 'the_content', array( 'ezTOC', 'the_content' ), 100 );
157
+ //$post->post_content = apply_filters( 'the_content', $post->post_content );
158
+ //add_filter( 'the_content', array( 'ezTOC', 'the_content' ), 100 );
159
+
160
+ if ( $post->hasTOCItems() ) {
161
+
162
+ /**
163
+ * @var string $before_widget
164
+ * @var string $after_widget
165
+ * @var string $before_title
166
+ * @var string $after_title
167
+ */
168
+ extract( $args );
169
+
170
+ $class = array(
171
+ 'ez-toc-v' . str_replace( '.', '_', ezTOC::VERSION ),
172
+ 'ez-toc-widget',
173
+ );
174
+
175
+ $title = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );
176
+ //$items = ezTOC::extract_headings( $find, $replace, $post );
177
+
178
+ if ( false !== strpos( $title, '%PAGE_TITLE%' ) || false !== strpos( $title, '%PAGE_NAME%' ) ) {
179
+
180
+ $title = str_replace( '%PAGE_TITLE%', get_the_title(), $title );
181
+ }
182
+
183
+ if ( ezTOC_Option::get( 'show_hierarchy' ) ) {
184
+
185
+ $class[] = 'counter-hierarchy';
186
+
187
+ } else {
188
+
189
+ $class[] = 'counter-flat';
190
+ }
191
+
192
+ switch ( ezTOC_Option::get( 'counter' ) ) {
193
+
194
+ case 'numeric':
195
+ $class[] = 'counter-numeric';
196
+ break;
197
+
198
+ case 'roman':
199
+ $class[] = 'counter-roman';
200
+ break;
201
+
202
+ case 'decimal':
203
+ $class[] = 'counter-decimal';
204
+ break;
205
+
206
+ case 'hyphen':
207
+ $class[] = 'counter-hyphen';
208
+ break;
209
+
210
+ case 'disc':
211
+ $class[] = 'counter-disc';
212
+ break;
213
+
214
+ }
215
+
216
+ if ( $instance['affix'] ) {
217
+
218
+ $class[] = 'ez-toc-affix';
219
+ }
220
+
221
+ $custom_classes = ezTOC_Option::get( 'css_container_class', '' );
222
+
223
+ if ( 0 < strlen( $custom_classes ) ) {
224
+
225
+ $custom_classes = explode( ' ', $custom_classes );
226
+ $custom_classes = apply_filters( 'ez_toc_container_class', $custom_classes, $this );
227
+
228
+ if ( is_array( $custom_classes ) ) {
229
+
230
+ $class = array_merge( $class, $custom_classes );
231
+ }
232
+ }
233
+
234
+ $class = array_filter( $class );
235
+ $class = array_map( 'trim', $class );
236
+ $class = array_map( 'sanitize_html_class', $class );
237
+
238
+ echo $before_widget;
239
+
240
+ echo '<div class="ez-toc-widget-container ' . implode( ' ', $class ) . '">' . PHP_EOL;
241
+
242
+ do_action( 'ez_toc_before_widget' );
243
+
244
+ /**
245
+ * @todo Instead of inline style, use the shadow DOM.
246
+ * @link https://css-tricks.com/playing-shadow-dom/
247
+ *
248
+ * @todo Consider not outputting the style if CSS is disabled.
249
+ * @link https://wordpress.org/support/topic/inline-styling-triggers-html-validation-error/
250
+ */
251
+
252
+ if ( 0 < strlen( $title ) ) {
253
+
254
+ ?>
255
+
256
+ <?php echo $before_title; ?>
257
+
258
+ <span class="ez-toc-title-container">
259
+
260
+ <style type="text/css">
261
+ #<?php echo $this->id ?> .ez-toc-widget-container ul.ez-toc-list li.active::before {
262
+ background-color: <?php echo esc_attr( $instance['highlight_color'] ); ?>;
263
+ }
264
+ </style>
265
+
266
+ <span class="ez-toc-title"><?php echo $title; ?></span>
267
+
268
+ <span class="ez-toc-title-toggle">
269
+
270
+ <?php
271
+ if ( ezTOC_Option::get( 'visibility' ) ) {
272
+
273
+ echo '<a class="ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle"><i class="ez-toc-glyphicon ez-toc-icon-toggle"></i></a>';
274
+ }
275
+ ?>
276
+
277
+ </span>
278
+
279
+ </span>
280
+
281
+ <?php echo $after_title; ?>
282
+
283
+ <?php
284
+ }
285
+ do_action( 'ez_toc_before' );
286
+ echo '<nav>'. PHP_EOL . $post->getTOCList() . '</nav>' . PHP_EOL;
287
+ do_action( 'ez_toc_after' );
288
+ do_action( 'ez_toc_after_widget' );
289
+
290
+ echo '</div>' . PHP_EOL;
291
+
292
+ echo $after_widget;
293
+
294
+ // Enqueue the script.
295
+ wp_enqueue_script( 'ez-toc-js' );
296
+ }
297
+ }
298
+
299
+ /**
300
+ * Update the widget settings.
301
+ *
302
+ * @access private
303
+ * @since 1.0
304
+ *
305
+ * @param array $new_instance
306
+ * @param array $old_instance
307
+ *
308
+ * @return array
309
+ */
310
+ public function update( $new_instance, $old_instance ) {
311
+
312
+ $instance = $old_instance;
313
+
314
+ $instance['title'] = strip_tags( $new_instance['title'] );
315
+
316
+ $instance['affix'] = array_key_exists( 'affix', $new_instance ) ? $new_instance['affix'] : '0';
317
+
318
+ $instance['highlight_color'] = strip_tags( $new_instance['highlight_color'] );
319
+
320
+ $instance['hide_inline'] = array_key_exists( 'hide_inline', $new_instance ) ? $new_instance['hide_inline'] : '0';
321
+
322
+ //ezTOC_Option::set( 'show_toc_in_widget_only', $instance['hide_inline'] );
323
+ //ezTOC_Option::set( 'show_toc_in_widget_only_post_types', $new_instance['show_toc_in_widget_only_post_types'] );
324
+
325
+ return $instance;
326
+ }
327
+
328
+ /**
329
+ * Displays the widget settings on the Widgets admin page.
330
+ *
331
+ * @access private
332
+ * @since 1.0
333
+ *
334
+ * @param array $instance
335
+ *
336
+ * @return string|void
337
+ */
338
+ public function form( $instance ) {
339
+
340
+ $defaults = array(
341
+ 'affix' => '0',
342
+ 'highlight_color' => '#ededed',
343
+ 'title' => '',
344
+ );
345
+
346
+ $instance = wp_parse_args( (array) $instance, $defaults );
347
+
348
+ $highlight_color = esc_attr( $instance[ 'highlight_color' ] );
349
+
350
+ ?>
351
+ <p>
352
+ <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title', 'easy-table-of-contents' ); ?>:</label>
353
+ <input type="text" id="<?php echo $this->get_field_id( 'title' ); ?>"
354
+ name="<?php echo $this->get_field_name( 'title' ); ?>" value="<?php echo $instance['title']; ?>"
355
+ style="width:100%;"/>
356
+ </p>
357
+
358
+ <p>
359
+ <label for="<?php echo $this->get_field_id( 'highlight_color' ); ?>"><?php _e( 'Active Section Highlight Color:', 'easy-table-of-contents' ); ?></label><br>
360
+ <input type="text" name="<?php echo $this->get_field_name( 'highlight_color' ); ?>" class="color-picker" id="<?php echo $this->get_field_id( 'highlight_color' ); ?>" value="<?php echo $highlight_color; ?>" data-default-color="<?php echo $defaults['highlight_color']; ?>" />
361
+ </p>
362
+
363
+ <p style="display: <?php echo ezTOC_Option::get( 'widget_affix_selector' ) ? 'block' : 'none'; ?>;">
364
+ <input class="checkbox" type="checkbox" <?php checked( $instance['affix'], 1 ); ?>
365
+ id="<?php echo $this->get_field_id( 'affix' ); ?>"
366
+ name="<?php echo $this->get_field_name( 'affix' ); ?>" value="1"/>
367
+ <label for="<?php echo $this->get_field_id( 'affix' ); ?>"> <?php _e( 'Affix or pin the widget.', 'easy-table-of-contents' ); ?></label>
368
+ </p>
369
+
370
+ <p class="description" style="display: <?php echo ezTOC_Option::get( 'widget_affix_selector' ) ? 'block' : 'none'; ?>;">
371
+ <?php _e( 'If you choose to affix the widget, do not add any other widgets on the sidebar. Also, make sure you have only one instance Table of Contents widget on the page.', 'easy-table-of-contents' ); ?>
372
+ </p>
373
+ <?php
374
+ }
375
+
376
+ } // end class
377
+
378
+ add_action( 'widgets_init', array( 'ezTOC_Widget', 'register' ) );
379
+ }
includes/inc.admin-options-page.php CHANGED
@@ -1,466 +1,466 @@
1
- <div id='toc' class='wrap'>
2
- <a href="https://tocwp.com/" target="_blank" >
3
- <img src="<?php echo plugins_url( 'assets/eztoc-logo.png', dirname(__FILE__) ) ?>" alt="tocwp" srcset="<?php echo plugins_url( 'assets/eztoc-logo.png', dirname(__FILE__) ) ?> 1x, <?php echo plugins_url( 'assets/eztoc-logo.png', dirname(__FILE__) ) ?> 2x" >
4
- </a>
5
- <div class="toc-tab-panel">
6
- <a id="eztoc-welcome" class="eztoc-tablinks" data-href="no" href="#welcome" onclick="tabToggle(event, 'welcome')">Welcome</a>
7
- <a id="eztoc-default" class="eztoc-tablinks" data-href="no" href="#general-settings" onclick="tabToggle(event, 'general')">Settings</a>
8
- <?php
9
- $pro = '';
10
-
11
- if (function_exists('ez_toc_pro_activation_link')) {
12
- $pro = '<a id="eztoc-default" class="eztoc-tablinks" data-href="no" href="#eztoc-prosettings" onclick="tabToggle(event, "prosettings")">PRO Settings</a>';
13
- }?>
14
- <?php echo $pro; ?>
15
-
16
- <?php
17
- if (!function_exists('ez_toc_pro_activation_link')) {?>
18
- <a class="eztoc-tablinks" id="eztoc-freevspro" href="#freevspro-support" onclick="tabToggle(event, 'freevspro')" data-href="no">Free vs PRO</a>
19
- <?php }
20
- ?>
21
- <a class="eztoc-tablinks" id="eztoc-technical" href="#technical-support" onclick="tabToggle(event, 'technical')" data-href="no">Help & Support</a>
22
- <a class="eztoc-tablinks" id="eztoc-upgrade" href="https://tocwp.com/pricing/" target="_blank" >UPGRADE to PRO</a>
23
- <?php
24
-
25
- if (function_exists('ez_toc_pro_activation_link')) {
26
- $license_info = get_option("easytoc_pro_upgrade_license");
27
- $license_exp = date('Y-m-d', strtotime($license_info['pro']['license_key_expires']));
28
- $today = date('Y-m-d');
29
- $exp_date = $license_exp;
30
- $date1 = date_create($today);
31
- $date2 = date_create($exp_date);
32
- $diff = date_diff($date1,$date2);
33
- $days = $diff->format("%a");
34
- $days = intval($days);?>
35
- <a class="eztoc-tablinks" id="eztoc-license" href="#license" onclick="tabToggle(event, 'license')" data-href="no">License</a>
36
- <?php
37
- if( $days < 30 ){?>
38
- <span class="dashicons dashicons-warning" style="color: #ffb229;position: relative;top: 15px;left: -10px;"></span>
39
- <?php } }?>
40
- </div><!-- /.Tab panel -->
41
- <div class="eztoc_support_div eztoc-tabcontent" id="welcome" style="display: block;">
42
- <p style="font-weight: bold;font-size: 30px;color: #000;">Thank YOU for using Easy Table of Content. </p>
43
- <p style="font-size: 18px;padding: 0 10%;line-height: 1.7;color: #000;">We strive to create the best TOC solution in WordPress. Our dedicated development team does continious development and innoviation to make sure we are able to meet your demand.</p>
44
- <p style="font-size: 16px;font-weight: 600;color: #000;">Please support us by Upgrading to Premium verison.</p>
45
- <a target="_blank" href="https://tocwp.com/pricing/"><button class="button-toc" style="display: inline-block;font-size: 20px;">
46
- <span>YES! I want to Support by UPGRADING.</span></button></a>
47
- <a href="<?php echo add_query_arg( 'page', 'table-of-contents', admin_url( 'options-general.php' ) ); ?>" style="text-decoration: none;"><button class="button-toc1" style="display: block;text-align: center;border: 0;margin: 0 auto;background: none;">
48
- <span style="cursor: pointer;">No Thanks, I will stick with FREE version for now.</span></button></a>
49
- </div><!-- /.Welcome ended -->
50
- <div class="eztoc-tabcontent" id="general">
51
- <div id="eztoc-tabs" style="margin-top: 10px;"><a href="#eztoc-general">General</a> | <a href="#eztoc-appearance" >Appearance</a> | <a href="#eztoc-advanced" >Advanced</a></div>
52
- <form method="post" action="<?php echo esc_url( self_admin_url( 'options.php' ) ); ?>">
53
-
54
- <div class="metabox-holder">
55
-
56
- <div class="postbox" id="eztoc-general">
57
- <h3><span><?php _e( 'General', 'easy-table-of-contents' ); ?></span></h3>
58
-
59
- <div class="inside">
60
-
61
- <table class="form-table">
62
-
63
- <?php do_settings_fields( 'ez_toc_settings_general', 'ez_toc_settings_general' ); ?>
64
-
65
- </table>
66
-
67
- </div><!-- /.inside -->
68
- </div><!-- /.postbox -->
69
-
70
- </div><!-- /.metabox-holder -->
71
-
72
- <div class="metabox-holder">
73
-
74
- <div class="postbox" id="eztoc-appearance">
75
- <h3><span><?php _e( 'Appearance', 'easy-table-of-contents' ); ?></span></h3>
76
-
77
- <div class="inside">
78
-
79
- <table class="form-table">
80
-
81
- <?php do_settings_fields( 'ez_toc_settings_appearance', 'ez_toc_settings_appearance' ); ?>
82
-
83
- </table>
84
-
85
- </div><!-- /.inside -->
86
- </div><!-- /.postbox -->
87
-
88
- </div><!-- /.metabox-holder -->
89
-
90
- <div class="metabox-holder">
91
-
92
- <div class="postbox" id="eztoc-advanced">
93
- <h3><span><?php _e( 'Advanced', 'easy-table-of-contents' ); ?></span></h3>
94
-
95
- <div class="inside">
96
-
97
- <table class="form-table">
98
-
99
- <?php do_settings_fields( 'ez_toc_settings_advanced', 'ez_toc_settings_advanced' ); ?>
100
-
101
- </table>
102
-
103
- </div><!-- /.inside -->
104
- </div><!-- /.postbox -->
105
-
106
- </div><!-- /.metabox-holder -->
107
- <?php if (function_exists('ez_toc_pro_activation_link')) {?>
108
- <div class="metabox-holder">
109
-
110
- <div class="postbox" id="eztoc-prosettings">
111
- <h3><span><?php _e( 'PRO Settings', 'easy-table-of-contents' ); ?></span></h3>
112
- <div class="inside">
113
-
114
- <table class="form-table">
115
- <?php do_settings_fields( 'ez_toc_settings_prosettings', 'ez_toc_settings_prosettings' ); ?>
116
-
117
- </table>
118
-
119
- </div><!-- /.inside -->
120
- </div><!-- /.postbox -->
121
-
122
- </div><!-- /.metabox-holder -->
123
- <?php } ?>
124
- <?php settings_fields( 'ez-toc-settings' ); ?>
125
- <?php submit_button( __( 'Save Changes', 'easy-table-of-contents' ) ); ?>
126
- </form>
127
- </div><!-- /.General Settings ended -->
128
-
129
-
130
-
131
-
132
- <div class="eztoc_support_div eztoc-tabcontent" id="technical">
133
- <div class="eztoc-form-page-ui">
134
- <div class="eztoc-left-side">
135
- <p><?php echo esc_html__('We are dedicated to provide Technical support & Help to our users. Use the below form for sending your questions.','easy-table-of-contents') ?> </p>
136
- <p><?php echo esc_html__('You can also contact us from ','easy-table-of-contents') ?><a href="https://tocwp.com/contact/">https://tocwp.com/contact/</a>.</p>
137
-
138
- <div class="eztoc_support_div_form" id="technical-form">
139
- <ul>
140
- <li>
141
- <label class="support-label">Email<span class="star-mark">*</span></label>
142
- <div class="support-input">
143
-
144
- <input type="text" id="eztoc_query_email" name="eztoc_query_email" placeholder="Enter your Email" required>
145
- </div>
146
- </li>
147
-
148
- <li>
149
- <label class="support-label">Query<span class="star-mark">*</span></label>
150
-
151
- <div class="support-input"><textarea rows="5" cols="50" id="eztoc_query_message" name="eztoc_query_message" placeholder="Write your query"></textarea>
152
- </div>
153
-
154
-
155
- </li>
156
-
157
- </ul>
158
- <li>
159
- <div class="eztoc-customer-type">
160
- <label class="support-label">Type</label>
161
- <div class="support-input">
162
- <select name="eztoc_customer_type" id="eztoc_customer_type">
163
- <option value="select">Select Customer Type</option>
164
- <option value="paid">Paid<span> (Response within 24 hrs)</span></option>
165
- <option value="free">Free<span> ( Avg Response within 48-72 hrs)</span></option>
166
- </select>
167
- </div>
168
- </div>
169
- </li>
170
- <li><button class="button button-primary eztoc-send-query"><?php echo esc_html__('Send Support Request','easy-table-of-contents'); ?></button></li>
171
- </ul>
172
- <div class="clear"> </div>
173
- <span class="eztoc-query-success eztoc-result eztoc_hide"><?php echo esc_html__('Message sent successfully, Please wait we will get back to you shortly','easy-table-of-contents'); ?></span>
174
- <span class="eztoc-query-error eztoc-result eztoc_hide"><?php echo esc_html__('Message not sent. please check your network connection','easy-table-of-contents'); ?></span>
175
- </div>
176
- </div>
177
- <div class="eztoc-right-side">
178
- <div class="eztoc-bio-box" id="ez_Bio">
179
- <h1>Vision & Mission</h1>
180
- <p class="eztoc-p">We strive to provide the best TOC in the world.</p>
181
- <section class="eztoc_dev-bio">
182
- <div class="ezoc-bio-wrap">
183
- <img width="50px" height="50px" src="<?php echo plugins_url( 'assets/ahmed-kaludi.jpg', dirname(__FILE__) ) ?>">
184
- <p>Lead Dev</p>
185
- </div>
186
- <div class="ezoc-bio-wrap">
187
- <img width="50px" height="50px" src="<?php echo plugins_url( 'assets/Mohammed-kaludi.jpeg', dirname(__FILE__) ) ?>">
188
- <p>Developer</p>
189
- </div>
190
- <div class="ezoc-bio-wrap">
191
- <img width="50px" height="50px" src="<?php echo plugins_url( 'assets/zabi.jpg', dirname(__FILE__) ) ?>">
192
- <p>Developer</p>
193
- </div>
194
- </section>
195
- <p class="eztoc_boxdesk"> Delivering a good user experience means a lot to us, so we try our best to reply each and every question.</p>
196
- <p class="company-link"> Support the innovation & development by upgrading to PRO <a href="https://tocwp.com/pricing/">I Want To Upgrade!</a></p>
197
- </div>
198
- </div> </div> </div> <!-- /.Technical support div ended -->
199
-
200
- <div class="eztoc_support_div eztoc-tabcontent" id="freevspro">
201
- <div class="eztoc-wrapper">
202
- <div class="eztoc-wr">
203
- <div class="etoc-eztoc-img">
204
- <span class="sp_ov"></span>
205
- </div>
206
- <div class="etoc-eztoc-cnt">
207
- <h1><?php _e( 'UPGRADE to PRO Version'); ?></h1>
208
- <p><?php _e( 'Take your Table of Contents to the NEXT Level!', 'easy-table-of-contents' ); ?></p>
209
- <a class="buy" href="#upgrade"><?php _e( 'Purchase Now', 'easy-table-of-contents' ); ?></a>
210
- </div>
211
- <div class="pvf">
212
- <div class="ext">
213
- <div class="ex-1 e-1">
214
- <h4><?php _e( 'Premium Features', 'easy-table-of-contents' ); ?></h4>
215
- <p><?php _e( 'Easy TOC Pro will enhances your website table of contents and takes it to a next level to help you reach more engagement and personalization with your users.', 'easy-table-of-contents' ); ?></p>
216
- </div>
217
- <div class="ex-1 e-2">
218
- <h4><?php _e( 'Continuous Innovation', 'easy-table-of-contents' ); ?></h4>
219
- <p><?php _e( 'We are planning to continiously build premium features and release them. We have a roadmap and we listen to our customers to turn their feedback into reality.', 'easy-table-of-contents' ); ?></p>
220
- </div>
221
- <div class="ex-1 e-3">
222
- <h4><?php _e( 'Tech Support', 'easy-table-of-contents' ); ?></h4>
223
- <p><?php _e( 'Get private ticketing help from our full-time technical staff & developers who helps you with the technical issues.', 'easy-table-of-contents' ); ?></p>
224
- </div>
225
- </div><!-- /. ext -->
226
- <div class="pvf-cnt">
227
- <div class="pvf-tlt">
228
- <h2><?php _e( 'Compare Pro vs. Free Version', 'easy-table-of-contents' ); ?></h2>
229
- <span><?php _e( 'See what you\'ll get with the professional version', 'easy-table-of-contents' ); ?></span>
230
- </div>
231
- <div class="pvf-cmp">
232
- <div class="fr">
233
- <h1>FREE</h1>
234
- <div class="fr-fe">
235
- <div class="fe-1">
236
- <h4><?php _e( 'Continious Development', 'easy-table-of-contents' ); ?></h4>
237
- <p><?php _e( 'We take bug reports and feature requests seriously. We’re continiously developing &amp; improve this product for last 2 years with passion and love.', 'easy-table-of-contents' ); ?></p>
238
- </div>
239
- <div class="fe-1">
240
- <h4><?php _e( '50+ Features', 'easy-table-of-contents' ); ?></h4>
241
- <p><?php _e( 'We\'re constantly expanding the plugin and make it more useful. We have wide variety of features which will fit any use-case.', 'easy-table-of-contents' ); ?></p>
242
- </div>
243
- </div><!-- /. fr-fe -->
244
- </div><!-- /. fr -->
245
- <div class="pr">
246
- <h1>PRO</h1>
247
- <div class="pr-fe">
248
- <span><?php _e( 'Everything in Free, and:', 'easy-table-of-contents' ); ?></span>
249
- <div class="fet">
250
- <div class="fe-2">
251
- <div class="fe-t">
252
- <img src="<?php echo plugins_url( 'assets/right-tick.png', dirname(__FILE__) ) ?>">
253
- <h4><?php _e( 'Gutenberg Block', 'easy-table-of-contents' ); ?></h4>
254
- </div>
255
- <p><?php _e( 'Easily create TOC in Gutenberg block without the need any coding or shortcode.', 'easy-table-of-contents' ); ?></p>
256
- </div>
257
- <div class="fe-2">
258
- <div class="fe-t">
259
- <img src="<?php echo plugins_url( 'assets/right-tick.png', dirname(__FILE__) ) ?>">
260
- <h4><?php _e( 'Elementor Widget', 'easy-table-of-contents' ); ?></h4>
261
- </div>
262
- <p><?php _e( 'Easily create TOC in Elementor with the widget without the need any coding or shortcode.', 'easy-table-of-contents' ); ?></p>
263
- </div>
264
-
265
- <div class="fe-2">
266
- <div class="fe-t">
267
- <img src="<?php echo plugins_url( 'assets/right-tick.png', dirname(__FILE__) ) ?>">
268
- <h4>Fixed/Sticky TOC</h4>
269
- </div>
270
- <p>Users can faster find the content they want with sticky</p>
271
- </div>
272
-
273
-
274
- <div class="fe-2">
275
- <div class="fe-t">
276
- <img src="<?php echo plugins_url( 'assets/right-tick.png', dirname(__FILE__) ) ?>">
277
- <h4>Full AMP Support</h4>
278
- </div>
279
- <p>Generates a table of contents with your existing setup and makes them AMP automatically.</p>
280
- </div>
281
- <div class="fe-2">
282
- <div class="fe-t">
283
- <img src="<?php echo plugins_url( 'assets/right-tick.png', dirname(__FILE__) ) ?>">
284
- <h4>Continious Updates</h4>
285
- </div>
286
- <p>We're continiously updating our premium features and releasing them.</p>
287
- </div>
288
- <div class="fe-2">
289
- <div class="fe-t">
290
- <img src="<?php echo plugins_url( 'assets/right-tick.png', dirname(__FILE__) ) ?>">
291
- <h4>Documentation</h4>
292
- </div>
293
- <p>We create tutorials for every possible feature and keep it updated for you.</p>
294
- </div>
295
- </div><!-- /. fet -->
296
- <div class="pr-btn">
297
- <a href="#upgrade">Upgrade to Pro</a>
298
- </div><!-- /. pr-btn -->
299
- </div><!-- /. pr-fe -->
300
- </div><!-- /.pr -->
301
- </div><!-- /. pvf-cmp -->
302
- </div><!-- /. pvf-cnt -->
303
- <div id="upgrade" class="amp-upg">
304
- <div class="upg-t">
305
- <h2>Let's Upgrade Your Easy Table of Contents</h2>
306
- <span>Choose your plan and upgrade in minutes!</span>
307
- </div>
308
- <div class="etoc-pri-lst">
309
- <div class="pri-tb">
310
- <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=1" target="_blank">
311
- <h5>PERSONAL</h5>
312
- <span class="d-amt"><sup>$</sup>49</span>
313
- <span class="amt"><sup>$</sup>49</span>
314
- <span class="s-amt">(Save $59)</span>
315
- <span class="bil">Billed Annually</span>
316
- <span class="s">1 Site License</span>
317
- <span class="e">Tech Support</span>
318
- <span class="f">1 year Updates </span>
319
- <span class="etoc-sv">Pro Features </span>
320
- <span class="pri-by">Buy Now</span>
321
- </a>
322
- </div>
323
- <div class="pri-tb rec">
324
- <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=2" target="_blank">
325
- <h5>MULTIPLE</h5>
326
- <span class="d-amt"><sup>$</sup>69</span>
327
- <span class="amt"><sup>$</sup>69</span>
328
- <span class="s-amt">(Save $79)</span>
329
- <span class="bil">Billed Annually</span>
330
- <span class="s">3 Site License</span>
331
- <span class="e">Tech Support</span>
332
- <span class="f">1 year Updates</span>
333
- <span class="etoc-sv">Save 78%</span>
334
- <span class="pri-by">Buy Now</span>
335
- <span class="etoc-rcm">RECOMMENDED</span>
336
- </a>
337
- </div>
338
- <div class="pri-tb">
339
- <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=3" target="_blank">
340
- <h5>WEBMASTER</h5>
341
- <span class="d-amt"><sup>$</sup>79</span>
342
- <span class="amt"><sup>$</sup>79</span>
343
- <span class="s-amt">(Save $99)</span>
344
- <span class="bil">Billed Annually</span>
345
- <span class="s">10 Site License</span>
346
- <span class="e">Tech Support</span>
347
- <span class="f">1 year Updates</span>
348
- <span class="etoc-sv">Save 83%</span>
349
- <span class="pri-by">Buy Now</span>
350
- </a>
351
- </div>
352
- <div class="pri-tb">
353
- <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=4" target="_blank">
354
- <h5>FREELANCER</h5>
355
- <span class="d-amt"><sup>$</sup>99</span>
356
- <span class="amt"><sup>$</sup>99</span>
357
- <span class="s-amt">(Save $119)</span>
358
- <span class="bil">Billed Annually</span>
359
- <span class="s">25 Site License</span>
360
- <span class="e">Tech Support</span>
361
- <span class="f">1 year Updates</span>
362
- <span class="etoc-sv">Save 90%</span>
363
- <span class="pri-by">Buy Now</span>
364
- </a>
365
- </div>
366
- <div class="pri-tb">
367
- <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=5" target="_blank">
368
- <h5>AGENCY</h5>
369
- <span class="d-amt"><sup>$</sup>199</span>
370
- <span class="amt"><sup>$</sup>199</span>
371
- <span class="s-amt">(Save $199)</span>
372
- <span class="bil">Billed Annually</span>
373
- <span class="s">Unlimited Sites</span>
374
- <span class="e">E-mail support</span>
375
- <span class="f">1 year Updates</span>
376
- <span class="etoc-sv">UNLIMITED</span>
377
- <span class="pri-by">Buy Now</span>
378
- </a>
379
- </div>
380
- <div class="pri-tb">
381
- <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=6" target="_blank">
382
- <h5>LIFETIME</h5>
383
- <span class="d-amt"><sup>$</sup>499</span>
384
- <span class="amt"><sup>$</sup>499</span>
385
- <span class="s-amt">(Save $199)</span>
386
- <span class="bil">Billed Annually</span>
387
- <span class="s">Unlimited Sites</span>
388
- <span class="e">Unlimited E-mail support</span>
389
- <span class="f">Lifetime License</span>
390
- <span class="etoc-sv">UNLIMITED</span>
391
- <span class="pri-by">Buy Now</span>
392
- </a>
393
- </div>
394
- </div><!-- /.pri-lst -->
395
- <div class="tru-us">
396
- <img src="<?php echo plugins_url( 'assets/toc-rating.png', dirname(__FILE__) ) ?>">
397
- <h2>Used by more than 300,000+ Users!</h2>
398
- <p>More than 300k Websites, Blogs &amp; E-Commerce shops are powered by our easy table of contents plugin making it the #1 Independent TOC plugin in WordPress.</p>
399
- <a href="https://wordpress.org/support/plugin/easy-table-of-contents/reviews/?filter=5" target="_blank">Read The Reviews</a>
400
- </div>
401
- </div><!--/ .amp-upg -->
402
- <div class="ampfaq">
403
- <h2>Frequently Asked Questions</h2>
404
- <div class="faq-lst">
405
- <div class="lt">
406
- <ul>
407
- <li>
408
- <span>Is there a setup fee?</span>
409
- <p>No. There are no setup fees on any of our plans</p>
410
- </li>
411
- <li>
412
- <span>What's the time span for your contracts?</span>
413
- <p>All the plans are year-to-year which are subscribed annually except for lifetime plan.</p>
414
- </li>
415
- <li>
416
- <span>What payment methods are accepted?</span>
417
- <p>We accepts PayPal and Credit Card payments.</p>
418
- </li>
419
- <li>
420
- <span>Do you offer support if I need help?</span>
421
- <p>Yes! Top-notch customer support for our paid customers is key for a quality product, so we’ll do our very best to resolve any issues you encounter via our support page.</p>
422
- </li>
423
- <li>
424
- <span>Can I use the plugins after my subscription is expired?</span>
425
- <p>Yes, you can use the plugins but you will not get future updates for those plugins.</p>
426
- </li>
427
- </ul>
428
- </div>
429
- <div class="rt">
430
- <ul>
431
- <li>
432
- <span>Can I cancel my membership at any time?</span>
433
- <p>Yes. You can cancel your membership by contacting us.</p>
434
- </li>
435
- <li>
436
- <span>Can I change my plan later on?</span>
437
- <p>Yes. You can upgrade your plan by contacting us.</p>
438
- </li>
439
- <li>
440
- <span>Do you offer refunds?</span>
441
- <p>You are fully protected by our 100% Money Back Guarantee Unconditional. If during the next 14 days you experience an issue that makes the plugin unusable and we are unable to resolve it, we’ll happily offer a full refund.</p>
442
- </li>
443
- <li>
444
- <span>Do I get updates for the premium plugin?</span>
445
- <p>Yes, you will get updates for all the premium plugins until your subscription is active.</p>
446
- </li>
447
- </ul>
448
- </div>
449
- </div><!-- /.faq-lst -->
450
- <div class="f-cnt">
451
- <span>I have other pre-sale questions, can you help?</span>
452
- <p>All the plans are year-to-year which are subscribed annually.</p>
453
- <a href="https://tocwp.com/contact/'?utm_source=tocwp-plugin&utm_medium=addon-card'" target="_blank">Contact a Human</a>
454
- </div><!-- /.f-cnt -->
455
- </div><!-- /.faq -->
456
- </div><!-- /. pvf -->
457
- </div>
458
- </div>
459
- </div><!-- /.freevspro div ended -->
460
-
461
- <div id="license" class="eztoc_support_div eztoc-tabcontent">
462
- <?php
463
- do_action("admin_upgrade_license_page");
464
- ?>
465
- </div>
466
- </div>
1
+ <div id='toc' class='wrap'>
2
+ <a href="https://tocwp.com/" target="_blank" >
3
+ <img src="<?php echo plugins_url( 'assets/eztoc-logo.png', dirname(__FILE__) ) ?>" alt="tocwp" srcset="<?php echo plugins_url( 'assets/eztoc-logo.png', dirname(__FILE__) ) ?> 1x, <?php echo plugins_url( 'assets/eztoc-logo.png', dirname(__FILE__) ) ?> 2x" >
4
+ </a>
5
+ <div class="toc-tab-panel">
6
+ <a id="eztoc-welcome" class="eztoc-tablinks" data-href="no" href="#welcome" onclick="tabToggle(event, 'welcome')">Welcome</a>
7
+ <a id="eztoc-default" class="eztoc-tablinks" data-href="no" href="#general-settings" onclick="tabToggle(event, 'general')">Settings</a>
8
+ <?php
9
+ $pro = '';
10
+
11
+ if (function_exists('ez_toc_pro_activation_link')) {
12
+ $pro = '<a id="eztoc-default" class="eztoc-tablinks" data-href="no" href="#eztoc-prosettings" onclick="tabToggle(event, "prosettings")">PRO Settings</a>';
13
+ }?>
14
+ <?php echo $pro; ?>
15
+
16
+ <?php
17
+ if (!function_exists('ez_toc_pro_activation_link')) {?>
18
+ <a class="eztoc-tablinks" id="eztoc-freevspro" href="#freevspro-support" onclick="tabToggle(event, 'freevspro')" data-href="no">Free vs PRO</a>
19
+ <?php }
20
+ ?>
21
+ <a class="eztoc-tablinks" id="eztoc-technical" href="#technical-support" onclick="tabToggle(event, 'technical')" data-href="no">Help & Support</a>
22
+ <a class="eztoc-tablinks" id="eztoc-upgrade" href="https://tocwp.com/pricing/" target="_blank" >UPGRADE to PRO</a>
23
+ <?php
24
+
25
+ if (function_exists('ez_toc_pro_activation_link')) {
26
+ $license_info = get_option("easytoc_pro_upgrade_license");
27
+ $license_exp = date('Y-m-d', strtotime($license_info['pro']['license_key_expires']));
28
+ $today = date('Y-m-d');
29
+ $exp_date = $license_exp;
30
+ $date1 = date_create($today);
31
+ $date2 = date_create($exp_date);
32
+ $diff = date_diff($date1,$date2);
33
+ $days = $diff->format("%a");
34
+ $days = intval($days);?>
35
+ <a class="eztoc-tablinks" id="eztoc-license" href="#license" onclick="tabToggle(event, 'license')" data-href="no">License</a>
36
+ <?php
37
+ if( $days < 30 ){?>
38
+ <span class="dashicons dashicons-warning" style="color: #ffb229;position: relative;top: 15px;left: -10px;"></span>
39
+ <?php } }?>
40
+ </div><!-- /.Tab panel -->
41
+ <div class="eztoc_support_div eztoc-tabcontent" id="welcome" style="display: block;">
42
+ <p style="font-weight: bold;font-size: 30px;color: #000;">Thank YOU for using Easy Table of Content. </p>
43
+ <p style="font-size: 18px;padding: 0 10%;line-height: 1.7;color: #000;">We strive to create the best TOC solution in WordPress. Our dedicated development team does continious development and innoviation to make sure we are able to meet your demand.</p>
44
+ <p style="font-size: 16px;font-weight: 600;color: #000;">Please support us by Upgrading to Premium verison.</p>
45
+ <a target="_blank" href="https://tocwp.com/pricing/"><button class="button-toc" style="display: inline-block;font-size: 20px;">
46
+ <span>YES! I want to Support by UPGRADING.</span></button></a>
47
+ <a href="<?php echo add_query_arg( 'page', 'table-of-contents', admin_url( 'options-general.php' ) ); ?>" style="text-decoration: none;"><button class="button-toc1" style="display: block;text-align: center;border: 0;margin: 0 auto;background: none;">
48
+ <span style="cursor: pointer;">No Thanks, I will stick with FREE version for now.</span></button></a>
49
+ </div><!-- /.Welcome ended -->
50
+ <div class="eztoc-tabcontent" id="general">
51
+ <div id="eztoc-tabs" style="margin-top: 10px;"><a href="#eztoc-general">General</a> | <a href="#eztoc-appearance" >Appearance</a> | <a href="#eztoc-advanced" >Advanced</a></div>
52
+ <form method="post" action="<?php echo esc_url( self_admin_url( 'options.php' ) ); ?>">
53
+
54
+ <div class="metabox-holder">
55
+
56
+ <div class="postbox" id="eztoc-general">
57
+ <h3><span><?php _e( 'General', 'easy-table-of-contents' ); ?></span></h3>
58
+
59
+ <div class="inside">
60
+
61
+ <table class="form-table">
62
+
63
+ <?php do_settings_fields( 'ez_toc_settings_general', 'ez_toc_settings_general' ); ?>
64
+
65
+ </table>
66
+
67
+ </div><!-- /.inside -->
68
+ </div><!-- /.postbox -->
69
+
70
+ </div><!-- /.metabox-holder -->
71
+
72
+ <div class="metabox-holder">
73
+
74
+ <div class="postbox" id="eztoc-appearance">
75
+ <h3><span><?php _e( 'Appearance', 'easy-table-of-contents' ); ?></span></h3>
76
+
77
+ <div class="inside">
78
+
79
+ <table class="form-table">
80
+
81
+ <?php do_settings_fields( 'ez_toc_settings_appearance', 'ez_toc_settings_appearance' ); ?>
82
+
83
+ </table>
84
+
85
+ </div><!-- /.inside -->
86
+ </div><!-- /.postbox -->
87
+
88
+ </div><!-- /.metabox-holder -->
89
+
90
+ <div class="metabox-holder">
91
+
92
+ <div class="postbox" id="eztoc-advanced">
93
+ <h3><span><?php _e( 'Advanced', 'easy-table-of-contents' ); ?></span></h3>
94
+
95
+ <div class="inside">
96
+
97
+ <table class="form-table">
98
+
99
+ <?php do_settings_fields( 'ez_toc_settings_advanced', 'ez_toc_settings_advanced' ); ?>
100
+
101
+ </table>
102
+
103
+ </div><!-- /.inside -->
104
+ </div><!-- /.postbox -->
105
+
106
+ </div><!-- /.metabox-holder -->
107
+ <?php if (function_exists('ez_toc_pro_activation_link')) {?>
108
+ <div class="metabox-holder">
109
+
110
+ <div class="postbox" id="eztoc-prosettings">
111
+ <h3><span><?php _e( 'PRO Settings', 'easy-table-of-contents' ); ?></span></h3>
112
+ <div class="inside">
113
+
114
+ <table class="form-table">
115
+ <?php do_settings_fields( 'ez_toc_settings_prosettings', 'ez_toc_settings_prosettings' ); ?>
116
+
117
+ </table>
118
+
119
+ </div><!-- /.inside -->
120
+ </div><!-- /.postbox -->
121
+
122
+ </div><!-- /.metabox-holder -->
123
+ <?php } ?>
124
+ <?php settings_fields( 'ez-toc-settings' ); ?>
125
+ <?php submit_button( __( 'Save Changes', 'easy-table-of-contents' ) ); ?>
126
+ </form>
127
+ </div><!-- /.General Settings ended -->
128
+
129
+
130
+
131
+
132
+ <div class="eztoc_support_div eztoc-tabcontent" id="technical">
133
+ <div class="eztoc-form-page-ui">
134
+ <div class="eztoc-left-side">
135
+ <p><?php echo esc_html__('We are dedicated to provide Technical support & Help to our users. Use the below form for sending your questions.','easy-table-of-contents') ?> </p>
136
+ <p><?php echo esc_html__('You can also contact us from ','easy-table-of-contents') ?><a href="https://tocwp.com/contact/">https://tocwp.com/contact/</a>.</p>
137
+
138
+ <div class="eztoc_support_div_form" id="technical-form">
139
+ <ul>
140
+ <li>
141
+ <label class="support-label">Email<span class="star-mark">*</span></label>
142
+ <div class="support-input">
143
+
144
+ <input type="text" id="eztoc_query_email" name="eztoc_query_email" placeholder="Enter your Email" required>
145
+ </div>
146
+ </li>
147
+
148
+ <li>
149
+ <label class="support-label">Query<span class="star-mark">*</span></label>
150
+
151
+ <div class="support-input"><textarea rows="5" cols="50" id="eztoc_query_message" name="eztoc_query_message" placeholder="Write your query"></textarea>
152
+ </div>
153
+
154
+
155
+ </li>
156
+
157
+ </ul>
158
+ <li>
159
+ <div class="eztoc-customer-type">
160
+ <label class="support-label">Type</label>
161
+ <div class="support-input">
162
+ <select name="eztoc_customer_type" id="eztoc_customer_type">
163
+ <option value="select">Select Customer Type</option>
164
+ <option value="paid">Paid<span> (Response within 24 hrs)</span></option>
165
+ <option value="free">Free<span> ( Avg Response within 48-72 hrs)</span></option>
166
+ </select>
167
+ </div>
168
+ </div>
169
+ </li>
170
+ <li><button class="button button-primary eztoc-send-query"><?php echo esc_html__('Send Support Request','easy-table-of-contents'); ?></button></li>
171
+ </ul>
172
+ <div class="clear"> </div>
173
+ <span class="eztoc-query-success eztoc-result eztoc_hide"><?php echo esc_html__('Message sent successfully, Please wait we will get back to you shortly','easy-table-of-contents'); ?></span>
174
+ <span class="eztoc-query-error eztoc-result eztoc_hide"><?php echo esc_html__('Message not sent. please check your network connection','easy-table-of-contents'); ?></span>
175
+ </div>
176
+ </div>
177
+ <div class="eztoc-right-side">
178
+ <div class="eztoc-bio-box" id="ez_Bio">
179
+ <h1>Vision & Mission</h1>
180
+ <p class="eztoc-p">We strive to provide the best TOC in the world.</p>
181
+ <section class="eztoc_dev-bio">
182
+ <div class="ezoc-bio-wrap">
183
+ <img width="50px" height="50px" src="<?php echo plugins_url( 'assets/ahmed-kaludi.jpg', dirname(__FILE__) ) ?>">
184
+ <p>Lead Dev</p>
185
+ </div>
186
+ <div class="ezoc-bio-wrap">
187
+ <img width="50px" height="50px" src="<?php echo plugins_url( 'assets/Mohammed-kaludi.jpeg', dirname(__FILE__) ) ?>">
188
+ <p>Developer</p>
189
+ </div>
190
+ <div class="ezoc-bio-wrap">
191
+ <img width="50px" height="50px" src="<?php echo plugins_url( 'assets/zabi.jpg', dirname(__FILE__) ) ?>">
192
+ <p>Developer</p>
193
+ </div>
194
+ </section>
195
+ <p class="eztoc_boxdesk"> Delivering a good user experience means a lot to us, so we try our best to reply each and every question.</p>
196
+ <p class="company-link"> Support the innovation & development by upgrading to PRO <a href="https://tocwp.com/pricing/">I Want To Upgrade!</a></p>
197
+ </div>
198
+ </div> </div> </div> <!-- /.Technical support div ended -->
199
+
200
+ <div class="eztoc_support_div eztoc-tabcontent" id="freevspro">
201
+ <div class="eztoc-wrapper">
202
+ <div class="eztoc-wr">
203
+ <div class="etoc-eztoc-img">
204
+ <span class="sp_ov"></span>
205
+ </div>
206
+ <div class="etoc-eztoc-cnt">
207
+ <h1><?php _e( 'UPGRADE to PRO Version'); ?></h1>
208
+ <p><?php _e( 'Take your Table of Contents to the NEXT Level!', 'easy-table-of-contents' ); ?></p>
209
+ <a class="buy" href="#upgrade"><?php _e( 'Purchase Now', 'easy-table-of-contents' ); ?></a>
210
+ </div>
211
+ <div class="pvf">
212
+ <div class="ext">
213
+ <div class="ex-1 e-1">
214
+ <h4><?php _e( 'Premium Features', 'easy-table-of-contents' ); ?></h4>
215
+ <p><?php _e( 'Easy TOC Pro will enhances your website table of contents and takes it to a next level to help you reach more engagement and personalization with your users.', 'easy-table-of-contents' ); ?></p>
216
+ </div>
217
+ <div class="ex-1 e-2">
218
+ <h4><?php _e( 'Continuous Innovation', 'easy-table-of-contents' ); ?></h4>
219
+ <p><?php _e( 'We are planning to continiously build premium features and release them. We have a roadmap and we listen to our customers to turn their feedback into reality.', 'easy-table-of-contents' ); ?></p>
220
+ </div>
221
+ <div class="ex-1 e-3">
222
+ <h4><?php _e( 'Tech Support', 'easy-table-of-contents' ); ?></h4>
223
+ <p><?php _e( 'Get private ticketing help from our full-time technical staff & developers who helps you with the technical issues.', 'easy-table-of-contents' ); ?></p>
224
+ </div>
225
+ </div><!-- /. ext -->
226
+ <div class="pvf-cnt">
227
+ <div class="pvf-tlt">
228
+ <h2><?php _e( 'Compare Pro vs. Free Version', 'easy-table-of-contents' ); ?></h2>
229
+ <span><?php _e( 'See what you\'ll get with the professional version', 'easy-table-of-contents' ); ?></span>
230
+ </div>
231
+ <div class="pvf-cmp">
232
+ <div class="fr">
233
+ <h1>FREE</h1>
234
+ <div class="fr-fe">
235
+ <div class="fe-1">
236
+ <h4><?php _e( 'Continious Development', 'easy-table-of-contents' ); ?></h4>
237
+ <p><?php _e( 'We take bug reports and feature requests seriously. We’re continiously developing &amp; improve this product for last 2 years with passion and love.', 'easy-table-of-contents' ); ?></p>
238
+ </div>
239
+ <div class="fe-1">
240
+ <h4><?php _e( '50+ Features', 'easy-table-of-contents' ); ?></h4>
241
+ <p><?php _e( 'We\'re constantly expanding the plugin and make it more useful. We have wide variety of features which will fit any use-case.', 'easy-table-of-contents' ); ?></p>
242
+ </div>
243
+ </div><!-- /. fr-fe -->
244
+ </div><!-- /. fr -->
245
+ <div class="pr">
246
+ <h1>PRO</h1>
247
+ <div class="pr-fe">
248
+ <span><?php _e( 'Everything in Free, and:', 'easy-table-of-contents' ); ?></span>
249
+ <div class="fet">
250
+ <div class="fe-2">
251
+ <div class="fe-t">
252
+ <img src="<?php echo plugins_url( 'assets/right-tick.png', dirname(__FILE__) ) ?>">
253
+ <h4><?php _e( 'Gutenberg Block', 'easy-table-of-contents' ); ?></h4>
254
+ </div>
255
+ <p><?php _e( 'Easily create TOC in Gutenberg block without the need any coding or shortcode.', 'easy-table-of-contents' ); ?></p>
256
+ </div>
257
+ <div class="fe-2">
258
+ <div class="fe-t">
259
+ <img src="<?php echo plugins_url( 'assets/right-tick.png', dirname(__FILE__) ) ?>">
260
+ <h4><?php _e( 'Elementor Widget', 'easy-table-of-contents' ); ?></h4>
261
+ </div>
262
+ <p><?php _e( 'Easily create TOC in Elementor with the widget without the need any coding or shortcode.', 'easy-table-of-contents' ); ?></p>
263
+ </div>
264
+
265
+ <div class="fe-2">
266
+ <div class="fe-t">
267
+ <img src="<?php echo plugins_url( 'assets/right-tick.png', dirname(__FILE__) ) ?>">
268
+ <h4>Fixed/Sticky TOC</h4>
269
+ </div>
270
+ <p>Users can faster find the content they want with sticky</p>
271
+ </div>
272
+
273
+
274
+ <div class="fe-2">
275
+ <div class="fe-t">
276
+ <img src="<?php echo plugins_url( 'assets/right-tick.png', dirname(__FILE__) ) ?>">
277
+ <h4>Full AMP Support</h4>
278
+ </div>
279
+ <p>Generates a table of contents with your existing setup and makes them AMP automatically.</p>
280
+ </div>
281
+ <div class="fe-2">
282
+ <div class="fe-t">
283
+ <img src="<?php echo plugins_url( 'assets/right-tick.png', dirname(__FILE__) ) ?>">
284
+ <h4>Continious Updates</h4>
285
+ </div>
286
+ <p>We're continiously updating our premium features and releasing them.</p>
287
+ </div>
288
+ <div class="fe-2">
289
+ <div class="fe-t">
290
+ <img src="<?php echo plugins_url( 'assets/right-tick.png', dirname(__FILE__) ) ?>">
291
+ <h4>Documentation</h4>
292
+ </div>
293
+ <p>We create tutorials for every possible feature and keep it updated for you.</p>
294
+ </div>
295
+ </div><!-- /. fet -->
296
+ <div class="pr-btn">
297
+ <a href="#upgrade">Upgrade to Pro</a>
298
+ </div><!-- /. pr-btn -->
299
+ </div><!-- /. pr-fe -->
300
+ </div><!-- /.pr -->
301
+ </div><!-- /. pvf-cmp -->
302
+ </div><!-- /. pvf-cnt -->
303
+ <div id="upgrade" class="amp-upg">
304
+ <div class="upg-t">
305
+ <h2>Let's Upgrade Your Easy Table of Contents</h2>
306
+ <span>Choose your plan and upgrade in minutes!</span>
307
+ </div>
308
+ <div class="etoc-pri-lst">
309
+ <div class="pri-tb">
310
+ <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=1" target="_blank">
311
+ <h5>PERSONAL</h5>
312
+ <span class="d-amt"><sup>$</sup>49</span>
313
+ <span class="amt"><sup>$</sup>49</span>
314
+ <span class="s-amt">(Save $59)</span>
315
+ <span class="bil">Billed Annually</span>
316
+ <span class="s">1 Site License</span>
317
+ <span class="e">Tech Support</span>
318
+ <span class="f">1 year Updates </span>
319
+ <span class="etoc-sv">Pro Features </span>
320
+ <span class="pri-by">Buy Now</span>
321
+ </a>
322
+ </div>
323
+ <div class="pri-tb rec">
324
+ <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=2" target="_blank">
325
+ <h5>MULTIPLE</h5>
326
+ <span class="d-amt"><sup>$</sup>69</span>
327
+ <span class="amt"><sup>$</sup>69</span>
328
+ <span class="s-amt">(Save $79)</span>
329
+ <span class="bil">Billed Annually</span>
330
+ <span class="s">3 Site License</span>
331
+ <span class="e">Tech Support</span>
332
+ <span class="f">1 year Updates</span>
333
+ <span class="etoc-sv">Save 78%</span>
334
+ <span class="pri-by">Buy Now</span>
335
+ <span class="etoc-rcm">RECOMMENDED</span>
336
+ </a>
337
+ </div>
338
+ <div class="pri-tb">
339
+ <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=3" target="_blank">
340
+ <h5>WEBMASTER</h5>
341
+ <span class="d-amt"><sup>$</sup>79</span>
342
+ <span class="amt"><sup>$</sup>79</span>
343
+ <span class="s-amt">(Save $99)</span>
344
+ <span class="bil">Billed Annually</span>
345
+ <span class="s">10 Site License</span>
346
+ <span class="e">Tech Support</span>
347
+ <span class="f">1 year Updates</span>
348
+ <span class="etoc-sv">Save 83%</span>
349
+ <span class="pri-by">Buy Now</span>
350
+ </a>
351
+ </div>
352
+ <div class="pri-tb">
353
+ <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=4" target="_blank">
354
+ <h5>FREELANCER</h5>
355
+ <span class="d-amt"><sup>$</sup>99</span>
356
+ <span class="amt"><sup>$</sup>99</span>
357
+ <span class="s-amt">(Save $119)</span>
358
+ <span class="bil">Billed Annually</span>
359
+ <span class="s">25 Site License</span>
360
+ <span class="e">Tech Support</span>
361
+ <span class="f">1 year Updates</span>
362
+ <span class="etoc-sv">Save 90%</span>
363
+ <span class="pri-by">Buy Now</span>
364
+ </a>
365
+ </div>
366
+ <div class="pri-tb">
367
+ <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=5" target="_blank">
368
+ <h5>AGENCY</h5>
369
+ <span class="d-amt"><sup>$</sup>199</span>
370
+ <span class="amt"><sup>$</sup>199</span>
371
+ <span class="s-amt">(Save $199)</span>
372
+ <span class="bil">Billed Annually</span>
373
+ <span class="s">Unlimited Sites</span>
374
+ <span class="e">E-mail support</span>
375
+ <span class="f">1 year Updates</span>
376
+ <span class="etoc-sv">UNLIMITED</span>
377
+ <span class="pri-by">Buy Now</span>
378
+ </a>
379
+ </div>
380
+ <div class="pri-tb">
381
+ <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=6" target="_blank">
382
+ <h5>LIFETIME</h5>
383
+ <span class="d-amt"><sup>$</sup>499</span>
384
+ <span class="amt"><sup>$</sup>499</span>
385
+ <span class="s-amt">(Save $199)</span>
386
+ <span class="bil">Billed Annually</span>
387
+ <span class="s">Unlimited Sites</span>
388
+ <span class="e">Unlimited E-mail support</span>
389
+ <span class="f">Lifetime License</span>
390
+ <span class="etoc-sv">UNLIMITED</span>
391
+ <span class="pri-by">Buy Now</span>
392
+ </a>
393
+ </div>
394
+ </div><!-- /.pri-lst -->
395
+ <div class="tru-us">
396
+ <img src="<?php echo plugins_url( 'assets/toc-rating.png', dirname(__FILE__) ) ?>">
397
+ <h2>Used by more than 300,000+ Users!</h2>
398
+ <p>More than 300k Websites, Blogs &amp; E-Commerce shops are powered by our easy table of contents plugin making it the #1 Independent TOC plugin in WordPress.</p>
399
+ <a href="https://wordpress.org/support/plugin/easy-table-of-contents/reviews/?filter=5" target="_blank">Read The Reviews</a>
400
+ </div>
401
+ </div><!--/ .amp-upg -->
402
+ <div class="ampfaq">
403
+ <h2>Frequently Asked Questions</h2>
404
+ <div class="faq-lst">
405
+ <div class="lt">
406
+ <ul>
407
+ <li>
408
+ <span>Is there a setup fee?</span>
409
+ <p>No. There are no setup fees on any of our plans</p>
410
+ </li>
411
+ <li>
412
+ <span>What's the time span for your contracts?</span>
413
+ <p>All the plans are year-to-year which are subscribed annually except for lifetime plan.</p>
414
+ </li>
415
+ <li>
416
+ <span>What payment methods are accepted?</span>
417
+ <p>We accepts PayPal and Credit Card payments.</p>
418
+ </li>
419
+ <li>
420
+ <span>Do you offer support if I need help?</span>
421
+ <p>Yes! Top-notch customer support for our paid customers is key for a quality product, so we’ll do our very best to resolve any issues you encounter via our support page.</p>
422
+ </li>
423
+ <li>
424
+ <span>Can I use the plugins after my subscription is expired?</span>
425
+ <p>Yes, you can use the plugins but you will not get future updates for those plugins.</p>
426
+ </li>
427
+ </ul>
428
+ </div>
429
+ <div class="rt">
430
+ <ul>
431
+ <li>
432
+ <span>Can I cancel my membership at any time?</span>
433
+ <p>Yes. You can cancel your membership by contacting us.</p>
434
+ </li>
435
+ <li>
436
+ <span>Can I change my plan later on?</span>
437
+ <p>Yes. You can upgrade your plan by contacting us.</p>
438
+ </li>
439
+ <li>
440
+ <span>Do you offer refunds?</span>
441
+ <p>You are fully protected by our 100% Money Back Guarantee Unconditional. If during the next 14 days you experience an issue that makes the plugin unusable and we are unable to resolve it, we’ll happily offer a full refund.</p>
442
+ </li>
443
+ <li>
444
+ <span>Do I get updates for the premium plugin?</span>
445
+ <p>Yes, you will get updates for all the premium plugins until your subscription is active.</p>
446
+ </li>
447
+ </ul>
448
+ </div>
449
+ </div><!-- /.faq-lst -->
450
+ <div class="f-cnt">
451
+ <span>I have other pre-sale questions, can you help?</span>
452
+ <p>All the plans are year-to-year which are subscribed annually.</p>
453
+ <a href="https://tocwp.com/contact/'?utm_source=tocwp-plugin&utm_medium=addon-card'" target="_blank">Contact a Human</a>
454
+ </div><!-- /.f-cnt -->
455
+ </div><!-- /.faq -->
456
+ </div><!-- /. pvf -->
457
+ </div>
458
+ </div>
459
+ </div><!-- /.freevspro div ended -->
460
+
461
+ <div id="license" class="eztoc_support_div eztoc-tabcontent">
462
+ <?php
463
+ do_action("admin_upgrade_license_page");
464
+ ?>
465
+ </div>
466
+ </div>
includes/inc.functions.php CHANGED
@@ -1,99 +1,99 @@
1
- <?php
2
-
3
- // Exit if accessed directly
4
- if ( ! defined( 'ABSPATH' ) ) exit;
5
-
6
- /**
7
- * Get the current post's TOC list or supplied post's TOC list.
8
- *
9
- * @access public
10
- * @since 2.0
11
- *
12
- * @param int|null|WP_Post $post An instance of WP_Post or post ID. Defaults to current post.
13
- * @param bool $apply_content_filter Whether or not to apply `the_content` filter when processing post for headings.
14
- *
15
- * @return string
16
- */
17
- function get_ez_toc_list( $post = null, $apply_content_filter = true ) {
18
-
19
- if ( ! $post instanceof WP_Post ) {
20
-
21
- $post = get_post( $post );
22
- }
23
-
24
- if ( $apply_content_filter ) {
25
-
26
- $ezPost = new ezTOC_Post( $post );
27
-
28
- } else {
29
-
30
- $ezPost = new ezTOC_Post( $post, false );
31
- }
32
-
33
- return $ezPost->getTOCList();
34
- }
35
-
36
- /**
37
- * Display the current post's TOC list or supplied post's TOC list.
38
- *
39
- * @access public
40
- * @since 2.0
41
- *
42
- * @param null|WP_Post $post An instance of WP_Post
43
- * @param bool $apply_content_filter Whether or not to apply `the_content` filter when processing post for headings.
44
- */
45
- function ez_toc_list( $post = null, $apply_content_filter = true ) {
46
-
47
- echo get_ez_toc_list( $post, $apply_content_filter );
48
- }
49
-
50
- /**
51
- * Get the current post's TOC content block or supplied post's TOC content block.
52
- *
53
- * @access public
54
- * @since 2.0
55
- *
56
- * @param int|null|WP_Post $post An instance of WP_Post or post ID. Defaults to current post.
57
- * @param bool $apply_content_filter Whether or not to apply `the_content` filter when processing post for headings.
58
- *
59
- * @return string
60
- */
61
- function get_ez_toc_block( $post = null, $apply_content_filter = true ) {
62
-
63
- if ( ! $post instanceof WP_Post ) {
64
-
65
- $post = get_post( $post );
66
- }
67
-
68
- if ( $apply_content_filter ) {
69
-
70
- $ezPost = new ezTOC_Post( $post );
71
-
72
- } else {
73
-
74
- $ezPost = new ezTOC_Post( $post, false );
75
- }
76
-
77
- return $ezPost->getTOC();
78
- }
79
-
80
- /**
81
- * Display the current post's TOC content or supplied post's TOC content.
82
- *
83
- * @access public
84
- * @since 2.0
85
- *
86
- * @param null|WP_Post $post An instance of WP_Post
87
- * @param bool $apply_content_filter Whether or not to apply `the_content` filter when processing post for headings.
88
- */
89
- function ez_toc_block( $post = null, $apply_content_filter = true ) {
90
-
91
- echo get_ez_toc_block( $post, $apply_content_filter );
92
- }
93
-
94
- function ez_toc_inline_styles(){
95
- echo "<style>@font-face{font-display:swap;font-family:ez-toc-icomoon;src:url('".EZ_TOC_URL."vendor/icomoon/fonts/ez-toc-icomoon.eot');src:url('".EZ_TOC_URL."vendor/icomoon/fonts/ez-toc-icomoon.eot?#iefix') format('embedded-opentype'),url('".EZ_TOC_URL."vendor/icomoon/fonts/ez-toc-icomoon.woff2') format('woff2'),url('".EZ_TOC_URL."vendor/icomoon/fonts/ez-toc-icomoon.woff') format('woff'),url('".EZ_TOC_URL."vendor/icomoon/fonts/ez-toc-icomoon.ttf') format('truetype'),url('".EZ_TOC_URL."vendor/icomoon/fonts/ez-toc-icomoon.svg#ez-toc-icomoon') format('svg');font-weight:400;font-style:normal}#ez-toc-container {background: #F9F9F9;border: 1px solid #AAAAAA;border-radius: 4px;-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);display: table;margin-bottom: 1em;padding: 10px;position: relative;width: auto;}div.ez-toc-widget-container {padding: 0;position: relative;}#ez-toc-container.ez-toc-light-blue {background: #EDF6FF;}#ez-toc-container.ez-toc-white {background: #FFFFFF;}#ez-toc-container.ez-toc-black {background: #000000;}#ez-toc-container.ez-toc-transparent {background: none transparent;}div.ez-toc-widget-container ul {display: block;}div.ez-toc-widget-container li {border: none;padding: 0;}div.ez-toc-widget-container ul.ez-toc-list {padding: 10px;}#ez-toc-container ul ul, .ez-toc div.ez-toc-widget-container ul ul {margin-left: 1.5em;}#ez-toc-container ul, #ez-toc-container li {margin: 0;padding: 0;}#ez-toc-container ul, #ez-toc-container li, #ez-toc-container ul li, div.ez-toc-widget-container, div.ez-toc-widget-container li {background: none;list-style: none none;line-height: 1.6;margin: 0;overflow: hidden;z-index: 1;}#ez-toc-container p.ez-toc-title {text-align: left;line-height: 1.45;margin: 0;padding: 0;}.ez-toc-title-container {display: table;width: 100%;}.ez-toc-title, .ez-toc-title-toggle {display: table-cell;text-align: left;vertical-align: middle;}#ez-toc-container.ez-toc-black p.ez-toc-title {color: #FFF;}#ez-toc-container div.ez-toc-title-container + ul.ez-toc-list {margin-top: 1em;}.ez-toc-wrap-left {float: left;margin-right: 10px;}.ez-toc-wrap-right {float: right;margin-left: 10px;}#ez-toc-container a {color: #444444;box-shadow: none;text-decoration: none;text-shadow: none;}#ez-toc-container a:visited {color: #9f9f9f;}#ez-toc-container a:hover {text-decoration: underline;}#ez-toc-container.ez-toc-black a {color: #FFF;}#ez-toc-container.ez-toc-black a:visited {color: #FFF;}#ez-toc-container a.ez-toc-toggle {color: #444444;}#ez-toc-container.counter-hierarchy ul, .ez-toc-widget-container.counter-hierarchy ul, #ez-toc-container.counter-flat ul, .ez-toc-widget-container.counter-flat ul {counter-reset: item;}#ez-toc-container.counter-numeric li, .ez-toc-widget-container.counter-numeric li {list-style-type: decimal;list-style-position: inside;}#ez-toc-container.counter-decimal ul.ez-toc-list li a::before, .ez-toc-widget-container.counter-decimal ul.ez-toc-list li a::before {content: counters(item, ".") ". ";display: inline-block;counter-increment: item;margin-right: .2em;}#ez-toc-container.counter-roman li a::before, .ez-toc-widget-container.counter-roman ul.ez-toc-list li a::before {content: counters(item, ".", upper-roman) ". ";counter-increment: item;}.ez-toc-widget-container ul.ez-toc-list li::before {content: ' ';position: absolute;left: 0;right: 0;height: 30px;line-height: 30px;z-index: -1;}.ez-toc-widget-container ul.ez-toc-list li.active::before {background-color: #EDEDED;}.ez-toc-widget-container li.active > a {font-weight: 900;}.ez-toc-btn {display: inline-block;padding: 6px 12px;margin-bottom: 0;font-size: 14px;font-weight: normal;line-height: 1.428571429;text-align: center;white-space: nowrap;vertical-align: middle;cursor: pointer;background-image: none;border: 1px solid transparent;border-radius: 4px;-webkit-user-select: none;-moz-user-select: none;-ms-user-select: none;-o-user-select: none;user-select: none }.ez-toc-btn:focus {outline: thin dotted #333;outline: 5px auto -webkit-focus-ring-color;outline-offset: -2px }.ez-toc-btn:hover,.ez-toc-btn:focus {color: #333;text-decoration: none }.ez-toc-btn:active,.ez-toc-btn.active {background-image: none;outline: 0;-webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);box-shadow: inset 0 3px 5px rgba(0,0,0,0.125) }.ez-toc-btn-default {color: #333;background-color: #fff;border-color: #ccc }.ez-toc-btn-default:hover,.ez-toc-btn-default:focus,.ez-toc-btn-default:active,.ez-toc-btn-default.active {color: #333;background-color: #ebebeb;border-color: #adadad }.ez-toc-btn-default:active,.ez-toc-btn-default.active {background-image: none }.ez-toc-btn-sm,.ez-toc-btn-xs {padding: 5px 10px;font-size: 12px;line-height: 1.5;border-radius: 3px }.ez-toc-btn-xs {padding: 1px 5px }.ez-toc-btn-default {text-shadow: 0 -1px 0 rgba(0,0,0,0.2);-webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);box-shadow: inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075) }.ez-toc-btn-default:active {-webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);box-shadow: inset 0 3px 5px rgba(0,0,0,0.125) }.ez-toc-btn:active,.btn.active {background-image: none }.ez-toc-btn-default {text-shadow: 0 1px 0 #fff;background-image: -webkit-gradient(linear,left 0,left 100%,from(#fff),to(#e0e0e0));background-image: -webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image: -moz-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image: linear-gradient(to bottom,#fff 0,#e0e0e0 100%);background-repeat: repeat-x;border-color: #dbdbdb;border-color: #ccc;filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe0e0e0',GradientType=0);filter: progid:DXImageTransform.Microsoft.gradient(enabled=false) }.ez-toc-btn-default:hover,.ez-toc-btn-default:focus {background-color: #e0e0e0;background-position: 0 -15px }.ez-toc-btn-default:active,.ez-toc-btn-default.active {background-color: #e0e0e0;border-color: #dbdbdb }.ez-toc-pull-right {float: right !important;margin-left: 10px;}.ez-toc-glyphicon {position: relative;top: 1px;display: inline-block;font-family: 'Glyphicons Halflings';-webkit-font-smoothing: antialiased;font-style: normal;font-weight: normal;line-height: 1;-moz-osx-font-smoothing: grayscale }.ez-toc-glyphicon:empty {width: 1em }.ez-toc-toggle i.ez-toc-glyphicon {font-size: 16px;margin-left: 2px;}[class*=\"ez-toc-icon-\"] {font-family: 'ez-toc-icomoon' !important;speak: none;font-style: normal;font-weight: normal;font-variant: normal;text-transform: none;line-height: 1;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;}.ez-toc-icon-toggle:before {content: \"\\e87a\";}#ez-toc-container input {position: absolute;left: -999em;}#ez-toc-container input[type=\"checkbox\"]:checked + nav {opacity: 0;max-height: 0;border: none;}#ez-toc-container label {float: right;position: relative;left: 3px;font-size: 16px;/* background: #f9efef; */padding: 0px 4px 0px 5px;border: 1px solid #999191;border-radius: 5px;cursor: pointer;}div#ez-toc-container p.ez-toc-title {display: contents;}div#ez-toc-container {padding-right: 20px;}#ez-toc-container label {left: 10px;}.ez-toc-wrap-center {margin: 0 auto;}#ez-toc-container.counter-hyphen ul.ez-toc-list li a::before,#ez-toc-container.counter-disc li,.ez-toc-widget-container.counter-disc li {list-style-type: disc;list-style-position: inside;}#ez-toc-container.counter-hyphen li,.ez-toc-widget-container.counter-hyphen li {list-style-type: '- ';list-style-position: inside;}#ez-toc-container a.ez-toc-toggle {color: #444444;background: inherit;border: inherit;}.ez-toc-toggle #item{position: absolute;left: -999em;}</style>";
96
- }
97
- if (ezTOC_Option::get( 'inline_css' )) {
98
- add_action('wp_head', 'ez_toc_inline_styles');
99
  }
1
+ <?php
2
+
3
+ // Exit if accessed directly
4
+ if ( ! defined( 'ABSPATH' ) ) exit;
5
+
6
+ /**
7
+ * Get the current post's TOC list or supplied post's TOC list.
8
+ *
9
+ * @access public
10
+ * @since 2.0
11
+ *
12
+ * @param int|null|WP_Post $post An instance of WP_Post or post ID. Defaults to current post.
13
+ * @param bool $apply_content_filter Whether or not to apply `the_content` filter when processing post for headings.
14
+ *
15
+ * @return string
16
+ */
17
+ function get_ez_toc_list( $post = null, $apply_content_filter = true ) {
18
+
19
+ if ( ! $post instanceof WP_Post ) {
20
+
21
+ $post = get_post( $post );
22
+ }
23
+
24
+ if ( $apply_content_filter ) {
25
+
26
+ $ezPost = new ezTOC_Post( $post );
27
+
28
+ } else {
29
+
30
+ $ezPost = new ezTOC_Post( $post, false );
31
+ }
32
+
33
+ return $ezPost->getTOCList();
34
+ }
35
+
36
+ /**
37
+ * Display the current post's TOC list or supplied post's TOC list.
38
+ *
39
+ * @access public
40
+ * @since 2.0
41
+ *
42
+ * @param null|WP_Post $post An instance of WP_Post
43
+ * @param bool $apply_content_filter Whether or not to apply `the_content` filter when processing post for headings.
44
+ */
45
+ function ez_toc_list( $post = null, $apply_content_filter = true ) {
46
+
47
+ echo get_ez_toc_list( $post, $apply_content_filter );
48
+ }
49
+
50
+ /**
51
+ * Get the current post's TOC content block or supplied post's TOC content block.
52
+ *
53
+ * @access public
54
+ * @since 2.0
55
+ *
56
+ * @param int|null|WP_Post $post An instance of WP_Post or post ID. Defaults to current post.
57
+ * @param bool $apply_content_filter Whether or not to apply `the_content` filter when processing post for headings.
58
+ *
59
+ * @return string
60
+ */
61
+ function get_ez_toc_block( $post = null, $apply_content_filter = true ) {
62
+
63
+ if ( ! $post instanceof WP_Post ) {
64
+
65
+ $post = get_post( $post );
66
+ }
67
+
68
+ if ( $apply_content_filter ) {
69
+
70
+ $ezPost = new ezTOC_Post( $post );
71
+
72
+ } else {
73
+
74
+ $ezPost = new ezTOC_Post( $post, false );
75
+ }
76
+
77
+ return $ezPost->getTOC();
78
+ }
79
+
80
+ /**
81
+ * Display the current post's TOC content or supplied post's TOC content.
82
+ *
83
+ * @access public
84
+ * @since 2.0
85
+ *
86
+ * @param null|WP_Post $post An instance of WP_Post
87
+ * @param bool $apply_content_filter Whether or not to apply `the_content` filter when processing post for headings.
88
+ */
89
+ function ez_toc_block( $post = null, $apply_content_filter = true ) {
90
+
91
+ echo get_ez_toc_block( $post, $apply_content_filter );
92
+ }
93
+
94
+ function ez_toc_inline_styles(){
95
+ echo "<style>@font-face{font-display:swap;font-family:ez-toc-icomoon;src:url('".EZ_TOC_URL."vendor/icomoon/fonts/ez-toc-icomoon.eot');src:url('".EZ_TOC_URL."vendor/icomoon/fonts/ez-toc-icomoon.eot?#iefix') format('embedded-opentype'),url('".EZ_TOC_URL."vendor/icomoon/fonts/ez-toc-icomoon.woff2') format('woff2'),url('".EZ_TOC_URL."vendor/icomoon/fonts/ez-toc-icomoon.woff') format('woff'),url('".EZ_TOC_URL."vendor/icomoon/fonts/ez-toc-icomoon.ttf') format('truetype'),url('".EZ_TOC_URL."vendor/icomoon/fonts/ez-toc-icomoon.svg#ez-toc-icomoon') format('svg');font-weight:400;font-style:normal}#ez-toc-container {background: #F9F9F9;border: 1px solid #AAAAAA;border-radius: 4px;-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);display: table;margin-bottom: 1em;padding: 10px;position: relative;width: auto;}div.ez-toc-widget-container {padding: 0;position: relative;}#ez-toc-container.ez-toc-light-blue {background: #EDF6FF;}#ez-toc-container.ez-toc-white {background: #FFFFFF;}#ez-toc-container.ez-toc-black {background: #000000;}#ez-toc-container.ez-toc-transparent {background: none transparent;}div.ez-toc-widget-container ul {display: block;}div.ez-toc-widget-container li {border: none;padding: 0;}div.ez-toc-widget-container ul.ez-toc-list {padding: 10px;}#ez-toc-container ul ul, .ez-toc div.ez-toc-widget-container ul ul {margin-left: 1.5em;}#ez-toc-container ul, #ez-toc-container li {margin: 0;padding: 0;}#ez-toc-container ul, #ez-toc-container li, #ez-toc-container ul li, div.ez-toc-widget-container, div.ez-toc-widget-container li {background: none;list-style: none none;line-height: 1.6;margin: 0;overflow: hidden;z-index: 1;}#ez-toc-container p.ez-toc-title {text-align: left;line-height: 1.45;margin: 0;padding: 0;}.ez-toc-title-container {display: table;width: 100%;}.ez-toc-title, .ez-toc-title-toggle {display: table-cell;text-align: left;vertical-align: middle;}#ez-toc-container.ez-toc-black p.ez-toc-title {color: #FFF;}#ez-toc-container div.ez-toc-title-container + ul.ez-toc-list {margin-top: 1em;}.ez-toc-wrap-left {float: left;margin-right: 10px;}.ez-toc-wrap-right {float: right;margin-left: 10px;}#ez-toc-container a {color: #444444;box-shadow: none;text-decoration: none;text-shadow: none;}#ez-toc-container a:visited {color: #9f9f9f;}#ez-toc-container a:hover {text-decoration: underline;}#ez-toc-container.ez-toc-black a {color: #FFF;}#ez-toc-container.ez-toc-black a:visited {color: #FFF;}#ez-toc-container a.ez-toc-toggle {color: #444444;}#ez-toc-container.counter-hierarchy ul, .ez-toc-widget-container.counter-hierarchy ul, #ez-toc-container.counter-flat ul, .ez-toc-widget-container.counter-flat ul {counter-reset: item;}#ez-toc-container.counter-numeric li, .ez-toc-widget-container.counter-numeric li {list-style-type: decimal;list-style-position: inside;}#ez-toc-container.counter-decimal ul.ez-toc-list li a::before, .ez-toc-widget-container.counter-decimal ul.ez-toc-list li a::before {content: counters(item, ".") ". ";display: inline-block;counter-increment: item;margin-right: .2em;}#ez-toc-container.counter-roman li a::before, .ez-toc-widget-container.counter-roman ul.ez-toc-list li a::before {content: counters(item, ".", upper-roman) ". ";counter-increment: item;}.ez-toc-widget-container ul.ez-toc-list li::before {content: ' ';position: absolute;left: 0;right: 0;height: 30px;line-height: 30px;z-index: -1;}.ez-toc-widget-container ul.ez-toc-list li.active::before {background-color: #EDEDED;}.ez-toc-widget-container li.active > a {font-weight: 900;}.ez-toc-btn {display: inline-block;padding: 6px 12px;margin-bottom: 0;font-size: 14px;font-weight: normal;line-height: 1.428571429;text-align: center;white-space: nowrap;vertical-align: middle;cursor: pointer;background-image: none;border: 1px solid transparent;border-radius: 4px;-webkit-user-select: none;-moz-user-select: none;-ms-user-select: none;-o-user-select: none;user-select: none }.ez-toc-btn:focus {outline: thin dotted #333;outline: 5px auto -webkit-focus-ring-color;outline-offset: -2px }.ez-toc-btn:hover,.ez-toc-btn:focus {color: #333;text-decoration: none }.ez-toc-btn:active,.ez-toc-btn.active {background-image: none;outline: 0;-webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);box-shadow: inset 0 3px 5px rgba(0,0,0,0.125) }.ez-toc-btn-default {color: #333;background-color: #fff;border-color: #ccc }.ez-toc-btn-default:hover,.ez-toc-btn-default:focus,.ez-toc-btn-default:active,.ez-toc-btn-default.active {color: #333;background-color: #ebebeb;border-color: #adadad }.ez-toc-btn-default:active,.ez-toc-btn-default.active {background-image: none }.ez-toc-btn-sm,.ez-toc-btn-xs {padding: 5px 10px;font-size: 12px;line-height: 1.5;border-radius: 3px }.ez-toc-btn-xs {padding: 1px 5px }.ez-toc-btn-default {text-shadow: 0 -1px 0 rgba(0,0,0,0.2);-webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);box-shadow: inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075) }.ez-toc-btn-default:active {-webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);box-shadow: inset 0 3px 5px rgba(0,0,0,0.125) }.ez-toc-btn:active,.btn.active {background-image: none }.ez-toc-btn-default {text-shadow: 0 1px 0 #fff;background-image: -webkit-gradient(linear,left 0,left 100%,from(#fff),to(#e0e0e0));background-image: -webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image: -moz-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image: linear-gradient(to bottom,#fff 0,#e0e0e0 100%);background-repeat: repeat-x;border-color: #dbdbdb;border-color: #ccc;filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe0e0e0',GradientType=0);filter: progid:DXImageTransform.Microsoft.gradient(enabled=false) }.ez-toc-btn-default:hover,.ez-toc-btn-default:focus {background-color: #e0e0e0;background-position: 0 -15px }.ez-toc-btn-default:active,.ez-toc-btn-default.active {background-color: #e0e0e0;border-color: #dbdbdb }.ez-toc-pull-right {float: right !important;margin-left: 10px;}.ez-toc-glyphicon {position: relative;top: 1px;display: inline-block;font-family: 'Glyphicons Halflings';-webkit-font-smoothing: antialiased;font-style: normal;font-weight: normal;line-height: 1;-moz-osx-font-smoothing: grayscale }.ez-toc-glyphicon:empty {width: 1em }.ez-toc-toggle i.ez-toc-glyphicon {font-size: 16px;margin-left: 2px;}[class*=\"ez-toc-icon-\"] {font-family: 'ez-toc-icomoon' !important;speak: none;font-style: normal;font-weight: normal;font-variant: normal;text-transform: none;line-height: 1;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;}.ez-toc-icon-toggle:before {content: \"\\e87a\";}#ez-toc-container input {position: absolute;left: -999em;}#ez-toc-container input[type=\"checkbox\"]:checked + nav {opacity: 0;max-height: 0;border: none;}#ez-toc-container label {float: right;position: relative;left: 3px;font-size: 16px;/* background: #f9efef; */padding: 0px 4px 0px 5px;border: 1px solid #999191;border-radius: 5px;cursor: pointer;}div#ez-toc-container p.ez-toc-title {display: contents;}div#ez-toc-container {padding-right: 20px;}#ez-toc-container label {left: 10px;}.ez-toc-wrap-center {margin: 0 auto;}#ez-toc-container.counter-hyphen ul.ez-toc-list li a::before,#ez-toc-container.counter-disc li,.ez-toc-widget-container.counter-disc li {list-style-type: disc;list-style-position: inside;}#ez-toc-container.counter-hyphen li,.ez-toc-widget-container.counter-hyphen li {list-style-type: '- ';list-style-position: inside;}#ez-toc-container a.ez-toc-toggle {color: #444444;background: inherit;border: inherit;}.ez-toc-toggle #item{position: absolute;left: -999em;}</style>";
96
+ }
97
+ if (ezTOC_Option::get( 'inline_css' )) {
98
+ add_action('wp_head', 'ez_toc_inline_styles');
99
  }
includes/inc.string-functions.php CHANGED
@@ -1,347 +1,347 @@
1
- <?php
2
-
3
- namespace Easy_Plugins\Table_Of_Contents\String;
4
-
5
- /**
6
- * Replace `<br />` tags with parameter.
7
- *
8
- * @since 2.0.8
9
- *
10
- * @param string $string
11
- * @param string $to
12
- *
13
- * @return string
14
- */
15
- function br2( $string, $to = "\r\n" ) {
16
-
17
- $string = preg_replace( '`<br[/\s]*>`i', $to, $string );
18
-
19
- return $string;
20
- }
21
-
22
- /**
23
- * Replace `<br />` tags with new lines.
24
- *
25
- * @link https://stackoverflow.com/a/27509016/5351316
26
- *
27
- * @since 2.0.8
28
- *
29
- * @param string $string
30
- *
31
- * @return string
32
- */
33
- function br2nl( $string ) {
34
-
35
- return br2( $string );
36
- }
37
-
38
- /**
39
- * Pulled from WordPress formatting functions.
40
- *
41
- * Edited to add space before self closing tags.
42
- *
43
- * @since 2.0
44
- *
45
- * @param string $text
46
- *
47
- * @return string|string[]
48
- */
49
- function force_balance_tags( $text ) {
50
- $tagstack = array();
51
- $stacksize = 0;
52
- $tagqueue = '';
53
- $newtext = '';
54
- // Known single-entity/self-closing tags
55
- $single_tags = array( 'area', 'base', 'basefont', 'br', 'col', 'command', 'embed', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param', 'source' );
56
- // Tags that can be immediately nested within themselves
57
- $nestable_tags = array( 'blockquote', 'div', 'object', 'q', 'span' );
58
-
59
- // WP bug fix for comments - in case you REALLY meant to type '< !--'
60
- $text = str_replace( '< !--', '< !--', $text );
61
- // WP bug fix for LOVE <3 (and other situations with '<' before a number)
62
- $text = preg_replace( '#<([0-9]{1})#', '&lt;$1', $text );
63
-
64
- /**
65
- * Matches supported tags.
66
- *
67
- * To get the pattern as a string without the comments paste into a PHP
68
- * REPL like `php -a`.
69
- *
70
- * @see https://html.spec.whatwg.org/#elements-2
71
- * @see https://w3c.github.io/webcomponents/spec/custom/#valid-custom-element-name
72
- *
73
- * @example
74
- * ~# php -a
75
- * php > $s = [paste copied contents of expression below including parentheses];
76
- * php > echo $s;
77
- */
78
- $tag_pattern = (
79
- '#<' . // Start with an opening bracket.
80
- '(/?)' . // Group 1 - If it's a closing tag it'll have a leading slash.
81
- '(' . // Group 2 - Tag name.
82
- // Custom element tags have more lenient rules than HTML tag names.
83
- '(?:[a-z](?:[a-z0-9._]*)-(?:[a-z0-9._-]+)+)' .
84
- '|' .
85
- // Traditional tag rules approximate HTML tag names.
86
- '(?:[\w:]+)' .
87
- ')' .
88
- '(?:' .
89
- // We either immediately close the tag with its '>' and have nothing here.
90
- '\s*' .
91
- '(/?)' . // Group 3 - "attributes" for empty tag.
92
- '|' .
93
- // Or we must start with space characters to separate the tag name from the attributes (or whitespace).
94
- '(\s+)' . // Group 4 - Pre-attribute whitespace.
95
- '([^>]*)' . // Group 5 - Attributes.
96
- ')' .
97
- '>#' // End with a closing bracket.
98
- );
99
-
100
- while ( preg_match( $tag_pattern, $text, $regex ) ) {
101
- $full_match = $regex[0];
102
- $has_leading_slash = ! empty( $regex[1] );
103
- $tag_name = $regex[2];
104
- $tag = strtolower( $tag_name );
105
- $is_single_tag = in_array( $tag, $single_tags, true );
106
- $pre_attribute_ws = isset( $regex[4] ) ? $regex[4] : '';
107
- $attributes = trim( isset( $regex[5] ) ? $regex[5] : $regex[3] );
108
- $has_self_closer = '/' === substr( $attributes, -1 );
109
-
110
- $newtext .= $tagqueue;
111
-
112
- $i = strpos( $text, $full_match );
113
- $l = strlen( $full_match );
114
-
115
- // Clear the shifter.
116
- $tagqueue = '';
117
- if ( $has_leading_slash ) { // End Tag.
118
- // If too many closing tags.
119
- if ( $stacksize <= 0 ) {
120
- $tag = '';
121
- // Or close to be safe $tag = '/' . $tag.
122
-
123
- // If stacktop value = tag close value, then pop.
124
- } elseif ( $tagstack[ $stacksize - 1 ] === $tag ) { // Found closing tag.
125
- $tag = '</' . $tag . '>'; // Close Tag.
126
- array_pop( $tagstack );
127
- $stacksize--;
128
- } else { // Closing tag not at top, search for it.
129
- for ( $j = $stacksize - 1; $j >= 0; $j-- ) {
130
- if ( $tagstack[ $j ] === $tag ) {
131
- // Add tag to tagqueue.
132
- for ( $k = $stacksize - 1; $k >= $j; $k-- ) {
133
- $tagqueue .= '</' . array_pop( $tagstack ) . '>';
134
- $stacksize--;
135
- }
136
- break;
137
- }
138
- }
139
- $tag = '';
140
- }
141
- } else { // Begin Tag.
142
- if ( $has_self_closer ) { // If it presents itself as a self-closing tag...
143
- // ...but it isn't a known single-entity self-closing tag, then don't let it be treated as such and
144
- // immediately close it with a closing tag (the tag will encapsulate no text as a result)
145
- if ( ! $is_single_tag ) {
146
- $attributes = trim( substr( $attributes, 0, -1 ) ) . "></$tag";
147
- }
148
- } elseif ( $is_single_tag ) { // ElseIf it's a known single-entity tag but it doesn't close itself, do so
149
- $pre_attribute_ws = ' ';
150
- $attributes .= 0 < strlen( $attributes ) ? ' /' : '/'; // EDIT: If there are attributes, add space before closing tag to match how WP insert br, hr and img tags.
151
- } else { // It's not a single-entity tag.
152
- // If the top of the stack is the same as the tag we want to push, close previous tag.
153
- if ( $stacksize > 0 && ! in_array( $tag, $nestable_tags, true ) && $tagstack[ $stacksize - 1 ] === $tag ) {
154
- $tagqueue = '</' . array_pop( $tagstack ) . '>';
155
- $stacksize--;
156
- }
157
- $stacksize = array_push( $tagstack, $tag );
158
- }
159
-
160
- // Attributes.
161
- if ( $has_self_closer && $is_single_tag ) {
162
- // We need some space - avoid <br/> and prefer <br />.
163
- $pre_attribute_ws = ' ';
164
- }
165
-
166
- $tag = '<' . $tag . $pre_attribute_ws . $attributes . '>';
167
- // If already queuing a close tag, then put this tag on too.
168
- if ( ! empty( $tagqueue ) ) {
169
- $tagqueue .= $tag;
170
- $tag = '';
171
- }
172
- }
173
- $newtext .= substr( $text, 0, $i ) . $tag;
174
- $text = substr( $text, $i + $l );
175
- }
176
-
177
- // Clear Tag Queue.
178
- $newtext .= $tagqueue;
179
-
180
- // Add remaining text.
181
- $newtext .= $text;
182
-
183
- while ( $x = array_pop( $tagstack ) ) {
184
- $newtext .= '</' . $x . '>'; // Add remaining tags to close.
185
- }
186
-
187
- // WP fix for the bug with HTML comments.
188
- $newtext = str_replace( '< !--', '<!--', $newtext );
189
- $newtext = str_replace( '< !--', '< !--', $newtext );
190
-
191
- return $newtext;
192
- }
193
-
194
- /**
195
- * Multibyte substr_replace(). The mbstring library does not come with a multibyte equivalent of substr_replace().
196
- * This function behaves exactly like substr_replace() even when the arguments are arrays.
197
- *
198
- * @link https://gist.github.com/stemar/8287074
199
- *
200
- * @since 2.0
201
- *
202
- * @param $string
203
- * @param $replacement
204
- * @param $start
205
- * @param null $length
206
- *
207
- * @return array|string
208
- */
209
- if ( ! function_exists( __NAMESPACE__ . '\mb_substr_replace' ) ) :
210
- function mb_substr_replace( $string, $replacement, $start, $length = null ) {
211
-
212
- if ( is_array( $string ) ) {
213
-
214
- $num = count( $string );
215
-
216
- // $replacement
217
- $replacement = is_array( $replacement ) ? array_slice( $replacement, 0, $num ) : array_pad( array( $replacement ), $num, $replacement );
218
-
219
- // $start
220
- if ( is_array( $start ) ) {
221
- $start = array_slice( $start, 0, $num );
222
- foreach ( $start as $key => $value ) {
223
- $start[ $key ] = is_int( $value ) ? $value : 0;
224
- }
225
- } else {
226
- $start = array_pad( array( $start ), $num, $start );
227
- }
228
-
229
- // $length
230
- if ( ! isset( $length ) ) {
231
- $length = array_fill( 0, $num, 0 );
232
- } elseif ( is_array( $length ) ) {
233
- $length = array_slice( $length, 0, $num );
234
- foreach ( $length as $key => $value ) {
235
- $length[ $key ] = isset( $value ) ? ( is_int( $value ) ? $value : $num ) : 0;
236
- }
237
- } else {
238
- $length = array_pad( array( $length ), $num, $length );
239
- }
240
-
241
- // Recursive call
242
- return array_map( __FUNCTION__, $string, $replacement, $start, $length );
243
- }
244
-
245
- preg_match_all( '/./us', (string) $string, $smatches );
246
- preg_match_all( '/./us', (string) $replacement, $rmatches );
247
-
248
- if ( $length === null ) {
249
-
250
- $length = mb_strlen( $string );
251
- }
252
-
253
- array_splice( $smatches[0], $start, $length, $rmatches[0] );
254
-
255
- return join( $smatches[0] );
256
- }
257
- endif;
258
- /**
259
- * Returns a string with all items from the $find array replaced with their matching
260
- * items in the $replace array. This does a one to one replacement (rather than globally).
261
- *
262
- * This function is multibyte safe.
263
- *
264
- * $find and $replace are arrays, $string is the haystack. All variables are passed by reference.
265
- *
266
- * @since 1.0
267
- *
268
- * @param bool $find
269
- * @param bool $replace
270
- * @param string $string
271
- *
272
- * @return mixed|string
273
- */
274
- if ( ! function_exists( __NAMESPACE__ . '\mb_find_replace' ) ) :
275
- function mb_find_replace( &$find = false, &$replace = false, &$string = '' ) {
276
-
277
- if ( is_array( $find ) && is_array( $replace ) && $string ) {
278
-
279
- // check if multibyte strings are supported
280
- if ( function_exists( 'mb_strpos' ) ) {
281
-
282
- //for ( $i = 0; $i < count( $find ); $i ++ ) {
283
- //
284
- // $string = mb_substr(
285
- // $string,
286
- // 0,
287
- // mb_strpos( $string, $find[ $i ] )
288
- // ) . // everything before $find
289
- // $replace[ $i ] . // its replacement
290
- // mb_substr(
291
- // $string,
292
- // mb_strpos( $string, $find[ $i ] ) + mb_strlen( $find[ $i ] )
293
- // ) // everything after $find
294
- // ;
295
- //}
296
-
297
- for ( $i = 0; $i < count( $find ); $i ++ ) {
298
-
299
- $needle = $find[ $i ];
300
- $start = mb_strpos( $string, $needle );
301
-
302
- // If heading can not be found, let try decoding entities to see if it can be found.
303
- if ( false === $start ) {
304
-
305
- $needle = html_entity_decode(
306
- $needle,
307
- ENT_QUOTES,
308
- get_option( 'blog_charset' )
309
- );
310
-
311
- $needle = str_replace(array('’','“','”'), array('\'','"','"'), $needle);
312
-
313
- $start = mb_strpos( $string, $needle );
314
- }
315
-
316
- /*
317
- * `mb_strpos()` can return `false`. Only process `mb_substr_replace()` if position in string is found.
318
- */
319
- if ( is_int( $start ) ) {
320
-
321
- $length = mb_strlen( $needle );
322
- $string = mb_substr_replace( $string, $replace[ $i ], $start, $length );
323
- }
324
-
325
- }
326
-
327
- } else {
328
-
329
- for ( $i = 0; $i < count( $find ); $i ++ ) {
330
-
331
- $start = strpos( $string, $find[ $i ] );
332
- $length = strlen( $find[ $i ] );
333
-
334
- /*
335
- * `strpos()` can return `false`. Only process `substr_replace()` if position in string is found.
336
- */
337
- if ( is_int( $start ) ) {
338
-
339
- $string = substr_replace( $string, $replace[ $i ], $start, $length );
340
- }
341
- }
342
- }
343
- }
344
-
345
- return $string;
346
- }
347
  endif;
1
+ <?php
2
+
3
+ namespace Easy_Plugins\Table_Of_Contents\String;
4
+
5
+ /**
6
+ * Replace `<br />` tags with parameter.
7
+ *
8
+ * @since 2.0.8
9
+ *
10
+ * @param string $string
11
+ * @param string $to
12
+ *
13
+ * @return string
14
+ */
15
+ function br2( $string, $to = "\r\n" ) {
16
+
17
+ $string = preg_replace( '`<br[/\s]*>`i', $to, $string );
18
+
19
+ return $string;
20
+ }
21
+
22
+ /**
23
+ * Replace `<br />` tags with new lines.
24
+ *
25
+ * @link https://stackoverflow.com/a/27509016/5351316
26
+ *
27
+ * @since 2.0.8
28
+ *
29
+ * @param string $string
30
+ *
31
+ * @return string
32
+ */
33
+ function br2nl( $string ) {
34
+
35
+ return br2( $string );
36
+ }
37
+
38
+ /**
39
+ * Pulled from WordPress formatting functions.
40
+ *
41
+ * Edited to add space before self closing tags.
42
+ *
43
+ * @since 2.0
44
+ *
45
+ * @param string $text
46
+ *
47
+ * @return string|string[]
48
+ */
49
+ function force_balance_tags( $text ) {
50
+ $tagstack = array();
51
+ $stacksize = 0;
52
+ $tagqueue = '';
53
+ $newtext = '';
54
+ // Known single-entity/self-closing tags
55
+ $single_tags = array( 'area', 'base', 'basefont', 'br', 'col', 'command', 'embed', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param', 'source' );
56
+ // Tags that can be immediately nested within themselves
57
+ $nestable_tags = array( 'blockquote', 'div', 'object', 'q', 'span' );
58
+
59
+ // WP bug fix for comments - in case you REALLY meant to type '< !--'
60
+ $text = str_replace( '< !--', '< !--', $text );
61
+ // WP bug fix for LOVE <3 (and other situations with '<' before a number)
62
+ $text = preg_replace( '#<([0-9]{1})#', '&lt;$1', $text );
63
+
64
+ /**
65
+ * Matches supported tags.
66
+ *
67
+ * To get the pattern as a string without the comments paste into a PHP
68
+ * REPL like `php -a`.
69
+ *
70
+ * @see https://html.spec.whatwg.org/#elements-2
71
+ * @see https://w3c.github.io/webcomponents/spec/custom/#valid-custom-element-name
72
+ *
73
+ * @example
74
+ * ~# php -a
75
+ * php > $s = [paste copied contents of expression below including parentheses];
76
+ * php > echo $s;
77
+ */
78
+ $tag_pattern = (
79
+ '#<' . // Start with an opening bracket.
80
+ '(/?)' . // Group 1 - If it's a closing tag it'll have a leading slash.
81
+ '(' . // Group 2 - Tag name.
82
+ // Custom element tags have more lenient rules than HTML tag names.
83
+ '(?:[a-z](?:[a-z0-9._]*)-(?:[a-z0-9._-]+)+)' .
84
+ '|' .
85
+ // Traditional tag rules approximate HTML tag names.
86
+ '(?:[\w:]+)' .
87
+ ')' .
88
+ '(?:' .
89
+ // We either immediately close the tag with its '>' and have nothing here.
90
+ '\s*' .
91
+ '(/?)' . // Group 3 - "attributes" for empty tag.
92
+ '|' .
93
+ // Or we must start with space characters to separate the tag name from the attributes (or whitespace).
94
+ '(\s+)' . // Group 4 - Pre-attribute whitespace.
95
+ '([^>]*)' . // Group 5 - Attributes.
96
+ ')' .
97
+ '>#' // End with a closing bracket.
98
+ );
99
+
100
+ while ( preg_match( $tag_pattern, $text, $regex ) ) {
101
+ $full_match = $regex[0];
102
+ $has_leading_slash = ! empty( $regex[1] );
103
+ $tag_name = $regex[2];
104
+ $tag = strtolower( $tag_name );
105
+ $is_single_tag = in_array( $tag, $single_tags, true );
106
+ $pre_attribute_ws = isset( $regex[4] ) ? $regex[4] : '';
107
+ $attributes = trim( isset( $regex[5] ) ? $regex[5] : $regex[3] );
108
+ $has_self_closer = '/' === substr( $attributes, -1 );
109
+
110
+ $newtext .= $tagqueue;
111
+
112
+ $i = strpos( $text, $full_match );
113
+ $l = strlen( $full_match );
114
+
115
+ // Clear the shifter.
116
+ $tagqueue = '';
117
+ if ( $has_leading_slash ) { // End Tag.
118
+ // If too many closing tags.
119
+ if ( $stacksize <= 0 ) {
120
+ $tag = '';
121
+ // Or close to be safe $tag = '/' . $tag.
122
+
123
+ // If stacktop value = tag close value, then pop.
124
+ } elseif ( $tagstack[ $stacksize - 1 ] === $tag ) { // Found closing tag.
125
+ $tag = '</' . $tag . '>'; // Close Tag.
126
+ array_pop( $tagstack );
127
+ $stacksize--;
128
+ } else { // Closing tag not at top, search for it.
129
+ for ( $j = $stacksize - 1; $j >= 0; $j-- ) {
130
+ if ( $tagstack[ $j ] === $tag ) {
131
+ // Add tag to tagqueue.
132
+ for ( $k = $stacksize - 1; $k >= $j; $k-- ) {
133
+ $tagqueue .= '</' . array_pop( $tagstack ) . '>';
134
+ $stacksize--;
135
+ }
136
+ break;
137
+ }
138
+ }
139
+ $tag = '';
140
+ }
141
+ } else { // Begin Tag.
142
+ if ( $has_self_closer ) { // If it presents itself as a self-closing tag...
143
+ // ...but it isn't a known single-entity self-closing tag, then don't let it be treated as such and
144
+ // immediately close it with a closing tag (the tag will encapsulate no text as a result)
145
+ if ( ! $is_single_tag ) {
146
+ $attributes = trim( substr( $attributes, 0, -1 ) ) . "></$tag";
147
+ }
148
+ } elseif ( $is_single_tag ) { // ElseIf it's a known single-entity tag but it doesn't close itself, do so
149
+ $pre_attribute_ws = ' ';
150
+ $attributes .= 0 < strlen( $attributes ) ? ' /' : '/'; // EDIT: If there are attributes, add space before closing tag to match how WP insert br, hr and img tags.
151
+ } else { // It's not a single-entity tag.
152
+ // If the top of the stack is the same as the tag we want to push, close previous tag.
153
+ if ( $stacksize > 0 && ! in_array( $tag, $nestable_tags, true ) && $tagstack[ $stacksize - 1 ] === $tag ) {
154
+ $tagqueue = '</' . array_pop( $tagstack ) . '>';
155
+ $stacksize--;
156
+ }
157
+ $stacksize = array_push( $tagstack, $tag );
158
+ }
159
+
160
+ // Attributes.
161
+ if ( $has_self_closer && $is_single_tag ) {
162
+ // We need some space - avoid <br/> and prefer <br />.
163
+ $pre_attribute_ws = ' ';
164
+ }
165
+
166
+ $tag = '<' . $tag . $pre_attribute_ws . $attributes . '>';
167
+ // If already queuing a close tag, then put this tag on too.
168
+ if ( ! empty( $tagqueue ) ) {
169
+ $tagqueue .= $tag;
170
+ $tag = '';
171
+ }
172
+ }
173
+ $newtext .= substr( $text, 0, $i ) . $tag;
174
+ $text = substr( $text, $i + $l );
175
+ }
176
+
177
+ // Clear Tag Queue.
178
+ $newtext .= $tagqueue;
179
+
180
+ // Add remaining text.
181
+ $newtext .= $text;
182
+
183
+ while ( $x = array_pop( $tagstack ) ) {
184
+ $newtext .= '</' . $x . '>'; // Add remaining tags to close.
185
+ }
186
+
187
+ // WP fix for the bug with HTML comments.
188
+ $newtext = str_replace( '< !--', '<!--', $newtext );
189
+ $newtext = str_replace( '< !--', '< !--', $newtext );
190
+
191
+ return $newtext;
192
+ }
193
+
194
+ /**
195
+ * Multibyte substr_replace(). The mbstring library does not come with a multibyte equivalent of substr_replace().
196
+ * This function behaves exactly like substr_replace() even when the arguments are arrays.
197
+ *
198
+ * @link https://gist.github.com/stemar/8287074
199
+ *
200
+ * @since 2.0
201
+ *
202
+ * @param $string
203
+ * @param $replacement
204
+ * @param $start
205
+ * @param null $length
206
+ *
207
+ * @return array|string
208
+ */
209
+ if ( ! function_exists( __NAMESPACE__ . '\mb_substr_replace' ) ) :
210
+ function mb_substr_replace( $string, $replacement, $start, $length = null ) {
211
+
212
+ if ( is_array( $string ) ) {
213
+
214
+ $num = count( $string );
215
+
216
+ // $replacement
217
+ $replacement = is_array( $replacement ) ? array_slice( $replacement, 0, $num ) : array_pad( array( $replacement ), $num, $replacement );
218
+
219
+ // $start
220
+ if ( is_array( $start ) ) {
221
+ $start = array_slice( $start, 0, $num );
222
+ foreach ( $start as $key => $value ) {
223
+ $start[ $key ] = is_int( $value ) ? $value : 0;
224
+ }
225
+ } else {
226
+ $start = array_pad( array( $start ), $num, $start );
227
+ }
228
+
229
+ // $length
230
+ if ( ! isset( $length ) ) {
231
+ $length = array_fill( 0, $num, 0 );
232
+ } elseif ( is_array( $length ) ) {
233
+ $length = array_slice( $length, 0, $num );
234
+ foreach ( $length as $key => $value ) {
235
+ $length[ $key ] = isset( $value ) ? ( is_int( $value ) ? $value : $num ) : 0;
236
+ }
237
+ } else {
238
+ $length = array_pad( array( $length ), $num, $length );
239
+ }
240
+
241
+ // Recursive call
242
+ return array_map( __FUNCTION__, $string, $replacement, $start, $length );
243
+ }
244
+
245
+ preg_match_all( '/./us', (string) $string, $smatches );
246
+ preg_match_all( '/./us', (string) $replacement, $rmatches );
247
+
248
+ if ( $length === null ) {
249
+
250
+ $length = mb_strlen( $string );
251
+ }
252
+
253
+ array_splice( $smatches[0], $start, $length, $rmatches[0] );
254
+
255
+ return join( $smatches[0] );
256
+ }
257
+ endif;
258
+ /**
259
+ * Returns a string with all items from the $find array replaced with their matching
260
+ * items in the $replace array. This does a one to one replacement (rather than globally).
261
+ *
262
+ * This function is multibyte safe.
263
+ *
264
+ * $find and $replace are arrays, $string is the haystack. All variables are passed by reference.
265
+ *
266
+ * @since 1.0
267
+ *
268
+ * @param bool $find
269
+ * @param bool $replace
270
+ * @param string $string
271
+ *
272
+ * @return mixed|string
273
+ */
274
+ if ( ! function_exists( __NAMESPACE__ . '\mb_find_replace' ) ) :
275
+ function mb_find_replace( &$find = false, &$replace = false, &$string = '' ) {
276
+
277
+ if ( is_array( $find ) && is_array( $replace ) && $string ) {
278
+
279
+ // check if multibyte strings are supported
280
+ if ( function_exists( 'mb_strpos' ) ) {
281
+
282
+ //for ( $i = 0; $i < count( $find ); $i ++ ) {
283
+ //
284
+ // $string = mb_substr(
285
+ // $string,
286
+ // 0,
287
+ // mb_strpos( $string, $find[ $i ] )
288
+ // ) . // everything before $find
289
+ // $replace[ $i ] . // its replacement
290
+ // mb_substr(
291
+ // $string,
292
+ // mb_strpos( $string, $find[ $i ] ) + mb_strlen( $find[ $i ] )
293
+ // ) // everything after $find
294
+ // ;
295
+ //}
296
+
297
+ for ( $i = 0; $i < count( $find ); $i ++ ) {
298
+
299
+ $needle = $find[ $i ];
300
+ $start = mb_strpos( $string, $needle );
301
+
302
+ // If heading can not be found, let try decoding entities to see if it can be found.
303
+ if ( false === $start ) {
304
+
305
+ $needle = html_entity_decode(
306
+ $needle,
307
+ ENT_QUOTES,
308
+ get_option( 'blog_charset' )
309
+ );
310
+
311
+ $needle = str_replace(array('’','“','”'), array('\'','"','"'), $needle);
312
+
313
+ $start = mb_strpos( $string, $needle );
314
+ }
315
+
316
+ /*
317
+ * `mb_strpos()` can return `false`. Only process `mb_substr_replace()` if position in string is found.
318
+ */
319
+ if ( is_int( $start ) ) {
320
+
321
+ $length = mb_strlen( $needle );
322
+ $string = mb_substr_replace( $string, $replace[ $i ], $start, $length );
323
+ }
324
+
325
+ }
326
+
327
+ } else {
328
+
329
+ for ( $i = 0; $i < count( $find ); $i ++ ) {
330
+
331
+ $start = strpos( $string, $find[ $i ] );
332
+ $length = strlen( $find[ $i ] );
333
+
334
+ /*
335
+ * `strpos()` can return `false`. Only process `substr_replace()` if position in string is found.
336
+ */
337
+ if ( is_int( $start ) ) {
338
+
339
+ $string = substr_replace( $string, $replace[ $i ], $start, $length );
340
+ }
341
+ }
342
+ }
343
+ }
344
+
345
+ return $string;
346
+ }
347
  endif;