Easy Table of Contents - Version 2.0.24.1

Version Description

06/14/2022 = * BUG: TOC not displaying properly when initial view option is disabled #195 * BUG: Initial View option not working with Pure CSS Loading Method #194

Download this release

Release Info

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

Code changes from version 2.0.20 to 2.0.24.1

README.txt CHANGED
@@ -1,495 +1,522 @@
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: 5.9.3
7
- Requires PHP: 5.6.20
8
- Stable tag: 2.0.20
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 CHAT 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.20 05/05/2022 =
101
- * TWEAK: Added Toggle with CSS for websites runs without jQuery #153
102
- * TWEAK: Added telegram group join link for suggestions and feedback #159
103
- * BUG: TOC links not jumping in some posts which have special characters #163
104
- * BUG: Incorrect email ID updated in the plugin #165
105
- * BUG: Proper documentation added for adding TOC with shortcodes & do_shortcode #152
106
- * BUG: TOC links not working when do_shortcode added directly in the template #147
107
- * BUG: TOC links not working with some specical character with Elementor #162
108
-
109
- = 2.0.19 04/16/2022 =
110
- * Bug Fixed : While Using Elementor Page builder TOC is not working when special characters are used in headings. #150
111
- * Bug Fixed : Need to load CSS/JS files only on the selected post types. #154
112
-
113
- = 2.0.18 03/29/2022 =
114
- * TWEAK: Added Technical Support Tab in Settings Panel.
115
-
116
- = 2.0.17 03/26/2021 =
117
- * TWEAK: Add additional check to prevent `Uncaught Error: Call to undefined function is_woocommerce()`.
118
- * TWEAK: Ensure an instance of `ezTOC_Post ` is returned before accessing methods/properties.
119
-
120
- = 2.0.16 02/01/2021 =
121
- * TWEAK: Remove special characters such as fancy quotes, en and, em dashes when generating in-page anchor IDs.
122
-
123
- = 2.0.15 01/27/2021 =
124
- * TWEAK: Remove additional reserved characters when generating in-page anchor IDs.
125
-
126
- = 2.0.14 01/26/2021 =
127
- * TWEAK: Refactor debug log as a Singleton.
128
- * TWEAK: Add additional logging to aid in debugging.
129
- * BUG: Correct logic for PHP where empty string no longer evaluates as integer `0`.
130
-
131
- = 2.0.13 01/25/2021 =
132
- * TWEAK: Restrict debug logging to when `WP_DEBUG` is enabled *and* current user capability of `manage_options`.
133
- * TWEAK: Add logging to aid in support.
134
- * DEV: phpDoc update.
135
-
136
- = 2.0.12 01/22/2021 =
137
- * TWEAK: Allow `_` and `-` in anchors.
138
- * TWEAK: Minor CSS tweaks that prevent theme from breaking the layout.
139
- * TWEAK: Minor tweak to class initialization.
140
- * TWEAK: Do not display the view toggle if JavaScript is broken on the site.
141
- * TWEAK: Add the ability to enable displaying of displaying debug information on the page.
142
- * BUG: Check for array and keys before accessing values.
143
- * BUG: Check for array key be fore access.
144
- * BUG: Remove reserved characters when generating in-page anchor IDs.
145
- * DEV: Remove unnecessary vendor library files.
146
- * DEV: Deal with phpStorm showing a warning about path not found when including files.
147
-
148
- = 2.0.11 05/01/2020 =
149
- * COMPATIBILITY: Add support for the Uncode theme.
150
- * COMPATIBILITY: Do not run on WooCommerce pages.
151
- * DEV: Correct typo in phpDoc.
152
-
153
- = 2.0.10 04/20/2020 =
154
- * TWEAK: Add trailing `span` to heading, to prepare for `#` option and to fix duplicate heading title matching.
155
- * 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.
156
-
157
-
158
- = 2.0.9 04/08/2020 =
159
- * TWEAK: AMP/Caching plugins seems to break anchors with colons and periods even though they are valid characters for the id attribute in HTML5.
160
- * TWEAK: Replace multiple underscores with a single underscore.
161
- * DEV: Update the UWS library which fixes the deprecation notice for PHP 7.4.
162
- * DEV: Add phpcs.xml.dist.
163
- * DEV: Strict type checks.
164
- * DEV: Inline doc updates.
165
-
166
- = 2.0.8 04/03/2020 =
167
- * TWEAK: Convert `<br />` tags in headings to a space.
168
- * TWEAK: Add additional widget classes.
169
- * TWEAK: Improve the sanitization of the excluded headings field post setting.
170
- * TWEAK: Minor optimization of creating the matching pattern for excluding headings for improved performance.
171
- * COMPATIBILITY: Exclude Create by Mediavine from heading eligibility.
172
- * BUG: Ensure excluded headings are removed from the headings array.
173
- * BUG: Ensure empty headings are removed from the headings array.
174
-
175
- = 2.0.7 04/02/2020 =
176
- * NEW: Exclude any HTML nodes with the class of `.ez-toc-exclude-headings`.
177
- * TWEAK: Change smooth scroll selector from `'body a'` to `'a.ez-toc-link'`.
178
- * TWEAK: Declare JS variables.
179
- * TWEAK: Support unicode characters for the `id` attribute. Permitted by HTML5.
180
- * TWEAK: Move the in-page anchor/span to before the heading text to account for long headings where it line wraps.
181
- * TWEAK: Slight rework to ezTOC widget container classes logic.
182
- * TWEAK: Cache bust the JS to make dev easier.
183
- * TWEAK: JavaScript cleanup.
184
- * 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.
185
- * COMPATIBILITY: Reintroduce filter to exclude Ultimate Addons for VC Composer Tabs from heading eligibility.
186
- * BUG: Correct array iteration logic when processing headings.
187
- * BUG: Tighten matching for headings in excluded HTML nodes. The loose matching was excluding far too many headings.
188
- * 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.
189
-
190
- = 2.0.6 03/30/2020 =
191
- * BUG: Ensure minified files are current.
192
-
193
- = 2.0.5 03/27/2020 =
194
- * BUG: Prevent possible "strpos(): Empty needle in" warnings when excluding nodes from TOC eligibility.
195
-
196
- = 2.0.4 03/16/2020 =
197
- * NEW: Introduce the `ez_toc_container_class` filter.
198
- * TWEAK: Slight rework to ezTOC container classes logic.
199
- * BUG: `sprintf()` was eating `%` in the TOC heading item.
200
- * 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.
201
-
202
- = 2.0.3 03/12/2020 =
203
- * TWEAK: Slightly tighten heading matching, last update made it a little too loose.
204
- * BUG: Correct logic required to place TOC before first heading which is required for the more lax heading matching required for page builders.
205
-
206
- = 2.0.2 03/12/2020 =
207
- * COMPATIBILITY: Remove filter to exclude Ultimate Addons for VC Composer Tabs from heading eligibility.
208
- * COMPATIBILITY: Add additional filters to improve Elementor compatibility.
209
- * 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.
210
-
211
- = 2.0.1 03/09/2020 =
212
- * COMPATIBILITY: Exclude the WordPress Related Posts plugin nodes.
213
- * COMPATIBILITY: Exclude a couple Atomic Block plugin nodes.
214
- * COMPATIBILITY: Exclude JetPack Related Posts from heading eligibility.
215
- * COMPATIBILITY: Exclude Ultimate Addons for VC Composer Tabs from heading eligibility.
216
- * COMPATIBILITY: Exclude WP Product Reviews from heading eligibility.
217
- * TWEAK: Prevent possible "strpos(): Empty needle in" warnings when excluding nodes from TOC eligibility.
218
-
219
- = 2.0 02/01/2020 =
220
- * NEW: Major rewrite of all code and processing logic to make it faster and more reliable.
221
- * NEW: Support for the <!--nextpage--> tag.
222
- * NEW: Introduce helper functions for devs.
223
- * NEW: Support WPML.
224
- * NEW: Support Polylang.
225
- * NEW: Add filter to support the Rank Math plugin.
226
- * NEW: Introduce the `ez_toc_maybe_apply_the_content_filter` filter.
227
- * TWEAK: Improve translation compatibility.
228
- * TWEAK: Rework widget logic to allow multi-line TOC items, improve active item highlighting while removing the use of the jQuery Waypoints library.
229
- * TWEAK Add additional classes to TOC list items.
230
- * TWEAK: Add WOFF2 format for icon format and change font references in CSS.
231
- * TWEAK: Add font-display: swap for toggle icon.
232
- * TWEAK: Update JS Cookie to 2.2.1.
233
- * TWEAK: Update jQuery Smooth Scroll to 2.2.0.
234
- * TWEAK: Allow forward slash and angle brackets in headings and alternate headings.
235
- * TWEAK: Allow forward slash in excluded headings.
236
- * TWEAK: Remove new line/returns when matching excluded headings.
237
- * TWEAK: Simple transient cache to ensure a post is only processed once per request for a TOC.
238
- * TWEAK: Improve sanitization of alternate headings field value.
239
- * TWEAK: Deal with non-breaking-spaces in alternate headings.
240
- * TWEAK: Add the ability to exclude by selector content eligible to be included in the TOC.
241
- * TWEAK: Change the shortcode priority to a higher value.
242
- * 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.
243
- * TWEAK: Add compatibility filters to remove shortcodes for Connections and Striking theme to remove them from eligible TOC item content.
244
- * TWEAK: Do not execute if root current filter is the `wp_head` or `get_the_excerpt` filters.
245
- * TWEAK: Add filter to exclude content by selector.
246
- * TWEAK: Move in-page anchor to after the heading instead of wrapping the heading to prevent conflicts with theme styling.
247
- * TWEAK: Utilize the `ez_toc_exclude_by_selector` filter the exclude the JetPack share buttons from eligible headings.
248
- * TWEAK: Remove the Elegant Themes Bloom plugin node from the post content before extracting headings.
249
- * TWEAK: Add compatibility filter for the Visual Composer plugin.
250
- * TWEAK: Utilize the `ez_toc_exclude_by_selector` filter the exclude the Starbox author heading from eligible headings.
251
- * I18N: Add wpml-config.xml file.
252
- * BUG: Correct option misspelling.
253
- * BUG: Do not need to run values for alternate and exclude headings thru `wp_unslash()` because `update_post_meta()` already does.
254
- * BUG: Do not need to run `stripslashes()` when escaping the alternate heading value.
255
- * BUG: Sanitize the excluded heading string before saving post meta.
256
- * DEV: Change PHP keywords to comply with PSR2.
257
- * DEV:Bump minimum PHP version to 5.6.20 which matches WP core.
258
-
259
- = 1.7 05/09/2018 =
260
- * NEW: Introduce the `ez_toc_shortcode` filter.
261
- * TWEAK: Fix notices due to late eligibility check. props unixtam
262
- * TWEAK: Tweak eligibility check to support the TOC widget.
263
- * TWEAK: Prefix a few CSS classes in order to prevent collisions with theme's and other plugins.
264
- * TWEAK: Avoid potential PHP notice in admin when saving the post by checking for nonce before validating it.
265
- * TWEAK: Using the shortcode now overrides global options.
266
- * TWEAK: `the_content()` now caches result of `is_eligible()`.
267
- * TWEAK: Refactor to pass the WP_Post object internally vs. accessing it via the `$wp_query->post` which may not in all cases exist.
268
- * TWEAK: Use `pre_replace()` to replace one or more spaces with an underscore.
269
- * TWEAK: Return original title in the `ez_toc_url_anchor_target` filter.
270
- * TWEAK: Strip `&nbsp;`, replacing it with a space character.
271
- * TWEAK: Minor tweaks to the in page URL creating.
272
- * TWEAK: Wrap TOC list in a nav element.
273
- * TWEAK: Init plugin on the `plugins_loaded` hook.
274
- * TWEAK: Tweak the minimum number of headers to 1.
275
- * BUG: The header options from the post meta should be used when building the TOC hierarchy, not the header options from the global settings.
276
- * BUG: Do not double escape field values.
277
- * BUG: Ensure Apostrophe / Single quote use in Exclude Headings work.
278
- * OTHER: Update CSS to include the newly prefixed classes.
279
- * DEV: Remove some commented out unused code.
280
-
281
- = 1.6.1 03/16/2018 =
282
- * TWEAK: Revert change made to allow HTML added via the `ez_toc_title` filter as it caused undesirable side effects.
283
- * BUG: Ensure Smooth Scroll Offset is parsed as an integer.
284
-
285
- = 1.6 03/15/2018 =
286
- * NEW: Add `px` option for font size unit.
287
- * NEW: Add title font size and weight settings options.
288
- * NEW: Add the Mobile Smooth Scroll Offset option.
289
- * TWEAK: Change default for font size unit from `px` to `%` to match the default options values.
290
- * TWEAK: Correct CSS selector so margin is properly applied between the title and TOC items.
291
- * TWEAK: Honor HTML added via `ez_toc_title` filter.
292
- * TWEAK: Ensure the ezTOC content filter is not applied when running `the_content` filter.
293
- * TWEAK: Only enqueue the javascript if the page is eligible for a TOC.
294
- * TWEAK: Update icomoon CSS to remove unecessary CSS selectors to prevent possible conflicts.
295
- * TWEAK: The smooth scroll offset needs to be taken into account when defining the offset_top property when affixing the widget.
296
- * OTHER: Update frontend minified CSS file.
297
- * OTHER: Update the frontend minified javascript file.
298
- * DEV: phpDoc corrections.
299
-
300
- = 1.5 02/20/2018 =
301
- * BUG: Correct CSS selector to properly target the link color.
302
- * OTHER: Update the WayPoints library.
303
- * DEV: Add a couple @todo's.
304
-
305
- = 1.4 01/29/2018 =
306
- * TWEAK: Change text domain from ez_toc to easy-table-of-contents.
307
- * TWEAK: Rename translation files with correct text domain.
308
- * BUG: Ensure page headers are processed to add the in page header link when using the shortcodes.
309
- * BUG: Add forward slash to domain path in the plugin header.
310
- * I18N: Update POT file.
311
- * I18N: Update Dutch (nl_NL) translation.
312
-
313
- = 1.3 12/18/2017 =
314
- * FEATURE: Add support for the `[ez-toc]` shortcode.
315
- * NEW: For backwards compatibility with "Table of Content Plus", register the `[toc]` shortcode.
316
- * NEW: Introduce the `ez_toc_extract_headings_content` filter.
317
- * TWEAK: Update the tested to and required readme header text.
318
- * TWEAK: Do not show the widget on the 404, archive, search and posts pages.
319
- * I18N: Add the nl_NL translation.
320
-
321
- = 1.2 04/29/2016 =
322
- * TWEAK: Remove the font family from styling the TOC title header.
323
- * TWEAK: Pass the raw title to the `ez_toc_title` filter.
324
- * BUG: A jQuery 1.12 fix for WordPress 4.5.
325
-
326
- = 1.1 02/24/2016 =
327
- * FEATURE: Add option to replace header wither alternate header text in the table of content.
328
- * NEW: Introduce the ez_toc_filter.
329
- * NEW: Introduce ezTOC_Option::textarea() to render textareas.
330
- * NEW: Introduce array_search_deep() to recursively search an array for a value.
331
- * TWEAK: Run table of contents headers thru wp_kses_post().
332
- * TWEAK: Escape URL.
333
- * TWEAK: Count excluded headings only once instead of multiple times.
334
- * TWEAK: Escape translated string before rendering.
335
- * TWEAK: Use wp_unslash() instead of stripslashes().
336
- * TWEAK: Escape translated string.
337
- * BUG: Fix restrict path logic.
338
- * OTHER: Readme tweaks.
339
- * I18N: Add POT file.
340
- * I18N: Add Dutch translation.
341
- * DEV: Update .gitignore to allow PO files.
342
- * DEV: phpDoc fix.
343
-
344
- = 1.0 09/08/2015 =
345
- * Initial release.
346
- - 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.
347
- - Update all third party libraries.
348
- - Make much better use of the WordPress Settings API.
349
- - Minified CSS and JS files are used by default. Using SCRIPT_DEBUG will use the un-minified versions.
350
- - Add substantial amounts of phpDoc for developers.
351
- - Add many hooks to permit third party integrations.
352
- - Widget can be affixed/stuck to the page so it is always visible.
353
- - Widget will highlight the table of content sections that are currently visible in the browser viewport.
354
- - Widget will now generate table of contents using output from third party shortcodes.
355
- - Use wpColorPicker instead of farbtastic.
356
- - Remove all shortcodes.
357
- - Per post options are saved in post meta instead of set by shortcode.
358
-
359
- == Frequently Asked Questions ==
360
-
361
- = Ok, I've installed this... what do I do next? =
362
-
363
- You first stop should be the Table of Contents settings admin page. You can find this under the Settings menu item.
364
-
365
- 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 :)
366
-
367
- 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.
368
-
369
- = How are the tables of contents created? =
370
-
371
- 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.
372
-
373
- `<h1>Item 1</h1>
374
- <h1>Item 2</h1>
375
- <h1>Item 3</h1>
376
- <h1>Item 4</h1>
377
- <h1>Item 5</h1>
378
- <h1>Item 6</h1>`
379
-
380
- 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.
381
-
382
- `<h1>Item 1</h1>
383
- <h2>Item 1.1 -- Level 2</h2>
384
- <h1>Item 2</h1>
385
- <h2>Item 2.1 -- Level 2</h2>
386
- <h1>Item 3</h1>
387
- <h2>Item 3.1 -- Level 2</h2>
388
- <h1>Item 4</h1>
389
- <h1>Item 5</h1>
390
- <h1>Item 6</h1>`
391
-
392
- 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...
393
-
394
- `<h1>Item 1</h1>
395
- <h2>Item 1.1 -- Level 2</h2>
396
- <h3>Item 1.1.1 -- Level 3</h3>
397
- <h3>Item 1.1.2 -- Level 3</h3>
398
- <h3>Item 1.1.3 -- Level 3</h3>
399
- <h2>Item 1.2 -- Level 2</h2>
400
- <h3>Item 1.2.1 -- Level 3</h3>
401
- <h3>Item 1.2.2 -- Level 3</h3>
402
- <h3>Item 1.2.3 -- Level 3</h3>
403
- <h2>Item 1.3 -- Level 2</h2>
404
- <h1>Item 2</h1>
405
- <h2>Item 2.1 -- Level 2</h2>
406
- <h2>Item 2.2 -- Level 2</h2>
407
- <h1>Item 3</h1>
408
- <h2>Item 3.1 -- Level 2</h2>
409
- <h2>Item 3.2 -- Level 2</h2>
410
- <h1>Item 4</h1>
411
- <h1>Item 5</h1>
412
- <h1>Item 6</h1>`
413
-
414
- 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!
415
-
416
- = Is there any shortcode to add the table of content to anywhere I want ? =
417
-
418
- 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.
419
-
420
- == Upgrade Notice ==
421
-
422
- = 1.0 =
423
- Initial release.
424
-
425
- = 1.3 =
426
- Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
427
-
428
- = 1.4 =
429
- Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
430
-
431
- = 1.5 =
432
- Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
433
-
434
- = 1.6 =
435
- Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
436
-
437
- = 1.6.1 =
438
- Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
439
-
440
- = 1.7 =
441
- Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
442
-
443
- = 2.0-rc4 =
444
- Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
445
-
446
- = 2.0.1 =
447
- Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
448
-
449
- = 2.0.2 =
450
- Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
451
-
452
- = 2.0.3 =
453
- Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
454
-
455
- = 2.0.4 =
456
- Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
457
-
458
- = 2.0.5 =
459
- Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
460
-
461
- = 2.0.6 =
462
- Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
463
-
464
- = 2.0.7 =
465
- Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
466
-
467
- = 2.0.8 =
468
- Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
469
-
470
- = 2.0.9 =
471
- Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
472
-
473
- = 2.0.10 =
474
- Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
475
-
476
- = 2.0.11 =
477
- Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
478
-
479
- = 2.0.12 =
480
- Requires WordPress >= 5.3 and PHP version >= 5.6.20 (>= 7.4 is recommended).
481
-
482
- = 2.0.13 =
483
- Requires WordPress >= 5.3 and PHP version >= 5.6.20 (>= 7.4 is recommended).
484
-
485
- = 2.0.14 =
486
- Requires WordPress >= 5.3 and PHP version >= 5.6.20 (>= 7.4 is recommended).
487
-
488
- = 2.0.15 =
489
- Requires WordPress >= 5.3 and PHP version >= 5.6.20 (>= 7.4 is recommended).
490
-
491
- = 2.0.16 =
492
- Requires WordPress >= 5.3 and PHP version >= 5.6.20 (>= 7.4 is recommended).
493
-
494
- = 2.0.17 =
495
- 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.24.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.24.1 06/14/2022 =
101
+ * BUG: TOC not displaying properly when initial view option is disabled #195
102
+ * BUG: Initial View option not working with Pure CSS Loading Method #194
103
+
104
+ = 2.0.24 06/10/2022 =
105
+ * TWEAK: Added TOC in Infinite Scroll #138
106
+ * TWEAK: Improved the activation process #187
107
+ * BUG: TOC Toggle not working with Magnolia Theme #174
108
+ * BUG: Initial view not working with TOC Loading Method of CSS #179
109
+ * BUG: Toggle is not visible when Display Header option is disable #171
110
+ * BUG: CSS not loading when using shortcode in theme file #175
111
+ * BUG: the_content filter run twice #182
112
+ * BUG: Form UI looks ugly #169
113
+ * BUG: Debug Warnings in multibyte string functions #185
114
+
115
+ = 2.0.23 05/31/2022 =
116
+ * TWEAK: Added filter to modify anchor links #167
117
+ * TWEAK: Added filter to add TOC before or after the sidebar widget #166
118
+ * TWEAK: Added option to align TOC to center #158
119
+ * TWEAK: Design improvements in options panel #172
120
+
121
+ = 2.0.22 05/06/2022 =
122
+ * BUG: Double hyphens are getting removed from content issue fixed #163
123
+
124
+ = 2.0.21 05/06/2022 =
125
+ * BUG: Critical error fixed #147
126
+
127
+ = 2.0.20 05/05/2022 =
128
+ * TWEAK: Added Toggle with CSS for websites runs without jQuery #153
129
+ * TWEAK: Added telegram group join link for suggestions and feedback #159
130
+ * BUG: TOC links not jumping in some posts which have special characters #163
131
+ * BUG: Incorrect email ID updated in the plugin #165
132
+ * BUG: Proper documentation added for adding TOC with shortcodes & do_shortcode #152
133
+ * BUG: TOC links not working when do_shortcode added directly in the template #147
134
+ * BUG: TOC links not working with some specical character with Elementor #162
135
+
136
+ = 2.0.19 04/16/2022 =
137
+ * Bug Fixed : While Using Elementor Page builder TOC is not working when special characters are used in headings. #150
138
+ * Bug Fixed : Need to load CSS/JS files only on the selected post types. #154
139
+
140
+ = 2.0.18 03/29/2022 =
141
+ * TWEAK: Added Technical Support Tab in Settings Panel.
142
+
143
+ = 2.0.17 03/26/2021 =
144
+ * TWEAK: Add additional check to prevent `Uncaught Error: Call to undefined function is_woocommerce()`.
145
+ * TWEAK: Ensure an instance of `ezTOC_Post ` is returned before accessing methods/properties.
146
+
147
+ = 2.0.16 02/01/2021 =
148
+ * TWEAK: Remove special characters such as fancy quotes, en and, em dashes when generating in-page anchor IDs.
149
+
150
+ = 2.0.15 01/27/2021 =
151
+ * TWEAK: Remove additional reserved characters when generating in-page anchor IDs.
152
+
153
+ = 2.0.14 01/26/2021 =
154
+ * TWEAK: Refactor debug log as a Singleton.
155
+ * TWEAK: Add additional logging to aid in debugging.
156
+ * BUG: Correct logic for PHP where empty string no longer evaluates as integer `0`.
157
+
158
+ = 2.0.13 01/25/2021 =
159
+ * TWEAK: Restrict debug logging to when `WP_DEBUG` is enabled *and* current user capability of `manage_options`.
160
+ * TWEAK: Add logging to aid in support.
161
+ * DEV: phpDoc update.
162
+
163
+ = 2.0.12 01/22/2021 =
164
+ * TWEAK: Allow `_` and `-` in anchors.
165
+ * TWEAK: Minor CSS tweaks that prevent theme from breaking the layout.
166
+ * TWEAK: Minor tweak to class initialization.
167
+ * TWEAK: Do not display the view toggle if JavaScript is broken on the site.
168
+ * TWEAK: Add the ability to enable displaying of displaying debug information on the page.
169
+ * BUG: Check for array and keys before accessing values.
170
+ * BUG: Check for array key be fore access.
171
+ * BUG: Remove reserved characters when generating in-page anchor IDs.
172
+ * DEV: Remove unnecessary vendor library files.
173
+ * DEV: Deal with phpStorm showing a warning about path not found when including files.
174
+
175
+ = 2.0.11 05/01/2020 =
176
+ * COMPATIBILITY: Add support for the Uncode theme.
177
+ * COMPATIBILITY: Do not run on WooCommerce pages.
178
+ * DEV: Correct typo in phpDoc.
179
+
180
+ = 2.0.10 04/20/2020 =
181
+ * TWEAK: Add trailing `span` to heading, to prepare for `#` option and to fix duplicate heading title matching.
182
+ * 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.
183
+
184
+
185
+ = 2.0.9 04/08/2020 =
186
+ * TWEAK: AMP/Caching plugins seems to break anchors with colons and periods even though they are valid characters for the id attribute in HTML5.
187
+ * TWEAK: Replace multiple underscores with a single underscore.
188
+ * DEV: Update the UWS library which fixes the deprecation notice for PHP 7.4.
189
+ * DEV: Add phpcs.xml.dist.
190
+ * DEV: Strict type checks.
191
+ * DEV: Inline doc updates.
192
+
193
+ = 2.0.8 04/03/2020 =
194
+ * TWEAK: Convert `<br />` tags in headings to a space.
195
+ * TWEAK: Add additional widget classes.
196
+ * TWEAK: Improve the sanitization of the excluded headings field post setting.
197
+ * TWEAK: Minor optimization of creating the matching pattern for excluding headings for improved performance.
198
+ * COMPATIBILITY: Exclude Create by Mediavine from heading eligibility.
199
+ * BUG: Ensure excluded headings are removed from the headings array.
200
+ * BUG: Ensure empty headings are removed from the headings array.
201
+
202
+ = 2.0.7 04/02/2020 =
203
+ * NEW: Exclude any HTML nodes with the class of `.ez-toc-exclude-headings`.
204
+ * TWEAK: Change smooth scroll selector from `'body a'` to `'a.ez-toc-link'`.
205
+ * TWEAK: Declare JS variables.
206
+ * TWEAK: Support unicode characters for the `id` attribute. Permitted by HTML5.
207
+ * TWEAK: Move the in-page anchor/span to before the heading text to account for long headings where it line wraps.
208
+ * TWEAK: Slight rework to ezTOC widget container classes logic.
209
+ * TWEAK: Cache bust the JS to make dev easier.
210
+ * TWEAK: JavaScript cleanup.
211
+ * 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.
212
+ * COMPATIBILITY: Reintroduce filter to exclude Ultimate Addons for VC Composer Tabs from heading eligibility.
213
+ * BUG: Correct array iteration logic when processing headings.
214
+ * BUG: Tighten matching for headings in excluded HTML nodes. The loose matching was excluding far too many headings.
215
+ * 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.
216
+
217
+ = 2.0.6 03/30/2020 =
218
+ * BUG: Ensure minified files are current.
219
+
220
+ = 2.0.5 03/27/2020 =
221
+ * BUG: Prevent possible "strpos(): Empty needle in" warnings when excluding nodes from TOC eligibility.
222
+
223
+ = 2.0.4 03/16/2020 =
224
+ * NEW: Introduce the `ez_toc_container_class` filter.
225
+ * TWEAK: Slight rework to ezTOC container classes logic.
226
+ * BUG: `sprintf()` was eating `%` in the TOC heading item.
227
+ * 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.
228
+
229
+ = 2.0.3 03/12/2020 =
230
+ * TWEAK: Slightly tighten heading matching, last update made it a little too loose.
231
+ * BUG: Correct logic required to place TOC before first heading which is required for the more lax heading matching required for page builders.
232
+
233
+ = 2.0.2 03/12/2020 =
234
+ * COMPATIBILITY: Remove filter to exclude Ultimate Addons for VC Composer Tabs from heading eligibility.
235
+ * COMPATIBILITY: Add additional filters to improve Elementor compatibility.
236
+ * 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.
237
+
238
+ = 2.0.1 03/09/2020 =
239
+ * COMPATIBILITY: Exclude the WordPress Related Posts plugin nodes.
240
+ * COMPATIBILITY: Exclude a couple Atomic Block plugin nodes.
241
+ * COMPATIBILITY: Exclude JetPack Related Posts from heading eligibility.
242
+ * COMPATIBILITY: Exclude Ultimate Addons for VC Composer Tabs from heading eligibility.
243
+ * COMPATIBILITY: Exclude WP Product Reviews from heading eligibility.
244
+ * TWEAK: Prevent possible "strpos(): Empty needle in" warnings when excluding nodes from TOC eligibility.
245
+
246
+ = 2.0 02/01/2020 =
247
+ * NEW: Major rewrite of all code and processing logic to make it faster and more reliable.
248
+ * NEW: Support for the <!--nextpage--> tag.
249
+ * NEW: Introduce helper functions for devs.
250
+ * NEW: Support WPML.
251
+ * NEW: Support Polylang.
252
+ * NEW: Add filter to support the Rank Math plugin.
253
+ * NEW: Introduce the `ez_toc_maybe_apply_the_content_filter` filter.
254
+ * TWEAK: Improve translation compatibility.
255
+ * TWEAK: Rework widget logic to allow multi-line TOC items, improve active item highlighting while removing the use of the jQuery Waypoints library.
256
+ * TWEAK Add additional classes to TOC list items.
257
+ * TWEAK: Add WOFF2 format for icon format and change font references in CSS.
258
+ * TWEAK: Add font-display: swap for toggle icon.
259
+ * TWEAK: Update JS Cookie to 2.2.1.
260
+ * TWEAK: Update jQuery Smooth Scroll to 2.2.0.
261
+ * TWEAK: Allow forward slash and angle brackets in headings and alternate headings.
262
+ * TWEAK: Allow forward slash in excluded headings.
263
+ * TWEAK: Remove new line/returns when matching excluded headings.
264
+ * TWEAK: Simple transient cache to ensure a post is only processed once per request for a TOC.
265
+ * TWEAK: Improve sanitization of alternate headings field value.
266
+ * TWEAK: Deal with non-breaking-spaces in alternate headings.
267
+ * TWEAK: Add the ability to exclude by selector content eligible to be included in the TOC.
268
+ * TWEAK: Change the shortcode priority to a higher value.
269
+ * 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.
270
+ * TWEAK: Add compatibility filters to remove shortcodes for Connections and Striking theme to remove them from eligible TOC item content.
271
+ * TWEAK: Do not execute if root current filter is the `wp_head` or `get_the_excerpt` filters.
272
+ * TWEAK: Add filter to exclude content by selector.
273
+ * TWEAK: Move in-page anchor to after the heading instead of wrapping the heading to prevent conflicts with theme styling.
274
+ * TWEAK: Utilize the `ez_toc_exclude_by_selector` filter the exclude the JetPack share buttons from eligible headings.
275
+ * TWEAK: Remove the Elegant Themes Bloom plugin node from the post content before extracting headings.
276
+ * TWEAK: Add compatibility filter for the Visual Composer plugin.
277
+ * TWEAK: Utilize the `ez_toc_exclude_by_selector` filter the exclude the Starbox author heading from eligible headings.
278
+ * I18N: Add wpml-config.xml file.
279
+ * BUG: Correct option misspelling.
280
+ * BUG: Do not need to run values for alternate and exclude headings thru `wp_unslash()` because `update_post_meta()` already does.
281
+ * BUG: Do not need to run `stripslashes()` when escaping the alternate heading value.
282
+ * BUG: Sanitize the excluded heading string before saving post meta.
283
+ * DEV: Change PHP keywords to comply with PSR2.
284
+ * DEV:Bump minimum PHP version to 5.6.20 which matches WP core.
285
+
286
+ = 1.7 05/09/2018 =
287
+ * NEW: Introduce the `ez_toc_shortcode` filter.
288
+ * TWEAK: Fix notices due to late eligibility check. props unixtam
289
+ * TWEAK: Tweak eligibility check to support the TOC widget.
290
+ * TWEAK: Prefix a few CSS classes in order to prevent collisions with theme's and other plugins.
291
+ * TWEAK: Avoid potential PHP notice in admin when saving the post by checking for nonce before validating it.
292
+ * TWEAK: Using the shortcode now overrides global options.
293
+ * TWEAK: `the_content()` now caches result of `is_eligible()`.
294
+ * TWEAK: Refactor to pass the WP_Post object internally vs. accessing it via the `$wp_query->post` which may not in all cases exist.
295
+ * TWEAK: Use `pre_replace()` to replace one or more spaces with an underscore.
296
+ * TWEAK: Return original title in the `ez_toc_url_anchor_target` filter.
297
+ * TWEAK: Strip `&nbsp;`, replacing it with a space character.
298
+ * TWEAK: Minor tweaks to the in page URL creating.
299
+ * TWEAK: Wrap TOC list in a nav element.
300
+ * TWEAK: Init plugin on the `plugins_loaded` hook.
301
+ * TWEAK: Tweak the minimum number of headers to 1.
302
+ * BUG: The header options from the post meta should be used when building the TOC hierarchy, not the header options from the global settings.
303
+ * BUG: Do not double escape field values.
304
+ * BUG: Ensure Apostrophe / Single quote use in Exclude Headings work.
305
+ * OTHER: Update CSS to include the newly prefixed classes.
306
+ * DEV: Remove some commented out unused code.
307
+
308
+ = 1.6.1 03/16/2018 =
309
+ * TWEAK: Revert change made to allow HTML added via the `ez_toc_title` filter as it caused undesirable side effects.
310
+ * BUG: Ensure Smooth Scroll Offset is parsed as an integer.
311
+
312
+ = 1.6 03/15/2018 =
313
+ * NEW: Add `px` option for font size unit.
314
+ * NEW: Add title font size and weight settings options.
315
+ * NEW: Add the Mobile Smooth Scroll Offset option.
316
+ * TWEAK: Change default for font size unit from `px` to `%` to match the default options values.
317
+ * TWEAK: Correct CSS selector so margin is properly applied between the title and TOC items.
318
+ * TWEAK: Honor HTML added via `ez_toc_title` filter.
319
+ * TWEAK: Ensure the ezTOC content filter is not applied when running `the_content` filter.
320
+ * TWEAK: Only enqueue the javascript if the page is eligible for a TOC.
321
+ * TWEAK: Update icomoon CSS to remove unecessary CSS selectors to prevent possible conflicts.
322
+ * TWEAK: The smooth scroll offset needs to be taken into account when defining the offset_top property when affixing the widget.
323
+ * OTHER: Update frontend minified CSS file.
324
+ * OTHER: Update the frontend minified javascript file.
325
+ * DEV: phpDoc corrections.
326
+
327
+ = 1.5 02/20/2018 =
328
+ * BUG: Correct CSS selector to properly target the link color.
329
+ * OTHER: Update the WayPoints library.
330
+ * DEV: Add a couple @todo's.
331
+
332
+ = 1.4 01/29/2018 =
333
+ * TWEAK: Change text domain from ez_toc to easy-table-of-contents.
334
+ * TWEAK: Rename translation files with correct text domain.
335
+ * BUG: Ensure page headers are processed to add the in page header link when using the shortcodes.
336
+ * BUG: Add forward slash to domain path in the plugin header.
337
+ * I18N: Update POT file.
338
+ * I18N: Update Dutch (nl_NL) translation.
339
+
340
+ = 1.3 12/18/2017 =
341
+ * FEATURE: Add support for the `[ez-toc]` shortcode.
342
+ * NEW: For backwards compatibility with "Table of Content Plus", register the `[toc]` shortcode.
343
+ * NEW: Introduce the `ez_toc_extract_headings_content` filter.
344
+ * TWEAK: Update the tested to and required readme header text.
345
+ * TWEAK: Do not show the widget on the 404, archive, search and posts pages.
346
+ * I18N: Add the nl_NL translation.
347
+
348
+ = 1.2 04/29/2016 =
349
+ * TWEAK: Remove the font family from styling the TOC title header.
350
+ * TWEAK: Pass the raw title to the `ez_toc_title` filter.
351
+ * BUG: A jQuery 1.12 fix for WordPress 4.5.
352
+
353
+ = 1.1 02/24/2016 =
354
+ * FEATURE: Add option to replace header wither alternate header text in the table of content.
355
+ * NEW: Introduce the ez_toc_filter.
356
+ * NEW: Introduce ezTOC_Option::textarea() to render textareas.
357
+ * NEW: Introduce array_search_deep() to recursively search an array for a value.
358
+ * TWEAK: Run table of contents headers thru wp_kses_post().
359
+ * TWEAK: Escape URL.
360
+ * TWEAK: Count excluded headings only once instead of multiple times.
361
+ * TWEAK: Escape translated string before rendering.
362
+ * TWEAK: Use wp_unslash() instead of stripslashes().
363
+ * TWEAK: Escape translated string.
364
+ * BUG: Fix restrict path logic.
365
+ * OTHER: Readme tweaks.
366
+ * I18N: Add POT file.
367
+ * I18N: Add Dutch translation.
368
+ * DEV: Update .gitignore to allow PO files.
369
+ * DEV: phpDoc fix.
370
+
371
+ = 1.0 09/08/2015 =
372
+ * Initial release.
373
+ - 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.
374
+ - Update all third party libraries.
375
+ - Make much better use of the WordPress Settings API.
376
+ - Minified CSS and JS files are used by default. Using SCRIPT_DEBUG will use the un-minified versions.
377
+ - Add substantial amounts of phpDoc for developers.
378
+ - Add many hooks to permit third party integrations.
379
+ - Widget can be affixed/stuck to the page so it is always visible.
380
+ - Widget will highlight the table of content sections that are currently visible in the browser viewport.
381
+ - Widget will now generate table of contents using output from third party shortcodes.
382
+ - Use wpColorPicker instead of farbtastic.
383
+ - Remove all shortcodes.
384
+ - Per post options are saved in post meta instead of set by shortcode.
385
+
386
+ == Frequently Asked Questions ==
387
+
388
+ = Ok, I've installed this... what do I do next? =
389
+
390
+ You first stop should be the Table of Contents settings admin page. You can find this under the Settings menu item.
391
+
392
+ 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 :)
393
+
394
+ 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.
395
+
396
+ = How are the tables of contents created? =
397
+
398
+ 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.
399
+
400
+ `<h1>Item 1</h1>
401
+ <h1>Item 2</h1>
402
+ <h1>Item 3</h1>
403
+ <h1>Item 4</h1>
404
+ <h1>Item 5</h1>
405
+ <h1>Item 6</h1>`
406
+
407
+ 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.
408
+
409
+ `<h1>Item 1</h1>
410
+ <h2>Item 1.1 -- Level 2</h2>
411
+ <h1>Item 2</h1>
412
+ <h2>Item 2.1 -- Level 2</h2>
413
+ <h1>Item 3</h1>
414
+ <h2>Item 3.1 -- Level 2</h2>
415
+ <h1>Item 4</h1>
416
+ <h1>Item 5</h1>
417
+ <h1>Item 6</h1>`
418
+
419
+ 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...
420
+
421
+ `<h1>Item 1</h1>
422
+ <h2>Item 1.1 -- Level 2</h2>
423
+ <h3>Item 1.1.1 -- Level 3</h3>
424
+ <h3>Item 1.1.2 -- Level 3</h3>
425
+ <h3>Item 1.1.3 -- Level 3</h3>
426
+ <h2>Item 1.2 -- Level 2</h2>
427
+ <h3>Item 1.2.1 -- Level 3</h3>
428
+ <h3>Item 1.2.2 -- Level 3</h3>
429
+ <h3>Item 1.2.3 -- Level 3</h3>
430
+ <h2>Item 1.3 -- Level 2</h2>
431
+ <h1>Item 2</h1>
432
+ <h2>Item 2.1 -- Level 2</h2>
433
+ <h2>Item 2.2 -- Level 2</h2>
434
+ <h1>Item 3</h1>
435
+ <h2>Item 3.1 -- Level 2</h2>
436
+ <h2>Item 3.2 -- Level 2</h2>
437
+ <h1>Item 4</h1>
438
+ <h1>Item 5</h1>
439
+ <h1>Item 6</h1>`
440
+
441
+ 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!
442
+
443
+ = Is there any shortcode to add the table of content to anywhere I want ? =
444
+
445
+ 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.
446
+
447
+ == Upgrade Notice ==
448
+
449
+ = 1.0 =
450
+ Initial release.
451
+
452
+ = 1.3 =
453
+ Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
454
+
455
+ = 1.4 =
456
+ Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
457
+
458
+ = 1.5 =
459
+ Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
460
+
461
+ = 1.6 =
462
+ Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
463
+
464
+ = 1.6.1 =
465
+ Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
466
+
467
+ = 1.7 =
468
+ Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
469
+
470
+ = 2.0-rc4 =
471
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
472
+
473
+ = 2.0.1 =
474
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
475
+
476
+ = 2.0.2 =
477
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
478
+
479
+ = 2.0.3 =
480
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
481
+
482
+ = 2.0.4 =
483
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
484
+
485
+ = 2.0.5 =
486
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
487
+
488
+ = 2.0.6 =
489
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
490
+
491
+ = 2.0.7 =
492
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
493
+
494
+ = 2.0.8 =
495
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
496
+
497
+ = 2.0.9 =
498
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
499
+
500
+ = 2.0.10 =
501
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
502
+
503
+ = 2.0.11 =
504
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
505
+
506
+ = 2.0.12 =
507
+ Requires WordPress >= 5.3 and PHP version >= 5.6.20 (>= 7.4 is recommended).
508
+
509
+ = 2.0.13 =
510
+ Requires WordPress >= 5.3 and PHP version >= 5.6.20 (>= 7.4 is recommended).
511
+
512
+ = 2.0.14 =
513
+ Requires WordPress >= 5.3 and PHP version >= 5.6.20 (>= 7.4 is recommended).
514
+
515
+ = 2.0.15 =
516
+ Requires WordPress >= 5.3 and PHP version >= 5.6.20 (>= 7.4 is recommended).
517
+
518
+ = 2.0.16 =
519
+ Requires WordPress >= 5.3 and PHP version >= 5.6.20 (>= 7.4 is recommended).
520
+
521
+ = 2.0.17 =
522
+ Requires WordPress >= 5.3 and PHP version >= 5.6.20 (>= 7.4 is recommended).
assets/Mohammed-kaludi.jpeg ADDED
Binary file
assets/ahmed-kaludi.jpg ADDED
Binary file
assets/css/admin.css CHANGED
@@ -1,222 +1,1221 @@
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#smooth_scroll_offset {
105
- width: 50px;
106
- text-align: center;
107
- }
108
- input.custom_colour_option {
109
- width: 75px;
110
- }
111
- table#theme_custom, div#farbtastic_colour_wheel {
112
- float: left;
113
- }
114
- table#theme_custom {
115
- margin-top: 30px;
116
- }
117
- table#theme_custom img {
118
- vertical-align: middle;
119
- opacity: 0.4;
120
- }
121
- table#theme_custom img:hover {
122
- cursor: pointer;
123
- opacity: 1;
124
- }
125
- div#farbtastic_colour_wheel {
126
- margin-left: 20px;
127
- }
128
- #tab3 h3:not(:first-child) {
129
- margin-top: 2em;
130
- }
131
-
132
- /* My styles */
133
- #toc input.small-text {
134
- width: 50px;
135
- padding: 2px;
136
- height: 28px;
137
- line-height: 28px;
138
- vertical-align: bottom;
139
- }
140
-
141
- #toc .form-table tr > th > strong {
142
- font-size: 18px;
143
- font-style: italic;
144
- }
145
- /* Tab panel styles */
146
- .postbox{
147
- padding: 10px;
148
- }
149
- html {
150
- scroll-behavior: smooth;
151
- }
152
- .toc-tab-panel {
153
- overflow: hidden;
154
- border: 1px solid #ccc;
155
- background-color: #fff;
156
- margin-top: 15px;}
157
- .toc-tab-panel a {
158
- background-color: inherit;
159
- text-decoration: none;
160
- float: left;
161
- border: none;
162
- outline: none;
163
- cursor: pointer;
164
- padding: 14px 16px;
165
- transition: 0s;
166
- font-size: 15px;
167
- color: #2271b1;
168
- }
169
- .toc-tab-panel a:hover {
170
- color: #0a4b78;
171
- }
172
- .toc-tab-panel a.active {
173
- box-shadow: none;
174
- border-bottom: 4px solid #646970;
175
- color: #1d2327;
176
- }
177
- .toc-tab-panel a:focus {
178
- box-shadow: none;
179
- outline: none;
180
- }
181
- .eztoc-tabcontent {
182
- display: none;
183
- border-top: none;
184
- animation: fadeEffect 1s;
185
- }
186
- .eztoc_support_div {
187
- background: #fff;
188
- margin-top: 10px;
189
- padding: 28px;
190
- min-width: 255px;
191
- border: 1px solid #c3c4c7;
192
- box-shadow: 0 1px 1px rgb(0 0 0 / 4%);
193
- }
194
- .support-label {
195
- float: left;
196
- width: 70px;
197
- font-size: 14px;
198
- }
199
- .star-mark{
200
- color: red;
201
- margin-left: 4px;
202
- font-family:bold;
203
- }
204
- .eztoc_support_div li {
205
- margin:25px 0px 20px 0px;
206
- }
207
- .eztoc-query-success{
208
- color: green;
209
- }
210
- .eztoc-query-error{
211
- color: red;
212
- }
213
- .eztoc_hide{
214
- display: none;
215
- }
216
- .eztoc-result{
217
- margin-left: 70px;
218
- }
219
- .eztoc-send-query{
220
- margin-left: 70px !important;;
221
- }
222
- @keyframes fadeEffect { from {opacity: 0;} to {opacity: 1;} }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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#smooth_scroll_offset {
105
+ width: 50px;
106
+ text-align: center;
107
+ }
108
+ input.custom_colour_option {
109
+ width: 75px;
110
+ }
111
+ table#theme_custom, div#farbtastic_colour_wheel {
112
+ float: left;
113
+ }
114
+ table#theme_custom {
115
+ margin-top: 30px;
116
+ }
117
+ table#theme_custom img {
118
+ vertical-align: middle;
119
+ opacity: 0.4;
120
+ }
121
+ table#theme_custom img:hover {
122
+ cursor: pointer;
123
+ opacity: 1;
124
+ }
125
+ div#farbtastic_colour_wheel {
126
+ margin-left: 20px;
127
+ }
128
+ #tab3 h3:not(:first-child) {
129
+ margin-top: 2em;
130
+ }
131
+
132
+ /* My styles */
133
+ #toc input.small-text {
134
+ width: 50px;
135
+ padding: 2px;
136
+ height: 28px;
137
+ line-height: 28px;
138
+ vertical-align: bottom;
139
+ }
140
+
141
+ #toc .form-table tr > th > strong {
142
+ font-size: 18px;
143
+ font-style: italic;
144
+ }
145
+ /* Tab panel styles */
146
+ .postbox{
147
+ padding: 10px;
148
+ }
149
+ html {
150
+ scroll-behavior: smooth;
151
+ }
152
+ .toc-tab-panel {
153
+ overflow: hidden;
154
+ border: 1px solid #ccc;
155
+ background-color: #fff;
156
+ margin-top: 15px;}
157
+ .toc-tab-panel a {
158
+ background-color: inherit;
159
+ text-decoration: none;
160
+ float: left;
161
+ border: none;
162
+ outline: none;
163
+ cursor: pointer;
164
+ padding: 14px 16px;
165
+ transition: 0s;
166
+ font-size: 15px;
167
+ color: #2271b1;
168
+ font-weight: 500;
169
+ }
170
+ .toc-tab-panel a:hover {
171
+ color: #0a4b78;
172
+ }
173
+ .toc-tab-panel a.active {
174
+ box-shadow: none;
175
+ border-bottom: 4px solid #646970;
176
+ color: #1d2327;
177
+ }
178
+ .toc-tab-panel a:focus {
179
+ box-shadow: none;
180
+ outline: none;
181
+ }
182
+ .eztoc-tabcontent {
183
+ display: none;
184
+ border-top: none;
185
+ animation: fadeEffect 1s;
186
+ }
187
+ #technical .eztoc-form-page-ui{
188
+ display:flex;
189
+ background: #fff;
190
+ width: auto;
191
+ height: auto;
192
+ }
193
+ #technical .eztoc-left-side{
194
+ width: 70%;
195
+
196
+ }
197
+ .eztoc-right-side{
198
+ width: 31%;
199
+ margin-top: auto;
200
+ margin-bottom: auto;
201
+ text-align: center;
202
+
203
+ }
204
+ .eztoc-tabcontent {
205
+ display: none;
206
+ border-top: none;
207
+ }
208
+ #technical {
209
+ background: #fff;
210
+ margin-top: 10px;
211
+ padding: 28px;
212
+ padding: 15px 28px 28px 28px;
213
+ min-width: 255px;
214
+ box-shadow: 0 1px 1px rgb(0 0 0 / 4%);
215
+ }
216
+ /* #technical p{
217
+ line-height: 0.5rem;
218
+ } */
219
+ #technical-form{
220
+
221
+ width: 60%;
222
+ }
223
+ .support-label {
224
+ margin-top: 4px;
225
+ float: left;
226
+ width: 70px;
227
+
228
+ font-size: 14px;
229
+ }
230
+
231
+ .star-mark{
232
+ color: red;
233
+ margin-left: 4px;
234
+ font-family: bold;
235
+ }
236
+ #technical li {
237
+ margin:25px 0px 20px 0px;
238
+ margin:10px 0px 10px 0px;
239
+ list-style: none;
240
+ }
241
+ .eztoc_support_div_form{
242
+ margin-top: 23px;
243
+ }
244
+ .eztoc-customer-type{
245
+ display: block;
246
+ }
247
+ .support-input select{
248
+ border-radius: 4px;
249
+ margin-top: -7px;
250
+ }
251
+ .eztoc_dev-bio{
252
+ display: block;
253
+ }
254
+ .ezoc-bio-wrap{
255
+ float: left;
256
+ text-align: center;
257
+ width: 33.33%;
258
+ text-transform: uppercase;
259
+ }
260
+ .ezoc-bio-wrap p{
261
+ width: auto;
262
+ font-size: 10px;
263
+ color: #555;
264
+ margin: 0px 0 20px 0;
265
+ }
266
+ .ezoc-bio-wrap img{
267
+ margin: 25px 0 0 0;
268
+ border-radius: 50%;
269
+ }
270
+ .eztoc-bio-box{
271
+ background: #fff;
272
+ border: 1px solid #ccc;
273
+ padding: 15px 20px;
274
+ border-radius: 4px;
275
+ margin: 15px 15px 15px 0;
276
+ /* height: 22rem; */
277
+ padding: 0px 20px;
278
+ }
279
+ .eztoc-bio-box:hover{
280
+ box-shadow: 5px 5px 8px #888888;
281
+ }
282
+ .eztoc-p{
283
+ font-size: 15px;
284
+ margin: 20px auto 0px auto;
285
+ text-align: center;
286
+ }
287
+ .eztoc-p{
288
+ line-height: 1.5rem;
289
+ padding: 0 25px;
290
+ margin-top: 10px;
291
+ font-size: 16px;
292
+ }
293
+ .eztoc-bio-box h1{
294
+ margin: 8px auto 0px auto;
295
+ text-align: center;
296
+ font-weight: bolder;
297
+ }
298
+ .eztoc_boxdesk{
299
+ clear: left;
300
+ font-size: 15px;
301
+ text-align: center;
302
+ margin: 20px 0 0 0;
303
+
304
+ }
305
+ .company-link{
306
+ font-weight: 500;
307
+ margin: 20px 0 0 0;
308
+ }
309
+ .company-link a{
310
+
311
+ display: table;
312
+ background: #e91e63;
313
+ width: auto;
314
+ margin: 0 auto;
315
+ padding: 7px 25px;
316
+ color: #fff;
317
+ text-decoration: none;
318
+ margin-top: 10px;
319
+ margin-bottom: 15px;
320
+ border-radius: 6px;
321
+ border: 0;
322
+ /* text-transform: uppercase; */
323
+ font-size: 16px;
324
+
325
+ }
326
+ .eztoc-send-query{
327
+ background: #2271b1;
328
+ border-color: #2271b1;
329
+ color:#fff;
330
+ text-decoration: none;
331
+ text-shadow: none;
332
+ margin-left: 70px !important;;
333
+ }
334
+
335
+ @media screen and (min-width: 870px) and (max-width: 1300px ){
336
+ .eztoc-bio-box{
337
+ padding-top: 20px;
338
+ height: 29.1rem;;
339
+ }
340
+ .eztoc-bio-box h1{
341
+ font-size: 20px;
342
+ }
343
+ .eztoc-bio-box p{
344
+ font-size: 13px;
345
+ margin: 20px auto 0px auto;
346
+ }
347
+ .ezoc-bio-wrap img{
348
+ width: 30px;
349
+ height: 30px;
350
+ }
351
+ .ezoc-bio-wrap p{
352
+ width: 55px;
353
+ font-size: 12px;
354
+ margin-bottom: 10px;
355
+ }
356
+
357
+ }
358
+ @keyframes fadeEffect { from {opacity: 0;} to {opacity: 1;} }
359
+
360
+
361
+ .eztoc-wrapper{
362
+ max-width: 100%;
363
+ width: 100%;
364
+ display: flex;
365
+ flex-wrap: wrap;
366
+ margin: auto;
367
+ }
368
+
369
+ .eztoc-wrapper .table{
370
+ margin: 0 auto;
371
+ background: #fff;
372
+ width: calc(30%);
373
+ padding: 30px 20px;
374
+ position: relative;
375
+ box-shadow: 0 5px 10px rgb(0 0 0 / 10%);
376
+ }
377
+
378
+ .table .price-section{
379
+ display: flex;
380
+ justify-content: center;
381
+ }
382
+
383
+ .price-section .price-area{
384
+ height: 120px;
385
+ width: 120px;
386
+ background: #ffd861;
387
+ border-radius: 50%;
388
+ padding: 2px;
389
+ }
390
+
391
+ .price-section .price-area .inner-area{
392
+ height: 100%;
393
+ width: 100%;
394
+ border-radius: 50%;
395
+ border: 3px solid #fff;
396
+ color: #fff;
397
+ line-height: 117px;
398
+ text-align: center;
399
+ position: relative;
400
+ }
401
+
402
+ .price-area .inner-area .text{
403
+ font-size: 25px;
404
+ font-weight: 400;
405
+ position: absolute;
406
+ top: -10px;
407
+ left: 17px;
408
+ }
409
+
410
+ .price-area .inner-area .price{
411
+ font-size: 55px;
412
+ font-weight: 500;
413
+ }
414
+
415
+ .table .package-name{
416
+ width: 100%;
417
+ height: 2px;
418
+ background: #ffecb3;
419
+ margin: 35px 0;
420
+ position: relative;
421
+ }
422
+
423
+ .table .package-name::before{
424
+ position: absolute;
425
+ content: "Basic";
426
+ top: 50%;
427
+ left: 50%;
428
+ transform: translate(-50%, -50%);
429
+ background: #fff;
430
+ font-size: 25px;
431
+ padding: 0 10px;
432
+ font-weight: bolder;
433
+ }
434
+
435
+ .table .features li{
436
+ list-style: none;
437
+ display: flex;
438
+ justify-content: space-between;
439
+ margin-bottom: 15px;
440
+ }
441
+
442
+ .features li .list-name{
443
+ font-size: 17px;
444
+ font-weight: 400;
445
+ }
446
+
447
+ .features li .icon{
448
+ font-size: 15px;
449
+ }
450
+
451
+ .features li .icon.check{
452
+ color: #2db94d;
453
+ }
454
+
455
+ .features li .icon.cross{
456
+ color: #cd3241;
457
+ }
458
+
459
+ .table .btn{
460
+ display: flex;
461
+ justify-content: center;
462
+ margin-top: 35px;
463
+ }
464
+
465
+ .table .btn button{
466
+ width: 80%;
467
+ height: 50px;
468
+ font-weight: 700;
469
+ color: #fff;
470
+ font-size: 20px;
471
+ border: none;
472
+ outline: none;
473
+ border-radius: 25px;
474
+ cursor: pointer;
475
+ transition: all 0.3s ease;
476
+ }
477
+
478
+ .basic .price-area,
479
+ .basic .inner-area{
480
+ background: #ffd861;
481
+ }
482
+
483
+ .basic .btn button{
484
+ background: #fff;
485
+ color: #ffd861;
486
+ border: 2px solid #ffd861;
487
+ }
488
+
489
+ .basic .btn button:hover{
490
+ border-radius: 6px;
491
+ background: #ffd861;
492
+ color: #fff;
493
+ }
494
+
495
+ .Premium .price-area,
496
+ .Premium .inner-area{
497
+ background: #a26bfa;
498
+ }
499
+
500
+ .Premium .btn button{
501
+ background: #fff;
502
+ color: #a26bfa;
503
+ border: 2px solid #a26bfa;
504
+ }
505
+
506
+ .Premium .btn button:hover{
507
+ border-radius: 6px;
508
+ background: #a26bfa;
509
+ color: #fff;
510
+ }
511
+
512
+
513
+ .basic .package-name{
514
+ background: #ffecb3;
515
+ }
516
+
517
+ .Premium .package-name{
518
+ background: #a26bfa;
519
+ }
520
+
521
+
522
+
523
+ .basic .package-name::before{
524
+ content: "Free";
525
+ }
526
+
527
+ .Premium .package-name::before{
528
+ content: "PRO";
529
+ }
530
+
531
+
532
+
533
+ .basic ::selection,
534
+ .basic .price-area,
535
+ .basic .inner-area{
536
+ background: #ffd861;
537
+ }
538
+
539
+ .Premium ::selection,
540
+ .Premium .price-area,
541
+ .Premium .inner-area{
542
+ background: #a26bfa;
543
+ }
544
+
545
+ div#eztoc-tabs a {
546
+ text-decoration: none;
547
+ }
548
+ div#eztoc-tabs a:first-child {
549
+ color: #000;
550
+ }
551
+
552
+ #the-list{position: relative;}
553
+ .eztoc-wr {
554
+ width: 100%;
555
+ margin: 0 auto;
556
+ position: relative
557
+ }
558
+
559
+ .etoc-eztoc-img {
560
+ width: 100%;
561
+ margin: 0 auto;
562
+ text-align: center;
563
+ position: relative;
564
+ line-height: 0;
565
+ height: 300px;
566
+ }
567
+
568
+ .eztoc-img img {
569
+ position: relative
570
+ }
571
+
572
+ .sp_ov {
573
+ background: #fd789f;
574
+ bottom: 0;
575
+ left: 0;
576
+ position: absolute;
577
+ right: 0;
578
+ top: 0;
579
+ }
580
+
581
+ .etoc-eztoc-cnt {
582
+ position: absolute;
583
+ top: 40px;
584
+ bottom: 0;
585
+ left: 40px;
586
+ right: 40px;
587
+ margin: 0 auto;
588
+ text-align: center
589
+ }
590
+
591
+ .etoc-eztoc-cnt h1 {
592
+ font-size: 60px;
593
+ color: #fff;
594
+ font-weight: 600;
595
+ }
596
+
597
+ .etoc-eztoc-cnt p {
598
+ margin-top: 0px;
599
+ color: #371b24;
600
+ font-size: 18px;
601
+ padding: 0 100px;
602
+ line-height: 1.4;
603
+ font-weight: 500;
604
+ }
605
+
606
+ .etoc-eztoc-cnt .buy {
607
+ border-width: 0px !important;
608
+ font-size: 1.25rem;
609
+ line-height: 2;
610
+ text-decoration: none;
611
+ background: white !important;
612
+ border-radius: 8px !important;
613
+ font-size: 16px !important;
614
+ padding: 12px 18px;
615
+ color: #e04371 !important;
616
+ font-weight: 500;
617
+ }
618
+ .etoc-eztoc-cnt .buy:hover{
619
+ box-shadow: 0px 2px 2px #999;
620
+ background: linear-gradient(to left, #fdfc35, #ffe258) !important;
621
+ }
622
+ .pvf {
623
+ position: relative;
624
+ top: -16px;
625
+ border: 1px solid #eee;
626
+ padding-bottom: 40px
627
+ }
628
+
629
+ .ext {
630
+ display: grid;
631
+ grid-template-columns: 1fr 1fr 1fr;
632
+ background: #f9f9f9;
633
+ padding: 45px 0 45px 25px
634
+ }
635
+
636
+ .ex-1 {
637
+ width: 80%;
638
+ }
639
+
640
+ .ex-1 h4 {
641
+ margin: 15px 0 12px 0;
642
+ font-weight: 600;
643
+ font-size: 20px;
644
+ color: #e04371;
645
+ }
646
+
647
+ .ex-1 p {
648
+ font-size: 14px;
649
+ font-weight: 400;
650
+ margin: 0;
651
+ color: #000;
652
+ }
653
+
654
+ .e-1 img {
655
+ width: 65px!important
656
+ }
657
+
658
+ .e-2 img {
659
+ width: 45px!important
660
+ }
661
+
662
+ .e-3 img {
663
+ width: 49px!important
664
+ }
665
+
666
+ .pvf-cnt {
667
+ width: 100%;
668
+ display: inline-block
669
+ }
670
+
671
+ .pvf-tlt {
672
+ text-align: center;
673
+ width: 100%;
674
+ margin: 70px 0 60px 0
675
+ }
676
+
677
+ .pvf-tlt h2 {
678
+ font-size: 36px;
679
+ line-height: 1.4;
680
+ color: #000;
681
+ font-weight: 500;
682
+ margin: 0
683
+ }
684
+
685
+ .pvf-tlt span {
686
+ font-size: 16px;
687
+ color: #000;
688
+ margin-top: 15px;
689
+ display: inline-block;
690
+ position: relative;
691
+ top: 4px
692
+ }
693
+
694
+ .pvf-cmp {
695
+ display: grid;
696
+ grid-template-columns: 1fr 2fr
697
+ }
698
+
699
+ .fr {
700
+ border-right: 1px solid #eee
701
+ }
702
+
703
+ .fr h1,
704
+ .pr h1 {
705
+ font-size: 36px;
706
+ font-weight: 700;
707
+ line-height: 1.5;
708
+ border-bottom: 1px solid #efefef;
709
+ padding: 0 0 20px 35px;
710
+ }
711
+
712
+ .pr h1 {
713
+ padding-left: 50px;
714
+ color: #e04371;
715
+ }
716
+
717
+ .fr-fe {
718
+ color: #222;
719
+ padding-top: 10px
720
+ }
721
+
722
+ .fe-1 {
723
+ padding: 22px 35px 35px 35px
724
+ }
725
+
726
+ .fe-1 h4 {
727
+ margin: 0 0 10px 0;
728
+ font-size: 20px;
729
+ line-height: 1.4;
730
+ font-weight: 400;
731
+ color: #000
732
+ }
733
+
734
+ .fe-1 p {
735
+ font-size: 15px;
736
+ line-height: 1.4;
737
+ margin: 0;
738
+ color: #333
739
+ }
740
+
741
+ .pr-fe {
742
+ padding: 34px 35px 35px 35px
743
+ }
744
+
745
+ .pr-fe span {
746
+ font-family: georgia;
747
+ font-size: 16px;
748
+ font-weight: 700;
749
+ color: #000;
750
+ font-style: italic;
751
+ line-height: 1.3
752
+ }
753
+
754
+ .fet {
755
+ width: 100%;
756
+ display: grid;
757
+ grid-template-columns: 1fr 1fr;
758
+ grid-gap: 25px;
759
+ margin-top: 40px
760
+ }
761
+
762
+ .fe-2 {
763
+ color: #222
764
+ }
765
+
766
+ .fe-t img {
767
+ width: 22px!important;
768
+ display: inline-block;
769
+ vertical-align: middle
770
+ }
771
+
772
+ .fe-t h4 {
773
+ margin: 0;
774
+ display: inline-block;
775
+ vertical-align: middle;
776
+ font-size: 19px;
777
+ color: #000;
778
+ font-weight: 400;
779
+ line-height: 1.4;
780
+ padding-left: 8px;
781
+ margin-top: -5px;
782
+ }
783
+
784
+ .fe-2 p {
785
+ font-size: 15px;
786
+ line-height: 1.4;
787
+ margin: 0;
788
+ color: #555;
789
+ padding-top: 8px
790
+ }
791
+
792
+ .pr-btn {
793
+ width: 100%;
794
+ display: inline-block;
795
+ text-align: center;
796
+ margin: 50px 0 25px 0
797
+ }
798
+
799
+ .pr-btn a {
800
+ text-decoration: none;
801
+ color: #fff;
802
+ padding: 12px 35px 17px 35px;
803
+ display: inline-block;
804
+ border-radius: 5px;
805
+ font-size: 28px;
806
+ font-weight: 500;
807
+ line-height: 1.2;
808
+ background: -webkit-linear-gradient(to right, #e35796, #fc789f);
809
+ font-weight: 600;
810
+ background: linear-gradient(to right, #e35796, #fc789f);
811
+ margin-top: 0;
812
+ box-shadow: 0 .15em .65em 0 rgba(0, 0, 0, .25);
813
+ }
814
+
815
+ .amp-upg {
816
+ background: #f5f5f5;
817
+ padding: 60px 10px 0 10px
818
+ }
819
+
820
+ .upg-t {
821
+ text-align: center;
822
+ color: #222
823
+ }
824
+
825
+ .upg-t h2 {
826
+ margin: 0;
827
+ font-size: 35px;
828
+ color: #060606;
829
+ line-height: 1.3;
830
+ font-weight: 500
831
+ }
832
+
833
+ .upg-t>span {
834
+ font-size: 14px;
835
+ line-height: 1.2;
836
+ margin-top: 15px;
837
+ display: inline-block;
838
+ color: #666
839
+ }
840
+
841
+ .etoc-pri-lst {
842
+ width: 100%;
843
+ display: grid;
844
+ grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
845
+ margin-top: 70px;
846
+ grid-gap: 1px;
847
+ box-shadow: 0 10px 15px 1px #ddd
848
+ }
849
+
850
+ .pri-tb {
851
+ background: #fff;
852
+ text-align: center;
853
+ border: 1px solid #f9f9f9;
854
+ position: relative
855
+ }
856
+
857
+ .pri-tb:hover {
858
+ border: 1px solid #e04371;
859
+ }
860
+
861
+ .pri-tb a:hover .pri-by {
862
+ background: #e04371;
863
+ }
864
+ .pri-tb a:hover .amt {
865
+ color: #7241a7;
866
+ }
867
+
868
+ .pri-tb a {
869
+ display: inline-block;
870
+ text-decoration: none;
871
+ color: #222;
872
+ padding: 20px 12px;
873
+ }
874
+
875
+ .pri-tb h5 {
876
+ margin: 0 0 20px 0;
877
+ font-size: 13px;
878
+ line-height: 1.2;
879
+ letter-spacing: 2px;
880
+ font-weight: 400;
881
+ color: #000
882
+ }
883
+
884
+ .pri-tb span {
885
+ display: inline-block
886
+ }
887
+
888
+ .pri-tb .amt {
889
+ font-size: 40px;
890
+ color: #e04371;
891
+ font-weight: 500;
892
+ margin-bottom: 20px;
893
+ display: block;
894
+ }
895
+
896
+ .pri-tb .d-amt {
897
+ font-size: 24px;
898
+ color: #666;
899
+ font-weight: 500;
900
+ margin-bottom: 15px;
901
+ display: none;
902
+ text-decoration: line-through
903
+ }
904
+
905
+ .d-amt sup {
906
+ line-height: 0;
907
+ position: relative;
908
+ top: 7px
909
+ }
910
+
911
+ .pri-tb .s-amt {
912
+ font-size: 13px;
913
+ color: #4caf50;
914
+ font-weight: 500;
915
+ margin-bottom: 10px;
916
+ display: none
917
+ }
918
+
919
+ .pri-tb .amt sup {
920
+ font-size: 22px;
921
+ padding: 0 4px 0 0;
922
+ position: relative;
923
+ top: 7px
924
+ }
925
+
926
+ .pri-tb .bil {
927
+ color: #aaa;
928
+ font-size: 12px;
929
+ margin-bottom: 20px
930
+ }
931
+
932
+ .pri-tb .e,
933
+ .pri-tb .f,
934
+ .pri-tb .s {
935
+ font-size: 14px;
936
+ margin-bottom: 15px;
937
+ color: #3b4750;
938
+ display: block;
939
+ }
940
+
941
+ .pri-tb .etoc-sv {
942
+ display: none;
943
+ font-size: 12px;
944
+ color: #fff;
945
+ background: #4caf50;
946
+ margin: 0 auto;
947
+ padding: 1px 7px 2px 7px;
948
+ border-radius: 45px
949
+ }
950
+
951
+ .pri-by {
952
+ font-size: 15px;
953
+ line-height: 1.2;
954
+ background: #333;
955
+ border-radius: 2px;
956
+ padding: 9px 18px 10px 18px;
957
+ display: inline-block;
958
+ color: #fff;
959
+ margin-top: 29px;
960
+ font-weight: 500
961
+ }
962
+
963
+ .etoc-pri-lst .rec {
964
+ box-shadow: 0 1px 40px 0 #ccc;
965
+ background: #fff;
966
+ z-index: 9;
967
+ margin-top: -20px;
968
+ position: relative
969
+ }
970
+
971
+ .etoc-pri-lst .rec:hover .etoc-rcm {
972
+ background: #000;
973
+ color: #fff;
974
+ }
975
+
976
+ .etoc-pri-lst .rec .pri-by {
977
+ background: #e04371;
978
+ }
979
+
980
+ .etoc-rcm {
981
+ background: linear-gradient(to right, #e35796, #fc789f);
982
+ color: #fff;
983
+ position: absolute;
984
+ top: -20px;
985
+ left: 0;
986
+ right: -1px;
987
+ bottom: auto;
988
+ padding: 2px 0;
989
+ font-size: 11px;
990
+ letter-spacing: 2px
991
+ }
992
+
993
+ .tru-us {
994
+ text-align: center;
995
+ padding: 60px 0;
996
+ margin: 0 auto;
997
+ font-size: 16px;
998
+ color: #222
999
+ }
1000
+
1001
+ .tru-us h2 {
1002
+ margin: 20px 0 0 0;
1003
+ font-size: 28px;
1004
+ font-weight: 500
1005
+ }
1006
+
1007
+ .tru-us p {
1008
+ font-size: 17px;
1009
+ margin: 19px 15% 18px 15%;
1010
+ color: #666;
1011
+ line-height: 29px
1012
+ }
1013
+
1014
+ .tru-us a {
1015
+ font-size: 18px;
1016
+ color: #489bff;
1017
+ text-decoration: none;
1018
+ font-weight: 400
1019
+ }
1020
+
1021
+ .ampfaq {
1022
+ width: 100%;
1023
+ margin: 25px 0
1024
+ }
1025
+
1026
+ .ampfaq h4 {
1027
+ margin: 0;
1028
+ text-align: center;
1029
+ font-size: 20px;
1030
+ font-weight: 500;
1031
+ color: #333
1032
+ }
1033
+
1034
+ .faq-lst {
1035
+ margin-top: 50px;
1036
+ display: grid;
1037
+ grid-template-columns: 1fr 1fr
1038
+ }
1039
+
1040
+ .lt {
1041
+ padding-left: 50px
1042
+ }
1043
+
1044
+ .lt,
1045
+ .rt {
1046
+ width: 70%
1047
+ }
1048
+
1049
+ .lt ul,
1050
+ .rt ul {
1051
+ margin: 0
1052
+ }
1053
+
1054
+ .lt ul li,
1055
+ .rt ul li {
1056
+ color: #222;
1057
+ margin-bottom: 30px!important
1058
+ }
1059
+
1060
+ .lt span,
1061
+ .rt span {
1062
+ font-size: 17px;
1063
+ font-weight: 500;
1064
+ margin-bottom: 6px;
1065
+ display: inline-block
1066
+ }
1067
+
1068
+ .lt p,
1069
+ .rt p {
1070
+ font-size: 15px;
1071
+ margin: 0
1072
+ }
1073
+
1074
+ .f-cnt {
1075
+ text-align: center;
1076
+ margin-top: 20px;
1077
+ color: #222
1078
+ }
1079
+
1080
+ .f-cnt span {
1081
+ font-size: 17px;
1082
+ margin: 8px 0;
1083
+ font-weight: 500
1084
+ }
1085
+
1086
+ .f-cnt p {
1087
+ font-size: 15px;
1088
+ margin: 6px 0
1089
+ }
1090
+
1091
+ .f-cnt a {
1092
+ background: #333;
1093
+ color: #fff;
1094
+ padding: 15px 30px;
1095
+ text-decoration: none;
1096
+ font-size: 18px;
1097
+ font-weight: 500;
1098
+ display: inline-block;
1099
+ margin-top: 15px
1100
+ }
1101
+
1102
+ @media(max-width:1366px) {
1103
+ .amp-upg {
1104
+ padding: 60px 0 0 0
1105
+ }
1106
+ .etoc-eztoc-cnt p {
1107
+
1108
+ line-height: 35px;
1109
+ font-size: 18px;
1110
+
1111
+ }
1112
+ }
1113
+
1114
+ @media(max-width:1280px) {
1115
+ .etoc-eztoc-cnt {
1116
+ top: 1.3%
1117
+ }
1118
+ }
1119
+
1120
+ @media(max-width:768px) {
1121
+ .ext {
1122
+ grid-template-columns: 1fr;
1123
+ grid-gap: 30px 0;
1124
+ padding: 30px
1125
+ }
1126
+ .pvf-tlt h2 {
1127
+ font-size: 26px
1128
+ }
1129
+ .pvf-cmp {
1130
+ grid-template-columns: 1fr
1131
+ }
1132
+ .pr-btn a {
1133
+ font-size: 22px
1134
+ }
1135
+ .etoc-pri-lst {
1136
+ grid-template-columns: 1fr 1fr 1fr
1137
+ }
1138
+ .etoc-eztoc-cnt p {
1139
+ line-height: 1.5;
1140
+ font-size: 16px;
1141
+ margin-top: 15px;
1142
+ padding: 0 20px
1143
+ }
1144
+ .etoc-eztoc-cnt .buy {
1145
+ font-size: 16px;
1146
+ padding: 8px 30px
1147
+ }
1148
+ .etoc-eztoc-cnt {
1149
+ top: 15px
1150
+ }
1151
+ .etoc-eztoc-cnt h1 {
1152
+ font-size: 30px
1153
+ }
1154
+ .ex-1 {
1155
+ width: 100%
1156
+ }
1157
+ .faq-lst {
1158
+ grid-template-columns: 1fr
1159
+ }
1160
+ .rt {
1161
+ padding-left: 50px
1162
+ }
1163
+ }
1164
+ div#freevspro {
1165
+ padding: 0;
1166
+ }
1167
+
1168
+ .ampfaq h2 {
1169
+ margin: 40px 0 0 0;
1170
+ font-size: 30px;
1171
+ font-weight: 500;
1172
+ text-align: center;
1173
+ }
1174
+ a#eztoc-upgrade {
1175
+ color: #ffffff;
1176
+ background: #fd789f;
1177
+ padding: 16px;
1178
+ }
1179
+ div#welcome {
1180
+ text-align: center;
1181
+ }
1182
+ a#eztoc-welcome {
1183
+ display: none;
1184
+ }
1185
+ .button-toc{
1186
+ text-align: center;
1187
+ cursor: pointer;
1188
+ font-size: 16px;
1189
+ margin: 20px;
1190
+ color: #fff;
1191
+ border-radius: 4px;
1192
+ background-color: #ec407a;
1193
+ border: none;
1194
+ padding: 20px;
1195
+ transition: all 0.5s;
1196
+ font-weight: 600;
1197
+ }
1198
+ .button-toc span {
1199
+ cursor: pointer;
1200
+ display: inline-block;
1201
+ position: relative;
1202
+ transition: 0.5s;
1203
+ }
1204
+
1205
+ .button-toc span:after {
1206
+ content: '»';
1207
+ position: absolute;
1208
+ opacity: 0;
1209
+ top: 0;
1210
+ right: -20px;
1211
+ transition: 0.5s;
1212
+ }
1213
+
1214
+ .button-toc:hover span {
1215
+ padding-right: 25px;
1216
+ }
1217
+
1218
+ .button-toc:hover span:after {
1219
+ opacity: 1;
1220
+ right: 0;
1221
+ }
assets/css/admin.min.css CHANGED
@@ -1 +1 @@
1
- div.tab_content table{margin-bottom:1em}table.more_toc_options_table td,table.more_toc_options_table th{padding:0;margin:0}table.more_toc_options_table th{width:auto;padding-right:4px;padding-top:2px}div.tab_content ul li{margin-left:2em;list-style-type:disc}div.tab_content ol li{list-style:inherit}div.tab_content pre{margin-left:2em}ul#tabbed-nav{margin-top:1em}#tabbed-nav{margin:0;padding:0;float:left;list-style:none;height:32px;border-bottom:1px solid #dfdfdf;border-left:1px solid #dfdfdf;width:100%}#tabbed-nav li{float:left;margin:0;padding:0;height:31px;line-height:31px;border:1px solid #dfdfdf;border-left:none;margin-bottom:-1px;overflow:hidden;position:relative;background:#f5f5f5;background-image:linear-gradient(center top,#fff,#f5f5f5)}#tabbed-nav li a{text-decoration:none;color:#000;display:block;font-size:1.2em;padding:0 20px;border:1px solid #fff;outline:0}#tabbed-nav li a:hover{background:#ececec}html #tabbed-nav li.active,html #tabbed-nav li.active a:hover{background:#fff;border-bottom:1px solid #fff}div.tab_container{border:1px solid #dfdfdf;border-top:none;overflow:hidden;clear:both;float:left;width:100%;background:#fff;margin-bottom:2em;padding-bottom:2em}div.tab_content{padding:10px;padding-bottom:0;font-size:1em}h3 span.show_hide{font-size:.85em;font-weight:400}div.more_toc_options{margin-top:4px;margin-left:2em}div.toc_theme_option{width:200px;float:left;margin-right:5px}#wpcontent select optgroup option{padding-left:15px}input#font_size,input#smooth_scroll_offset,input#width_custom{width:50px;text-align:center}input.custom_colour_option{width:75px}div#farbtastic_colour_wheel,table#theme_custom{float:left}table#theme_custom{margin-top:30px}table#theme_custom img{vertical-align:middle;opacity:.4}table#theme_custom img:hover{cursor:pointer;opacity:1}div#farbtastic_colour_wheel{margin-left:20px}#tab3 h3:not(:first-child){margin-top:2em}#toc input.small-text{width:50px;padding:2px;height:28px;line-height:28px;vertical-align:bottom}#toc .form-table tr>th>strong{font-size:18px;font-style:italic}.postbox{padding: 10px;}html {scroll-behavior: smooth;}.toc-tab-panel {overflow: hidden;border: 1px solid #ccc;background-color: #fff;margin-top: 15px;}.toc-tab-panel a {background-color: inherit;text-decoration: none;float: left;border: none;outline: none;cursor: pointer;padding: 14px 16px;transition: 0s;font-size: 15px;color: #2271b1;}.toc-tab-panel a:hover {color: #0a4b78;}.toc-tab-panel a.active {box-shadow: none;border-bottom: 4px solid #646970;color: #1d2327;}.toc-tab-panel a:focus {box-shadow: none;outline: none;}.eztoc-tabcontent {display: none;border-top: none; animation: fadeEffect 1s; }.eztoc_support_div {background: #fff;margin-top: 10px;padding: 28px;min-width: 255px; border: 1px solid #c3c4c7;box-shadow: 0 1px 1px rgb(0 0 0 / 4%);}.support-label {float: left;width: 70px;font-size: 14px;}.star-mark{color: red;margin-left: 4px;font-family:bold;}.eztoc_support_div li {margin:25px 0px 20px 0px; }.eztoc-query-success{color: green;}.eztoc-query-error{color: red;}.eztoc_hide{display: none;}.eztoc-result{margin-left: 70px;}.eztoc-send-query{margin-left: 70px !important;}@keyframes fadeEffect { from {opacity: 0;} to {opacity: 1;} }
1
+ div.tab_content table {margin-bottom: 1em;}table.more_toc_options_table th, table.more_toc_options_table td {padding: 0;margin: 0;}table.more_toc_options_table th {width: auto;padding-right: 4px;padding-top: 2px;}div.tab_content ul li {margin-left: 2em;list-style-type: disc;}div.tab_content ol li {list-style: inherit;}div.tab_content pre {margin-left: 2em;}ul#tabbed-nav {margin-top: 1em;}#tabbed-nav {margin: 0;padding: 0;float: left;list-style: none;height: 32px;border-bottom: 1px solid #DFDFDF;border-left: 1px solid #DFDFDF;width: 100%;}#tabbed-nav li {float: left;margin: 0;padding: 0;height: 31px;line-height: 31px;border: 1px solid #DFDFDF;border-left: none;margin-bottom: -1px;overflow: hidden;position: relative;background: #F5F5F5;background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#F5F5F5));background-image: -webkit-linear-gradient(center top, #fff, #F5F5F5);background-image: -moz-linear-gradient(center top, #fff, #F5F5F5);background-image: -ms-linear-gradient(center top, #fff, #F5F5F5);background-image: -o-linear-gradient(center top, #fff, #F5F5F5);background-image: linear-gradient(center top, #fff, #F5F5F5);}#tabbed-nav li a {text-decoration: none;color: #000;display: block;font-size: 1.2em;padding: 0 20px;border: 1px solid #fff;outline: none;}#tabbed-nav li a:hover {background: #ECECEC;}html #tabbed-nav li.active, html #tabbed-nav li.active a:hover {background: #fff;border-bottom: 1px solid #fff;}div.tab_container {border: 1px solid #DFDFDF;border-top: none;overflow: hidden;clear: both;float: left;width: 100%;background: #fff;margin-bottom: 2em;padding-bottom: 2em;}div.tab_content {padding: 10px;padding-bottom: 0;font-size: 1em;}h3 span.show_hide {font-size: 0.85em;font-weight: normal;}div.more_toc_options {margin-top: 4px;margin-left: 2em;}div.toc_theme_option {width: 200px;float: left;margin-right: 5px;}#wpcontent select optgroup option {padding-left: 15px;}input#width_custom, input#font_size, input#smooth_scroll_offset {width: 50px;text-align: center;}input.custom_colour_option {width: 75px;}table#theme_custom, div#farbtastic_colour_wheel {float: left;}table#theme_custom {margin-top: 30px;}table#theme_custom img {vertical-align: middle;opacity: 0.4;}table#theme_custom img:hover {cursor: pointer;opacity: 1;}div#farbtastic_colour_wheel {margin-left: 20px;}#tab3 h3:not(:first-child) {margin-top: 2em;}#toc input.small-text {width: 50px;padding: 2px;height: 28px;line-height: 28px;vertical-align: bottom;}#toc .form-table tr > th > strong {font-size: 18px;font-style: italic;}.postbox{padding: 10px;}html {scroll-behavior: smooth;}.toc-tab-panel {overflow: hidden;border: 1px solid #ccc;background-color: #fff;margin-top: 15px;}.toc-tab-panel a {background-color: inherit;text-decoration: none;float: left;border: none;outline: none;cursor: pointer;padding: 14px 16px;transition: 0s;font-size: 15px;color: #2271b1;font-weight: 500;}.toc-tab-panel a:hover {color: #0a4b78;}.toc-tab-panel a.active {box-shadow: none;border-bottom: 4px solid #646970;color: #1d2327;}.toc-tab-panel a:focus {box-shadow: none;outline: none;}.eztoc-tabcontent {display: none;border-top: none;animation: fadeEffect 1s;}.eztoc_support_div {background: #fff;margin-top: 10px;padding: 28px;min-width: 255px;border: 1px solid #c3c4c7;box-shadow: 0 1px 1px rgb(0 0 0 / 4%);}.support-label {float: left;width: 70px;font-size: 14px;}.star-mark{color: red;margin-left: 4px;font-family:bold;}.eztoc_support_div li {margin:25px 0px 20px 0px;}.eztoc-query-success{color: green;}.eztoc-query-error{color: red;}.eztoc_hide{display: none;}.eztoc-result{margin-left: 70px;}.eztoc-send-query{margin-left: 70px !important;;}@keyframes fadeEffect {from {opacity: 0;}to {opacity: 1;}}.eztoc-wrapper{max-width: 1090px;width: 100%;display: flex;flex-wrap: wrap;margin: auto;}.eztoc-wrapper .table{margin: 0 auto;background: #fff;width: calc(30%);padding: 30px 20px;position: relative;box-shadow: 0 5px 10px rgb(0 0 0 / 10%);}.table .price-section{display: flex;justify-content: center;}.price-section .price-area{height: 120px;width: 120px;background: #ffd861;border-radius: 50%;padding: 2px;}.price-section .price-area .inner-area{height: 100%;width: 100%;border-radius: 50%;border: 3px solid #fff;color: #fff;line-height: 117px;text-align: center;position: relative;}.price-area .inner-area .text{font-size: 25px;font-weight: 400;position: absolute;top: -10px;left: 17px;}.price-area .inner-area .price{font-size: 55px;font-weight: 500;}.table .package-name{width: 100%;height: 2px;background: #ffecb3;margin: 35px 0;position: relative;}.table .package-name::before{position: absolute;content: "Basic";top: 50%;left: 50%;transform: translate(-50%, -50%);background: #fff;font-size: 25px;padding: 0 10px;font-weight: bolder;}.table .features li{list-style: none;display: flex;justify-content: space-between;margin-bottom: 15px;}.features li .list-name{font-size: 17px;font-weight: 400;}.features li .icon{font-size: 15px;}.features li .icon.check{color: #2db94d;}.features li .icon.cross{color: #cd3241;}.table .btn{display: flex;justify-content: center;margin-top: 35px;}.table .btn button{width: 80%;height: 50px;font-weight: 700;color: #fff;font-size: 20px;border: none;outline: none;border-radius: 25px;cursor: pointer;transition: all 0.3s ease;}.basic .price-area, .basic .inner-area{background: #ffd861;}.basic .btn button{background: #fff;color: #ffd861;border: 2px solid #ffd861;}.basic .btn button:hover{border-radius: 6px;background: #ffd861;color: #fff;}.Premium .price-area, .Premium .inner-area{background: #a26bfa;}.Premium .btn button{background: #fff;color: #a26bfa;border: 2px solid #a26bfa;}.Premium .btn button:hover{border-radius: 6px;background: #a26bfa;color: #fff;}.basic .package-name{background: #ffecb3;}.Premium .package-name{background: #a26bfa;}.basic .package-name::before{content: "Free";}.Premium .package-name::before{content: "PRO";}.basic ::selection, .basic .price-area, .basic .inner-area{background: #ffd861;}.Premium ::selection, .Premium .price-area, .Premium .inner-area{background: #a26bfa;}div#eztoc-tabs a {text-decoration: none;}div#eztoc-tabs a:first-child {color: #000;}a#eztoc-upgrade {color: #b8ef0e;background: #000;padding: 16px;}
assets/css/screen.css CHANGED
@@ -1,374 +1,376 @@
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
-
122
- #ez-toc-container a {
123
- color: #444444;
124
- box-shadow: none;
125
- text-decoration: none;
126
- text-shadow: none;
127
- }
128
-
129
- #ez-toc-container a:visited {
130
- color: #9f9f9f;
131
- }
132
-
133
- #ez-toc-container a:hover {
134
- text-decoration: underline;
135
- }
136
-
137
- #ez-toc-container.ez-toc-black a {
138
- color: #FFF;
139
- }
140
-
141
- #ez-toc-container.ez-toc-black a:visited {
142
- color: #FFF;
143
- }
144
-
145
- #ez-toc-container a.ez-toc-toggle {
146
- color: #444444;
147
- }
148
-
149
- #ez-toc-container.counter-hierarchy ul,
150
- .ez-toc-widget-container.counter-hierarchy ul,
151
- #ez-toc-container.counter-flat ul,
152
- .ez-toc-widget-container.counter-flat ul {
153
- counter-reset: item;
154
- }
155
-
156
- #ez-toc-container.counter-numeric li,
157
- .ez-toc-widget-container.counter-numeric li {
158
- list-style-type: decimal;
159
- list-style-position: inside;
160
- }
161
-
162
- #ez-toc-container.counter-decimal ul.ez-toc-list li a::before,
163
- .ez-toc-widget-container.counter-decimal ul.ez-toc-list li a::before {
164
- content: counters(item, ".") ". ";
165
- display: inline-block;
166
- counter-increment: item;
167
- margin-right: .2em;
168
- }
169
-
170
- #ez-toc-container.counter-roman li a::before,
171
- .ez-toc-widget-container.counter-roman ul.ez-toc-list li a::before {
172
- content: counters(item, ".", upper-roman) ". ";
173
- counter-increment: item;
174
- }
175
-
176
- .ez-toc-widget-container ul.ez-toc-list li::before {
177
- content: ' ';
178
- position: absolute;
179
- left: 0;
180
- right: 0;
181
- height: 30px;
182
- line-height: 30px;
183
- z-index: -1;
184
- }
185
-
186
- .ez-toc-widget-container ul.ez-toc-list li.active::before {
187
- background-color: #EDEDED;
188
- }
189
-
190
- .ez-toc-widget-container li.active > a {
191
- font-weight: 900;
192
- }
193
-
194
- .ez-toc-btn {
195
- display: inline-block;
196
- padding: 6px 12px;
197
- margin-bottom: 0;
198
- font-size: 14px;
199
- font-weight: normal;
200
- line-height: 1.428571429;
201
- text-align: center;
202
- white-space: nowrap;
203
- vertical-align: middle;
204
- cursor: pointer;
205
- background-image: none;
206
- border: 1px solid transparent;
207
- border-radius: 4px;
208
- -webkit-user-select: none;
209
- -moz-user-select: none;
210
- -ms-user-select: none;
211
- -o-user-select: none;
212
- user-select: none
213
- }
214
-
215
- .ez-toc-btn:focus {
216
- outline: thin dotted #333;
217
- outline: 5px auto -webkit-focus-ring-color;
218
- outline-offset: -2px
219
- }
220
-
221
- .ez-toc-btn:hover,.ez-toc-btn:focus {
222
- color: #333;
223
- text-decoration: none
224
- }
225
-
226
- .ez-toc-btn:active,.ez-toc-btn.active {
227
- background-image: none;
228
- outline: 0;
229
- -webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);
230
- box-shadow: inset 0 3px 5px rgba(0,0,0,0.125)
231
- }
232
-
233
- .ez-toc-btn-default {
234
- color: #333;
235
- background-color: #fff;
236
- border-color: #ccc
237
- }
238
-
239
- .ez-toc-btn-default:hover,.ez-toc-btn-default:focus,.ez-toc-btn-default:active,.ez-toc-btn-default.active {
240
- color: #333;
241
- background-color: #ebebeb;
242
- border-color: #adadad
243
- }
244
-
245
- .ez-toc-btn-default:active,.ez-toc-btn-default.active {
246
- background-image: none
247
- }
248
-
249
- /*.btn-lg {*/
250
- /*padding: 10px 16px;*/
251
- /*font-size: 18px;*/
252
- /*line-height: 1.33;*/
253
- /*border-radius: 6px*/
254
- /*}*/
255
-
256
- .ez-toc-btn-sm,.ez-toc-btn-xs {
257
- padding: 5px 10px;
258
- font-size: 12px;
259
- line-height: 1.5;
260
- border-radius: 3px
261
- }
262
-
263
- .ez-toc-btn-xs {
264
- padding: 1px 5px
265
- }
266
-
267
- .ez-toc-btn-default {
268
- text-shadow: 0 -1px 0 rgba(0,0,0,0.2);
269
- -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);
270
- box-shadow: inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075)
271
- }
272
-
273
- .ez-toc-btn-default:active {
274
- -webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);
275
- box-shadow: inset 0 3px 5px rgba(0,0,0,0.125)
276
- }
277
-
278
- .ez-toc-btn:active,.btn.active {
279
- background-image: none
280
- }
281
-
282
- .ez-toc-btn-default {
283
- text-shadow: 0 1px 0 #fff;
284
- background-image: -webkit-gradient(linear,left 0,left 100%,from(#fff),to(#e0e0e0));
285
- background-image: -webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);
286
- background-image: -moz-linear-gradient(top,#fff 0,#e0e0e0 100%);
287
- background-image: linear-gradient(to bottom,#fff 0,#e0e0e0 100%);
288
- background-repeat: repeat-x;
289
- border-color: #dbdbdb;
290
- border-color: #ccc;
291
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe0e0e0',GradientType=0);
292
- filter: progid:DXImageTransform.Microsoft.gradient(enabled=false)
293
- }
294
-
295
- .ez-toc-btn-default:hover,.ez-toc-btn-default:focus {
296
- background-color: #e0e0e0;
297
- background-position: 0 -15px
298
- }
299
-
300
- .ez-toc-btn-default:active,.ez-toc-btn-default.active {
301
- background-color: #e0e0e0;
302
- border-color: #dbdbdb
303
- }
304
-
305
- .ez-toc-pull-right {
306
- float: right !important;
307
- margin-left: 10px;
308
- }
309
-
310
- .ez-toc-glyphicon {
311
- position: relative;
312
- top: 1px;
313
- display: inline-block;
314
- font-family: 'Glyphicons Halflings';
315
- -webkit-font-smoothing: antialiased;
316
- font-style: normal;
317
- font-weight: normal;
318
- line-height: 1;
319
- -moz-osx-font-smoothing: grayscale
320
- }
321
-
322
- .ez-toc-glyphicon:empty {
323
- width: 1em
324
- }
325
-
326
- .ez-toc-toggle i.ez-toc-glyphicon {
327
- font-size: 16px;
328
- margin-left: 2px;
329
- }
330
-
331
- [class*="ez-toc-icon-"] {
332
- font-family: 'ez-toc-icomoon' !important; /* For better glyphicon compatibility */
333
- speak: none;
334
- font-style: normal;
335
- font-weight: normal;
336
- font-variant: normal;
337
- text-transform: none;
338
- line-height: 1;
339
-
340
- /* Better Font Rendering =========== */
341
- -webkit-font-smoothing: antialiased;
342
- -moz-osx-font-smoothing: grayscale;
343
- }
344
-
345
- .ez-toc-icon-toggle:before {
346
- content: "\e87a";
347
- }
348
- #ez-toc-container input {
349
- position: absolute;
350
- left: -999em;
351
- }
352
- #ez-toc-container input[type="checkbox"]:checked + nav {
353
- opacity: 0;
354
- max-height: 0;
355
- border: none;
356
- }
357
-
358
- #ez-toc-container label {
359
- float: right;
360
- position: relative;
361
- left: 10px;
362
- font-size: 16px;
363
- background: #f9efef;
364
- padding: 0px 4px 0px 5px;
365
- border: 1px solid #999191;
366
- border-radius: 5px;
367
- cursor: pointer;
368
- }
369
- div#ez-toc-container p.ez-toc-title {
370
- display: contents;
371
- }
372
- div#ez-toc-container {
373
- padding-right: 20px;
 
 
374
  }
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-decimal ul.ez-toc-list li a::before,
165
+ .ez-toc-widget-container.counter-decimal ul.ez-toc-list li a::before {
166
+ content: counters(item, ".") ". ";
167
+ display: inline-block;
168
+ counter-increment: item;
169
+ margin-right: .2em;
170
+ }
171
+
172
+ #ez-toc-container.counter-roman li a::before,
173
+ .ez-toc-widget-container.counter-roman ul.ez-toc-list li a::before {
174
+ content: counters(item, ".", upper-roman) ". ";
175
+ counter-increment: item;
176
+ }
177
+
178
+ .ez-toc-widget-container ul.ez-toc-list li::before {
179
+ content: ' ';
180
+ position: absolute;
181
+ left: 0;
182
+ right: 0;
183
+ height: 30px;
184
+ line-height: 30px;
185
+ z-index: -1;
186
+ }
187
+
188
+ .ez-toc-widget-container ul.ez-toc-list li.active::before {
189
+ background-color: #EDEDED;
190
+ }
191
+
192
+ .ez-toc-widget-container li.active > a {
193
+ font-weight: 900;
194
+ }
195
+
196
+ .ez-toc-btn {
197
+ display: inline-block;
198
+ padding: 6px 12px;
199
+ margin-bottom: 0;
200
+ font-size: 14px;
201
+ font-weight: normal;
202
+ line-height: 1.428571429;
203
+ text-align: center;
204
+ white-space: nowrap;
205
+ vertical-align: middle;
206
+ cursor: pointer;
207
+ background-image: none;
208
+ border: 1px solid transparent;
209
+ border-radius: 4px;
210
+ -webkit-user-select: none;
211
+ -moz-user-select: none;
212
+ -ms-user-select: none;
213
+ -o-user-select: none;
214
+ user-select: none
215
+ }
216
+
217
+ .ez-toc-btn:focus {
218
+ outline: thin dotted #333;
219
+ outline: 5px auto -webkit-focus-ring-color;
220
+ outline-offset: -2px
221
+ }
222
+
223
+ .ez-toc-btn:hover,.ez-toc-btn:focus {
224
+ color: #333;
225
+ text-decoration: none
226
+ }
227
+
228
+ .ez-toc-btn:active,.ez-toc-btn.active {
229
+ background-image: none;
230
+ outline: 0;
231
+ -webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);
232
+ box-shadow: inset 0 3px 5px rgba(0,0,0,0.125)
233
+ }
234
+
235
+ .ez-toc-btn-default {
236
+ color: #333;
237
+ background-color: #fff;
238
+ border-color: #ccc
239
+ }
240
+
241
+ .ez-toc-btn-default:hover,.ez-toc-btn-default:focus,.ez-toc-btn-default:active,.ez-toc-btn-default.active {
242
+ color: #333;
243
+ background-color: #ebebeb;
244
+ border-color: #adadad
245
+ }
246
+
247
+ .ez-toc-btn-default:active,.ez-toc-btn-default.active {
248
+ background-image: none
249
+ }
250
+
251
+ /*.btn-lg {*/
252
+ /*padding: 10px 16px;*/
253
+ /*font-size: 18px;*/
254
+ /*line-height: 1.33;*/
255
+ /*border-radius: 6px*/
256
+ /*}*/
257
+
258
+ .ez-toc-btn-sm,.ez-toc-btn-xs {
259
+ padding: 5px 10px;
260
+ font-size: 12px;
261
+ line-height: 1.5;
262
+ border-radius: 3px
263
+ }
264
+
265
+ .ez-toc-btn-xs {
266
+ padding: 1px 5px
267
+ }
268
+
269
+ .ez-toc-btn-default {
270
+ text-shadow: 0 -1px 0 rgba(0,0,0,0.2);
271
+ -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);
272
+ box-shadow: inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075)
273
+ }
274
+
275
+ .ez-toc-btn-default:active {
276
+ -webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);
277
+ box-shadow: inset 0 3px 5px rgba(0,0,0,0.125)
278
+ }
279
+
280
+ .ez-toc-btn:active,.btn.active {
281
+ background-image: none
282
+ }
283
+
284
+ .ez-toc-btn-default {
285
+ text-shadow: 0 1px 0 #fff;
286
+ background-image: -webkit-gradient(linear,left 0,left 100%,from(#fff),to(#e0e0e0));
287
+ background-image: -webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);
288
+ background-image: -moz-linear-gradient(top,#fff 0,#e0e0e0 100%);
289
+ background-image: linear-gradient(to bottom,#fff 0,#e0e0e0 100%);
290
+ background-repeat: repeat-x;
291
+ border-color: #dbdbdb;
292
+ border-color: #ccc;
293
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe0e0e0',GradientType=0);
294
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false)
295
+ }
296
+
297
+ .ez-toc-btn-default:hover,.ez-toc-btn-default:focus {
298
+ background-color: #e0e0e0;
299
+ background-position: 0 -15px
300
+ }
301
+
302
+ .ez-toc-btn-default:active,.ez-toc-btn-default.active {
303
+ background-color: #e0e0e0;
304
+ border-color: #dbdbdb
305
+ }
306
+
307
+ .ez-toc-pull-right {
308
+ float: right !important;
309
+ margin-left: 10px;
310
+ }
311
+
312
+ .ez-toc-glyphicon {
313
+ position: relative;
314
+ top: 1px;
315
+ display: inline-block;
316
+ font-family: 'Glyphicons Halflings';
317
+ -webkit-font-smoothing: antialiased;
318
+ font-style: normal;
319
+ font-weight: normal;
320
+ line-height: 1;
321
+ -moz-osx-font-smoothing: grayscale
322
+ }
323
+
324
+ .ez-toc-glyphicon:empty {
325
+ width: 1em
326
+ }
327
+
328
+ .ez-toc-toggle i.ez-toc-glyphicon {
329
+ font-size: 16px;
330
+ margin-left: 2px;
331
+ }
332
+
333
+ [class*="ez-toc-icon-"] {
334
+ font-family: 'ez-toc-icomoon' !important; /* For better glyphicon compatibility */
335
+ speak: none;
336
+ font-style: normal;
337
+ font-weight: normal;
338
+ font-variant: normal;
339
+ text-transform: none;
340
+ line-height: 1;
341
+
342
+ /* Better Font Rendering =========== */
343
+ -webkit-font-smoothing: antialiased;
344
+ -moz-osx-font-smoothing: grayscale;
345
+ }
346
+
347
+ .ez-toc-icon-toggle:before {
348
+ content: "\e87a";
349
+ }
350
+ #ez-toc-container input {
351
+ position: absolute;
352
+ left: -999em;
353
+ }
354
+ #ez-toc-container input[type="checkbox"]:checked + nav {
355
+ opacity: 0;
356
+ max-height: 0;
357
+ border: none;
358
+ }
359
+
360
+ #ez-toc-container label {
361
+ float: right;
362
+ position: relative;
363
+ left: 10px;
364
+ font-size: 16px;
365
+ background: #f9efef;
366
+ padding: 0px 4px 0px 5px;
367
+ border: 1px solid #999191;
368
+ border-radius: 5px;
369
+ cursor: pointer;
370
+ }
371
+ div#ez-toc-container p.ez-toc-title {
372
+ display: contents;
373
+ }
374
+ div#ez-toc-container {
375
+ padding-right: 20px;
376
  }
assets/css/screen.min.css CHANGED
@@ -1 +1 @@
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;}
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;}
assets/eztoc-logo.png ADDED
Binary file
assets/js/eztoc-admin.js CHANGED
@@ -1,77 +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{
28
- $("#eztoc-default").click();
29
- }
30
-
31
- $(".eztoc-send-query").on("click", function(e){
32
- e.preventDefault();
33
- var message = $("#eztoc_query_message").val();
34
- var email = $("#eztoc_query_email").val();
35
- var premium_cus = $("#saswp_query_premium_cus").val();
36
-
37
- if($.trim(message) !='' && $.trim(email) !='' && eztocIsEmail(email) == true){
38
- $.ajax({
39
- type: "POST",
40
- url:ajaxurl,
41
- dataType: "json",
42
- data:{action:"eztoc_send_query_message",message:message,email:email, eztoc_security_nonce:eztoc_admin_data.eztoc_security_nonce},
43
- success:function(response){
44
- if(response['status'] =='t'){
45
- $(".eztoc-query-success").show();
46
- $(".eztoc-query-error").hide();
47
- }else{
48
- $(".eztoc-query-success").hide();
49
- $(".eztoc-query-error").show();
50
- }
51
- },
52
- error: function(response){
53
- console.log(response);
54
- }
55
- });
56
- }else{
57
-
58
- if($.trim(message) =='' && $.trim(email) ==''){
59
- alert('Please enter the message, email and select customer type');
60
- }else{
61
-
62
- if($.trim(message) == ''){
63
- alert('Please enter the message');
64
- }
65
- if($.trim(email) == ''){
66
- alert('Please enter the email');
67
- }
68
- if(eztocIsEmail(email) == false){
69
- alert('Please enter a valid email');
70
- }
71
-
72
- }
73
-
74
- }
75
-
76
- });
 
 
 
 
 
 
77
  });
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,309 +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
- var affix = $( '.ez-toc-widget-container.ez-toc-affix' );
15
-
16
- if ( 0 !== affix.length ) {
17
-
18
- /**
19
- * The smooth scroll offset needs to be taken into account when defining the offset_top property.
20
- * @link https://github.com/shazahm1/Easy-Table-of-Contents/issues/19
21
- *
22
- * @type {number}
23
- */
24
- var affixOffset = 30;
25
-
26
- // check offset setting
27
- if ( typeof ezTOC.scroll_offset != 'undefined' ) {
28
-
29
- affixOffset = parseInt( ezTOC.scroll_offset );
30
- }
31
-
32
- $( ezTOC.affixSelector ).stick_in_parent( {
33
- inner_scrolling: false,
34
- offset_top: affixOffset
35
- } )
36
- }
37
-
38
- $.fn.shrinkTOCWidth = function() {
39
-
40
- $( this ).css( {
41
- width: 'auto',
42
- display: 'table'
43
- });
44
-
45
- if ( /MSIE 7\./.test( navigator.userAgent ) )
46
- $( this ).css( 'width', '' );
47
- };
48
-
49
- var smoothScroll = parseInt( ezTOC.smooth_scroll );
50
-
51
- if ( 1 === smoothScroll ) {
52
-
53
- $( 'a.ez-toc-link' ).on( 'click', function() {
54
-
55
- var self = $( this );
56
-
57
- var target = '';
58
- var hostname = self.prop( 'hostname' );
59
- var pathname = self.prop( 'pathname' );
60
- var qs = self.prop( 'search' );
61
- var hash = self.prop( 'hash' );
62
-
63
- // ie strips out the preceding / from pathname
64
- if ( pathname.length > 0 ) {
65
- if ( pathname.charAt( 0 ) !== '/' ) {
66
- pathname = '/' + pathname;
67
- }
68
- }
69
-
70
- if ( ( window.location.hostname === hostname ) &&
71
- ( window.location.pathname === pathname ) &&
72
- ( window.location.search === qs ) &&
73
- ( hash !== '' )
74
- ) {
75
-
76
- // var id = decodeURIComponent( hash.replace( '#', '' ) );
77
- target = '[id="' + hash.replace( '#', '' ) + '"]';
78
-
79
- // verify it exists
80
- if ( $( target ).length === 0 ) {
81
- console.log( 'ezTOC scrollTarget Not Found: ' + target );
82
- target = '';
83
- }
84
-
85
- // check offset setting
86
- if ( typeof ezTOC.scroll_offset != 'undefined' ) {
87
-
88
- var offset = -1 * ezTOC.scroll_offset;
89
-
90
- } else {
91
-
92
- var adminbar = $( '#wpadminbar' );
93
-
94
- if ( adminbar.length > 0 ) {
95
-
96
- if ( adminbar.is( ':visible' ) )
97
- offset = -30; // admin bar exists, give it the default
98
- else
99
- offset = 0; // there is an admin bar but it's hidden, so no offset!
100
-
101
- } else {
102
-
103
- // no admin bar, so no offset!
104
- offset = 0;
105
- }
106
- }
107
-
108
- if ( target ) {
109
- $.smoothScroll( {
110
- scrollTarget: target,
111
- offset: offset,
112
- beforeScroll: deactivateSetActiveEzTocListElement,
113
- afterScroll: function() { setActiveEzTocListElement(); activateSetActiveEzTocListElement(); }
114
- } );
115
-
116
- }
117
- }
118
- } );
119
- }
120
-
121
- if ( typeof ezTOC.visibility_hide_by_default != 'undefined' ) {
122
-
123
- var toc = $( 'ul.ez-toc-list' );
124
- var toggle = $( 'a.ez-toc-toggle' );
125
- var invert = ezTOC.visibility_hide_by_default;
126
-
127
- toggle.css( 'display', 'inline' );
128
-
129
- if ( Cookies ) {
130
-
131
- Cookies.get( 'ezTOC_hidetoc' ) == 1 ? toggle.data( 'visible', false ) : toggle.data( 'visible', true );
132
-
133
- } else {
134
-
135
- toggle.data( 'visible', true );
136
- }
137
-
138
- if ( invert ) {
139
-
140
- toggle.data( 'visible', false )
141
- }
142
-
143
- if ( ! toggle.data( 'visible' ) ) {
144
-
145
- toc.hide();
146
- }
147
-
148
- toggle.on( 'click', function( event ) {
149
-
150
- event.preventDefault();
151
-
152
- if ( $( this ).data( 'visible' ) ) {
153
-
154
- $( this ).data( 'visible', false );
155
-
156
- if ( Cookies ) {
157
-
158
- if ( invert )
159
- Cookies.set( 'ezTOC_hidetoc', null, { path: '/' } );
160
- else
161
- Cookies.set( 'ezTOC_hidetoc', '1', { expires: 30, path: '/' } );
162
- }
163
-
164
- toc.hide( 'fast' );
165
-
166
- } else {
167
-
168
- $( this ).data( 'visible', true );
169
-
170
- if ( Cookies ) {
171
-
172
- if ( invert )
173
- Cookies.set( 'ezTOC_hidetoc', '1', { expires: 30, path: '/' } );
174
- else
175
- Cookies.set( 'ezTOC_hidetoc', null, { path: '/' } );
176
- }
177
-
178
- toc.show( 'fast' );
179
-
180
- }
181
-
182
- } );
183
- }
184
-
185
-
186
- // ======================================
187
- // Set active heading in ez-toc-widget list
188
- // ======================================
189
-
190
- var headings = $( 'span.ez-toc-section' ).toArray();
191
- var headingToListElementLinkMap = getHeadingToListElementLinkMap( headings );
192
- var listElementLinks = $.map( headingToListElementLinkMap, function ( value, key ) {
193
- return value
194
- } );
195
- var scrollOffset = getScrollOffset();
196
-
197
- activateSetActiveEzTocListElement();
198
-
199
- function setActiveEzTocListElement() {
200
- var activeHeading = getActiveHeading( scrollOffset, headings );
201
- if ( activeHeading ) {
202
- var activeListElementLink = headingToListElementLinkMap[ activeHeading.id ];
203
- removeStyleFromNonActiveListElement( activeListElementLink, listElementLinks );
204
- setStyleForActiveListElementElement( activeListElementLink );
205
- }
206
- }
207
-
208
- function activateSetActiveEzTocListElement() {
209
- if ( headings.length > 0 && $('.ez-toc-widget-container').length) {
210
- $( window ).on( 'load resize scroll', setActiveEzTocListElement );
211
- }
212
- }
213
-
214
- function deactivateSetActiveEzTocListElement() {
215
- $( window ).off( 'load resize scroll', setActiveEzTocListElement );
216
- }
217
-
218
- function getEzTocListElementLinkByHeading( heading ) {
219
- return $( '.ez-toc-widget-container .ez-toc-list a[href="#' + $( heading ).attr( 'id' ) + '"]' );
220
- }
221
-
222
- function getHeadingToListElementLinkMap( headings ) {
223
- return headings.reduce( function ( map, heading ) {
224
- map[ heading.id ] = getEzTocListElementLinkByHeading( heading );
225
- return map;
226
- }, {} );
227
- }
228
-
229
- function getScrollOffset() {
230
- var scrollOffset = 5; // so if smooth offset is off, the correct title is set as active
231
- if ( typeof ezTOC.smooth_scroll != 'undefined' && parseInt( ezTOC.smooth_scroll ) === 1 ) {
232
- scrollOffset = ( typeof ezTOC.scroll_offset != 'undefined' ) ? parseInt( ezTOC.scroll_offset ) : 30;
233
- }
234
-
235
- var adminbar = $( '#wpadminbar' );
236
-
237
- if ( adminbar.length ) {
238
- scrollOffset += adminbar.height();
239
- }
240
- return scrollOffset;
241
- }
242
-
243
- function getActiveHeading( topOffset, headings ) {
244
- var scrollTop = $( window ).scrollTop();
245
- var relevantOffset = scrollTop + topOffset + 1;
246
- var activeHeading = headings[ 0 ];
247
- var closestHeadingAboveOffset = relevantOffset - $( activeHeading ).offset().top;
248
- headings.forEach( function ( section ) {
249
- var topOffset = relevantOffset - $( section ).offset().top;
250
- if ( topOffset > 0 && topOffset < closestHeadingAboveOffset ) {
251
- closestHeadingAboveOffset = topOffset;
252
- activeHeading = section;
253
- }
254
- } );
255
- return activeHeading;
256
- }
257
-
258
- function removeStyleFromNonActiveListElement( activeListElementLink, listElementLinks ) {
259
- listElementLinks.forEach( function ( listElementLink ) {
260
- if ( activeListElementLink !== listElementLink && listElementLink.parent().hasClass( 'active' ) ) {
261
- listElementLink.parent().removeClass( 'active' );
262
- }
263
- } );
264
- }
265
-
266
- function correctActiveListElementBackgroundColorHeight( activeListElement ) {
267
- var listElementHeight = getListElementHeightWithoutUlChildren( activeListElement );
268
- addListElementBackgroundColorHeightStyleToHead( listElementHeight );
269
- }
270
-
271
- function getListElementHeightWithoutUlChildren( listElement ) {
272
- var $listElement = $( listElement );
273
- var content = $listElement.html();
274
- // Adding list item with class '.active' to get the real height.
275
- // When adding a class to an existing element and using jQuery(..).height() directly afterwards,
276
- // the height is the 'old' height. The height might change due to text-wraps when setting the text-weight bold for example
277
- // When adding a new item, the height is calculated correctly.
278
- // But only when it might be visible (so display:none; is not possible...)
279
- // But because it get's directly removed afterwards it never will be rendered by the browser
280
- // (at least in my tests in FF, Chrome, IE11 and Edge)
281
- $listElement.parent().append( '<li id="ez-toc-height-test" class="active">' + content + '</li>' );
282
- var listItem = $( '#ez-toc-height-test' );
283
- var height = listItem.height();
284
- listItem.remove();
285
- return height - $listElement.children( 'ul' ).first().height();
286
- }
287
-
288
- function addListElementBackgroundColorHeightStyleToHead( listElementHeight ) {
289
- // Remove existing
290
- $( '#ez-toc-active-height' ).remove();
291
- // jQuery(..).css(..) doesn't work, because ::before is a pseudo element and not part of the DOM
292
- // Workaround is to add it to head
293
- $( '<style id="ez-toc-active-height">' +
294
- '.ez-toc-widget-container ul.ez-toc-list li.active::before {' +
295
- // 'line-heigh:' + listElementHeight + 'px; ' +
296
- 'height:' + listElementHeight + 'px;' +
297
- '} </style>' )
298
- .appendTo( 'head' );
299
- }
300
-
301
- function setStyleForActiveListElementElement( activeListElementLink ) {
302
- var activeListElement = activeListElementLink.parent();
303
- if ( !activeListElement.hasClass( 'active' ) ) {
304
- activeListElement.addClass( 'active' );
305
- }
306
- correctActiveListElementBackgroundColorHeight( activeListElement );
307
- }
308
- }
309
- } );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ } );
assets/right-tick.png ADDED
Binary file
assets/toc-rating.png ADDED
Binary file
assets/zabi.jpg ADDED
Binary file
easy-table-of-contents.php CHANGED
@@ -1,743 +1,758 @@
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.20
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.20
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.20';
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( apply_filters( 'ez_toc_shortcode', 'toc' ), array( __CLASS__, 'shortcode' ) );
158
- }
159
-
160
- /**
161
- * Load the plugin translation.
162
- *
163
- * Credit: Adapted from Ninja Forms / Easy Digital Downloads.
164
- *
165
- * @access private
166
- * @since 1.0
167
- * @static
168
- *
169
- * @uses apply_filters()
170
- * @uses get_locale()
171
- * @uses load_textdomain()
172
- * @uses load_plugin_textdomain()
173
- *
174
- * @return void
175
- */
176
- public static function loadTextdomain() {
177
-
178
- // Plugin textdomain. This should match the one set in the plugin header.
179
- $domain = 'easy-table-of-contents';
180
-
181
- // Set filter for plugin's languages directory
182
- $languagesDirectory = apply_filters( "ez_{$domain}_languages_directory", EZ_TOC_DIR_NAME . '/languages/' );
183
-
184
- // Traditional WordPress plugin locale filter
185
- $locale = apply_filters( 'plugin_locale', get_locale(), $domain );
186
- $fileName = sprintf( '%1$s-%2$s.mo', $domain, $locale );
187
-
188
- // Setup paths to current locale file
189
- $local = $languagesDirectory . $fileName;
190
- $global = WP_LANG_DIR . "/{$domain}/" . $fileName;
191
-
192
- if ( file_exists( $global ) ) {
193
-
194
- // Look in global `../wp-content/languages/{$domain}/` folder.
195
- load_textdomain( $domain, $global );
196
-
197
- } elseif ( file_exists( $local ) ) {
198
-
199
- // Look in local `../wp-content/plugins/{plugin-directory}/languages/` folder.
200
- load_textdomain( $domain, $local );
201
-
202
- } else {
203
-
204
- // Load the default language files
205
- load_plugin_textdomain( $domain, false, $languagesDirectory );
206
- }
207
- }
208
-
209
- /**
210
- * Call back for the `wp_enqueue_scripts` action.
211
- *
212
- * Register and enqueue CSS and javascript files for frontend.
213
- *
214
- * @access private
215
- * @since 1.0
216
- * @static
217
- */
218
- public static function enqueueScripts() {
219
-
220
- // If SCRIPT_DEBUG is set and TRUE load the non-minified JS files, otherwise, load the minified files.
221
- $min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
222
-
223
- $js_vars = array();
224
-
225
- $isEligible = self::is_eligible( get_post() );
226
-
227
- if ( ! $isEligible && ! is_active_widget( false, false, 'ezw_tco' ) ) {
228
- return false;
229
- }
230
-
231
- wp_register_style( 'ez-icomoon', EZ_TOC_URL . "vendor/icomoon/style$min.css", array(), ezTOC::VERSION );
232
- wp_register_style( 'ez-toc', EZ_TOC_URL . "assets/css/screen$min.css", array( 'ez-icomoon' ), ezTOC::VERSION );
233
-
234
- wp_register_script( 'js-cookie', EZ_TOC_URL . "vendor/js-cookie/js.cookie$min.js", array(), '2.2.1', TRUE );
235
- wp_register_script( 'jquery-smooth-scroll', EZ_TOC_URL . "vendor/smooth-scroll/jquery.smooth-scroll$min.js", array( 'jquery' ), '2.2.0', TRUE );
236
- wp_register_script( 'jquery-sticky-kit', EZ_TOC_URL . "vendor/sticky-kit/jquery.sticky-kit$min.js", array( 'jquery' ), '1.9.2', TRUE );
237
-
238
- if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
239
- wp_register_script(
240
- 'ez-toc-js',
241
- EZ_TOC_URL . "assets/js/front{$min}.js",
242
- array( 'jquery-smooth-scroll', 'js-cookie', 'jquery-sticky-kit' ),
243
- ezTOC::VERSION . '-' . filemtime( EZ_TOC_PATH . "/assets/js/front{$min}.js" ),
244
- true
245
- );
246
- }
247
-
248
- if ( ! ezTOC_Option::get( 'exclude_css' ) ) {
249
-
250
- wp_enqueue_style( 'ez-toc' );
251
- self::inlineCSS();
252
- }
253
-
254
- if ( ezTOC_Option::get( 'smooth_scroll' ) ) {
255
-
256
- $js_vars['smooth_scroll'] = true;
257
- }
258
-
259
- //wp_enqueue_script( 'ez-toc-js' );
260
-
261
- if ( ezTOC_Option::get( 'show_heading_text' ) && ezTOC_Option::get( 'visibility' ) ) {
262
-
263
- $width = ezTOC_Option::get( 'width' ) !== 'custom' ? ezTOC_Option::get( 'width' ) : ezTOC_Option::get( 'width_custom' ) . ezTOC_Option::get( 'width_custom_units' );
264
-
265
- $js_vars['visibility_hide_by_default'] = ezTOC_Option::get( 'visibility_hide_by_default' ) ? true : false;
266
-
267
- $js_vars['width'] = esc_js( $width );
268
- }
269
-
270
- $offset = wp_is_mobile() ? ezTOC_Option::get( 'mobile_smooth_scroll_offset', 0 ) : ezTOC_Option::get( 'smooth_scroll_offset', 30 );
271
-
272
- $js_vars['scroll_offset'] = esc_js( $offset );
273
-
274
- if ( ezTOC_Option::get( 'widget_affix_selector' ) ) {
275
-
276
- $js_vars['affixSelector'] = ezTOC_Option::get( 'widget_affix_selector' );
277
- }
278
-
279
- if ( 0 < count( $js_vars ) ) {
280
-
281
- wp_localize_script( 'ez-toc-js', 'ezTOC', $js_vars );
282
- }
283
- }
284
-
285
- /**
286
- * Prints out inline CSS after the core CSS file to allow overriding core styles via options.
287
- *
288
- * @access private
289
- * @since 1.0
290
- * @static
291
- */
292
- public static function inlineCSS() {
293
-
294
- $css = '';
295
-
296
- if ( ! ezTOC_Option::get( 'exclude_css' ) ) {
297
-
298
- $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', '%' ) . ';}';
299
- $css .= 'div#ez-toc-container p.ez-toc-title {font-weight: ' . ezTOC_Option::get( 'title_font_weight', 500 ) . ';}';
300
- $css .= 'div#ez-toc-container ul li {font-size: ' . ezTOC_Option::get( 'font_size' ) . ezTOC_Option::get( 'font_size_units' ) . ';}';
301
-
302
- if ( ezTOC_Option::get( 'theme' ) === 'custom' || ezTOC_Option::get( 'width' ) != 'auto' ) {
303
-
304
- $css .= 'div#ez-toc-container {';
305
-
306
- if ( ezTOC_Option::get( 'theme' ) === 'custom' ) {
307
-
308
- $css .= 'background: ' . ezTOC_Option::get( 'custom_background_colour' ) . ';border: 1px solid ' . ezTOC_Option::get( 'custom_border_colour' ) . ';';
309
- }
310
-
311
- if ( 'auto' !== ezTOC_Option::get( 'width' ) ) {
312
-
313
- $css .= 'width: ';
314
-
315
- if ( 'custom' !== ezTOC_Option::get( 'width' ) ) {
316
-
317
- $css .= ezTOC_Option::get( 'width' );
318
-
319
- } else {
320
-
321
- $css .= ezTOC_Option::get( 'width_custom' ) . ezTOC_Option::get( 'width_custom_units' );
322
- }
323
-
324
- $css .= ';';
325
- }
326
-
327
- $css .= '}';
328
- }
329
-
330
- if ( 'custom' === ezTOC_Option::get( 'theme' ) ) {
331
-
332
- $css .= 'div#ez-toc-container p.ez-toc-title {color: ' . ezTOC_Option::get( 'custom_title_colour' ) . ';}';
333
- //$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' ) . ';}';
334
- $css .= 'div#ez-toc-container ul.ez-toc-list a {color: ' . ezTOC_Option::get( 'custom_link_colour' ) . ';}';
335
- $css .= 'div#ez-toc-container ul.ez-toc-list a:hover {color: ' . ezTOC_Option::get( 'custom_link_hover_colour' ) . ';}';
336
- $css .= 'div#ez-toc-container ul.ez-toc-list a:visited {color: ' . ezTOC_Option::get( 'custom_link_visited_colour' ) . ';}';
337
- }
338
- }
339
-
340
- if ( $css ) {
341
-
342
- wp_add_inline_style( 'ez-toc', $css );
343
- }
344
- }
345
-
346
- /**
347
- * Array search deep.
348
- *
349
- * Search an array recursively for a value.
350
- *
351
- * @link https://stackoverflow.com/a/5427665/5351316
352
- *
353
- * @param $search
354
- * @param array $array
355
- * @param string $mode
356
- *
357
- * @return bool
358
- */
359
- public static function array_search_deep( $search, array $array, $mode = 'value' ) {
360
-
361
- foreach ( new RecursiveIteratorIterator( new RecursiveArrayIterator( $array ) ) as $key => $value ) {
362
-
363
- if ( $search === ${${"mode"}} ) {
364
- return true;
365
- }
366
- }
367
-
368
- return false;
369
- }
370
-
371
- /**
372
- * Returns true if the table of contents is eligible to be printed, false otherwise.
373
- *
374
- * NOTE: Must bve use only within the loop.
375
- *
376
- * @access public
377
- * @since 1.0
378
- * @static
379
- *
380
- * @param WP_Post $post
381
- *
382
- * @return bool
383
- */
384
- public static function is_eligible( $post ) {
385
-
386
- //global $wp_current_filter;
387
-
388
- if ( empty( $post ) || ! $post instanceof WP_Post ) {
389
-
390
- Debug::log( 'not_instance_of_post', 'Not an instance if `WP_Post`.', $post );
391
- return false;
392
- }
393
-
394
- // This can likely be removed since it is checked in maybeApplyTheContentFilter().
395
- // Do not execute if root filter is one of those in the array.
396
- //if ( in_array( $wp_current_filter[0], array( 'get_the_excerpt', 'wp_head' ), true ) ) {
397
- //
398
- // return false;
399
- //}
400
-
401
- if ( has_shortcode( $post->post_content, apply_filters( 'ez_toc_shortcode', 'toc' ) ) ||
402
- has_shortcode( $post->post_content, 'ez-toc' ) ) {
403
-
404
- Debug::log( 'has_ez_toc_shortcode', 'Has instance of shortcode.', true );
405
- return true;
406
- }
407
-
408
- if ( is_front_page() && ! ezTOC_Option::get( 'include_homepage' ) ) {
409
-
410
- Debug::log( 'is_front_page', 'Is frontpage, TOC is not enabled.', false );
411
- return false;
412
- }
413
-
414
- $type = get_post_type( $post->ID );
415
-
416
- Debug::log( 'current_post_type', 'Post type is.', $type );
417
-
418
- $enabled = in_array( $type, ezTOC_Option::get( 'enabled_post_types', array() ), true );
419
- $insert = in_array( $type, ezTOC_Option::get( 'auto_insert_post_types', array() ), true );
420
-
421
- Debug::log( 'is_supported_post_type', 'Is supported post type?', $enabled );
422
- Debug::log( 'is_auto_insert_post_type', 'Is auto insert for post types?', $insert );
423
-
424
- if ( $insert || $enabled ) {
425
-
426
- if ( ezTOC_Option::get( 'restrict_path' ) ) {
427
-
428
- /**
429
- * @link https://wordpress.org/support/topic/restrict-path-logic-does-not-work-correctly?
430
- */
431
- if ( false !== strpos( ezTOC_Option::get( 'restrict_path' ), $_SERVER['REQUEST_URI'] ) ) {
432
-
433
- Debug::log( 'is_restricted_path', 'In restricted path, post not eligible.', ezTOC_Option::get( 'restrict_path' ) );
434
- return false;
435
-
436
- } else {
437
-
438
- Debug::log( 'is_not_restricted_path', 'Not in restricted path, post is eligible.', ezTOC_Option::get( 'restrict_path' ) );
439
- return true;
440
- }
441
-
442
- } else {
443
-
444
- if ( $insert && 1 === (int) get_post_meta( $post->ID, '_ez-toc-disabled', true ) ) {
445
-
446
- Debug::log( 'is_auto_insert_disable_post_meta', 'Auto insert enabled and disable TOC is enabled in post meta.', false );
447
- return false;
448
-
449
- } elseif ( $insert && 0 === (int) get_post_meta( $post->ID, '_ez-toc-disabled', true ) ) {
450
-
451
- Debug::log( 'is_auto_insert_enabled_post_meta', 'Auto insert enabled and disable TOC is not enabled in post meta.', true );
452
- return true;
453
-
454
- } elseif ( $enabled && 1 === (int) get_post_meta( $post->ID, '_ez-toc-insert', true ) ) {
455
-
456
- Debug::log( 'is_supported_post_type_disable_insert_post_meta', 'Supported post type and insert TOC is enabled in post meta.', true );
457
- return true;
458
-
459
- } elseif ( $enabled && $insert ) {
460
-
461
- Debug::log( 'supported_post_type_and_auto_insert', 'Supported post type and auto insert TOC is enabled.', true );
462
- return true;
463
- }
464
-
465
- Debug::log( 'not_auto_insert_or_not_supported_post_type', 'Not supported post type or insert TOC is disabled.', false );
466
- return false;
467
- }
468
-
469
- } else {
470
-
471
- Debug::log( 'not_auto_insert_and_not_supported post_type', 'Not supported post type and do not auto insert TOC.', false );
472
- return false;
473
- }
474
- }
475
-
476
- /**
477
- * Get TOC from store and if not in store process post and add it to the store.
478
- *
479
- * @since 2.0
480
- *
481
- * @param int $id
482
- *
483
- * @return ezTOC_Post|null
484
- */
485
- public static function get( $id ) {
486
-
487
- $post = null;
488
-
489
- if ( isset( self::$store[ $id ] ) && self::$store[ $id ] instanceof ezTOC_Post ) {
490
-
491
- $post = self::$store[ $id ];
492
-
493
- } else {
494
-
495
- $post = ezTOC_Post::get( get_the_ID() );
496
-
497
- if ( $post instanceof ezTOC_Post ) {
498
-
499
- self::$store[ $id ] = $post;
500
- }
501
- }
502
-
503
- return $post;
504
- }
505
-
506
- /**
507
- * Callback for the registered shortcode `[ez-toc]`
508
- *
509
- * NOTE: Shortcode is run before the callback @see ezTOC::the_content() for the `the_content` filter
510
- *
511
- * @access private
512
- * @since 1.3
513
- *
514
- * @param array|string $atts Shortcode attributes array or empty string.
515
- * @param string $content The enclosed content (if the shortcode is used in its enclosing form)
516
- * @param string $tag Shortcode name.
517
- *
518
- * @return string
519
- */
520
- public static function shortcode( $atts, $content, $tag ) {
521
-
522
- static $run = true;
523
- $html = '';
524
-
525
- if ( $run ) {
526
-
527
- $post = self::get( get_the_ID() );
528
-
529
- if ( ! $post instanceof ezTOC_Post ) {
530
-
531
- Debug::log( 'not_instance_of_post', 'Not an instance if `WP_Post`.', get_the_ID() );
532
-
533
- return Debug::log()->appendTo( $content );
534
- }
535
-
536
- $html = $post->getTOC();
537
- $run = false;
538
- }
539
-
540
- return $html;
541
- }
542
-
543
- /**
544
- * Whether or not apply `the_content` filter.
545
- *
546
- * @since 2.0
547
- *
548
- * @return bool
549
- */
550
- private static function maybeApplyTheContentFilter() {
551
-
552
- $apply = true;
553
-
554
- global $wp_current_filter;
555
-
556
- // Do not execute if root current filter is one of those in the array.
557
- if ( in_array( $wp_current_filter[0], array( 'get_the_excerpt', 'init', 'wp_head' ), true ) ) {
558
-
559
- $apply = false;
560
- }
561
-
562
- // bail if feed, search or archive
563
- if ( is_feed() || is_search() || is_archive() ) {
564
-
565
- $apply = false;
566
- }
567
-
568
- /**
569
- * Whether or not to apply `the_content` filter callback.
570
- *
571
- * @see ezTOC::the_content()
572
- *
573
- * @since 2.0
574
- *
575
- * @param bool $apply
576
- */
577
- return apply_filters( 'ez_toc_maybe_apply_the_content_filter', $apply );
578
- }
579
-
580
- /**
581
- * Callback for the `the_content` filter.
582
- *
583
- * This will add the inline table of contents page anchors to the post content. It will also insert the
584
- * table of contents inline with the post content as defined by the user defined preference.
585
- *
586
- * @since 1.0
587
- *
588
- * @param string $content
589
- *
590
- * @return string
591
- */
592
- public static function the_content( $content ) {
593
- $content = str_replace('&#8211;', '', $content);
594
- $maybeApplyFilter = self::maybeApplyTheContentFilter();
595
-
596
- Debug::log( 'the_content_filter', 'The `the_content` filter applied.', $maybeApplyFilter );
597
-
598
- if ( ! $maybeApplyFilter ) {
599
-
600
- return Debug::log()->appendTo( $content );
601
- }
602
-
603
- // Bail if post not eligible and widget is not active.
604
- $isEligible = self::is_eligible( get_post() );
605
-
606
- Debug::log( 'post_eligible', 'Post eligible.', $isEligible );
607
-
608
- $getpost = self::get( get_the_ID() );
609
- $getTOC = $getpost->getTOC();
610
- if ( ! $isEligible && ! is_active_widget( false, false, 'ezw_tco' ) && empty($getTOC) ) {
611
-
612
- return Debug::log()->appendTo( $content );
613
- }
614
-
615
- $post = self::get( get_the_ID() );
616
-
617
- if ( ! $post instanceof ezTOC_Post ) {
618
-
619
- Debug::log( 'not_instance_of_post', 'Not an instance if `WP_Post`.', get_the_ID() );
620
-
621
- return Debug::log()->appendTo( $content );
622
- }
623
-
624
- // Bail if no headings found.
625
- if ( ! $post->hasTOCItems() ) {
626
-
627
- return Debug::log()->appendTo( $content );
628
- }
629
-
630
- $find = $post->getHeadings();
631
- $replace = $post->getHeadingsWithAnchors();
632
- $toc = $post->getTOC();
633
- $find = str_replace('&ndash;', '', $find);
634
- $replace = str_replace('&#8211;', '', $replace);
635
- $headings = implode( PHP_EOL, $find );
636
- $anchors = implode( PHP_EOL, $replace );
637
-
638
- $headingRows = count( $find ) + 1;
639
- $anchorRows = count( $replace ) + 1;
640
-
641
- $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%;";
642
-
643
- Debug::log(
644
- 'found_post_headings',
645
- 'Found headings:',
646
- "<textarea rows='{$headingRows}' style='{$style}' wrap='soft'>{$headings}</textarea>"
647
- );
648
-
649
- Debug::log(
650
- 'replace_post_headings',
651
- 'Replace found headings with:',
652
- "<textarea rows='{$anchorRows}' style='{$style}' wrap='soft'>{$anchors}</textarea>"
653
- );
654
-
655
- // If shortcode used or post not eligible, return content with anchored headings.
656
- if ( strpos( $content, 'ez-toc-container' ) || ! $isEligible ) {
657
-
658
- Debug::log( 'shortcode_found', 'Shortcode found, add links to content.', true );
659
-
660
- return mb_find_replace( $find, $replace, $content );
661
- }
662
-
663
- $position = ezTOC_Option::get( 'position' );
664
-
665
- Debug::log( 'toc_insert_position', 'Insert TOC at position', $position );
666
-
667
- // else also add toc to content
668
- switch ( $position ) {
669
-
670
- case 'top':
671
- $content = $toc . mb_find_replace( $find, $replace, $content );
672
- break;
673
-
674
- case 'bottom':
675
- $content = mb_find_replace( $find, $replace, $content ) . $toc;
676
- break;
677
-
678
- case 'after':
679
- $replace[0] = $replace[0] . $toc;
680
- $content = mb_find_replace( $find, $replace, $content );
681
- break;
682
-
683
- case 'before':
684
- default:
685
- //$replace[0] = $html . $replace[0];
686
- $content = mb_find_replace( $find, $replace, $content );
687
-
688
- /**
689
- * @link https://wordpress.org/support/topic/php-notice-undefined-offset-8/
690
- */
691
- if ( ! array_key_exists( 0, $replace ) ) {
692
- break;
693
- }
694
-
695
- $pattern = '`<h[1-6]{1}[^>]*' . preg_quote( $replace[0], '`' ) . '`msuU';
696
- $result = preg_match( $pattern, $content, $matches );
697
-
698
- /*
699
- * Try to place TOC before the first heading found in eligible heading, failing that,
700
- * insert TOC at top of content.
701
- */
702
- if ( 1 === $result ) {
703
-
704
- Debug::log( 'toc_insert_position_found', 'Insert TOC before first eligible heading.', $result );
705
-
706
- $start = strpos( $content, $matches[0] );
707
- $content = substr_replace( $content, $toc, $start, 0 );
708
-
709
- } else {
710
-
711
- Debug::log( 'toc_insert_position_not_found', 'Insert TOC before first eligible heading not found.', $result );
712
-
713
- // Somehow, there are scenarios where the processing get this far and
714
- // the TOC is being added to pages where it should not. Disable for now.
715
- //$content = $html . $content;
716
- }
717
- }
718
-
719
- return Debug::log()->appendTo( $content );
720
- }
721
-
722
- }
723
-
724
- /**
725
- * The main function responsible for returning the Easy Table of Contents instance to functions everywhere.
726
- *
727
- * Use this function like you would a global variable, except without needing to declare the global.
728
- *
729
- * Example: <?php $instance = ezTOC(); ?>
730
- *
731
- * @access public
732
- * @since 1.0
733
- *
734
- * @return ezTOC
735
- */
736
- function ezTOC() {
737
-
738
- return ezTOC::instance();
739
- }
740
-
741
- // Start Easy Table of Contents.
742
- add_action( 'plugins_loaded', 'ezTOC' );
743
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.24.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.24.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.24.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( apply_filters( 'ez_toc_shortcode', 'toc' ), array( __CLASS__, 'shortcode' ) );
158
+ }
159
+
160
+ /**
161
+ * Load the plugin translation.
162
+ *
163
+ * Credit: Adapted from Ninja Forms / Easy Digital Downloads.
164
+ *
165
+ * @access private
166
+ * @since 1.0
167
+ * @static
168
+ *
169
+ * @uses apply_filters()
170
+ * @uses get_locale()
171
+ * @uses load_textdomain()
172
+ * @uses load_plugin_textdomain()
173
+ *
174
+ * @return void
175
+ */
176
+ public static function loadTextdomain() {
177
+
178
+ // Plugin textdomain. This should match the one set in the plugin header.
179
+ $domain = 'easy-table-of-contents';
180
+
181
+ // Set filter for plugin's languages directory
182
+ $languagesDirectory = apply_filters( "ez_{$domain}_languages_directory", EZ_TOC_DIR_NAME . '/languages/' );
183
+
184
+ // Traditional WordPress plugin locale filter
185
+ $locale = apply_filters( 'plugin_locale', get_locale(), $domain );
186
+ $fileName = sprintf( '%1$s-%2$s.mo', $domain, $locale );
187
+
188
+ // Setup paths to current locale file
189
+ $local = $languagesDirectory . $fileName;
190
+ $global = WP_LANG_DIR . "/{$domain}/" . $fileName;
191
+
192
+ if ( file_exists( $global ) ) {
193
+
194
+ // Look in global `../wp-content/languages/{$domain}/` folder.
195
+ load_textdomain( $domain, $global );
196
+
197
+ } elseif ( file_exists( $local ) ) {
198
+
199
+ // Look in local `../wp-content/plugins/{plugin-directory}/languages/` folder.
200
+ load_textdomain( $domain, $local );
201
+
202
+ } else {
203
+
204
+ // Load the default language files
205
+ load_plugin_textdomain( $domain, false, $languagesDirectory );
206
+ }
207
+ }
208
+
209
+ /**
210
+ * Call back for the `wp_enqueue_scripts` action.
211
+ *
212
+ * Register and enqueue CSS and javascript files for frontend.
213
+ *
214
+ * @access private
215
+ * @since 1.0
216
+ * @static
217
+ */
218
+ public static function enqueueScripts() {
219
+
220
+ // If SCRIPT_DEBUG is set and TRUE load the non-minified JS files, otherwise, load the minified files.
221
+ $min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
222
+
223
+ $js_vars = array();
224
+
225
+ $isEligible = self::is_eligible( get_post() );
226
+
227
+ if ( ! $isEligible && ! is_active_widget( false, false, 'ezw_tco' ) ) {
228
+ return false;
229
+ }
230
+
231
+ wp_register_style( 'ez-icomoon', EZ_TOC_URL . "vendor/icomoon/style$min.css", array(), ezTOC::VERSION );
232
+ wp_register_style( 'ez-toc', EZ_TOC_URL . "assets/css/screen$min.css", array( 'ez-icomoon' ), ezTOC::VERSION );
233
+
234
+ wp_register_script( 'js-cookie', EZ_TOC_URL . "vendor/js-cookie/js.cookie$min.js", array(), '2.2.1', TRUE );
235
+ wp_register_script( 'jquery-smooth-scroll', EZ_TOC_URL . "vendor/smooth-scroll/jquery.smooth-scroll$min.js", array( 'jquery' ), '2.2.0', TRUE );
236
+ wp_register_script( 'jquery-sticky-kit', EZ_TOC_URL . "vendor/sticky-kit/jquery.sticky-kit$min.js", array( 'jquery' ), '1.9.2', TRUE );
237
+
238
+ if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
239
+ wp_register_script(
240
+ 'ez-toc-js',
241
+ EZ_TOC_URL . "assets/js/front{$min}.js",
242
+ array( 'jquery-smooth-scroll', 'js-cookie', 'jquery-sticky-kit' ),
243
+ ezTOC::VERSION . '-' . filemtime( EZ_TOC_PATH . "/assets/js/front{$min}.js" ),
244
+ true
245
+ );
246
+ }
247
+
248
+ if ( ! ezTOC_Option::get( 'exclude_css' ) ) {
249
+
250
+ wp_enqueue_style( 'ez-toc' );
251
+ self::inlineCSS();
252
+ }
253
+
254
+ if ( ezTOC_Option::get( 'smooth_scroll' ) ) {
255
+
256
+ $js_vars['smooth_scroll'] = true;
257
+ }
258
+
259
+ //wp_enqueue_script( 'ez-toc-js' );
260
+
261
+ if ( ezTOC_Option::get( 'show_heading_text' ) && ezTOC_Option::get( 'visibility' ) ) {
262
+
263
+ $width = ezTOC_Option::get( 'width' ) !== 'custom' ? ezTOC_Option::get( 'width' ) : ezTOC_Option::get( 'width_custom' ) . ezTOC_Option::get( 'width_custom_units' );
264
+
265
+ $js_vars['visibility_hide_by_default'] = ezTOC_Option::get( 'visibility_hide_by_default' ) ? true : false;
266
+
267
+ $js_vars['width'] = esc_js( $width );
268
+ }else{
269
+ if(ezTOC_Option::get( 'visibility' )){
270
+ $js_vars['visibility_hide_by_default'] = ezTOC_Option::get( 'visibility_hide_by_default' ) ? true : false;
271
+ }
272
+ }
273
+
274
+ $offset = wp_is_mobile() ? ezTOC_Option::get( 'mobile_smooth_scroll_offset', 0 ) : ezTOC_Option::get( 'smooth_scroll_offset', 30 );
275
+
276
+ $js_vars['scroll_offset'] = esc_js( $offset );
277
+
278
+ if ( ezTOC_Option::get( 'widget_affix_selector' ) ) {
279
+
280
+ $js_vars['affixSelector'] = ezTOC_Option::get( 'widget_affix_selector' );
281
+ }
282
+
283
+ if ( 0 < count( $js_vars ) ) {
284
+
285
+ wp_localize_script( 'ez-toc-js', 'ezTOC', $js_vars );
286
+ }
287
+ }
288
+
289
+ /**
290
+ * Prints out inline CSS after the core CSS file to allow overriding core styles via options.
291
+ *
292
+ * @access private
293
+ * @since 1.0
294
+ * @static
295
+ */
296
+ public static function inlineCSS() {
297
+
298
+ $css = '';
299
+
300
+ if ( ! ezTOC_Option::get( 'exclude_css' ) ) {
301
+
302
+ $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', '%' ) . ';}';
303
+ $css .= 'div#ez-toc-container p.ez-toc-title {font-weight: ' . ezTOC_Option::get( 'title_font_weight', 500 ) . ';}';
304
+ $css .= 'div#ez-toc-container ul li {font-size: ' . ezTOC_Option::get( 'font_size' ) . ezTOC_Option::get( 'font_size_units' ) . ';}';
305
+
306
+ if ( ezTOC_Option::get( 'theme' ) === 'custom' || ezTOC_Option::get( 'width' ) != 'auto' ) {
307
+
308
+ $css .= 'div#ez-toc-container {';
309
+
310
+ if ( ezTOC_Option::get( 'theme' ) === 'custom' ) {
311
+
312
+ $css .= 'background: ' . ezTOC_Option::get( 'custom_background_colour' ) . ';border: 1px solid ' . ezTOC_Option::get( 'custom_border_colour' ) . ';';
313
+ }
314
+
315
+ if ( 'auto' !== ezTOC_Option::get( 'width' ) ) {
316
+
317
+ $css .= 'width: ';
318
+
319
+ if ( 'custom' !== ezTOC_Option::get( 'width' ) ) {
320
+
321
+ $css .= ezTOC_Option::get( 'width' );
322
+
323
+ } else {
324
+
325
+ $css .= ezTOC_Option::get( 'width_custom' ) . ezTOC_Option::get( 'width_custom_units' );
326
+ }
327
+
328
+ $css .= ';';
329
+ }
330
+
331
+ $css .= '}';
332
+ }
333
+
334
+ if ( 'custom' === ezTOC_Option::get( 'theme' ) ) {
335
+
336
+ $css .= 'div#ez-toc-container p.ez-toc-title {color: ' . ezTOC_Option::get( 'custom_title_colour' ) . ';}';
337
+ //$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' ) . ';}';
338
+ $css .= 'div#ez-toc-container ul.ez-toc-list a {color: ' . ezTOC_Option::get( 'custom_link_colour' ) . ';}';
339
+ $css .= 'div#ez-toc-container ul.ez-toc-list a:hover {color: ' . ezTOC_Option::get( 'custom_link_hover_colour' ) . ';}';
340
+ $css .= 'div#ez-toc-container ul.ez-toc-list a:visited {color: ' . ezTOC_Option::get( 'custom_link_visited_colour' ) . ';}';
341
+ }
342
+ }
343
+
344
+ if ( $css ) {
345
+
346
+ wp_add_inline_style( 'ez-toc', $css );
347
+ }
348
+ }
349
+
350
+ /**
351
+ * Array search deep.
352
+ *
353
+ * Search an array recursively for a value.
354
+ *
355
+ * @link https://stackoverflow.com/a/5427665/5351316
356
+ *
357
+ * @param $search
358
+ * @param array $array
359
+ * @param string $mode
360
+ *
361
+ * @return bool
362
+ */
363
+ public static function array_search_deep( $search, array $array, $mode = 'value' ) {
364
+
365
+ foreach ( new RecursiveIteratorIterator( new RecursiveArrayIterator( $array ) ) as $key => $value ) {
366
+
367
+ if ( $search === ${${"mode"}} ) {
368
+ return true;
369
+ }
370
+ }
371
+
372
+ return false;
373
+ }
374
+
375
+ /**
376
+ * Returns true if the table of contents is eligible to be printed, false otherwise.
377
+ *
378
+ * NOTE: Must bve use only within the loop.
379
+ *
380
+ * @access public
381
+ * @since 1.0
382
+ * @static
383
+ *
384
+ * @param WP_Post $post
385
+ *
386
+ * @return bool
387
+ */
388
+ public static function is_eligible( $post ) {
389
+
390
+ //global $wp_current_filter;
391
+
392
+ if ( empty( $post ) || ! $post instanceof WP_Post ) {
393
+
394
+ Debug::log( 'not_instance_of_post', 'Not an instance if `WP_Post`.', $post );
395
+ return false;
396
+ }
397
+
398
+ // This can likely be removed since it is checked in maybeApplyTheContentFilter().
399
+ // Do not execute if root filter is one of those in the array.
400
+ //if ( in_array( $wp_current_filter[0], array( 'get_the_excerpt', 'wp_head' ), true ) ) {
401
+ //
402
+ // return false;
403
+ //}
404
+
405
+ if ( has_shortcode( $post->post_content, apply_filters( 'ez_toc_shortcode', 'toc' ) ) ||
406
+ has_shortcode( $post->post_content, 'ez-toc' ) ) {
407
+
408
+ Debug::log( 'has_ez_toc_shortcode', 'Has instance of shortcode.', true );
409
+ return true;
410
+ }
411
+
412
+ if ( is_front_page() && ! ezTOC_Option::get( 'include_homepage' ) ) {
413
+
414
+ Debug::log( 'is_front_page', 'Is frontpage, TOC is not enabled.', false );
415
+ return false;
416
+ }
417
+
418
+ $type = get_post_type( $post->ID );
419
+
420
+ Debug::log( 'current_post_type', 'Post type is.', $type );
421
+
422
+ $enabled = in_array( $type, ezTOC_Option::get( 'enabled_post_types', array() ), true );
423
+ $insert = in_array( $type, ezTOC_Option::get( 'auto_insert_post_types', array() ), true );
424
+
425
+ Debug::log( 'is_supported_post_type', 'Is supported post type?', $enabled );
426
+ Debug::log( 'is_auto_insert_post_type', 'Is auto insert for post types?', $insert );
427
+
428
+ if ( $insert || $enabled ) {
429
+
430
+ if ( ezTOC_Option::get( 'restrict_path' ) ) {
431
+
432
+ /**
433
+ * @link https://wordpress.org/support/topic/restrict-path-logic-does-not-work-correctly?
434
+ */
435
+ if ( false !== strpos( ezTOC_Option::get( 'restrict_path' ), $_SERVER['REQUEST_URI'] ) ) {
436
+
437
+ Debug::log( 'is_restricted_path', 'In restricted path, post not eligible.', ezTOC_Option::get( 'restrict_path' ) );
438
+ return false;
439
+
440
+ } else {
441
+
442
+ Debug::log( 'is_not_restricted_path', 'Not in restricted path, post is eligible.', ezTOC_Option::get( 'restrict_path' ) );
443
+ return true;
444
+ }
445
+
446
+ } else {
447
+
448
+ if ( $insert && 1 === (int) get_post_meta( $post->ID, '_ez-toc-disabled', true ) ) {
449
+
450
+ Debug::log( 'is_auto_insert_disable_post_meta', 'Auto insert enabled and disable TOC is enabled in post meta.', false );
451
+ return false;
452
+
453
+ } elseif ( $insert && 0 === (int) get_post_meta( $post->ID, '_ez-toc-disabled', true ) ) {
454
+
455
+ Debug::log( 'is_auto_insert_enabled_post_meta', 'Auto insert enabled and disable TOC is not enabled in post meta.', true );
456
+ return true;
457
+
458
+ } elseif ( $enabled && 1 === (int) get_post_meta( $post->ID, '_ez-toc-insert', true ) ) {
459
+
460
+ Debug::log( 'is_supported_post_type_disable_insert_post_meta', 'Supported post type and insert TOC is enabled in post meta.', true );
461
+ return true;
462
+
463
+ } elseif ( $enabled && $insert ) {
464
+
465
+ Debug::log( 'supported_post_type_and_auto_insert', 'Supported post type and auto insert TOC is enabled.', true );
466
+ return true;
467
+ }
468
+
469
+ Debug::log( 'not_auto_insert_or_not_supported_post_type', 'Not supported post type or insert TOC is disabled.', false );
470
+ return false;
471
+ }
472
+
473
+ } else {
474
+
475
+ Debug::log( 'not_auto_insert_and_not_supported post_type', 'Not supported post type and do not auto insert TOC.', false );
476
+ return false;
477
+ }
478
+ }
479
+
480
+ /**
481
+ * Get TOC from store and if not in store process post and add it to the store.
482
+ *
483
+ * @since 2.0
484
+ *
485
+ * @param int $id
486
+ *
487
+ * @return ezTOC_Post|null
488
+ */
489
+ public static function get( $id ) {
490
+
491
+ $post = null;
492
+
493
+ if ( isset( self::$store[ $id ] ) && self::$store[ $id ] instanceof ezTOC_Post ) {
494
+
495
+ $post = self::$store[ $id ];
496
+
497
+ } else {
498
+
499
+ $post = ezTOC_Post::get( get_the_ID() );
500
+
501
+ if ( $post instanceof ezTOC_Post ) {
502
+
503
+ self::$store[ $id ] = $post;
504
+ }
505
+ }
506
+
507
+ return $post;
508
+ }
509
+
510
+ /**
511
+ * Callback for the registered shortcode `[ez-toc]`
512
+ *
513
+ * NOTE: Shortcode is run before the callback @see ezTOC::the_content() for the `the_content` filter
514
+ *
515
+ * @access private
516
+ * @since 1.3
517
+ *
518
+ * @param array|string $atts Shortcode attributes array or empty string.
519
+ * @param string $content The enclosed content (if the shortcode is used in its enclosing form)
520
+ * @param string $tag Shortcode name.
521
+ *
522
+ * @return string
523
+ */
524
+ public static function shortcode( $atts, $content, $tag ) {
525
+
526
+ static $run = true;
527
+ $html = '';
528
+
529
+ if ( $run ) {
530
+
531
+ $post = self::get( get_the_ID() );
532
+
533
+ if ( ! $post instanceof ezTOC_Post ) {
534
+
535
+ Debug::log( 'not_instance_of_post', 'Not an instance if `WP_Post`.', get_the_ID() );
536
+
537
+ return Debug::log()->appendTo( $content );
538
+ }
539
+
540
+ $html = $post->getTOC();
541
+ $run = false;
542
+ }
543
+
544
+ return $html;
545
+ }
546
+
547
+ /**
548
+ * Whether or not apply `the_content` filter.
549
+ *
550
+ * @since 2.0
551
+ *
552
+ * @return bool
553
+ */
554
+ private static function maybeApplyTheContentFilter() {
555
+
556
+ $apply = true;
557
+
558
+ global $wp_current_filter;
559
+
560
+ // Do not execute if root current filter is one of those in the array.
561
+ if ( in_array( $wp_current_filter[0], array( 'get_the_excerpt', 'init', 'wp_head' ), true ) ) {
562
+
563
+ $apply = false;
564
+ }
565
+
566
+ // bail if feed, search or archive
567
+ if ( is_feed() || is_search() || is_archive() ) {
568
+
569
+ $apply = false;
570
+ }
571
+
572
+ /**
573
+ * Whether or not to apply `the_content` filter callback.
574
+ *
575
+ * @see ezTOC::the_content()
576
+ *
577
+ * @since 2.0
578
+ *
579
+ * @param bool $apply
580
+ */
581
+ return apply_filters( 'ez_toc_maybe_apply_the_content_filter', $apply );
582
+ }
583
+
584
+ /**
585
+ * Callback for the `the_content` filter.
586
+ *
587
+ * This will add the inline table of contents page anchors to the post content. It will also insert the
588
+ * table of contents inline with the post content as defined by the user defined preference.
589
+ *
590
+ * @since 1.0
591
+ *
592
+ * @param string $content
593
+ *
594
+ * @return string
595
+ */
596
+ public static function the_content( $content ) {
597
+ $maybeApplyFilter = self::maybeApplyTheContentFilter();
598
+
599
+ Debug::log( 'the_content_filter', 'The `the_content` filter applied.', $maybeApplyFilter );
600
+
601
+ if ( ! $maybeApplyFilter ) {
602
+
603
+ return Debug::log()->appendTo( $content );
604
+ }
605
+
606
+ // Bail if post not eligible and widget is not active.
607
+ $isEligible = self::is_eligible( get_post() );
608
+ $isEligible = apply_filters('eztoc_do_shortcode',$isEligible);
609
+ Debug::log( 'post_eligible', 'Post eligible.', $isEligible );
610
+
611
+ if ( ! $isEligible && ! is_active_widget( false, false, 'ezw_tco' ) ) {
612
+
613
+ return Debug::log()->appendTo( $content );
614
+ }
615
+
616
+ $post = self::get( get_the_ID() );
617
+
618
+ if ( ! $post instanceof ezTOC_Post ) {
619
+
620
+ Debug::log( 'not_instance_of_post', 'Not an instance if `WP_Post`.', get_the_ID() );
621
+
622
+ return Debug::log()->appendTo( $content );
623
+ }
624
+
625
+ // Bail if no headings found.
626
+ if ( ! $post->hasTOCItems() ) {
627
+
628
+ return Debug::log()->appendTo( $content );
629
+ }
630
+
631
+ $find = $post->getHeadings();
632
+ $replace = $post->getHeadingsWithAnchors();
633
+ $toc = $post->getTOC();
634
+ $headings = implode( PHP_EOL, $find );
635
+ $anchors = implode( PHP_EOL, $replace );
636
+
637
+ $headingRows = count( $find ) + 1;
638
+ $anchorRows = count( $replace ) + 1;
639
+
640
+ $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%;";
641
+
642
+ Debug::log(
643
+ 'found_post_headings',
644
+ 'Found headings:',
645
+ "<textarea rows='{$headingRows}' style='{$style}' wrap='soft'>{$headings}</textarea>"
646
+ );
647
+
648
+ Debug::log(
649
+ 'replace_post_headings',
650
+ 'Replace found headings with:',
651
+ "<textarea rows='{$anchorRows}' style='{$style}' wrap='soft'>{$anchors}</textarea>"
652
+ );
653
+
654
+ // If shortcode used or post not eligible, return content with anchored headings.
655
+ if ( strpos( $content, 'ez-toc-container' ) || ! $isEligible ) {
656
+
657
+ Debug::log( 'shortcode_found', 'Shortcode found, add links to content.', true );
658
+
659
+ return mb_find_replace( $find, $replace, $content );
660
+ }
661
+
662
+ $position = ezTOC_Option::get( 'position' );
663
+
664
+ Debug::log( 'toc_insert_position', 'Insert TOC at position', $position );
665
+
666
+ // else also add toc to content
667
+ switch ( $position ) {
668
+
669
+ case 'top':
670
+ $content = $toc . mb_find_replace( $find, $replace, $content );
671
+ break;
672
+
673
+ case 'bottom':
674
+ $content = mb_find_replace( $find, $replace, $content ) . $toc;
675
+ break;
676
+
677
+ case 'after':
678
+ $replace[0] = $replace[0] . $toc;
679
+ $content = mb_find_replace( $find, $replace, $content );
680
+ break;
681
+
682
+ case 'before':
683
+ default:
684
+ //$replace[0] = $html . $replace[0];
685
+ $content = mb_find_replace( $find, $replace, $content );
686
+
687
+ /**
688
+ * @link https://wordpress.org/support/topic/php-notice-undefined-offset-8/
689
+ */
690
+ if ( ! array_key_exists( 0, $replace ) ) {
691
+ break;
692
+ }
693
+
694
+ $pattern = '`<h[1-6]{1}[^>]*' . preg_quote( $replace[0], '`' ) . '`msuU';
695
+ $result = preg_match( $pattern, $content, $matches );
696
+
697
+ /*
698
+ * Try to place TOC before the first heading found in eligible heading, failing that,
699
+ * insert TOC at top of content.
700
+ */
701
+ if ( 1 === $result ) {
702
+
703
+ Debug::log( 'toc_insert_position_found', 'Insert TOC before first eligible heading.', $result );
704
+
705
+ $start = strpos( $content, $matches[0] );
706
+ $content = substr_replace( $content, $toc, $start, 0 );
707
+
708
+ } else {
709
+
710
+ Debug::log( 'toc_insert_position_not_found', 'Insert TOC before first eligible heading not found.', $result );
711
+
712
+ // Somehow, there are scenarios where the processing get this far and
713
+ // the TOC is being added to pages where it should not. Disable for now.
714
+ //$content = $html . $content;
715
+ }
716
+ }
717
+
718
+ return Debug::log()->appendTo( $content );
719
+ }
720
+
721
+ }
722
+
723
+ /**
724
+ * The main function responsible for returning the Easy Table of Contents instance to functions everywhere.
725
+ *
726
+ * Use this function like you would a global variable, except without needing to declare the global.
727
+ *
728
+ * Example: <?php $instance = ezTOC(); ?>
729
+ *
730
+ * @access public
731
+ * @since 1.0
732
+ *
733
+ * @return ezTOC
734
+ */
735
+ function ezTOC() {
736
+
737
+ return ezTOC::instance();
738
+ }
739
+
740
+ // Start Easy Table of Contents.
741
+ add_action( 'plugins_loaded', 'ezTOC' );
742
+ }
743
+ register_activation_hook(__FILE__, 'ez_toc_activate');
744
+ add_action('admin_init', 'ez_toc_redirect');
745
+
746
+ function ez_toc_activate() {
747
+ add_option('ez_toc_do_activation_redirect', true);
748
+ }
749
+
750
+ function ez_toc_redirect() {
751
+ if (get_option('ez_toc_do_activation_redirect', false)) {
752
+ delete_option('ez_toc_do_activation_redirect');
753
+ if(!isset($_GET['activate-multi']))
754
+ {
755
+ wp_redirect("options-general.php?page=table-of-contents#welcome");
756
+ }
757
+ }
758
+ }
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,569 +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
- $action = array();
58
-
59
- $action[] = sprintf(
60
- '<a href="%1$s">%2$s</a>',
61
- esc_url( add_query_arg( 'page', 'table-of-contents', self_admin_url( 'options-general.php' ) ) ),
62
- esc_html__( 'Settings', 'easy-table-of-contents' )
63
- );
64
-
65
- return array_merge( $action, $links );
66
- }
67
-
68
- /**
69
- * Register the scripts used in the admin.
70
- *
71
- * @access private
72
- * @since 1.0
73
- * @static
74
- */
75
- public function registerScripts() {
76
-
77
- wp_register_script( 'cn_toc_admin_script', EZ_TOC_URL . 'assets/js/admin.js', array( 'jquery', 'wp-color-picker' ), ezTOC::VERSION, true );
78
- wp_register_style( 'cn_toc_admin_style', EZ_TOC_URL . 'assets/css/admin.css', array( 'wp-color-picker' ), ezTOC::VERSION );
79
- }
80
-
81
- /**
82
- * Callback to add plugin as a submenu page of the Options page.
83
- *
84
- * This also adds the action to enqueue the scripts to be loaded on plugin's admin pages only.
85
- *
86
- * @access private
87
- * @since 1.0
88
- * @static
89
- */
90
- public function menu() {
91
-
92
- $page = add_submenu_page(
93
- 'options-general.php',
94
- esc_html__( 'Table of Contents', 'easy-table-of-contents' ),
95
- esc_html__( 'Table of Contents', 'easy-table-of-contents' ),
96
- 'manage_options',
97
- 'table-of-contents',
98
- array( $this, 'page' )
99
- );
100
-
101
- add_action( 'admin_print_styles-' . $page, array( $this, 'enqueueScripts' ) );
102
- }
103
-
104
- /**
105
- * Enqueue the scripts.
106
- *
107
- * @access private
108
- * @since 1.0
109
- * @static
110
- */
111
- public function enqueueScripts() {
112
-
113
- wp_enqueue_script( 'cn_toc_admin_script' );
114
- wp_enqueue_style( 'cn_toc_admin_style' );
115
- }
116
-
117
- /**
118
- * Callback to add the action which will register the table of contents post metaboxes.
119
- *
120
- * Metaboxes will only be registered for the post types per user preferences.
121
- *
122
- * @access private
123
- * @since 1.0
124
- * @static
125
- */
126
- public function registerMetaboxes() {
127
-
128
- foreach ( get_post_types() as $type ) {
129
-
130
- if ( in_array( $type, ezTOC_Option::get( 'enabled_post_types', array() ) ) ) {
131
-
132
- add_action( "add_meta_boxes_$type", array( $this, 'metabox' ) );
133
- add_action( "save_post_$type", array( $this, 'save' ), 10, 3 );
134
- }
135
- }
136
- }
137
-
138
- /**
139
- * Callback to register the table of contents metaboxes.
140
- *
141
- * @access private
142
- * @since 1.0
143
- * @static
144
- */
145
- public function metabox() {
146
-
147
- add_meta_box( 'ez-toc', esc_html__( 'Table of Contents', 'ez-toc' ), array( $this, 'displayMetabox' ) );
148
- }
149
-
150
- /**
151
- * Callback to render the content of the table of contents metaboxes.
152
- *
153
- * @access private
154
- * @since 1.0
155
- * @static
156
- *
157
- * @param object $post The post object.
158
- * @param $atts
159
- */
160
- public function displayMetabox( $post, $atts ) {
161
-
162
- // Add an nonce field so we can check for it on save.
163
- wp_nonce_field( 'ez_toc_save', '_ez_toc_nonce' );
164
-
165
- $suppress = get_post_meta( $post->ID, '_ez-toc-disabled', true ) == 1 ? true : false;
166
- $insert = get_post_meta( $post->ID, '_ez-toc-insert', true ) == 1 ? true : false;
167
- $headings = get_post_meta( $post->ID, '_ez-toc-heading-levels', true );
168
- $exclude = get_post_meta( $post->ID, '_ez-toc-exclude', true );
169
- $altText = get_post_meta( $post->ID, '_ez-toc-alttext', true );
170
-
171
- if ( ! is_array( $headings ) ) {
172
-
173
- $headings = array();
174
- }
175
- ?>
176
-
177
- <table class="form-table">
178
-
179
- <tbody>
180
-
181
- <tr>
182
- <th scope="row"></th>
183
- <td>
184
-
185
- <?php if ( in_array( get_post_type( $post ), ezTOC_Option::get( 'auto_insert_post_types', array() ) ) ) :
186
-
187
- ezTOC_Option::checkbox(
188
- array(
189
- 'id' => 'disabled-toc',
190
- 'desc' => esc_html__( 'Disable the automatic insertion of the table of contents.', 'easy-table-of-contents' ),
191
- 'default' => $suppress,
192
- ),
193
- $suppress
194
- );
195
-
196
- elseif( in_array( get_post_type( $post ), ezTOC_Option::get( 'enabled_post_types', array() ) ) ):
197
-
198
- ezTOC_Option::checkbox(
199
- array(
200
- 'id' => 'insert-toc',
201
- 'desc' => esc_html__( 'Insert table of contents.', 'easy-table-of-contents' ),
202
- 'default' => $insert,
203
- ),
204
- $insert
205
- );
206
-
207
- endif; ?>
208
-
209
- </td>
210
- </tr>
211
-
212
- <tr>
213
- <th scope="row"><?php esc_html_e( 'Advanced:', 'easy-table-of-contents' ); ?></th>
214
- <td>
215
- <?php
216
- ezTOC_Option::descriptive_text(
217
- array(
218
- 'id' => 'exclude-desc',
219
- 'name' => '',
220
- 'desc' => '<p><strong>' . esc_html__( 'NOTE:', 'easy-table-of-contents' ) . '</strong></p>' .
221
- '<ul>' .
222
- '<li>' . esc_html__( 'Using the advanced options below will override the global advanced settings.', 'easy-table-of-contents' ) . '</li>' .
223
- '</ul>',
224
- )
225
- );
226
- ?>
227
- </td>
228
- </tr>
229
-
230
- <tr>
231
- <th scope="row"><?php esc_html_e( 'Headings:', 'easy-table-of-contents' ); ?></th>
232
- <td>
233
- <?php
234
- ezTOC_Option::checkboxgroup(
235
- array(
236
- 'id' => 'heading-levels',
237
- 'desc' => esc_html__( 'Select the heading to consider when generating the table of contents. Deselecting a heading will exclude it.', 'easy-table-of-contents' ),
238
- 'options' => array(
239
- '1' => __( 'Heading 1 (h1)', 'easy-table-of-contents' ),
240
- '2' => __( 'Heading 2 (h2)', 'easy-table-of-contents' ),
241
- '3' => __( 'Heading 3 (h3)', 'easy-table-of-contents' ),
242
- '4' => __( 'Heading 4 (h4)', 'easy-table-of-contents' ),
243
- '5' => __( 'Heading 5 (h5)', 'easy-table-of-contents' ),
244
- '6' => __( 'Heading 6 (h6)', 'easy-table-of-contents' ),
245
- ),
246
- 'default' => array(),
247
- ),
248
- array_map( 'absint', $headings )
249
- );
250
- ?>
251
- </td>
252
- </tr>
253
- <tr>
254
- <th scope="row"><?php esc_html_e( 'Alternate Headings', 'easy-table-of-contents' ); ?></th>
255
- <td>
256
- <?php
257
- ezTOC_Option::textarea(
258
- array(
259
- 'id' => 'alttext',
260
- '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' ),
261
- 'size' => 'large',
262
- 'default' => '',
263
- ),
264
- $altText
265
- );
266
- ?>
267
- </td>
268
- </tr>
269
- <tr>
270
- <th scope="row"></th>
271
- <td>
272
- <?php
273
- ezTOC_Option::descriptive_text(
274
- array(
275
- 'id' => 'alttext-desc',
276
- 'name' => '',
277
- 'desc' => '<p><strong>' . esc_html__( 'Examples:', 'easy-table-of-contents' ) . '</strong></p>' .
278
- '<ul>' .
279
- '<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>' .
280
- '</ul>' .
281
- '<p>' . __( '<strong>Note:</strong> This is case sensitive.', 'easy-table-of-contents' ) . '</p>',
282
- )
283
- );
284
- ?>
285
- </td>
286
- </tr>
287
- <tr>
288
- <th scope="row"><?php esc_html_e( 'Exclude Headings', 'easy-table-of-contents' ); ?></th>
289
- <td>
290
- <?php
291
- ezTOC_Option::text(
292
- array(
293
- 'id' => 'exclude',
294
- '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' ),
295
- 'size' => 'large',
296
- 'default' => '',
297
- ),
298
- $exclude
299
- );
300
- ?>
301
- </td>
302
- </tr>
303
- <tr>
304
- <th scope="row"></th>
305
- <td>
306
- <?php
307
- ezTOC_Option::descriptive_text(
308
- array(
309
- 'id' => 'exclude-desc',
310
- 'name' => '',
311
- 'desc' => '<p><strong>' . esc_html__( 'Examples:', 'easy-table-of-contents' ) . '</strong></p>' .
312
- '<ul>' .
313
- '<li>' . __( '<code>Fruit*</code> Ignore headings starting with "Fruit".', 'easy-table-of-contents' ) . '</li>' .
314
- '<li>' . __( '<code>*Fruit Diet*</code> Ignore headings with "Fruit Diet" somewhere in the heading.', 'easy-table-of-contents' ) . '</li>' .
315
- '<li>' . __( '<code>Apple Tree|Oranges|Yellow Bananas</code> Ignore headings that are exactly "Apple Tree", "Oranges" or "Yellow Bananas".', 'easy-table-of-contents' ) . '</li>' .
316
- '</ul>' .
317
- '<p>' . __( '<strong>Note:</strong> This is not case sensitive.', 'easy-table-of-contents' ) . '</p>',
318
- )
319
- );
320
- ?>
321
- </td>
322
- </tr>
323
- </tbody>
324
- </table>
325
-
326
- <?php
327
- }
328
-
329
- /**
330
- * Callback which saves the user preferences from the table of contents metaboxes.
331
- *
332
- * @access private
333
- * @since 1.0
334
- * @static
335
- *
336
- * @param int $post_id The post ID.
337
- * @param object $post The post object.
338
- * @param bool $update Whether this is an existing post being updated or not.
339
- */
340
- public function save( $post_id, $post, $update ) {
341
-
342
- if ( current_user_can( 'edit_post', $post_id ) &&
343
- isset( $_REQUEST['_ez_toc_nonce'] ) &&
344
- wp_verify_nonce( $_REQUEST['_ez_toc_nonce'], 'ez_toc_save' )
345
- ) {
346
-
347
- // Checkboxes are present if checked, absent if not.
348
- if ( isset( $_REQUEST['ez-toc-settings']['disabled-toc'] ) ) {
349
-
350
- update_post_meta( $post_id, '_ez-toc-disabled', true );
351
-
352
- } else {
353
-
354
- update_post_meta( $post_id, '_ez-toc-disabled', false );
355
-
356
- }
357
-
358
- if ( isset( $_REQUEST['ez-toc-settings']['insert-toc'] ) ) {
359
-
360
- update_post_meta( $post_id, '_ez-toc-insert', true );
361
-
362
- } else {
363
-
364
- update_post_meta( $post_id, '_ez-toc-insert', false );
365
- }
366
-
367
- if ( isset( $_REQUEST['ez-toc-settings']['heading-levels'] ) && ! empty( $_REQUEST['ez-toc-settings']['heading-levels'] ) ) {
368
-
369
- if ( is_array( $_REQUEST['ez-toc-settings']['heading-levels'] ) ) {
370
-
371
- $headings = array_map( 'absint', $_REQUEST['ez-toc-settings']['heading-levels'] );
372
-
373
- } else {
374
-
375
- $headings = array();
376
- }
377
-
378
- update_post_meta( $post_id, '_ez-toc-heading-levels', $headings );
379
-
380
- } else {
381
-
382
- update_post_meta( $post_id, '_ez-toc-heading-levels', array() );
383
- }
384
-
385
- if ( isset( $_REQUEST['ez-toc-settings']['alttext'] ) && ! empty( $_REQUEST['ez-toc-settings']['alttext'] ) ) {
386
-
387
- if ( is_string( $_REQUEST['ez-toc-settings']['alttext'] ) ) {
388
-
389
- $alttext = trim( $_REQUEST['ez-toc-settings']['alttext'] );
390
-
391
- } else {
392
-
393
- $alttext = '';
394
- }
395
-
396
- /*
397
- * This is basically `esc_html()` but does not encode quotes.
398
- * This is to allow angle brackets and such which `wp_kses_post` would strip as "evil" scripts.
399
- */
400
- $alttext = wp_check_invalid_utf8( $alttext );
401
- $alttext = _wp_specialchars( $alttext, ENT_NOQUOTES );
402
-
403
- update_post_meta( $post_id, '_ez-toc-alttext', wp_kses_post( $alttext ) );
404
-
405
- } else {
406
-
407
- update_post_meta( $post_id, '_ez-toc-alttext', '' );
408
- }
409
-
410
- if ( isset( $_REQUEST['ez-toc-settings']['exclude'] ) && ! empty( $_REQUEST['ez-toc-settings']['exclude'] ) ) {
411
-
412
- if ( is_string( $_REQUEST['ez-toc-settings']['exclude'] ) ) {
413
-
414
- $exclude = trim( $_REQUEST['ez-toc-settings']['exclude'] );
415
-
416
- } else {
417
-
418
- $exclude = '';
419
- }
420
-
421
- /*
422
- * This is basically `esc_html()` but does not encode quotes.
423
- * This is to allow angle brackets and such which `wp_kses_post` would strip as "evil" scripts.
424
- */
425
- $exclude = wp_check_invalid_utf8( $exclude );
426
- $exclude = _wp_specialchars( $exclude, ENT_NOQUOTES );
427
-
428
- update_post_meta( $post_id, '_ez-toc-exclude', wp_kses_post( $exclude ) );
429
-
430
- } else {
431
-
432
- update_post_meta( $post_id, '_ez-toc-exclude', '' );
433
- }
434
-
435
- }
436
-
437
- }
438
-
439
-
440
- /**
441
- * Enqueue Admin js scripts
442
- *
443
- */
444
- public function load_scripts($pagenow){
445
-
446
- if (isset($pagenow) && $pagenow != 'settings_page_table-of-contents' && strpos($pagenow, 'table-of-contents') == false) {
447
-
448
- return false;
449
- }
450
-
451
- wp_enqueue_script( 'eztoc-admin-js', EZ_TOC_URL . 'assets/js/eztoc-admin.js',array('jquery'), ezTOC::VERSION,true );
452
-
453
- $data = array(
454
- 'ajax_url' => admin_url( 'admin-ajax.php' ),
455
- 'eztoc_security_nonce' => wp_create_nonce('eztoc_ajax_check_nonce'),
456
- );
457
-
458
- $data = apply_filters('eztoc_localize_filter',$data,'eztoc_admin_data');
459
-
460
- wp_localize_script( 'eztoc-admin-js', 'eztoc_admin_data', $data );
461
- }
462
-
463
- /**
464
- * This is a ajax handler function for sending email from user admin panel to us.
465
- * @return type json string
466
- */
467
-
468
- public function eztoc_send_query_message(){
469
-
470
- if ( ! isset( $_POST['eztoc_security_nonce'] ) ){
471
- return;
472
- }
473
- if ( !wp_verify_nonce( $_POST['eztoc_security_nonce'], 'eztoc_ajax_check_nonce' ) ){
474
- return;
475
- }
476
- $message = $this->eztoc_sanitize_textarea_field($_POST['message']);
477
- $email = $this->eztoc_sanitize_textarea_field($_POST['email']);
478
-
479
- if(function_exists('wp_get_current_user')){
480
-
481
- $user = wp_get_current_user();
482
-
483
-
484
- $message = '<p>'.$message.'</p><br><br>'.'Query from Easy Table of Content plugin support tab';
485
-
486
- $user_data = $user->data;
487
- $user_email = $user_data->user_email;
488
-
489
- if($email){
490
- $user_email = $email;
491
- }
492
- //php mailer variables
493
- $sendto = 'team@magazine3.in';
494
- $subject = "Easy Table of Content Query";
495
-
496
- $headers[] = 'Content-Type: text/html; charset=UTF-8';
497
- $headers[] = 'From: '. esc_attr($user_email);
498
- $headers[] = 'Reply-To: ' . esc_attr($user_email);
499
- // Load WP components, no themes.
500
-
501
- $sent = wp_mail($sendto, $subject, $message, $headers);
502
-
503
- if($sent){
504
-
505
- echo json_encode(array('status'=>'t'));
506
-
507
- }else{
508
-
509
- echo json_encode(array('status'=>'f'));
510
-
511
- }
512
-
513
- }
514
-
515
- wp_die();
516
- }
517
-
518
- public function eztoc_sanitize_textarea_field( $str ) {
519
-
520
- if ( is_object( $str ) || is_array( $str ) ) {
521
- return '';
522
- }
523
-
524
- $str = (string) $str;
525
-
526
- $filtered = wp_check_invalid_utf8( $str );
527
-
528
- if ( strpos( $filtered, '<' ) !== false ) {
529
- $filtered = wp_pre_kses_less_than( $filtered );
530
- // This will strip extra whitespace for us.
531
- $filtered = wp_strip_all_tags( $filtered, false );
532
-
533
- // Use HTML entities in a special case to make sure no later
534
- // newline stripping stage could lead to a functional tag.
535
- $filtered = str_replace( "<\n", "&lt;\n", $filtered );
536
- }
537
-
538
- $filtered = trim( $filtered );
539
-
540
- $found = false;
541
- while ( preg_match( '/%[a-f0-9]{2}/i', $filtered, $match ) ) {
542
- $filtered = str_replace( $match[0], '', $filtered );
543
- $found = true;
544
- }
545
-
546
- if ( $found ) {
547
- // Strip out the whitespace that may now exist after removing the octets.
548
- $filtered = trim( preg_replace( '/ +/', ' ', $filtered ) );
549
- }
550
-
551
- return $filtered;
552
- }
553
-
554
- /**
555
- * Callback used to render the admin options page.
556
- *
557
- * @access private
558
- * @since 1.0
559
- * @static
560
- */
561
- public function page() {
562
-
563
- include EZ_TOC_PATH . '/includes/inc.admin-options-page.php';
564
- }
565
- }
566
-
567
- new ezTOC_Admin();
568
-
569
- }
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,1294 +1,1315 @@
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
- 'numeric' => __( 'Numeric', 'easy-table-of-contents' ),
257
- 'roman' => __( 'Roman', 'easy-table-of-contents' ),
258
- 'none' => __( 'None', 'easy-table-of-contents' ),
259
- ),
260
- 'default' => 'decimal',
261
- ),
262
- 'smooth_scroll' => array(
263
- 'id' => 'smooth_scroll',
264
- 'name' => __( 'Smooth Scroll', 'easy-table-of-contents' ),
265
- 'desc' => '',
266
- 'type' => 'checkbox',
267
- 'default' => true,
268
- ),
269
- 'toc_loading' => array(
270
- 'id' => 'toc_loading',
271
- 'name' => __( 'TOC Loading Method', 'easy-table-of-contents' ),
272
- 'desc' => '',
273
- 'type' => 'select',
274
- 'options' => array(
275
- 'js' => __( 'JavaScript (default)', 'easy-table-of-contents' ),
276
- 'css' => __( 'Pure CSS', 'easy-table-of-contents' ),
277
-
278
- ),
279
- 'default' => 'js',
280
- ),
281
- )
282
- ),
283
- 'appearance' => apply_filters(
284
- 'ez_toc_settings_appearance',
285
- array(
286
- 'width' => array(
287
- 'id' => 'width',
288
- 'name' => __( 'Width', 'easy-table-of-contents' ),
289
- 'desc' => '',
290
- 'type' => 'selectgroup',
291
- 'options' => array(
292
- 'fixed' => array(
293
- 'name' => __( 'Fixed', 'easy-table-of-contents' ),
294
- 'options' => array(
295
- '200px' => '200px',
296
- '225px' => '225px',
297
- '250px' => '250px',
298
- '275px' => '275px',
299
- '300px' => '300px',
300
- '325px' => '325px',
301
- '350px' => '350px',
302
- '375px' => '375px',
303
- '400px' => '400px',
304
- ),
305
- ),
306
- 'relative' => array(
307
- 'name' => __( 'Relative', 'easy-table-of-contents' ),
308
- 'options' => array(
309
- 'auto' => 'Auto',
310
- '25%' => '25%',
311
- '33%' => '33%',
312
- '50%' => '50%',
313
- '66%' => '66%',
314
- '75%' => '75%',
315
- '100%' => '100%',
316
- ),
317
- ),
318
- 'other' => array(
319
- 'name' => __( 'Custom', 'easy-table-of-contents' ),
320
- 'options' => array(
321
- 'custom' => __( 'User Defined', 'easy-table-of-contents' ),
322
- ),
323
- ),
324
- ),
325
- 'default' => 'auto',
326
- ),
327
- 'width_custom' => array(
328
- 'id' => 'width_custom',
329
- 'name' => __( 'Custom Width', 'easy-table-of-contents' ),
330
- 'desc' => __( 'Select the User Defined option from the Width option to utilitze the custom width.', 'easy-table-of-contents' ),
331
- 'type' => 'custom_width',
332
- 'default' => 275,
333
- ),
334
- 'wrapping' => array(
335
- 'id' => 'wrapping',
336
- 'name' => __( 'Float', 'easy-table-of-contents' ),
337
- 'desc' => '',
338
- 'type' => 'select',
339
- 'options' => array(
340
- 'none' => __( 'None (Default)', 'easy-table-of-contents' ),
341
- 'left' => __( 'Left', 'easy-table-of-contents' ),
342
- 'right' => __( 'Right', 'easy-table-of-contents' ),
343
- ),
344
- 'default' => 'none',
345
- ),
346
- 'title_font_size' => array(
347
- 'id' => 'title_font_size',
348
- 'name' => __( 'Title Font Size', 'easy-table-of-contents' ),
349
- 'desc' => '',
350
- 'type' => 'font_size',
351
- 'default' => 120,
352
- ),
353
- 'title_font_weight' => array(
354
- 'id' => 'title_font_weight',
355
- 'name' => __( 'Title Font Weight', 'easy-table-of-contents' ),
356
- 'desc' => '',
357
- 'type' => 'select',
358
- 'options' => array(
359
- '100' => __( 'Thin', 'easy-table-of-contents' ),
360
- '200' => __( 'Extra Light', 'easy-table-of-contents' ),
361
- '300' => __( 'Light', 'easy-table-of-contents' ),
362
- '400' => __( 'Normal', 'easy-table-of-contents' ),
363
- '500' => __( 'Medium', 'easy-table-of-contents' ),
364
- '600' => __( 'Semi Bold', 'easy-table-of-contents' ),
365
- '700' => __( 'Bold', 'easy-table-of-contents' ),
366
- '800' => __( 'Extra Bold', 'easy-table-of-contents' ),
367
- '900' => __( 'Heavy', 'easy-table-of-contents' ),
368
- ),
369
- 'default' => '500',
370
- ),
371
- 'font_size' => array(
372
- 'id' => 'font_size',
373
- 'name' => __( 'Font Size', 'easy-table-of-contents' ),
374
- 'desc' => '',
375
- 'type' => 'font_size',
376
- 'default' => 95,
377
- ),
378
- 'theme' => array(
379
- 'id' => 'theme',
380
- 'name' => __( 'Theme', 'easy-table-of-contents' ),
381
- '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' ),
382
- 'type' => 'radio',
383
- 'options' => array(
384
- 'grey' => __( 'Grey', 'easy-table-of-contents' ),
385
- 'light-blue' => __( 'Light Blue', 'easy-table-of-contents' ),
386
- 'white' => __( 'White', 'easy-table-of-contents' ),
387
- 'black' => __( 'Black', 'easy-table-of-contents' ),
388
- 'transparent' => __( 'Transparent', 'easy-table-of-contents' ),
389
- 'custom' => __( 'Custom', 'easy-table-of-contents' ),
390
- ),
391
- 'default' => 'grey',
392
- ),
393
- 'custom_theme_header' => array(
394
- 'id' => 'custom_theme_header',
395
- 'name' => '<strong>' . __( 'Custom Theme', 'easy-table-of-contents' ) . '</strong>',
396
- 'desc' => __( 'For the following settings to apply, select the Custom Theme option.', 'easy-table-of-contents' ),
397
- 'type' => 'header',
398
- ),
399
- 'custom_background_colour' => array(
400
- 'id' => 'custom_background_colour',
401
- 'name' => __( 'Background Color', 'easy-table-of-contents' ),
402
- 'desc' => '',
403
- 'type' => 'color',
404
- 'default' => '#fff',
405
- ),
406
- 'custom_border_colour' => array(
407
- 'id' => 'custom_border_colour',
408
- 'name' => __( 'Border Color', 'easy-table-of-contents' ),
409
- 'desc' => '',
410
- 'type' => 'color',
411
- 'default' => '#ddd',
412
- ),
413
- 'custom_title_colour' => array(
414
- 'id' => 'custom_title_colour',
415
- 'name' => __( 'Title Color', 'easy-table-of-contents' ),
416
- 'desc' => '',
417
- 'type' => 'color',
418
- 'default' => '#999',
419
- ),
420
- 'custom_link_colour' => array(
421
- 'id' => 'custom_link_colour',
422
- 'name' => __( 'Link Color', 'easy-table-of-contents' ),
423
- 'desc' => '',
424
- 'type' => 'color',
425
- 'default' => '#428bca',
426
- ),
427
- 'custom_link_hover_colour' => array(
428
- 'id' => 'custom_link_hover_colour',
429
- 'name' => __( 'Link Hover Color', 'easy-table-of-contents' ),
430
- 'desc' => '',
431
- 'type' => 'color',
432
- 'default' => '#2a6496',
433
- ),
434
- 'custom_link_visited_colour' => array(
435
- 'id' => 'custom_link_visited_colour',
436
- 'name' => __( 'Link Visited Color', 'easy-table-of-contents' ),
437
- 'desc' => '',
438
- 'type' => 'color',
439
- 'default' => '#428bca',
440
- ),
441
- )
442
- ),
443
- 'advanced' => apply_filters(
444
- 'ez_toc_settings_advanced',
445
- array(
446
- 'lowercase' => array(
447
- 'id' => 'lowercase',
448
- 'name' => __( 'Lowercase', 'easy-table-of-contents' ),
449
- 'desc' => __( 'Ensure anchors are in lowercase.', 'easy-table-of-contents' ),
450
- 'type' => 'checkbox',
451
- 'default' => false,
452
- ),
453
- 'hyphenate' => array(
454
- 'id' => 'hyphenate',
455
- 'name' => __( 'Hyphenate', 'easy-table-of-contents' ),
456
- 'desc' => __( 'Use - rather than _ in anchors.', 'easy-table-of-contents' ),
457
- 'type' => 'checkbox',
458
- 'default' => false,
459
- ),
460
- 'include_homepage' => array(
461
- 'id' => 'include_homepage',
462
- 'name' => __( 'Homepage', 'easy-table-of-contents' ),
463
- 'desc' => __( 'Show the table of contents for qualifying items on the homepage.', 'easy-table-of-contents' ),
464
- 'type' => 'checkbox',
465
- 'default' => false,
466
- ),
467
- 'exclude_css' => array(
468
- 'id' => 'exclude_css',
469
- 'name' => __( 'CSS', 'easy-table-of-contents' ),
470
- 'desc' => __( "Prevent the loading the core CSS styles. When selected, the appearance options from above will be ignored.", 'easy-table-of-contents' ),
471
- 'type' => 'checkbox',
472
- 'default' => false,
473
- ),
474
- //'bullet_spacing' => array(
475
- // 'id' => 'bullet_spacing',
476
- // 'name' => __( 'Theme Bullets', 'easy-table-of-contents' ),
477
- // 'desc' => __( 'If your theme includes background images for unordered list elements, enable this option to support them.', 'easy-table-of-contents' ),
478
- // 'type' => 'checkbox',
479
- // 'default' => false,
480
- //),
481
- 'heading_levels' => array(
482
- 'id' => 'heading_levels',
483
- 'name' => __( 'Headings:', 'easy-table-of-contents' ),
484
- 'desc' => __( 'Select the heading to consider when generating the table of contents. Deselecting a heading will exclude it.', 'easy-table-of-contents' ),
485
- 'type' => 'checkboxgroup',
486
- 'options' => array(
487
- '1' => __( 'Heading 1 (h1)', 'easy-table-of-contents' ),
488
- '2' => __( 'Heading 2 (h2)', 'easy-table-of-contents' ),
489
- '3' => __( 'Heading 3 (h3)', 'easy-table-of-contents' ),
490
- '4' => __( 'Heading 4 (h4)', 'easy-table-of-contents' ),
491
- '5' => __( 'Heading 5 (h5)', 'easy-table-of-contents' ),
492
- '6' => __( 'Heading 6 (h6)', 'easy-table-of-contents' ),
493
- ),
494
- 'default' => array( '1', '2', '3', '4', '5', '6' ),
495
- ),
496
- 'exclude' => array(
497
- 'id' => 'exclude',
498
- 'name' => __( 'Exclude Headings', 'easy-table-of-contents' ),
499
- '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' ),
500
- 'type' => 'text',
501
- 'size' => 'large',
502
- 'default' => '',
503
- ),
504
- 'exclude_desc' => array(
505
- 'id' => 'exclude_desc',
506
- 'name' => '',
507
- 'desc' => '<p><strong>' . __( 'Examples:', 'easy-table-of-contents' ) . '</strong></p>' .
508
- '<ul>' .
509
- '<li>' . __( '<code>Fruit*</code> Ignore headings starting with "Fruit".', 'easy-table-of-contents' ) . '</li>' .
510
- '<li>' . __( '<code>*Fruit Diet*</code> Ignore headings with "Fruit Diet" somewhere in the heading.', 'easy-table-of-contents' ) . '</li>' .
511
- '<li>' . __( '<code>Apple Tree|Oranges|Yellow Bananas</code> Ignore headings that are exactly "Apple Tree", "Oranges" or "Yellow Bananas".', 'easy-table-of-contents' ) . '</li>' .
512
- '</ul>' .
513
- '<p>' . __( '<strong>Note:</strong> This is not case sensitive.', 'easy-table-of-contents' ) . '</p>',
514
- 'type' => 'descriptive_text',
515
- ),
516
- 'smooth_scroll_offset' => array(
517
- 'id' => 'smooth_scroll_offset',
518
- 'name' => __( 'Smooth Scroll Offset', 'easy-table-of-contents' ),
519
- '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' ),
520
- 'type' => 'number',
521
- 'size' => 'small',
522
- 'default' => 30
523
- ),
524
- 'mobile_smooth_scroll_offset' => array(
525
- 'id' => 'mobile_smooth_scroll_offset',
526
- 'name' => __( 'Mobile Smooth Scroll Offset', 'easy-table-of-contents' ),
527
- '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' ),
528
- 'type' => 'number',
529
- 'size' => 'small',
530
- 'default' => 0
531
- ),
532
- 'restrict_path' => array(
533
- 'id' => 'restrict_path',
534
- 'name' => __( 'Limit Path', 'easy-table-of-contents' ),
535
- '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' ) .
536
- '<br/><span class="description">' . __( 'Eg: /wiki/, /corporate/annual-reports/', 'easy-table-of-contents' ) . '</span>',
537
- 'type' => 'text',
538
- ),
539
- 'fragment_prefix' => array(
540
- 'id' => 'fragment_prefix',
541
- 'name' => __( 'Default Anchor Prefix', 'easy-table-of-contents' ),
542
- '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' ) .
543
- '<br/>' . __( 'This option normally applies to content written in character sets other than ASCII.', 'easy-table-of-contents' ) .
544
- '<br/><span class="description">' . __( 'Eg: i, toc_index, index, _', 'easy-table-of-contents' ) . '</span>',
545
- 'type' => 'text',
546
- 'default' => 'i',
547
- ),
548
- 'widget_affix_selector' => array(
549
- 'id' => 'widget_affix_selector',
550
- 'name' => __( 'Widget Affix Selector', 'easy-table-of-contents' ),
551
- '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' ) .
552
- '<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' ) .
553
- '<br/><span class="description">' . __( 'Eg: .widget-area or #sidebar', 'easy-table-of-contents' ) . '</span>',
554
- 'type' => 'text',
555
- 'default' => '',
556
- ),
557
- )
558
- ),
559
- );
560
-
561
- return apply_filters( 'ez_toc_registered_settings', $options );
562
- }
563
-
564
- /**
565
- * The default values for the registered settings and options.
566
- *
567
- * @access private
568
- * @since 1.0
569
- * @static
570
- *
571
- * @return array
572
- */
573
- private static function getDefaults() {
574
-
575
- $defaults = array(
576
- 'fragment_prefix' => 'i',
577
- 'position' => 'before',
578
- 'start' => 4,
579
- 'show_heading_text' => true,
580
- 'heading_text' => 'Table of Contents',
581
- 'enabled_post_types' => array( 'page' ),
582
- 'auto_insert_post_types' => array(),
583
- 'show_hierarchy' => true,
584
- 'counter' => 'decimal',
585
- 'smooth_scroll' => true,
586
- 'smooth_scroll_offset' => 30,
587
- 'mobile_smooth_scroll_offset' => 0,
588
- 'visibility' => true,
589
- 'toc_loading' => 'js',
590
- //'visibility_show' => 'show',
591
- //'visibility_hide' => 'hide',
592
- 'visibility_hide_by_default' => false,
593
- 'width' => 'auto',
594
- 'width_custom' => 275,
595
- 'width_custom_units' => 'px',
596
- 'wrapping' => 'none',
597
- 'title_font_size' => 120,
598
- 'title_font_size_units' => '%',
599
- 'title_font_weight' => 500,
600
- 'font_size' => 95,
601
- 'font_size_units' => '%',
602
- 'theme' => 'grey',
603
- 'custom_background_colour' => '#fff',
604
- 'custom_border_colour' => '#ddd',
605
- 'custom_title_colour' => '#999',
606
- 'custom_link_colour' => '#428bca',
607
- 'custom_link_hover_colour' => '#2a6496',
608
- 'custom_link_visited_colour' => '#428bca',
609
- 'lowercase' => false,
610
- 'hyphenate' => false,
611
- //'bullet_spacing' => false,
612
- 'include_homepage' => false,
613
- 'exclude_css' => false,
614
- 'exclude' => '',
615
- 'heading_levels' => array( '1', '2', '3', '4', '5', '6' ),
616
- 'restrict_path' => '',
617
- 'css_container_class' => '',
618
- //'show_toc_in_widget_only' => false,
619
- //'show_toc_in_widget_only_post_types' => array(),
620
- 'widget_affix_selector' => '',
621
- );
622
-
623
- return apply_filters( 'ez_toc_get_default_options', $defaults );
624
- }
625
-
626
- /**
627
- * Get the default options array.
628
- *
629
- * @access private
630
- * @since 1.0
631
- * @static
632
- *
633
- * @return array
634
- */
635
- private static function getOptions() {
636
-
637
- $defaults = self::getDefaults();
638
- $options = get_option( 'ez-toc-settings', $defaults );
639
-
640
- //return apply_filters( 'ez_toc_get_options', wp_parse_args( $options, $defaults ) );
641
- return apply_filters( 'ez_toc_get_options', $options );
642
- }
643
-
644
- /**
645
- * Get option value by key name.
646
- *
647
- * @access public
648
- * @since 1.0
649
- * @static
650
- *
651
- * @param string $key
652
- * @param bool|false $default
653
- *
654
- * @return mixed
655
- */
656
- public static function get( $key, $default = false ) {
657
-
658
- $options = self::getOptions();
659
-
660
- $value = array_key_exists( $key, $options ) ? $options[ $key ] : $default;
661
- $value = apply_filters( 'ez_toc_get_option', $value, $key, $default );
662
-
663
- return apply_filters( 'ez_toc_get_option_' . $key, $value, $key, $default );
664
- }
665
-
666
- /**
667
- * Set an option value by key name.
668
- *
669
- * @access public
670
- * @since 1.0
671
- * @static
672
- *
673
- * @param string $key
674
- * @param bool|false $value
675
- *
676
- * @return bool
677
- */
678
- public static function set( $key, $value = false ) {
679
-
680
- if ( empty( $value ) ) {
681
-
682
- $remove_option = self::delete( $key );
683
-
684
- return $remove_option;
685
- }
686
-
687
- $options = self::getOptions();
688
-
689
- $options[ $key ] = apply_filters( 'ez_toc_update_option', $value, $key );
690
-
691
- return update_option( 'ez-toc-settings', $options );
692
- }
693
-
694
- /**
695
- * Delete an option from the options table by option key name.
696
- *
697
- * @access public
698
- * @since 1.0
699
- * @static
700
- *
701
- * @param string $key
702
- *
703
- * @return bool
704
- */
705
- public static function delete( $key ) {
706
-
707
- // First let's grab the current settings
708
- $options = get_option( 'ez-toc-settings' );
709
-
710
- // Next let's try to update the value
711
- if ( array_key_exists( $key, $options ) ) {
712
-
713
- unset( $options[ $key ] );
714
- }
715
-
716
- return update_option( 'ez-toc-settings', $options );
717
- }
718
-
719
- /**
720
- * Sanitize a hex color from user input.
721
- *
722
- * Tries to convert $string into a valid hex colour.
723
- * Returns $default if $string is not a hex value, otherwise returns verified hex.
724
- *
725
- * @access private
726
- * @since 1.0
727
- * @static
728
- *
729
- * @param string $string
730
- * @param string $default
731
- *
732
- * @return mixed|string
733
- */
734
- private static function hex_value( $string = '', $default = '#' ) {
735
-
736
- $return = $default;
737
-
738
- if ( $string ) {
739
- // strip out non hex chars
740
- $return = preg_replace( '/[^a-fA-F0-9]*/', '', $string );
741
-
742
- switch ( strlen( $return ) ) {
743
- case 3: // do next
744
- case 6:
745
- $return = '#' . $return;
746
- break;
747
-
748
- default:
749
- if ( strlen( $return ) > 6 ) {
750
- $return = '#' . substr( $return, 0, 6 );
751
- } // if > 6 chars, then take the first 6
752
- elseif ( strlen( $return ) > 3 && strlen( $return ) < 6 ) {
753
- $return = '#' . substr( $return, 0, 3 );
754
- } // if between 3 and 6, then take first 3
755
- else {
756
- $return = $default;
757
- } // not valid, return $default
758
- }
759
- }
760
-
761
- return $return;
762
- }
763
-
764
- /**
765
- * Get the registered post types minus excluded core types.
766
- *
767
- * @access public
768
- * @since 1.0
769
- * @static
770
- *
771
- * @return array
772
- */
773
- public static function getPostTypes() {
774
-
775
- $exclude = apply_filters( 'ez_toc_exclude_post_types', array( 'attachment', 'revision', 'nav_menu_item', 'safecss' ) );
776
- $registered = get_post_types( array(), 'objects' );
777
- $types = array();
778
-
779
- foreach ( $registered as $post ) {
780
-
781
- if ( in_array( $post->name, $exclude ) ) {
782
-
783
- continue;
784
- }
785
-
786
- $types[ $post->name ] = $post->label;
787
- }
788
-
789
- return $types;
790
- }
791
-
792
- /**
793
- * Missing Callback
794
- *
795
- * If a settings field type callback is not callable, alert the user.
796
- *
797
- * @access public
798
- * @since 1.0
799
- * @static
800
- *
801
- * @param array $args Arguments passed by the setting
802
- */
803
- public static function missingCallback( $args ) {
804
-
805
- printf(
806
- __( 'The callback function used for the <strong>%s</strong> setting is missing.', 'easy-table-of-contents' ),
807
- $args['id']
808
- );
809
- }
810
-
811
- /**
812
- * Text Callback
813
- *
814
- * Renders text fields.
815
- *
816
- * @access public
817
- * @since 1.0
818
- * @static
819
- *
820
- * @param array $args Arguments passed by the setting
821
- * @param null $value
822
- */
823
- public static function text( $args, $value = null ) {
824
-
825
- if ( is_null( $value ) ) {
826
-
827
- $value = self::get( $args['id'], $args['default'] );
828
- }
829
-
830
- if ( isset( $args['faux'] ) && true === $args['faux'] ) {
831
-
832
- $args['readonly'] = true;
833
- $value = isset( $args['default'] ) ? $args['default'] : '';
834
- $name = '';
835
-
836
- } else {
837
-
838
- $name = ' name="ez-toc-settings[' . $args['id'] . ']"';
839
- }
840
-
841
- $readonly = isset( $args['readonly'] ) && $args['readonly'] === true ? ' readonly="readonly"' : '';
842
- $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
843
-
844
- $html = '<input type="text" class="' . $size . '-text" id="ez-toc-settings[' . $args['id'] . ']"' . $name . ' value="' . esc_attr( stripslashes( $value ) ) . '"' . $readonly . '/>';
845
-
846
- if ( 0 < strlen( $args['desc'] ) ) {
847
-
848
- $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
849
- }
850
-
851
- echo $html;
852
- }
853
-
854
- /**
855
- * Textarea Callback.
856
- *
857
- * Renders a textarea.
858
- *
859
- * @access public
860
- * @since 1.1
861
- * @static
862
- *
863
- * @param array $args Arguments passed by the setting
864
- * @param null $value
865
- */
866
- public static function textarea( $args, $value = null ) {
867
-
868
- $html = '';
869
-
870
- if ( is_null( $value ) ) {
871
-
872
- $value = self::get( $args['id'], $args['default'] );
873
- }
874
-
875
- if ( isset( $args['faux'] ) && true === $args['faux'] ) {
876
-
877
- $args['readonly'] = true;
878
- $value = isset( $args['default'] ) ? $args['default'] : '';
879
- $name = '';
880
-
881
- } else {
882
-
883
- $name = ' name="ez-toc-settings[' . $args['id'] . ']"';
884
- }
885
-
886
- $readonly = isset( $args['readonly'] ) && $args['readonly'] === true ? ' readonly="readonly"' : '';
887
- $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
888
-
889
- if ( 0 < strlen( $args['desc'] ) ) {
890
-
891
- $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
892
- }
893
-
894
- $html .= '<textarea rows="10" cols="50" class="' . $size . '-text" id="ez-toc-settings[' . $args['id'] . ']"' . $name . $readonly . '/>' . esc_textarea( $value ) . '</textarea>';
895
-
896
- echo $html;
897
- }
898
-
899
- /**
900
- * Number Callback
901
- *
902
- * Renders number fields.
903
- *
904
- * @access public
905
- * @since 1.0
906
- * @static
907
- *
908
- * @param array $args Arguments passed by the setting
909
- */
910
- public static function number( $args ) {
911
-
912
- $value = self::get( $args['id'], $args['default'] );
913
-
914
- if ( isset( $args['faux'] ) && true === $args['faux'] ) {
915
-
916
- $args['readonly'] = true;
917
- $value = isset( $args['default'] ) ? $args['default'] : '';
918
- $name = '';
919
-
920
- } else {
921
-
922
- $name = ' name="ez-toc-settings[' . $args['id'] . ']"';
923
- }
924
-
925
- $readonly = isset( $args['readonly'] ) && $args['readonly'] === true ? ' readonly="readonly"' : '';
926
- $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
927
-
928
- $html = '<input type="number" class="' . $size . '-text" id="ez-toc-settings[' . $args['id'] . ']"' . $name . ' value="' . esc_attr( stripslashes( $value ) ) . '"' . $readonly . '/>';
929
-
930
- if ( 0 < strlen( $args['desc'] ) ) {
931
-
932
- $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
933
- }
934
-
935
- echo $html;
936
- }
937
-
938
- /**
939
- * Checkbox Callback
940
- *
941
- * Renders checkboxes.
942
- *
943
- * @access public
944
- * @since 1.0
945
- * @static
946
- *
947
- * @param array $args Arguments passed by the setting
948
- * @param null $value
949
- */
950
- public static function checkbox( $args, $value = null ) {
951
-
952
- if ( is_null( $value ) ) {
953
-
954
- $value = self::get( $args['id'], $args['default'] );
955
- }
956
-
957
- if ( isset( $args['faux'] ) && true === $args['faux'] ) {
958
-
959
- $name = '';
960
-
961
- } else {
962
-
963
- $name = ' name="ez-toc-settings[' . $args['id'] . ']"';
964
- }
965
-
966
- $checked = $value ? checked( 1, $value, false ) : '';
967
-
968
- $html = '<input type="checkbox" id="ez-toc-settings[' . $args['id'] . ']"' . $name . ' value="1" ' . $checked . '/>';
969
-
970
- if ( 0 < strlen( $args['desc'] ) ) {
971
-
972
- $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
973
- }
974
-
975
- echo $html;
976
- }
977
-
978
- /**
979
- * Multicheck Callback
980
- *
981
- * Renders multiple checkboxes.
982
- *
983
- * @access public
984
- * @since 1.0
985
- * @static
986
- *
987
- * @param array $args Arguments passed by the setting
988
- * @param null $value
989
- */
990
- public static function checkboxgroup( $args, $value = null ) {
991
-
992
- if ( is_null( $value ) ) {
993
-
994
- $value = self::get( $args['id'], $args['default'] );
995
- }
996
-
997
- if ( ! empty( $args['options'] ) ) {
998
-
999
- foreach ( $args['options'] as $key => $option ):
1000
-
1001
- if ( in_array( $key, $value ) ) {
1002
-
1003
- $enabled = $option;
1004
-
1005
- } else {
1006
-
1007
- $enabled = null;
1008
- }
1009
-
1010
- 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;';
1011
- echo '<label for="ez-toc-settings[' . $args['id'] . '][' . $key . ']">' . $option . '</label><br/>';
1012
-
1013
- endforeach;
1014
-
1015
- if ( 0 < strlen( $args['desc'] ) ) {
1016
-
1017
- echo '<p class="description">' . $args['desc'] . '</p>';
1018
- }
1019
- }
1020
- }
1021
-
1022
- /**
1023
- * Radio Callback
1024
- *
1025
- * Renders radio groups.
1026
- *
1027
- * @access public
1028
- * @since 1.0
1029
- * @static
1030
- *
1031
- * @param array $args Arguments passed by the setting
1032
- */
1033
- public static function radio( $args ) {
1034
-
1035
- $value = self::get( $args['id'], $args['default'] );
1036
-
1037
- foreach ( $args['options'] as $key => $option ) {
1038
-
1039
- echo '<input name="ez-toc-settings[' . $args['id'] . ']"" id="ez-toc-settings[' . $args['id'] . '][' . $key . ']" type="radio" value="' . $key . '" ' . checked( $key, $value, false ) . '/>&nbsp;';
1040
- echo '<label for="ez-toc-settings[' . $args['id'] . '][' . $key . ']">' . $option . '</label><br/>';
1041
- }
1042
-
1043
- if ( 0 < strlen( $args['desc'] ) ) {
1044
-
1045
- echo '<p class="description">' . $args['desc'] . '</p>';
1046
- }
1047
- }
1048
-
1049
- /**
1050
- * Select Callback
1051
- *
1052
- * Renders select fields.
1053
- *
1054
- * @access public
1055
- * @since 1.0
1056
- * @static
1057
- *
1058
- * @param array $args Arguments passed by the setting.
1059
- */
1060
- public static function select( $args ) {
1061
-
1062
- $value = self::get( $args['id'], $args['default'] );
1063
-
1064
- if ( isset( $args['placeholder'] ) ) {
1065
- $placeholder = $args['placeholder'];
1066
- } else {
1067
- $placeholder = '';
1068
- }
1069
-
1070
- if ( isset( $args['chosen'] ) ) {
1071
- $chosen = 'class="enhanced"';
1072
- } else {
1073
- $chosen = '';
1074
- }
1075
-
1076
- $html = '<select id="ez-toc-settings[' . $args['id'] . ']" name="ez-toc-settings[' . $args['id'] . ']" ' . $chosen . 'data-placeholder="' . $placeholder . '" />';
1077
-
1078
- foreach ( $args['options'] as $option => $name ) {
1079
- $selected = selected( $option, $value, false );
1080
- $html .= '<option value="' . $option . '" ' . $selected . '>' . $name . '</option>';
1081
- }
1082
-
1083
- $html .= '</select>';
1084
-
1085
- if ( 0 < strlen( $args['desc'] ) ) {
1086
-
1087
- $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1088
- }
1089
-
1090
- echo $html;
1091
- }
1092
-
1093
- /**
1094
- * Select Drop Down Callback
1095
- *
1096
- * Renders select with option group fields.
1097
- *
1098
- * @access public
1099
- * @since 1.0
1100
- * @static
1101
- *
1102
- * @param array $args Arguments passed by the setting.
1103
- */
1104
- public static function selectgroup( $args ) {
1105
-
1106
- $value = self::get( $args['id'], $args['default'] );
1107
-
1108
- if ( isset( $args['placeholder'] ) ) {
1109
- $placeholder = $args['placeholder'];
1110
- } else {
1111
- $placeholder = '';
1112
- }
1113
-
1114
- if ( isset( $args['chosen'] ) ) {
1115
- $chosen = 'class="enhanced"';
1116
- } else {
1117
- $chosen = '';
1118
- }
1119
-
1120
- $html = '<select id="ez-toc-settings[' . $args['id'] . ']" name="ez-toc-settings[' . $args['id'] . ']" ' . $chosen . 'data-placeholder="' . $placeholder . '" />';
1121
-
1122
- foreach ( $args['options'] as $group ) {
1123
-
1124
- $html .= sprintf( '<optgroup label="%1$s">', $group['name'] );
1125
-
1126
- foreach ( $group['options'] as $option => $name ) {
1127
-
1128
- $selected = selected( $option, $value, false );
1129
- $html .= '<option value="' . $option . '" ' . $selected . '>' . $name . '</option>';
1130
- }
1131
-
1132
- $html .= '</optgroup>';
1133
- }
1134
-
1135
- $html .= '</select>';
1136
-
1137
- if ( 0 < strlen( $args['desc'] ) ) {
1138
-
1139
- $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1140
- }
1141
-
1142
- echo $html;
1143
- }
1144
-
1145
- /**
1146
- * Header Callback
1147
- *
1148
- * Renders the header.
1149
- *
1150
- * @access public
1151
- * @since 1.0
1152
- * @static
1153
- *
1154
- * @param array $args Arguments passed by the setting
1155
- */
1156
- public static function header( $args ) {
1157
-
1158
- echo '<hr/>';
1159
-
1160
- if ( 0 < strlen( $args['desc'] ) ) {
1161
-
1162
- echo '<p>' . wp_kses_post( $args['desc'] ) . '</p>';
1163
- }
1164
- }
1165
-
1166
- /**
1167
- * Descriptive text callback.
1168
- *
1169
- * Renders descriptive text onto the settings field.
1170
- *
1171
- * @access public
1172
- * @since 1.0
1173
- * @static
1174
- *
1175
- * @param array $args Arguments passed by the setting
1176
- */
1177
- public static function descriptive_text( $args ) {
1178
-
1179
- echo wp_kses_post( $args['desc'] );
1180
- }
1181
-
1182
- /**
1183
- * Color picker Callback
1184
- *
1185
- * Renders color picker fields.
1186
- *
1187
- * @access public
1188
- * @since 1.0
1189
- * @static
1190
- *
1191
- * @param array $args Arguments passed by the setting
1192
- */
1193
- public static function color( $args ) {
1194
-
1195
- $value = self::get( $args['id'], $args['default'] );
1196
-
1197
- $default = isset( $args['default'] ) ? $args['default'] : '';
1198
-
1199
- $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 ) . '" />';
1200
-
1201
- if ( 0 < strlen( $args['desc'] ) ) {
1202
-
1203
- echo '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1204
- }
1205
-
1206
- echo $html;
1207
- }
1208
-
1209
- /**
1210
- * Custom table of contents width.
1211
- *
1212
- * @access public
1213
- * @since 1.0
1214
- * @static
1215
- *
1216
- * @param array $args
1217
- */
1218
- public static function custom_width( $args ) {
1219
-
1220
- //$value = self::get( $args['id'], $args['default'] );
1221
-
1222
- self::text(
1223
- array(
1224
- 'id' => $args['id'],
1225
- 'desc' => '',
1226
- 'size' => 'small',
1227
- 'default' => $args['default'],
1228
- )
1229
- );
1230
-
1231
- self::select(
1232
- array(
1233
- 'id' => $args['id'] . '_units',
1234
- 'desc' => '',
1235
- 'options' => array(
1236
- 'px' => 'px',
1237
- '%' => '%',
1238
- 'em' => 'em',
1239
- ),
1240
- 'default' => 'px',
1241
- )
1242
- );
1243
-
1244
- if ( 0 < strlen( $args['desc'] ) ) {
1245
-
1246
- echo '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1247
- }
1248
- }
1249
-
1250
- /**
1251
- * Custom font size callback.
1252
- *
1253
- * @access public
1254
- * @since 1.0
1255
- * @static
1256
- *
1257
- * @param array $args
1258
- */
1259
- public static function font_size( $args ) {
1260
-
1261
- //$value = self::get( $args['id'], $args['default'] );
1262
-
1263
- self::text(
1264
- array(
1265
- 'id' => $args['id'],
1266
- 'desc' => '',
1267
- 'size' => 'small',
1268
- 'default' => $args['default'],
1269
- )
1270
- );
1271
-
1272
- self::select(
1273
- array(
1274
- 'id' => $args['id'] . '_units',
1275
- 'desc' => '',
1276
- 'options' => array(
1277
- 'pt' => 'pt',
1278
- 'px' => 'px',
1279
- '%' => '%',
1280
- 'em' => 'em',
1281
- ),
1282
- 'default' => '%',
1283
- )
1284
- );
1285
-
1286
- if ( 0 < strlen( $args['desc'] ) ) {
1287
-
1288
- echo '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1289
- }
1290
- }
1291
- }
1292
-
1293
- add_action( 'admin_init', array( 'ezTOC_Option', 'register' ) );
1294
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ 'numeric' => __( 'Numeric', 'easy-table-of-contents' ),
257
+ 'roman' => __( 'Roman', 'easy-table-of-contents' ),
258
+ 'none' => __( 'None', 'easy-table-of-contents' ),
259
+ ),
260
+ 'default' => 'decimal',
261
+ ),
262
+ 'smooth_scroll' => array(
263
+ 'id' => 'smooth_scroll',
264
+ 'name' => __( 'Smooth Scroll', 'easy-table-of-contents' ),
265
+ 'desc' => '',
266
+ 'type' => 'checkbox',
267
+ 'default' => true,
268
+ ),
269
+ 'toc_loading' => array(
270
+ 'id' => 'toc_loading',
271
+ 'name' => __( 'TOC Loading Method', 'easy-table-of-contents' ),
272
+ 'desc' => '',
273
+ 'type' => 'select',
274
+ 'options' => array(
275
+ 'js' => __( 'JavaScript (default)', 'easy-table-of-contents' ),
276
+ 'css' => __( 'Pure CSS', 'easy-table-of-contents' ),
277
+
278
+ ),
279
+ 'default' => 'js',
280
+ ),
281
+ )
282
+ ),
283
+ 'appearance' => apply_filters(
284
+ 'ez_toc_settings_appearance',
285
+ array(
286
+ 'width' => array(
287
+ 'id' => 'width',
288
+ 'name' => __( 'Width', 'easy-table-of-contents' ),
289
+ 'desc' => '',
290
+ 'type' => 'selectgroup',
291
+ 'options' => array(
292
+ 'fixed' => array(
293
+ 'name' => __( 'Fixed', 'easy-table-of-contents' ),
294
+ 'options' => array(
295
+ '200px' => '200px',
296
+ '225px' => '225px',
297
+ '250px' => '250px',
298
+ '275px' => '275px',
299
+ '300px' => '300px',
300
+ '325px' => '325px',
301
+ '350px' => '350px',
302
+ '375px' => '375px',
303
+ '400px' => '400px',
304
+ ),
305
+ ),
306
+ 'relative' => array(
307
+ 'name' => __( 'Relative', 'easy-table-of-contents' ),
308
+ 'options' => array(
309
+ 'auto' => 'Auto',
310
+ '25%' => '25%',
311
+ '33%' => '33%',
312
+ '50%' => '50%',
313
+ '66%' => '66%',
314
+ '75%' => '75%',
315
+ '100%' => '100%',
316
+ ),
317
+ ),
318
+ 'other' => array(
319
+ 'name' => __( 'Custom', 'easy-table-of-contents' ),
320
+ 'options' => array(
321
+ 'custom' => __( 'User Defined', 'easy-table-of-contents' ),
322
+ ),
323
+ ),
324
+ ),
325
+ 'default' => 'auto',
326
+ ),
327
+ 'width_custom' => array(
328
+ 'id' => 'width_custom',
329
+ 'name' => __( 'Custom Width', 'easy-table-of-contents' ),
330
+ 'desc' => __( 'Select the User Defined option from the Width option to utilitze the custom width.', 'easy-table-of-contents' ),
331
+ 'type' => 'custom_width',
332
+ 'default' => 275,
333
+ ),
334
+ 'wrapping' => array(
335
+ 'id' => 'wrapping',
336
+ 'name' => __( 'Alignment', 'easy-table-of-contents' ),
337
+ 'desc' => '',
338
+ 'type' => 'select',
339
+ 'options' => array(
340
+ 'none' => __( 'None (Default)', 'easy-table-of-contents' ),
341
+ 'left' => __( 'Left', 'easy-table-of-contents' ),
342
+ 'right' => __( 'Right', 'easy-table-of-contents' ),
343
+ 'center' => __( 'Center', 'easy-table-of-contents' ),
344
+ ),
345
+ 'default' => 'none',
346
+ ),
347
+ 'title_font_size' => array(
348
+ 'id' => 'title_font_size',
349
+ 'name' => __( 'Title Font Size', 'easy-table-of-contents' ),
350
+ 'desc' => '',
351
+ 'type' => 'font_size',
352
+ 'default' => 120,
353
+ ),
354
+ 'title_font_weight' => array(
355
+ 'id' => 'title_font_weight',
356
+ 'name' => __( 'Title Font Weight', 'easy-table-of-contents' ),
357
+ 'desc' => '',
358
+ 'type' => 'select',
359
+ 'options' => array(
360
+ '100' => __( 'Thin', 'easy-table-of-contents' ),
361
+ '200' => __( 'Extra Light', 'easy-table-of-contents' ),
362
+ '300' => __( 'Light', 'easy-table-of-contents' ),
363
+ '400' => __( 'Normal', 'easy-table-of-contents' ),
364
+ '500' => __( 'Medium', 'easy-table-of-contents' ),
365
+ '600' => __( 'Semi Bold', 'easy-table-of-contents' ),
366
+ '700' => __( 'Bold', 'easy-table-of-contents' ),
367
+ '800' => __( 'Extra Bold', 'easy-table-of-contents' ),
368
+ '900' => __( 'Heavy', 'easy-table-of-contents' ),
369
+ ),
370
+ 'default' => '500',
371
+ ),
372
+ 'font_size' => array(
373
+ 'id' => 'font_size',
374
+ 'name' => __( 'Font Size', 'easy-table-of-contents' ),
375
+ 'desc' => '',
376
+ 'type' => 'font_size',
377
+ 'default' => 95,
378
+ ),
379
+ 'theme' => array(
380
+ 'id' => 'theme',
381
+ 'name' => __( 'Theme', 'easy-table-of-contents' ),
382
+ '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' ),
383
+ 'type' => 'radio',
384
+ 'options' => array(
385
+ 'grey' => __( 'Grey', 'easy-table-of-contents' ),
386
+ 'light-blue' => __( 'Light Blue', 'easy-table-of-contents' ),
387
+ 'white' => __( 'White', 'easy-table-of-contents' ),
388
+ 'black' => __( 'Black', 'easy-table-of-contents' ),
389
+ 'transparent' => __( 'Transparent', 'easy-table-of-contents' ),
390
+ 'custom' => __( 'Custom', 'easy-table-of-contents' ),
391
+ ),
392
+ 'default' => 'grey',
393
+ ),
394
+ 'custom_theme_header' => array(
395
+ 'id' => 'custom_theme_header',
396
+ 'name' => '<strong>' . __( 'Custom Theme', '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
+ 'custom_background_colour' => array(
401
+ 'id' => 'custom_background_colour',
402
+ 'name' => __( 'Background Color', 'easy-table-of-contents' ),
403
+ 'desc' => '',
404
+ 'type' => 'color',
405
+ 'default' => '#fff',
406
+ ),
407
+ 'custom_border_colour' => array(
408
+ 'id' => 'custom_border_colour',
409
+ 'name' => __( 'Border Color', 'easy-table-of-contents' ),
410
+ 'desc' => '',
411
+ 'type' => 'color',
412
+ 'default' => '#ddd',
413
+ ),
414
+ 'custom_title_colour' => array(
415
+ 'id' => 'custom_title_colour',
416
+ 'name' => __( 'Title Color', 'easy-table-of-contents' ),
417
+ 'desc' => '',
418
+ 'type' => 'color',
419
+ 'default' => '#999',
420
+ ),
421
+ 'custom_link_colour' => array(
422
+ 'id' => 'custom_link_colour',
423
+ 'name' => __( 'Link Color', 'easy-table-of-contents' ),
424
+ 'desc' => '',
425
+ 'type' => 'color',
426
+ 'default' => '#428bca',
427
+ ),
428
+ 'custom_link_hover_colour' => array(
429
+ 'id' => 'custom_link_hover_colour',
430
+ 'name' => __( 'Link Hover Color', 'easy-table-of-contents' ),
431
+ 'desc' => '',
432
+ 'type' => 'color',
433
+ 'default' => '#2a6496',
434
+ ),
435
+ 'custom_link_visited_colour' => array(
436
+ 'id' => 'custom_link_visited_colour',
437
+ 'name' => __( 'Link Visited Color', 'easy-table-of-contents' ),
438
+ 'desc' => '',
439
+ 'type' => 'color',
440
+ 'default' => '#428bca',
441
+ ),
442
+ )
443
+ ),
444
+ 'advanced' => apply_filters(
445
+ 'ez_toc_settings_advanced',
446
+ array(
447
+ 'lowercase' => array(
448
+ 'id' => 'lowercase',
449
+ 'name' => __( 'Lowercase', 'easy-table-of-contents' ),
450
+ 'desc' => __( 'Ensure anchors are in lowercase.', 'easy-table-of-contents' ),
451
+ 'type' => 'checkbox',
452
+ 'default' => false,
453
+ ),
454
+ 'hyphenate' => array(
455
+ 'id' => 'hyphenate',
456
+ 'name' => __( 'Hyphenate', 'easy-table-of-contents' ),
457
+ 'desc' => __( 'Use - rather than _ in anchors.', 'easy-table-of-contents' ),
458
+ 'type' => 'checkbox',
459
+ 'default' => false,
460
+ ),
461
+ 'include_homepage' => array(
462
+ 'id' => 'include_homepage',
463
+ 'name' => __( 'Homepage', 'easy-table-of-contents' ),
464
+ 'desc' => __( 'Show the table of contents for qualifying items on the homepage.', 'easy-table-of-contents' ),
465
+ 'type' => 'checkbox',
466
+ 'default' => false,
467
+ ),
468
+ 'exclude_css' => array(
469
+ 'id' => 'exclude_css',
470
+ 'name' => __( 'CSS', 'easy-table-of-contents' ),
471
+ 'desc' => __( "Prevent the loading the core CSS styles. When selected, the appearance options from above will be ignored.", 'easy-table-of-contents' ),
472
+ 'type' => 'checkbox',
473
+ 'default' => false,
474
+ ),
475
+ //'bullet_spacing' => array(
476
+ // 'id' => 'bullet_spacing',
477
+ // 'name' => __( 'Theme Bullets', 'easy-table-of-contents' ),
478
+ // 'desc' => __( 'If your theme includes background images for unordered list elements, enable this option to support them.', 'easy-table-of-contents' ),
479
+ // 'type' => 'checkbox',
480
+ // 'default' => false,
481
+ //),
482
+ 'heading_levels' => array(
483
+ 'id' => 'heading_levels',
484
+ 'name' => __( 'Headings:', 'easy-table-of-contents' ),
485
+ 'desc' => __( 'Select the heading to consider when generating the table of contents. Deselecting a heading will exclude it.', 'easy-table-of-contents' ),
486
+ 'type' => 'checkboxgroup',
487
+ 'options' => array(
488
+ '1' => __( 'Heading 1 (h1)', 'easy-table-of-contents' ),
489
+ '2' => __( 'Heading 2 (h2)', 'easy-table-of-contents' ),
490
+ '3' => __( 'Heading 3 (h3)', 'easy-table-of-contents' ),
491
+ '4' => __( 'Heading 4 (h4)', 'easy-table-of-contents' ),
492
+ '5' => __( 'Heading 5 (h5)', 'easy-table-of-contents' ),
493
+ '6' => __( 'Heading 6 (h6)', 'easy-table-of-contents' ),
494
+ ),
495
+ 'default' => array( '1', '2', '3', '4', '5', '6' ),
496
+ ),
497
+ 'exclude' => array(
498
+ 'id' => 'exclude',
499
+ 'name' => __( 'Exclude Headings', 'easy-table-of-contents' ),
500
+ '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' ),
501
+ 'type' => 'text',
502
+ 'size' => 'large',
503
+ 'default' => '',
504
+ ),
505
+ 'exclude_desc' => array(
506
+ 'id' => 'exclude_desc',
507
+ 'name' => '',
508
+ 'desc' => '<p><strong>' . __( 'Examples:', 'easy-table-of-contents' ) . '</strong></p>' .
509
+ '<ul>' .
510
+ '<li>' . __( '<code>Fruit*</code> Ignore headings starting with "Fruit".', 'easy-table-of-contents' ) . '</li>' .
511
+ '<li>' . __( '<code>*Fruit Diet*</code> Ignore headings with "Fruit Diet" somewhere in the heading.', 'easy-table-of-contents' ) . '</li>' .
512
+ '<li>' . __( '<code>Apple Tree|Oranges|Yellow Bananas</code> Ignore headings that are exactly "Apple Tree", "Oranges" or "Yellow Bananas".', 'easy-table-of-contents' ) . '</li>' .
513
+ '</ul>' .
514
+ '<p>' . __( '<strong>Note:</strong> This is not case sensitive.', 'easy-table-of-contents' ) . '</p>',
515
+ 'type' => 'descriptive_text',
516
+ ),
517
+ 'smooth_scroll_offset' => array(
518
+ 'id' => 'smooth_scroll_offset',
519
+ 'name' => __( 'Smooth Scroll Offset', 'easy-table-of-contents' ),
520
+ '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' ),
521
+ 'type' => 'number',
522
+ 'size' => 'small',
523
+ 'default' => 30
524
+ ),
525
+ 'mobile_smooth_scroll_offset' => array(
526
+ 'id' => 'mobile_smooth_scroll_offset',
527
+ 'name' => __( 'Mobile Smooth Scroll Offset', 'easy-table-of-contents' ),
528
+ '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' ),
529
+ 'type' => 'number',
530
+ 'size' => 'small',
531
+ 'default' => 0
532
+ ),
533
+ 'restrict_path' => array(
534
+ 'id' => 'restrict_path',
535
+ 'name' => __( 'Limit Path', 'easy-table-of-contents' ),
536
+ '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' ) .
537
+ '<br/><span class="description">' . __( 'Eg: /wiki/, /corporate/annual-reports/', 'easy-table-of-contents' ) . '</span>',
538
+ 'type' => 'text',
539
+ ),
540
+ 'fragment_prefix' => array(
541
+ 'id' => 'fragment_prefix',
542
+ 'name' => __( 'Default Anchor Prefix', 'easy-table-of-contents' ),
543
+ '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' ) .
544
+ '<br/>' . __( 'This option normally applies to content written in character sets other than ASCII.', 'easy-table-of-contents' ) .
545
+ '<br/><span class="description">' . __( 'Eg: i, toc_index, index, _', 'easy-table-of-contents' ) . '</span>',
546
+ 'type' => 'text',
547
+ 'default' => 'i',
548
+ ),
549
+ 'widget_affix_selector' => array(
550
+ 'id' => 'widget_affix_selector',
551
+ 'name' => __( 'Widget Affix Selector', 'easy-table-of-contents' ),
552
+ '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' ) .
553
+ '<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' ) .
554
+ '<br/><span class="description">' . __( 'Eg: .widget-area or #sidebar', 'easy-table-of-contents' ) . '</span>',
555
+ 'type' => 'text',
556
+ 'default' => '',
557
+ ),
558
+
559
+ )
560
+ ),
561
+ 'prosettings' => apply_filters(
562
+ 'ez_toc_settings_prosettings',
563
+ array(
564
+ 'exclude_by_class' => array(
565
+ 'id' => 'exclude_by_class',
566
+ 'name' => __( 'Exclude Headings by Class', 'easy-table-of-contents' ),
567
+ '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' ),
568
+ 'type' => 'text',
569
+ 'default' => '',
570
+ ),
571
+ 'fixedtoc' => array(
572
+ 'id' => 'fixedtoc',
573
+ 'name' => __( 'Fixed TOC', 'easy-table-of-contents' ),
574
+ 'desc' => __( 'Fixed TOC in the page display so it can be easier to navigate', 'easy-table-of-contents' ),
575
+ 'type' => 'checkbox',
576
+ 'default' => false,
577
+ ),
578
+ )
579
+ ),
580
+ );
581
+
582
+ return apply_filters( 'ez_toc_registered_settings', $options );
583
+ }
584
+
585
+ /**
586
+ * The default values for the registered settings and options.
587
+ *
588
+ * @access private
589
+ * @since 1.0
590
+ * @static
591
+ *
592
+ * @return array
593
+ */
594
+ private static function getDefaults() {
595
+
596
+ $defaults = array(
597
+ 'fragment_prefix' => 'i',
598
+ 'position' => 'before',
599
+ 'start' => 4,
600
+ 'show_heading_text' => true,
601
+ 'heading_text' => 'Table of Contents',
602
+ 'enabled_post_types' => array( 'page' ),
603
+ 'auto_insert_post_types' => array(),
604
+ 'show_hierarchy' => true,
605
+ 'counter' => 'decimal',
606
+ 'smooth_scroll' => true,
607
+ 'smooth_scroll_offset' => 30,
608
+ 'mobile_smooth_scroll_offset' => 0,
609
+ 'visibility' => true,
610
+ 'toc_loading' => 'js',
611
+ //'visibility_show' => 'show',
612
+ //'visibility_hide' => 'hide',
613
+ 'visibility_hide_by_default' => false,
614
+ 'width' => 'auto',
615
+ 'width_custom' => 275,
616
+ 'width_custom_units' => 'px',
617
+ 'wrapping' => 'none',
618
+ 'title_font_size' => 120,
619
+ 'title_font_size_units' => '%',
620
+ 'title_font_weight' => 500,
621
+ 'font_size' => 95,
622
+ 'font_size_units' => '%',
623
+ 'theme' => 'grey',
624
+ 'custom_background_colour' => '#fff',
625
+ 'custom_border_colour' => '#ddd',
626
+ 'custom_title_colour' => '#999',
627
+ 'custom_link_colour' => '#428bca',
628
+ 'custom_link_hover_colour' => '#2a6496',
629
+ 'custom_link_visited_colour' => '#428bca',
630
+ 'lowercase' => false,
631
+ 'hyphenate' => false,
632
+ //'bullet_spacing' => false,
633
+ 'include_homepage' => false,
634
+ 'exclude_css' => false,
635
+ 'exclude' => '',
636
+ 'heading_levels' => array( '1', '2', '3', '4', '5', '6' ),
637
+ 'restrict_path' => '',
638
+ 'css_container_class' => '',
639
+ //'show_toc_in_widget_only' => false,
640
+ //'show_toc_in_widget_only_post_types' => array(),
641
+ 'widget_affix_selector' => '',
642
+ );
643
+
644
+ return apply_filters( 'ez_toc_get_default_options', $defaults );
645
+ }
646
+
647
+ /**
648
+ * Get the default options array.
649
+ *
650
+ * @access private
651
+ * @since 1.0
652
+ * @static
653
+ *
654
+ * @return array
655
+ */
656
+ private static function getOptions() {
657
+
658
+ $defaults = self::getDefaults();
659
+ $options = get_option( 'ez-toc-settings', $defaults );
660
+
661
+ //return apply_filters( 'ez_toc_get_options', wp_parse_args( $options, $defaults ) );
662
+ return apply_filters( 'ez_toc_get_options', $options );
663
+ }
664
+
665
+ /**
666
+ * Get option value by key name.
667
+ *
668
+ * @access public
669
+ * @since 1.0
670
+ * @static
671
+ *
672
+ * @param string $key
673
+ * @param bool|false $default
674
+ *
675
+ * @return mixed
676
+ */
677
+ public static function get( $key, $default = false ) {
678
+
679
+ $options = self::getOptions();
680
+
681
+ $value = array_key_exists( $key, $options ) ? $options[ $key ] : $default;
682
+ $value = apply_filters( 'ez_toc_get_option', $value, $key, $default );
683
+
684
+ return apply_filters( 'ez_toc_get_option_' . $key, $value, $key, $default );
685
+ }
686
+
687
+ /**
688
+ * Set an option value by key name.
689
+ *
690
+ * @access public
691
+ * @since 1.0
692
+ * @static
693
+ *
694
+ * @param string $key
695
+ * @param bool|false $value
696
+ *
697
+ * @return bool
698
+ */
699
+ public static function set( $key, $value = false ) {
700
+
701
+ if ( empty( $value ) ) {
702
+
703
+ $remove_option = self::delete( $key );
704
+
705
+ return $remove_option;
706
+ }
707
+
708
+ $options = self::getOptions();
709
+
710
+ $options[ $key ] = apply_filters( 'ez_toc_update_option', $value, $key );
711
+
712
+ return update_option( 'ez-toc-settings', $options );
713
+ }
714
+
715
+ /**
716
+ * Delete an option from the options table by option key name.
717
+ *
718
+ * @access public
719
+ * @since 1.0
720
+ * @static
721
+ *
722
+ * @param string $key
723
+ *
724
+ * @return bool
725
+ */
726
+ public static function delete( $key ) {
727
+
728
+ // First let's grab the current settings
729
+ $options = get_option( 'ez-toc-settings' );
730
+
731
+ // Next let's try to update the value
732
+ if ( array_key_exists( $key, $options ) ) {
733
+
734
+ unset( $options[ $key ] );
735
+ }
736
+
737
+ return update_option( 'ez-toc-settings', $options );
738
+ }
739
+
740
+ /**
741
+ * Sanitize a hex color from user input.
742
+ *
743
+ * Tries to convert $string into a valid hex colour.
744
+ * Returns $default if $string is not a hex value, otherwise returns verified hex.
745
+ *
746
+ * @access private
747
+ * @since 1.0
748
+ * @static
749
+ *
750
+ * @param string $string
751
+ * @param string $default
752
+ *
753
+ * @return mixed|string
754
+ */
755
+ private static function hex_value( $string = '', $default = '#' ) {
756
+
757
+ $return = $default;
758
+
759
+ if ( $string ) {
760
+ // strip out non hex chars
761
+ $return = preg_replace( '/[^a-fA-F0-9]*/', '', $string );
762
+
763
+ switch ( strlen( $return ) ) {
764
+ case 3: // do next
765
+ case 6:
766
+ $return = '#' . $return;
767
+ break;
768
+
769
+ default:
770
+ if ( strlen( $return ) > 6 ) {
771
+ $return = '#' . substr( $return, 0, 6 );
772
+ } // if > 6 chars, then take the first 6
773
+ elseif ( strlen( $return ) > 3 && strlen( $return ) < 6 ) {
774
+ $return = '#' . substr( $return, 0, 3 );
775
+ } // if between 3 and 6, then take first 3
776
+ else {
777
+ $return = $default;
778
+ } // not valid, return $default
779
+ }
780
+ }
781
+
782
+ return $return;
783
+ }
784
+
785
+ /**
786
+ * Get the registered post types minus excluded core types.
787
+ *
788
+ * @access public
789
+ * @since 1.0
790
+ * @static
791
+ *
792
+ * @return array
793
+ */
794
+ public static function getPostTypes() {
795
+
796
+ $exclude = apply_filters( 'ez_toc_exclude_post_types', array( 'attachment', 'revision', 'nav_menu_item', 'safecss' ) );
797
+ $registered = get_post_types( array(), 'objects' );
798
+ $types = array();
799
+
800
+ foreach ( $registered as $post ) {
801
+
802
+ if ( in_array( $post->name, $exclude ) ) {
803
+
804
+ continue;
805
+ }
806
+
807
+ $types[ $post->name ] = $post->label;
808
+ }
809
+
810
+ return $types;
811
+ }
812
+
813
+ /**
814
+ * Missing Callback
815
+ *
816
+ * If a settings field type callback is not callable, alert the user.
817
+ *
818
+ * @access public
819
+ * @since 1.0
820
+ * @static
821
+ *
822
+ * @param array $args Arguments passed by the setting
823
+ */
824
+ public static function missingCallback( $args ) {
825
+
826
+ printf(
827
+ __( 'The callback function used for the <strong>%s</strong> setting is missing.', 'easy-table-of-contents' ),
828
+ $args['id']
829
+ );
830
+ }
831
+
832
+ /**
833
+ * Text Callback
834
+ *
835
+ * Renders text fields.
836
+ *
837
+ * @access public
838
+ * @since 1.0
839
+ * @static
840
+ *
841
+ * @param array $args Arguments passed by the setting
842
+ * @param null $value
843
+ */
844
+ public static function text( $args, $value = null ) {
845
+
846
+ if ( is_null( $value ) ) {
847
+
848
+ $value = self::get( $args['id'], $args['default'] );
849
+ }
850
+
851
+ if ( isset( $args['faux'] ) && true === $args['faux'] ) {
852
+
853
+ $args['readonly'] = true;
854
+ $value = isset( $args['default'] ) ? $args['default'] : '';
855
+ $name = '';
856
+
857
+ } else {
858
+
859
+ $name = ' name="ez-toc-settings[' . $args['id'] . ']"';
860
+ }
861
+
862
+ $readonly = isset( $args['readonly'] ) && $args['readonly'] === true ? ' readonly="readonly"' : '';
863
+ $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
864
+
865
+ $html = '<input type="text" class="' . $size . '-text" id="ez-toc-settings[' . $args['id'] . ']"' . $name . ' value="' . esc_attr( stripslashes( $value ) ) . '"' . $readonly . '/>';
866
+
867
+ if ( 0 < strlen( $args['desc'] ) ) {
868
+
869
+ $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
870
+ }
871
+
872
+ echo $html;
873
+ }
874
+
875
+ /**
876
+ * Textarea Callback.
877
+ *
878
+ * Renders a textarea.
879
+ *
880
+ * @access public
881
+ * @since 1.1
882
+ * @static
883
+ *
884
+ * @param array $args Arguments passed by the setting
885
+ * @param null $value
886
+ */
887
+ public static function textarea( $args, $value = null ) {
888
+
889
+ $html = '';
890
+
891
+ if ( is_null( $value ) ) {
892
+
893
+ $value = self::get( $args['id'], $args['default'] );
894
+ }
895
+
896
+ if ( isset( $args['faux'] ) && true === $args['faux'] ) {
897
+
898
+ $args['readonly'] = true;
899
+ $value = isset( $args['default'] ) ? $args['default'] : '';
900
+ $name = '';
901
+
902
+ } else {
903
+
904
+ $name = ' name="ez-toc-settings[' . $args['id'] . ']"';
905
+ }
906
+
907
+ $readonly = isset( $args['readonly'] ) && $args['readonly'] === true ? ' readonly="readonly"' : '';
908
+ $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
909
+
910
+ if ( 0 < strlen( $args['desc'] ) ) {
911
+
912
+ $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
913
+ }
914
+
915
+ $html .= '<textarea rows="10" cols="50" class="' . $size . '-text" id="ez-toc-settings[' . $args['id'] . ']"' . $name . $readonly . '/>' . esc_textarea( $value ) . '</textarea>';
916
+
917
+ echo $html;
918
+ }
919
+
920
+ /**
921
+ * Number Callback
922
+ *
923
+ * Renders number fields.
924
+ *
925
+ * @access public
926
+ * @since 1.0
927
+ * @static
928
+ *
929
+ * @param array $args Arguments passed by the setting
930
+ */
931
+ public static function number( $args ) {
932
+
933
+ $value = self::get( $args['id'], $args['default'] );
934
+
935
+ if ( isset( $args['faux'] ) && true === $args['faux'] ) {
936
+
937
+ $args['readonly'] = true;
938
+ $value = isset( $args['default'] ) ? $args['default'] : '';
939
+ $name = '';
940
+
941
+ } else {
942
+
943
+ $name = ' name="ez-toc-settings[' . $args['id'] . ']"';
944
+ }
945
+
946
+ $readonly = isset( $args['readonly'] ) && $args['readonly'] === true ? ' readonly="readonly"' : '';
947
+ $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
948
+
949
+ $html = '<input type="number" class="' . $size . '-text" id="ez-toc-settings[' . $args['id'] . ']"' . $name . ' value="' . esc_attr( stripslashes( $value ) ) . '"' . $readonly . '/>';
950
+
951
+ if ( 0 < strlen( $args['desc'] ) ) {
952
+
953
+ $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
954
+ }
955
+
956
+ echo $html;
957
+ }
958
+
959
+ /**
960
+ * Checkbox Callback
961
+ *
962
+ * Renders checkboxes.
963
+ *
964
+ * @access public
965
+ * @since 1.0
966
+ * @static
967
+ *
968
+ * @param array $args Arguments passed by the setting
969
+ * @param null $value
970
+ */
971
+ public static function checkbox( $args, $value = null ) {
972
+
973
+ if ( is_null( $value ) ) {
974
+
975
+ $value = self::get( $args['id'], $args['default'] );
976
+ }
977
+
978
+ if ( isset( $args['faux'] ) && true === $args['faux'] ) {
979
+
980
+ $name = '';
981
+
982
+ } else {
983
+
984
+ $name = ' name="ez-toc-settings[' . $args['id'] . ']"';
985
+ }
986
+
987
+ $checked = $value ? checked( 1, $value, false ) : '';
988
+
989
+ $html = '<input type="checkbox" id="ez-toc-settings[' . $args['id'] . ']"' . $name . ' value="1" ' . $checked . '/>';
990
+
991
+ if ( 0 < strlen( $args['desc'] ) ) {
992
+
993
+ $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
994
+ }
995
+
996
+ echo $html;
997
+ }
998
+
999
+ /**
1000
+ * Multicheck Callback
1001
+ *
1002
+ * Renders multiple checkboxes.
1003
+ *
1004
+ * @access public
1005
+ * @since 1.0
1006
+ * @static
1007
+ *
1008
+ * @param array $args Arguments passed by the setting
1009
+ * @param null $value
1010
+ */
1011
+ public static function checkboxgroup( $args, $value = null ) {
1012
+
1013
+ if ( is_null( $value ) ) {
1014
+
1015
+ $value = self::get( $args['id'], $args['default'] );
1016
+ }
1017
+
1018
+ if ( ! empty( $args['options'] ) ) {
1019
+
1020
+ foreach ( $args['options'] as $key => $option ):
1021
+
1022
+ if ( in_array( $key, $value ) ) {
1023
+
1024
+ $enabled = $option;
1025
+
1026
+ } else {
1027
+
1028
+ $enabled = null;
1029
+ }
1030
+
1031
+ 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;';
1032
+ echo '<label for="ez-toc-settings[' . $args['id'] . '][' . $key . ']">' . $option . '</label><br/>';
1033
+
1034
+ endforeach;
1035
+
1036
+ if ( 0 < strlen( $args['desc'] ) ) {
1037
+
1038
+ echo '<p class="description">' . $args['desc'] . '</p>';
1039
+ }
1040
+ }
1041
+ }
1042
+
1043
+ /**
1044
+ * Radio Callback
1045
+ *
1046
+ * Renders radio groups.
1047
+ *
1048
+ * @access public
1049
+ * @since 1.0
1050
+ * @static
1051
+ *
1052
+ * @param array $args Arguments passed by the setting
1053
+ */
1054
+ public static function radio( $args ) {
1055
+
1056
+ $value = self::get( $args['id'], $args['default'] );
1057
+
1058
+ foreach ( $args['options'] as $key => $option ) {
1059
+
1060
+ echo '<input name="ez-toc-settings[' . $args['id'] . ']"" id="ez-toc-settings[' . $args['id'] . '][' . $key . ']" type="radio" value="' . $key . '" ' . checked( $key, $value, false ) . '/>&nbsp;';
1061
+ echo '<label for="ez-toc-settings[' . $args['id'] . '][' . $key . ']">' . $option . '</label><br/>';
1062
+ }
1063
+
1064
+ if ( 0 < strlen( $args['desc'] ) ) {
1065
+
1066
+ echo '<p class="description">' . $args['desc'] . '</p>';
1067
+ }
1068
+ }
1069
+
1070
+ /**
1071
+ * Select Callback
1072
+ *
1073
+ * Renders select fields.
1074
+ *
1075
+ * @access public
1076
+ * @since 1.0
1077
+ * @static
1078
+ *
1079
+ * @param array $args Arguments passed by the setting.
1080
+ */
1081
+ public static function select( $args ) {
1082
+
1083
+ $value = self::get( $args['id'], $args['default'] );
1084
+
1085
+ if ( isset( $args['placeholder'] ) ) {
1086
+ $placeholder = $args['placeholder'];
1087
+ } else {
1088
+ $placeholder = '';
1089
+ }
1090
+
1091
+ if ( isset( $args['chosen'] ) ) {
1092
+ $chosen = 'class="enhanced"';
1093
+ } else {
1094
+ $chosen = '';
1095
+ }
1096
+
1097
+ $html = '<select id="ez-toc-settings[' . $args['id'] . ']" name="ez-toc-settings[' . $args['id'] . ']" ' . $chosen . 'data-placeholder="' . $placeholder . '" />';
1098
+
1099
+ foreach ( $args['options'] as $option => $name ) {
1100
+ $selected = selected( $option, $value, false );
1101
+ $html .= '<option value="' . $option . '" ' . $selected . '>' . $name . '</option>';
1102
+ }
1103
+
1104
+ $html .= '</select>';
1105
+
1106
+ if ( 0 < strlen( $args['desc'] ) ) {
1107
+
1108
+ $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1109
+ }
1110
+
1111
+ echo $html;
1112
+ }
1113
+
1114
+ /**
1115
+ * Select Drop Down Callback
1116
+ *
1117
+ * Renders select with option group fields.
1118
+ *
1119
+ * @access public
1120
+ * @since 1.0
1121
+ * @static
1122
+ *
1123
+ * @param array $args Arguments passed by the setting.
1124
+ */
1125
+ public static function selectgroup( $args ) {
1126
+
1127
+ $value = self::get( $args['id'], $args['default'] );
1128
+
1129
+ if ( isset( $args['placeholder'] ) ) {
1130
+ $placeholder = $args['placeholder'];
1131
+ } else {
1132
+ $placeholder = '';
1133
+ }
1134
+
1135
+ if ( isset( $args['chosen'] ) ) {
1136
+ $chosen = 'class="enhanced"';
1137
+ } else {
1138
+ $chosen = '';
1139
+ }
1140
+
1141
+ $html = '<select id="ez-toc-settings[' . $args['id'] . ']" name="ez-toc-settings[' . $args['id'] . ']" ' . $chosen . 'data-placeholder="' . $placeholder . '" />';
1142
+
1143
+ foreach ( $args['options'] as $group ) {
1144
+
1145
+ $html .= sprintf( '<optgroup label="%1$s">', $group['name'] );
1146
+
1147
+ foreach ( $group['options'] as $option => $name ) {
1148
+
1149
+ $selected = selected( $option, $value, false );
1150
+ $html .= '<option value="' . $option . '" ' . $selected . '>' . $name . '</option>';
1151
+ }
1152
+
1153
+ $html .= '</optgroup>';
1154
+ }
1155
+
1156
+ $html .= '</select>';
1157
+
1158
+ if ( 0 < strlen( $args['desc'] ) ) {
1159
+
1160
+ $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1161
+ }
1162
+
1163
+ echo $html;
1164
+ }
1165
+
1166
+ /**
1167
+ * Header Callback
1168
+ *
1169
+ * Renders the header.
1170
+ *
1171
+ * @access public
1172
+ * @since 1.0
1173
+ * @static
1174
+ *
1175
+ * @param array $args Arguments passed by the setting
1176
+ */
1177
+ public static function header( $args ) {
1178
+
1179
+ echo '<hr/>';
1180
+
1181
+ if ( 0 < strlen( $args['desc'] ) ) {
1182
+
1183
+ echo '<p>' . wp_kses_post( $args['desc'] ) . '</p>';
1184
+ }
1185
+ }
1186
+
1187
+ /**
1188
+ * Descriptive text callback.
1189
+ *
1190
+ * Renders descriptive text onto the settings field.
1191
+ *
1192
+ * @access public
1193
+ * @since 1.0
1194
+ * @static
1195
+ *
1196
+ * @param array $args Arguments passed by the setting
1197
+ */
1198
+ public static function descriptive_text( $args ) {
1199
+
1200
+ echo wp_kses_post( $args['desc'] );
1201
+ }
1202
+
1203
+ /**
1204
+ * Color picker Callback
1205
+ *
1206
+ * Renders color picker fields.
1207
+ *
1208
+ * @access public
1209
+ * @since 1.0
1210
+ * @static
1211
+ *
1212
+ * @param array $args Arguments passed by the setting
1213
+ */
1214
+ public static function color( $args ) {
1215
+
1216
+ $value = self::get( $args['id'], $args['default'] );
1217
+
1218
+ $default = isset( $args['default'] ) ? $args['default'] : '';
1219
+
1220
+ $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 ) . '" />';
1221
+
1222
+ if ( 0 < strlen( $args['desc'] ) ) {
1223
+
1224
+ echo '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1225
+ }
1226
+
1227
+ echo $html;
1228
+ }
1229
+
1230
+ /**
1231
+ * Custom table of contents width.
1232
+ *
1233
+ * @access public
1234
+ * @since 1.0
1235
+ * @static
1236
+ *
1237
+ * @param array $args
1238
+ */
1239
+ public static function custom_width( $args ) {
1240
+
1241
+ //$value = self::get( $args['id'], $args['default'] );
1242
+
1243
+ self::text(
1244
+ array(
1245
+ 'id' => $args['id'],
1246
+ 'desc' => '',
1247
+ 'size' => 'small',
1248
+ 'default' => $args['default'],
1249
+ )
1250
+ );
1251
+
1252
+ self::select(
1253
+ array(
1254
+ 'id' => $args['id'] . '_units',
1255
+ 'desc' => '',
1256
+ 'options' => array(
1257
+ 'px' => 'px',
1258
+ '%' => '%',
1259
+ 'em' => 'em',
1260
+ ),
1261
+ 'default' => 'px',
1262
+ )
1263
+ );
1264
+
1265
+ if ( 0 < strlen( $args['desc'] ) ) {
1266
+
1267
+ echo '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1268
+ }
1269
+ }
1270
+
1271
+ /**
1272
+ * Custom font size callback.
1273
+ *
1274
+ * @access public
1275
+ * @since 1.0
1276
+ * @static
1277
+ *
1278
+ * @param array $args
1279
+ */
1280
+ public static function font_size( $args ) {
1281
+
1282
+ //$value = self::get( $args['id'], $args['default'] );
1283
+
1284
+ self::text(
1285
+ array(
1286
+ 'id' => $args['id'],
1287
+ 'desc' => '',
1288
+ 'size' => 'small',
1289
+ 'default' => $args['default'],
1290
+ )
1291
+ );
1292
+
1293
+ self::select(
1294
+ array(
1295
+ 'id' => $args['id'] . '_units',
1296
+ 'desc' => '',
1297
+ 'options' => array(
1298
+ 'pt' => 'pt',
1299
+ 'px' => 'px',
1300
+ '%' => '%',
1301
+ 'em' => 'em',
1302
+ ),
1303
+ 'default' => '%',
1304
+ )
1305
+ );
1306
+
1307
+ if ( 0 < strlen( $args['desc'] ) ) {
1308
+
1309
+ echo '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
1310
+ }
1311
+ }
1312
+ }
1313
+
1314
+ add_action( 'admin_init', array( 'ezTOC_Option', 'register' ) );
1315
+ }
includes/class.post.php CHANGED
@@ -1,1415 +1,1428 @@
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
-
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
-
1109
- case 'none':
1110
- default:
1111
- // do nothing
1112
- }
1113
-
1114
- if ( ezTOC_Option::get( 'show_hierarchy' ) ) {
1115
-
1116
- $class[] = 'counter-hierarchy';
1117
-
1118
- } else {
1119
-
1120
- $class[] .= 'counter-flat';
1121
- }
1122
-
1123
- switch ( ezTOC_Option::get( 'counter' ) ) {
1124
-
1125
- case 'numeric':
1126
- $class[] .= 'counter-numeric';
1127
- break;
1128
-
1129
- case 'roman':
1130
- $class[] = 'counter-roman';
1131
- break;
1132
-
1133
- case 'decimal':
1134
- $class[] = 'counter-decimal';
1135
- break;
1136
- }
1137
-
1138
- // colour themes
1139
- switch ( ezTOC_Option::get( 'theme' ) ) {
1140
-
1141
- case 'light-blue':
1142
- $class[] = 'ez-toc-light-blue';
1143
- break;
1144
-
1145
- case 'white':
1146
- $class[] = 'ez-toc-white';
1147
- break;
1148
-
1149
- case 'black':
1150
- $class[] = 'ez-toc-black';
1151
- break;
1152
-
1153
- case 'transparent':
1154
- $class[] .= 'ez-toc-transparent';
1155
- break;
1156
-
1157
- case 'grey':
1158
- $class[] = 'ez-toc-grey';
1159
- break;
1160
- }
1161
-
1162
- $custom_classes = ezTOC_Option::get( 'css_container_class', '' );
1163
-
1164
- if ( 0 < strlen( $custom_classes ) ) {
1165
-
1166
- $custom_classes = explode( ' ', $custom_classes );
1167
- $custom_classes = apply_filters( 'ez_toc_container_class', $custom_classes, $this );
1168
-
1169
- if ( is_array( $custom_classes ) ) {
1170
-
1171
- $class = array_merge( $class, $custom_classes );
1172
- }
1173
- }
1174
-
1175
- $class = array_filter( $class );
1176
- $class = array_map( 'trim', $class );
1177
- $class = array_map( 'sanitize_html_class', $class );
1178
-
1179
- $html .= '<div id="ez-toc-container" class="' . implode( ' ', $class ) . '">' . PHP_EOL;
1180
-
1181
- if ( ezTOC_Option::get( 'show_heading_text' ) ) {
1182
-
1183
- $toc_title = ezTOC_Option::get( 'heading_text' );
1184
-
1185
- if ( strpos( $toc_title, '%PAGE_TITLE%' ) !== false ) {
1186
-
1187
- $toc_title = str_replace( '%PAGE_TITLE%', get_the_title(), $toc_title );
1188
- }
1189
-
1190
- if ( strpos( $toc_title, '%PAGE_NAME%' ) !== false ) {
1191
-
1192
- $toc_title = str_replace( '%PAGE_NAME%', get_the_title(), $toc_title );
1193
- }
1194
-
1195
- if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
1196
- $html .= '<div class="ez-toc-title-container">' . PHP_EOL;
1197
- }
1198
-
1199
- $html .= '<p class="ez-toc-title">' . esc_html__( htmlentities( $toc_title, ENT_COMPAT, 'UTF-8' ), 'easy-table-of-contents' ). '</p>' . PHP_EOL;
1200
-
1201
- if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
1202
- $html .= '<span class="ez-toc-title-toggle">';
1203
- }
1204
-
1205
- if ( ezTOC_Option::get( 'visibility' ) ) {
1206
- if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
1207
- $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>';
1208
- }else{
1209
- $html .= '<label for="item"><i class="ez-toc-glyphicon ez-toc-icon-toggle"></i></label><input type="checkbox" id="item">';
1210
- }
1211
- }
1212
-
1213
- if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
1214
- $html .= '</span>';
1215
- }
1216
- if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
1217
- $html .= '</div>' . PHP_EOL;
1218
- }
1219
- }
1220
-
1221
- ob_start();
1222
- do_action( 'ez_toc_before' );
1223
- $html .= ob_get_clean();
1224
-
1225
- $html .= '<nav>' . $this->getTOCList() . '</nav>';
1226
-
1227
- ob_start();
1228
- do_action( 'ez_toc_after' );
1229
- $html .= ob_get_clean();
1230
-
1231
- $html .= '</div>' . PHP_EOL;
1232
-
1233
- // Enqueue the script.
1234
- wp_enqueue_script( 'ez-toc-js' );
1235
- }
1236
-
1237
- return $html;
1238
- }
1239
-
1240
- /**
1241
- * Displays the post's TOC.
1242
- *
1243
- * @access public
1244
- * @since 2.0
1245
- */
1246
- public function toc() {
1247
-
1248
- echo $this->getTOC();
1249
- }
1250
-
1251
- /**
1252
- * Generate the TOC list items for a given page within a post.
1253
- *
1254
- * @access private
1255
- * @since 2.0
1256
- *
1257
- * @param int $page The page of the post to create the TOC items for.
1258
- * @param array $matches The heading from the post content extracted with preg_match_all().
1259
- *
1260
- * @return string The HTML list of TOC items.
1261
- */
1262
- private function createTOC( $page, $matches ) {
1263
-
1264
- // Whether or not the TOC should be built flat or hierarchical.
1265
- $hierarchical = ezTOC_Option::get( 'show_hierarchy' );
1266
- $html = '';
1267
-
1268
- if ( $hierarchical ) {
1269
-
1270
- $current_depth = 100; // headings can't be larger than h6 but 100 as a default to be sure
1271
- $numbered_items = array();
1272
- $numbered_items_min = null;
1273
-
1274
- // reset the internal collision collection
1275
- /** @todo does this need to be used??? */
1276
- //self::$collision_collector = array();
1277
-
1278
- // find the minimum heading to establish our baseline
1279
- //for ( $i = 0; $i < count( $matches ); $i ++ ) {
1280
- foreach ( $matches as $i => $match ) {
1281
- if ( $current_depth > $matches[ $i ][2] ) {
1282
- $current_depth = (int) $matches[ $i ][2];
1283
- }
1284
- }
1285
-
1286
- $numbered_items[ $current_depth ] = 0;
1287
- $numbered_items_min = $current_depth;
1288
-
1289
- //for ( $i = 0; $i < count( $matches ); $i ++ ) {
1290
- foreach ( $matches as $i => $match ) {
1291
-
1292
- $level = $matches[ $i ][2];
1293
- $count = $i + 1;
1294
-
1295
- if ( $current_depth == (int) $matches[ $i ][2] ) {
1296
-
1297
- $html .= '<li class="ez-toc-page-' . $page . ' ez-toc-heading-level-' . $current_depth . '">';
1298
- }
1299
-
1300
- // start lists
1301
- if ( $current_depth != (int) $matches[ $i ][2] ) {
1302
-
1303
- for ( $current_depth; $current_depth < (int) $matches[ $i ][2]; $current_depth++ ) {
1304
-
1305
- $numbered_items[ $current_depth + 1 ] = 0;
1306
- $html .= '<ul class="ez-toc-list-level-' . $level . '"><li class="ez-toc-heading-level-' . $level . '">';
1307
- }
1308
- }
1309
-
1310
- $title = isset( $matches[ $i ]['alternate'] ) ? $matches[ $i ]['alternate'] : $matches[ $i ][0];
1311
- $title = br2( $title, ' ' );
1312
- $title = strip_tags( apply_filters( 'ez_toc_title', $title ), apply_filters( 'ez_toc_title_allowable_tags', '' ) );
1313
-
1314
- $html .= $this->createTOCItemAnchor( $page, $matches[ $i ]['id'], $title, $count );
1315
-
1316
- // end lists
1317
- if ( $i != count( $matches ) - 1 ) {
1318
-
1319
- if ( $current_depth > (int) $matches[ $i + 1 ][2] ) {
1320
-
1321
- for ( $current_depth; $current_depth > (int) $matches[ $i + 1 ][2]; $current_depth-- ) {
1322
-
1323
- $html .= '</li></ul>';
1324
- $numbered_items[ $current_depth ] = 0;
1325
- }
1326
- }
1327
-
1328
- if ( $current_depth == (int) @$matches[ $i + 1 ][2] ) {
1329
-
1330
- $html .= '</li>';
1331
- }
1332
-
1333
- } else {
1334
-
1335
- // this is the last item, make sure we close off all tags
1336
- for ( $current_depth; $current_depth >= $numbered_items_min; $current_depth-- ) {
1337
-
1338
- $html .= '</li>';
1339
-
1340
- if ( $current_depth != $numbered_items_min ) {
1341
- $html .= '</ul>';
1342
- }
1343
- }
1344
- }
1345
- }
1346
-
1347
- } else {
1348
-
1349
- //for ( $i = 0; $i < count( $matches ); $i++ ) {
1350
- foreach ( $matches as $i => $match ) {
1351
-
1352
- $count = $i + 1;
1353
-
1354
- $title = isset( $matches[ $i ]['alternate'] ) ? $matches[ $i ]['alternate'] : $matches[ $i ][0];
1355
- $title = strip_tags( apply_filters( 'ez_toc_title', $title ), apply_filters( 'ez_toc_title_allowable_tags', '' ) );
1356
-
1357
- $html .= '<li class="ez-toc-page-' . $page . '">';
1358
-
1359
- $html .= $this->createTOCItemAnchor( $page, $matches[ $i ]['id'], $title, $count );
1360
-
1361
- $html .= '</li>';
1362
- }
1363
- }
1364
-
1365
- return $html;
1366
- }
1367
-
1368
- /**
1369
- * @access private
1370
- * @since 2.0
1371
- *
1372
- * @param int $page
1373
- * @param string $id
1374
- * @param string $title
1375
- * @param int $count
1376
- *
1377
- * @return string
1378
- */
1379
- private function createTOCItemAnchor( $page, $id, $title, $count ) {
1380
-
1381
- return sprintf(
1382
- '<a class="ez-toc-link ez-toc-heading-' . $count . '" href="%1$s" title="%2$s">%3$s</a>',
1383
- esc_attr( $this->createTOCItemURL( $id, $page ) ),
1384
- esc_attr( strip_tags( $title ) ),
1385
- $title
1386
- );
1387
- }
1388
-
1389
- /**
1390
- * @access private
1391
- * @since 2.0
1392
- *
1393
- * @param string $id
1394
- * @param int $page
1395
- *
1396
- * @return string
1397
- */
1398
- private function createTOCItemURL( $id, $page ) {
1399
-
1400
- $current_post = $this->post->ID === $this->queriedObjectID;
1401
- $current_page = $this->getCurrentPage();
1402
-
1403
- if ( $page === $current_page && $current_post ) {
1404
-
1405
- return '#' . $id;
1406
-
1407
- } elseif ( 1 === $page ) {
1408
-
1409
- return trailingslashit( $this->permalink ) . '#' . $id;
1410
-
1411
- }
1412
-
1413
- return trailingslashit( $this->permalink ) . $page . '/#' . $id;
1414
- }
1415
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ 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
+
1141
+ // colour themes
1142
+ switch ( ezTOC_Option::get( 'theme' ) ) {
1143
+
1144
+ case 'light-blue':
1145
+ $class[] = 'ez-toc-light-blue';
1146
+ break;
1147
+
1148
+ case 'white':
1149
+ $class[] = 'ez-toc-white';
1150
+ break;
1151
+
1152
+ case 'black':
1153
+ $class[] = 'ez-toc-black';
1154
+ break;
1155
+
1156
+ case 'transparent':
1157
+ $class[] .= 'ez-toc-transparent';
1158
+ break;
1159
+
1160
+ case 'grey':
1161
+ $class[] = 'ez-toc-grey';
1162
+ break;
1163
+ }
1164
+
1165
+ $custom_classes = ezTOC_Option::get( 'css_container_class', '' );
1166
+
1167
+ if ( 0 < strlen( $custom_classes ) ) {
1168
+
1169
+ $custom_classes = explode( ' ', $custom_classes );
1170
+ $custom_classes = apply_filters( 'ez_toc_container_class', $custom_classes, $this );
1171
+
1172
+ if ( is_array( $custom_classes ) ) {
1173
+
1174
+ $class = array_merge( $class, $custom_classes );
1175
+ }
1176
+ }
1177
+
1178
+ $class = array_filter( $class );
1179
+ $class = array_map( 'trim', $class );
1180
+ $class = array_map( 'sanitize_html_class', $class );
1181
+
1182
+ $html .= '<div id="ez-toc-container" class="' . implode( ' ', $class ) . '">' . PHP_EOL;
1183
+
1184
+ if ( ezTOC_Option::get( 'show_heading_text' ) ) {
1185
+
1186
+ $toc_title = ezTOC_Option::get( 'heading_text' );
1187
+
1188
+ if ( strpos( $toc_title, '%PAGE_TITLE%' ) !== false ) {
1189
+
1190
+ $toc_title = str_replace( '%PAGE_TITLE%', get_the_title(), $toc_title );
1191
+ }
1192
+
1193
+ if ( strpos( $toc_title, '%PAGE_NAME%' ) !== false ) {
1194
+
1195
+ $toc_title = str_replace( '%PAGE_NAME%', get_the_title(), $toc_title );
1196
+ }
1197
+
1198
+ if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
1199
+ $html .= '<div class="ez-toc-title-container">' . PHP_EOL;
1200
+ }
1201
+
1202
+ $html .= '<p class="ez-toc-title">' . esc_html__( htmlentities( $toc_title, ENT_COMPAT, 'UTF-8' ), 'easy-table-of-contents' ). '</p>' . PHP_EOL;
1203
+
1204
+ if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
1205
+ $html .= '<span class="ez-toc-title-toggle">';
1206
+ }
1207
+
1208
+ if ( ezTOC_Option::get( 'visibility' ) ) {
1209
+ if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
1210
+ $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>';
1211
+ }else{
1212
+ $toggle_view='';
1213
+ if(ezTOC_Option::get('visibility_hide_by_default')==true){
1214
+ $toggle_view= "checked";
1215
+ }
1216
+ $html .= '<label for="item"><i class="ez-toc-glyphicon ez-toc-icon-toggle"></i></label><input type="checkbox" id="item" '.$toggle_view.'>';
1217
+ }
1218
+ }
1219
+
1220
+ if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
1221
+ $html .= '</span>';
1222
+ }
1223
+ if (ezTOC_Option::get( 'toc_loading' ) != 'css') {
1224
+ $html .= '</div>' . PHP_EOL;
1225
+ }
1226
+ }else{
1227
+ $html .= '<div class="ez-toc-title-container">' . PHP_EOL;
1228
+ $html .= '<span class="ez-toc-title-toggle">';
1229
+ $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>';
1230
+ $html .= '</span>';
1231
+ $html .= '</div>' . PHP_EOL;
1232
+ }
1233
+
1234
+ ob_start();
1235
+ do_action( 'ez_toc_before' );
1236
+ $html .= ob_get_clean();
1237
+
1238
+ $html .= '<nav>' . $this->getTOCList() . '</nav>';
1239
+
1240
+ ob_start();
1241
+ do_action( 'ez_toc_after' );
1242
+ $html .= ob_get_clean();
1243
+
1244
+ $html .= '</div>' . PHP_EOL;
1245
+
1246
+ // Enqueue the script.
1247
+ wp_enqueue_script( 'ez-toc-js' );
1248
+ }
1249
+
1250
+ return $html;
1251
+ }
1252
+
1253
+ /**
1254
+ * Displays the post's TOC.
1255
+ *
1256
+ * @access public
1257
+ * @since 2.0
1258
+ */
1259
+ public function toc() {
1260
+
1261
+ echo $this->getTOC();
1262
+ }
1263
+
1264
+ /**
1265
+ * Generate the TOC list items for a given page within a post.
1266
+ *
1267
+ * @access private
1268
+ * @since 2.0
1269
+ *
1270
+ * @param int $page The page of the post to create the TOC items for.
1271
+ * @param array $matches The heading from the post content extracted with preg_match_all().
1272
+ *
1273
+ * @return string The HTML list of TOC items.
1274
+ */
1275
+ private function createTOC( $page, $matches ) {
1276
+
1277
+ // Whether or not the TOC should be built flat or hierarchical.
1278
+ $hierarchical = ezTOC_Option::get( 'show_hierarchy' );
1279
+ $html = '';
1280
+
1281
+ if ( $hierarchical ) {
1282
+
1283
+ $current_depth = 100; // headings can't be larger than h6 but 100 as a default to be sure
1284
+ $numbered_items = array();
1285
+ $numbered_items_min = null;
1286
+
1287
+ // reset the internal collision collection
1288
+ /** @todo does this need to be used??? */
1289
+ //self::$collision_collector = array();
1290
+
1291
+ // find the minimum heading to establish our baseline
1292
+ //for ( $i = 0; $i < count( $matches ); $i ++ ) {
1293
+ foreach ( $matches as $i => $match ) {
1294
+ if ( $current_depth > $matches[ $i ][2] ) {
1295
+ $current_depth = (int) $matches[ $i ][2];
1296
+ }
1297
+ }
1298
+
1299
+ $numbered_items[ $current_depth ] = 0;
1300
+ $numbered_items_min = $current_depth;
1301
+
1302
+ //for ( $i = 0; $i < count( $matches ); $i ++ ) {
1303
+ foreach ( $matches as $i => $match ) {
1304
+
1305
+ $level = $matches[ $i ][2];
1306
+ $count = $i + 1;
1307
+
1308
+ if ( $current_depth == (int) $matches[ $i ][2] ) {
1309
+
1310
+ $html .= '<li class="ez-toc-page-' . $page . ' ez-toc-heading-level-' . $current_depth . '">';
1311
+ }
1312
+
1313
+ // start lists
1314
+ if ( $current_depth != (int) $matches[ $i ][2] ) {
1315
+
1316
+ for ( $current_depth; $current_depth < (int) $matches[ $i ][2]; $current_depth++ ) {
1317
+
1318
+ $numbered_items[ $current_depth + 1 ] = 0;
1319
+ $html .= '<ul class="ez-toc-list-level-' . $level . '"><li class="ez-toc-heading-level-' . $level . '">';
1320
+ }
1321
+ }
1322
+
1323
+ $title = isset( $matches[ $i ]['alternate'] ) ? $matches[ $i ]['alternate'] : $matches[ $i ][0];
1324
+ $title = br2( $title, ' ' );
1325
+ $title = strip_tags( apply_filters( 'ez_toc_title', $title ), apply_filters( 'ez_toc_title_allowable_tags', '' ) );
1326
+
1327
+ $html .= $this->createTOCItemAnchor( $page, $matches[ $i ]['id'], $title, $count );
1328
+
1329
+ // end lists
1330
+ if ( $i != count( $matches ) - 1 ) {
1331
+
1332
+ if ( $current_depth > (int) $matches[ $i + 1 ][2] ) {
1333
+
1334
+ for ( $current_depth; $current_depth > (int) $matches[ $i + 1 ][2]; $current_depth-- ) {
1335
+
1336
+ $html .= '</li></ul>';
1337
+ $numbered_items[ $current_depth ] = 0;
1338
+ }
1339
+ }
1340
+
1341
+ if ( $current_depth == (int) @$matches[ $i + 1 ][2] ) {
1342
+
1343
+ $html .= '</li>';
1344
+ }
1345
+
1346
+ } else {
1347
+
1348
+ // this is the last item, make sure we close off all tags
1349
+ for ( $current_depth; $current_depth >= $numbered_items_min; $current_depth-- ) {
1350
+
1351
+ $html .= '</li>';
1352
+
1353
+ if ( $current_depth != $numbered_items_min ) {
1354
+ $html .= '</ul>';
1355
+ }
1356
+ }
1357
+ }
1358
+ }
1359
+
1360
+ } else {
1361
+
1362
+ //for ( $i = 0; $i < count( $matches ); $i++ ) {
1363
+ foreach ( $matches as $i => $match ) {
1364
+
1365
+ $count = $i + 1;
1366
+
1367
+ $title = isset( $matches[ $i ]['alternate'] ) ? $matches[ $i ]['alternate'] : $matches[ $i ][0];
1368
+ $title = strip_tags( apply_filters( 'ez_toc_title', $title ), apply_filters( 'ez_toc_title_allowable_tags', '' ) );
1369
+
1370
+ $html .= '<li class="ez-toc-page-' . $page . '">';
1371
+
1372
+ $html .= $this->createTOCItemAnchor( $page, $matches[ $i ]['id'], $title, $count );
1373
+
1374
+ $html .= '</li>';
1375
+ }
1376
+ }
1377
+
1378
+ return $html;
1379
+ }
1380
+
1381
+ /**
1382
+ * @access private
1383
+ * @since 2.0
1384
+ *
1385
+ * @param int $page
1386
+ * @param string $id
1387
+ * @param string $title
1388
+ * @param int $count
1389
+ *
1390
+ * @return string
1391
+ */
1392
+ private function createTOCItemAnchor( $page, $id, $title, $count ) {
1393
+
1394
+ return sprintf(
1395
+ '<a class="ez-toc-link ez-toc-heading-' . $count . '" href="%1$s" title="%2$s">%3$s</a>',
1396
+ esc_attr( $this->createTOCItemURL( $id, $page ) ),
1397
+ esc_attr( strip_tags( $title ) ),
1398
+ $title
1399
+ );
1400
+ }
1401
+
1402
+ /**
1403
+ * @access private
1404
+ * @since 2.0
1405
+ *
1406
+ * @param string $id
1407
+ * @param int $page
1408
+ *
1409
+ * @return string
1410
+ */
1411
+ private function createTOCItemURL( $id, $page ) {
1412
+
1413
+ $current_post = $this->post->ID === $this->queriedObjectID;
1414
+ $current_page = $this->getCurrentPage();
1415
+
1416
+ if ( $page === $current_page && $current_post ) {
1417
+
1418
+ return '#' . $id;
1419
+
1420
+ } elseif ( 1 === $page ) {
1421
+
1422
+ return trailingslashit( $this->permalink ) . '#' . $id;
1423
+
1424
+ }
1425
+
1426
+ return trailingslashit( $this->permalink ) . $page . '/#' . $id;
1427
+ }
1428
+ }
includes/class.widget-toc.php CHANGED
@@ -273,9 +273,9 @@ if ( ! class_exists( 'ezTOC_Widget' ) ) {
273
 
274
  <?php
275
  }
276
-
277
  echo '<nav>'. PHP_EOL . $post->getTOCList() . '</nav>' . PHP_EOL;
278
-
279
  do_action( 'ez_toc_after_widget' );
280
 
281
  echo '</div>' . PHP_EOL;
273
 
274
  <?php
275
  }
276
+ do_action( 'ez_toc_before' );
277
  echo '<nav>'. PHP_EOL . $post->getTOCList() . '</nav>' . PHP_EOL;
278
+ do_action( 'ez_toc_after' );
279
  do_action( 'ez_toc_after_widget' );
280
 
281
  echo '</div>' . PHP_EOL;
includes/inc.admin-options-page.php CHANGED
@@ -1,92 +1,463 @@
1
- <div id='toc' class='wrap'>
2
- <h1><?php _e( 'Table of Contents', 'easy-table-of-contents' ); ?></h1>
3
- <div class="toc-tab-panel">
4
- <a id="eztoc-default" class="eztoc-tablinks" data-href="no" href="#general-settings" onclick="tabToggle(event, 'general')">General</a>
5
- <a class="eztoc-tablinks" id="eztoc-technical" href="#technical-support" onclick="tabToggle(event, 'technical')" data-href="no">Technical Support</a>
6
- </div><!-- /.Tab panel -->
7
-
8
- <div class="eztoc-tabcontent" id="general">
9
- <form method="post" action="<?php echo esc_url( self_admin_url( 'options.php' ) ); ?>">
10
-
11
- <div class="metabox-holder">
12
-
13
- <div class="postbox" id="eztoc-general">
14
- <h3><span><?php _e( 'General', 'easy-table-of-contents' ); ?></span></h3>
15
-
16
- <div class="inside">
17
-
18
- <table class="form-table">
19
-
20
- <?php do_settings_fields( 'ez_toc_settings_general', 'ez_toc_settings_general' ); ?>
21
-
22
- </table>
23
-
24
- </div><!-- /.inside -->
25
- </div><!-- /.postbox -->
26
-
27
- </div><!-- /.metabox-holder -->
28
-
29
- <div class="metabox-holder">
30
-
31
- <div class="postbox" id="eztoc-appearance">
32
- <h3><span><?php _e( 'Appearance', 'easy-table-of-contents' ); ?></span></h3>
33
-
34
- <div class="inside">
35
-
36
- <table class="form-table">
37
-
38
- <?php do_settings_fields( 'ez_toc_settings_appearance', 'ez_toc_settings_appearance' ); ?>
39
-
40
- </table>
41
-
42
- </div><!-- /.inside -->
43
- </div><!-- /.postbox -->
44
-
45
- </div><!-- /.metabox-holder -->
46
-
47
- <div class="metabox-holder">
48
-
49
- <div class="postbox" id="eztoc-advanced">
50
- <h3><span><?php _e( 'Advanced', 'easy-table-of-contents' ); ?></span></h3>
51
-
52
- <div class="inside">
53
-
54
- <table class="form-table">
55
-
56
- <?php do_settings_fields( 'ez_toc_settings_advanced', 'ez_toc_settings_advanced' ); ?>
57
-
58
- </table>
59
-
60
- </div><!-- /.inside -->
61
- </div><!-- /.postbox -->
62
-
63
- </div><!-- /.metabox-holder -->
64
-
65
- <?php settings_fields( 'ez-toc-settings' ); ?>
66
- <?php submit_button( __( 'Save Changes', 'easy-table-of-contents' ) ); ?>
67
- </form>
68
- </div><!-- /.General Settings ended -->
69
-
70
- <div class="eztoc_support_div eztoc-tabcontent" id="technical">
71
- <strong><?php echo esc_html__('If you have any query, please write the query in below box or email us at','easy-table-of-contents') ?> <a href="mailto:team@magazine3.in">team@magazine3.in</a> <?php echo esc_html__('we will reply to your email address shortly.','easy-table-of-contents') ?></strong>
72
-
73
- <ul>
74
- <li>
75
- <label class="support-label">Email<span class="star-mark">*</span></label>
76
- <div class="support-input">
77
- <input type="text" id="eztoc_query_email" name="eztoc_query_email" placeholder="email" required>
78
- </div>
79
- </li>
80
- <li>
81
- <label class="support-label">Query<span class="star-mark">*</span></label>
82
- <div class="support-input"><textarea rows="5" cols="60" id="eztoc_query_message" name="eztoc_query_message" placeholder="Write your query"></textarea>
83
- </div>
84
- <div class="clear"> </div>
85
- <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>
86
- <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>
87
- </li>
88
- <li><button class="button eztoc-send-query"><?php echo esc_html__('Send Message','easy-table-of-contents'); ?></button></li>
89
- </ul>
90
-
91
- </div><!-- /.Technical support div ended -->
92
- </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>
173
+ </div>
174
+ <div class="eztoc-right-side">
175
+ <div class="eztoc-bio-box" id="ez_Bio">
176
+ <h1>Vision & Mission</h1>
177
+ <p class="eztoc-p">We strive to provide the best TOC in the world.</p>
178
+ <section class="eztoc_dev-bio">
179
+ <div class="ezoc-bio-wrap">
180
+ <img width="50px" height="50px" src="<?php echo plugins_url( 'assets/ahmed-kaludi.jpg', dirname(__FILE__) ) ?>">
181
+ <p>Lead Dev</p>
182
+ </div>
183
+ <div class="ezoc-bio-wrap">
184
+ <img width="50px" height="50px" src="<?php echo plugins_url( 'assets/Mohammed-kaludi.jpeg', dirname(__FILE__) ) ?>">
185
+ <p>Developer</p>
186
+ </div>
187
+ <div class="ezoc-bio-wrap">
188
+ <img width="50px" height="50px" src="<?php echo plugins_url( 'assets/zabi.jpg', dirname(__FILE__) ) ?>">
189
+ <p>Developer</p>
190
+ </div>
191
+ </section>
192
+ <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>
193
+ <p class="company-link"> Support the innovation & development by upgrading to PRO <a href="https://tocwp.com/pricing/">I Want To Upgrade!</a></p>
194
+ </div>
195
+ </div> </div> </div> <!-- /.Technical support div ended -->
196
+
197
+ <div class="eztoc_support_div eztoc-tabcontent" id="freevspro">
198
+ <div class="eztoc-wrapper">
199
+ <div class="eztoc-wr">
200
+ <div class="etoc-eztoc-img">
201
+ <span class="sp_ov"></span>
202
+ </div>
203
+ <div class="etoc-eztoc-cnt">
204
+ <h1><?php _e( 'UPGRADE to PRO Version'); ?></h1>
205
+ <p><?php _e( 'Take your Table of Contents to the NEXT Level!', 'easy-table-of-contents' ); ?></p>
206
+ <a class="buy" href="#upgrade"><?php _e( 'Purchase Now', 'easy-table-of-contents' ); ?></a>
207
+ </div>
208
+ <div class="pvf">
209
+ <div class="ext">
210
+ <div class="ex-1 e-1">
211
+ <h4><?php _e( 'Premium Features', 'easy-table-of-contents' ); ?></h4>
212
+ <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>
213
+ </div>
214
+ <div class="ex-1 e-2">
215
+ <h4><?php _e( 'Continuous Innovation', 'easy-table-of-contents' ); ?></h4>
216
+ <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>
217
+ </div>
218
+ <div class="ex-1 e-3">
219
+ <h4><?php _e( 'Tech Support', 'easy-table-of-contents' ); ?></h4>
220
+ <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>
221
+ </div>
222
+ </div><!-- /. ext -->
223
+ <div class="pvf-cnt">
224
+ <div class="pvf-tlt">
225
+ <h2><?php _e( 'Compare Pro vs. Free Version', 'easy-table-of-contents' ); ?></h2>
226
+ <span><?php _e( 'See what you\'ll get with the professional version', 'easy-table-of-contents' ); ?></span>
227
+ </div>
228
+ <div class="pvf-cmp">
229
+ <div class="fr">
230
+ <h1>FREE</h1>
231
+ <div class="fr-fe">
232
+ <div class="fe-1">
233
+ <h4><?php _e( 'Continious Development', 'easy-table-of-contents' ); ?></h4>
234
+ <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>
235
+ </div>
236
+ <div class="fe-1">
237
+ <h4><?php _e( '50+ Features', 'easy-table-of-contents' ); ?></h4>
238
+ <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>
239
+ </div>
240
+ </div><!-- /. fr-fe -->
241
+ </div><!-- /. fr -->
242
+ <div class="pr">
243
+ <h1>PRO</h1>
244
+ <div class="pr-fe">
245
+ <span><?php _e( 'Everything in Free, and:', 'easy-table-of-contents' ); ?></span>
246
+ <div class="fet">
247
+ <div class="fe-2">
248
+ <div class="fe-t">
249
+ <img src="<?php echo plugins_url( 'assets/right-tick.png', dirname(__FILE__) ) ?>">
250
+ <h4><?php _e( 'Gutenberg Block', 'easy-table-of-contents' ); ?></h4>
251
+ </div>
252
+ <p><?php _e( 'Easily create TOC in Gutenberg block without the need any coding or shortcode.', 'easy-table-of-contents' ); ?></p>
253
+ </div>
254
+ <div class="fe-2">
255
+ <div class="fe-t">
256
+ <img src="<?php echo plugins_url( 'assets/right-tick.png', dirname(__FILE__) ) ?>">
257
+ <h4><?php _e( 'Elementor Widget', 'easy-table-of-contents' ); ?></h4>
258
+ </div>
259
+ <p><?php _e( 'Easily create TOC in Elementor with the widget without the need any coding or shortcode.', 'easy-table-of-contents' ); ?></p>
260
+ </div>
261
+
262
+ <div class="fe-2">
263
+ <div class="fe-t">
264
+ <img src="<?php echo plugins_url( 'assets/right-tick.png', dirname(__FILE__) ) ?>">
265
+ <h4>Fixed/Sticky TOC</h4>
266
+ </div>
267
+ <p>Users can faster find the content they want with sticky</p>
268
+ </div>
269
+
270
+
271
+ <div class="fe-2">
272
+ <div class="fe-t">
273
+ <img src="<?php echo plugins_url( 'assets/right-tick.png', dirname(__FILE__) ) ?>">
274
+ <h4>Full AMP Support</h4>
275
+ </div>
276
+ <p>Generates a table of contents with your existing setup and makes them AMP automatically.</p>
277
+ </div>
278
+ <div class="fe-2">
279
+ <div class="fe-t">
280
+ <img src="<?php echo plugins_url( 'assets/right-tick.png', dirname(__FILE__) ) ?>">
281
+ <h4>Continious Updates</h4>
282
+ </div>
283
+ <p>We're continiously updating our premium features and releasing them.</p>
284
+ </div>
285
+ <div class="fe-2">
286
+ <div class="fe-t">
287
+ <img src="<?php echo plugins_url( 'assets/right-tick.png', dirname(__FILE__) ) ?>">
288
+ <h4>Documentation</h4>
289
+ </div>
290
+ <p>We create tutorials for every possible feature and keep it updated for you.</p>
291
+ </div>
292
+ </div><!-- /. fet -->
293
+ <div class="pr-btn">
294
+ <a href="#upgrade">Upgrade to Pro</a>
295
+ </div><!-- /. pr-btn -->
296
+ </div><!-- /. pr-fe -->
297
+ </div><!-- /.pr -->
298
+ </div><!-- /. pvf-cmp -->
299
+ </div><!-- /. pvf-cnt -->
300
+ <div id="upgrade" class="amp-upg">
301
+ <div class="upg-t">
302
+ <h2>Let's Upgrade Your Easy Table of Contents</h2>
303
+ <span>Choose your plan and upgrade in minutes!</span>
304
+ </div>
305
+ <div class="etoc-pri-lst">
306
+ <div class="pri-tb">
307
+ <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=1" target="_blank">
308
+ <h5>PERSONAL</h5>
309
+ <span class="d-amt"><sup>$</sup>49</span>
310
+ <span class="amt"><sup>$</sup>49</span>
311
+ <span class="s-amt">(Save $59)</span>
312
+ <span class="bil">Billed Annually</span>
313
+ <span class="s">1 Site License</span>
314
+ <span class="e">Tech Support</span>
315
+ <span class="f">1 year Updates </span>
316
+ <span class="etoc-sv">Pro Features </span>
317
+ <span class="pri-by">Buy Now</span>
318
+ </a>
319
+ </div>
320
+ <div class="pri-tb rec">
321
+ <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=2" target="_blank">
322
+ <h5>MULTIPLE</h5>
323
+ <span class="d-amt"><sup>$</sup>69</span>
324
+ <span class="amt"><sup>$</sup>69</span>
325
+ <span class="s-amt">(Save $79)</span>
326
+ <span class="bil">Billed Annually</span>
327
+ <span class="s">3 Site License</span>
328
+ <span class="e">Tech Support</span>
329
+ <span class="f">1 year Updates</span>
330
+ <span class="etoc-sv">Save 78%</span>
331
+ <span class="pri-by">Buy Now</span>
332
+ <span class="etoc-rcm">RECOMMENDED</span>
333
+ </a>
334
+ </div>
335
+ <div class="pri-tb">
336
+ <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=3" target="_blank">
337
+ <h5>WEBMASTER</h5>
338
+ <span class="d-amt"><sup>$</sup>79</span>
339
+ <span class="amt"><sup>$</sup>79</span>
340
+ <span class="s-amt">(Save $99)</span>
341
+ <span class="bil">Billed Annually</span>
342
+ <span class="s">10 Site License</span>
343
+ <span class="e">Tech Support</span>
344
+ <span class="f">1 year Updates</span>
345
+ <span class="etoc-sv">Save 83%</span>
346
+ <span class="pri-by">Buy Now</span>
347
+ </a>
348
+ </div>
349
+ <div class="pri-tb">
350
+ <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=4" target="_blank">
351
+ <h5>FREELANCER</h5>
352
+ <span class="d-amt"><sup>$</sup>99</span>
353
+ <span class="amt"><sup>$</sup>99</span>
354
+ <span class="s-amt">(Save $119)</span>
355
+ <span class="bil">Billed Annually</span>
356
+ <span class="s">25 Site License</span>
357
+ <span class="e">Tech Support</span>
358
+ <span class="f">1 year Updates</span>
359
+ <span class="etoc-sv">Save 90%</span>
360
+ <span class="pri-by">Buy Now</span>
361
+ </a>
362
+ </div>
363
+ <div class="pri-tb">
364
+ <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=5" target="_blank">
365
+ <h5>AGENCY</h5>
366
+ <span class="d-amt"><sup>$</sup>199</span>
367
+ <span class="amt"><sup>$</sup>199</span>
368
+ <span class="s-amt">(Save $199)</span>
369
+ <span class="bil">Billed Annually</span>
370
+ <span class="s">Unlimited Sites</span>
371
+ <span class="e">E-mail support</span>
372
+ <span class="f">1 year Updates</span>
373
+ <span class="etoc-sv">UNLIMITED</span>
374
+ <span class="pri-by">Buy Now</span>
375
+ </a>
376
+ </div>
377
+ <div class="pri-tb">
378
+ <a href="https://tocwp.com/checkout/?edd_action=add_to_cart&download_id=1618&edd_options[price_id]=6" target="_blank">
379
+ <h5>LIFETIME</h5>
380
+ <span class="d-amt"><sup>$</sup>499</span>
381
+ <span class="amt"><sup>$</sup>499</span>
382
+ <span class="s-amt">(Save $199)</span>
383
+ <span class="bil">Billed Annually</span>
384
+ <span class="s">Unlimited Sites</span>
385
+ <span class="e">Unlimited E-mail support</span>
386
+ <span class="f">Lifetime License</span>
387
+ <span class="etoc-sv">UNLIMITED</span>
388
+ <span class="pri-by">Buy Now</span>
389
+ </a>
390
+ </div>
391
+ </div><!-- /.pri-lst -->
392
+ <div class="tru-us">
393
+ <img src="<?php echo plugins_url( 'assets/toc-rating.png', dirname(__FILE__) ) ?>">
394
+ <h2>Used by more than 300,000+ Users!</h2>
395
+ <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>
396
+ <a href="https://wordpress.org/support/plugin/easy-table-of-contents/reviews/?filter=5" target="_blank">Read The Reviews</a>
397
+ </div>
398
+ </div><!--/ .amp-upg -->
399
+ <div class="ampfaq">
400
+ <h2>Frequently Asked Questions</h2>
401
+ <div class="faq-lst">
402
+ <div class="lt">
403
+ <ul>
404
+ <li>
405
+ <span>Is there a setup fee?</span>
406
+ <p>No. There are no setup fees on any of our plans</p>
407
+ </li>
408
+ <li>
409
+ <span>What's the time span for your contracts?</span>
410
+ <p>All the plans are year-to-year which are subscribed annually except for lifetime plan.</p>
411
+ </li>
412
+ <li>
413
+ <span>What payment methods are accepted?</span>
414
+ <p>We accepts PayPal and Credit Card payments.</p>
415
+ </li>
416
+ <li>
417
+ <span>Do you offer support if I need help?</span>
418
+ <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>
419
+ </li>
420
+ <li>
421
+ <span>Can I use the plugins after my subscription is expired?</span>
422
+ <p>Yes, you can use the plugins but you will not get future updates for those plugins.</p>
423
+ </li>
424
+ </ul>
425
+ </div>
426
+ <div class="rt">
427
+ <ul>
428
+ <li>
429
+ <span>Can I cancel my membership at any time?</span>
430
+ <p>Yes. You can cancel your membership by contacting us.</p>
431
+ </li>
432
+ <li>
433
+ <span>Can I change my plan later on?</span>
434
+ <p>Yes. You can upgrade your plan by contacting us.</p>
435
+ </li>
436
+ <li>
437
+ <span>Do you offer refunds?</span>
438
+ <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>
439
+ </li>
440
+ <li>
441
+ <span>Do I get updates for the premium plugin?</span>
442
+ <p>Yes, you will get updates for all the premium plugins until your subscription is active.</p>
443
+ </li>
444
+ </ul>
445
+ </div>
446
+ </div><!-- /.faq-lst -->
447
+ <div class="f-cnt">
448
+ <span>I have other pre-sale questions, can you help?</span>
449
+ <p>All the plans are year-to-year which are subscribed annually.</p>
450
+ <a href="https://tocwp.com/contact/'?utm_source=tocwp-plugin&utm_medium=addon-card'" target="_blank">Contact a Human</a>
451
+ </div><!-- /.f-cnt -->
452
+ </div><!-- /.faq -->
453
+ </div><!-- /. pvf -->
454
+ </div>
455
+ </div>
456
+ </div><!-- /.freevspro div ended -->
457
+
458
+ <div id="license" class="eztoc_support_div eztoc-tabcontent">
459
+ <?php
460
+ do_action("admin_upgrade_license_page");
461
+ ?>
462
+ </div>
463
+ </div>
includes/inc.functions.php CHANGED
@@ -89,4 +89,4 @@ function get_ez_toc_block( $post = null, $apply_content_filter = true ) {
89
  function ez_toc_block( $post = null, $apply_content_filter = true ) {
90
 
91
  echo get_ez_toc_block( $post, $apply_content_filter );
92
- }
89
  function ez_toc_block( $post = null, $apply_content_filter = true ) {
90
 
91
  echo get_ez_toc_block( $post, $apply_content_filter );
92
+ }
includes/inc.string-functions.php CHANGED
@@ -1,344 +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
- function mb_substr_replace( $string, $replacement, $start, $length = null ) {
210
-
211
- if ( is_array( $string ) ) {
212
-
213
- $num = count( $string );
214
-
215
- // $replacement
216
- $replacement = is_array( $replacement ) ? array_slice( $replacement, 0, $num ) : array_pad( array( $replacement ), $num, $replacement );
217
-
218
- // $start
219
- if ( is_array( $start ) ) {
220
- $start = array_slice( $start, 0, $num );
221
- foreach ( $start as $key => $value ) {
222
- $start[ $key ] = is_int( $value ) ? $value : 0;
223
- }
224
- } else {
225
- $start = array_pad( array( $start ), $num, $start );
226
- }
227
-
228
- // $length
229
- if ( ! isset( $length ) ) {
230
- $length = array_fill( 0, $num, 0 );
231
- } elseif ( is_array( $length ) ) {
232
- $length = array_slice( $length, 0, $num );
233
- foreach ( $length as $key => $value ) {
234
- $length[ $key ] = isset( $value ) ? ( is_int( $value ) ? $value : $num ) : 0;
235
- }
236
- } else {
237
- $length = array_pad( array( $length ), $num, $length );
238
- }
239
-
240
- // Recursive call
241
- return array_map( __FUNCTION__, $string, $replacement, $start, $length );
242
- }
243
-
244
- preg_match_all( '/./us', (string) $string, $smatches );
245
- preg_match_all( '/./us', (string) $replacement, $rmatches );
246
-
247
- if ( $length === null ) {
248
-
249
- $length = mb_strlen( $string );
250
- }
251
-
252
- array_splice( $smatches[0], $start, $length, $rmatches[0] );
253
-
254
- return join( $smatches[0] );
255
- }
256
-
257
- /**
258
- * Returns a string with all items from the $find array replaced with their matching
259
- * items in the $replace array. This does a one to one replacement (rather than globally).
260
- *
261
- * This function is multibyte safe.
262
- *
263
- * $find and $replace are arrays, $string is the haystack. All variables are passed by reference.
264
- *
265
- * @since 1.0
266
- *
267
- * @param bool $find
268
- * @param bool $replace
269
- * @param string $string
270
- *
271
- * @return mixed|string
272
- */
273
- function mb_find_replace( &$find = false, &$replace = false, &$string = '' ) {
274
-
275
- if ( is_array( $find ) && is_array( $replace ) && $string ) {
276
-
277
- // check if multibyte strings are supported
278
- if ( function_exists( 'mb_strpos' ) ) {
279
-
280
- //for ( $i = 0; $i < count( $find ); $i ++ ) {
281
- //
282
- // $string = mb_substr(
283
- // $string,
284
- // 0,
285
- // mb_strpos( $string, $find[ $i ] )
286
- // ) . // everything before $find
287
- // $replace[ $i ] . // its replacement
288
- // mb_substr(
289
- // $string,
290
- // mb_strpos( $string, $find[ $i ] ) + mb_strlen( $find[ $i ] )
291
- // ) // everything after $find
292
- // ;
293
- //}
294
-
295
- for ( $i = 0; $i < count( $find ); $i ++ ) {
296
-
297
- $needle = $find[ $i ];
298
- $start = mb_strpos( $string, $needle );
299
-
300
- // If heading can not be found, let try decoding entities to see if it can be found.
301
- if ( false === $start ) {
302
-
303
- $needle = html_entity_decode(
304
- $needle,
305
- ENT_QUOTES,
306
- get_option( 'blog_charset' )
307
- );
308
-
309
- $needle = str_replace(array('’','“','”'), array('\'','"','"'), $needle);
310
-
311
- $start = mb_strpos( $string, $needle );
312
- }
313
-
314
- /*
315
- * `mb_strpos()` can return `false`. Only process `mb_substr_replace()` if position in string is found.
316
- */
317
- if ( is_int( $start ) ) {
318
-
319
- $length = mb_strlen( $needle );
320
- $string = mb_substr_replace( $string, $replace[ $i ], $start, $length );
321
- }
322
-
323
- }
324
-
325
- } else {
326
-
327
- for ( $i = 0; $i < count( $find ); $i ++ ) {
328
-
329
- $start = strpos( $string, $find[ $i ] );
330
- $length = strlen( $find[ $i ] );
331
-
332
- /*
333
- * `strpos()` can return `false`. Only process `substr_replace()` if position in string is found.
334
- */
335
- if ( is_int( $start ) ) {
336
-
337
- $string = substr_replace( $string, $replace[ $i ], $start, $length );
338
- }
339
- }
340
- }
341
- }
342
-
343
- return $string;
344
- }
 
 
 
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;