PluginProbe
Text To Speech TTS Accessibility / 2.3.13
Text To Speech TTS Accessibility v2.3.13
2.3.13 2.3.12 2.3.11 2.3.10 2.3.9 2.3.8 2.3.7 2.3.6 2.3.5 2.3.4 2.3.3 2.3.2 2.3.1 2.3.0 2.2.5 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.1.20 2.1.19 2.1.18 2.1.17 1.9.16 All 253 releases
text-to-audio / text-to-audio.php

text-to-audio.php in Text To Speech TTS Accessibility 2.3.13, at text-to-audio.php

465 lines 15.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * The plugin bootstrap file
4 *
5 * This file is read by WordPress to generate the plugin information in the plugin
6 * admin area. This file also includes all of the dependencies used by the plugin,
7 * registers the activation and deactivation functions, and defines a function
8 * that starts the plugin.
9 *
10 * @link https://atlasaidev.com/
11 * @since 1.0.0
12 * @package TTA
13 *
14 * @wordpress-plugin
15 * Plugin Name: Text To Speech TTS Accessibility
16 * Plugin URI: https://atlasaidev.com/
17 * Description: The most user-friendly Text-to-Speech Accessibility plugin. Just install and automatically add a Text to Audio player to your WordPress site!
18 * Version: 2.3.13
19 * Author: AtlasAiDev
20 * Author URI: http://atlasaidev.com/
21 * License: GPL-3.0+
22 * License URI: https://www.gnu.org/licenses/gpl-3.0.txt
23 * Text Domain: text-to-audio
24 * Domain Path: /languages
25 * Requires PHP: 7.4
26 * Requires at least: 5.6
27 */
28
29
30
31 // If this file is called directly, abort.
32 if (!defined('WPINC')) {
33 die;
34 }
35
36 // Include Composer autoloader if using Composer
37 if (file_exists(__DIR__ . '/vendor/autoload.php')) {
38 require_once __DIR__ . '/vendor/autoload.php';
39 }
40
41 // Suppress WordPress 6.7+ "textdomain loaded too early" notice. Some
42 // bundled dependencies still call __() before init; the resulting
43 // _load_textdomain_just_in_time notice is harmless but corrupts REST API
44 // JSON responses when WP_DEBUG is on.
45 add_filter( 'doing_it_wrong_trigger_error', function ( $trigger, $function_name ) {
46 if ( '_load_textdomain_just_in_time' === $function_name ) {
47 return false;
48 }
49 return $trigger;
50 }, 10, 2 );
51
52 use TTA\TTA;
53 use TTA\TTA_Activator;
54 use TTA\TTA_Deactivator;
55 use TTA_Api\TTA_Api_Routes;
56 use TTA\TTA_Notices;
57 use TTA\TTA_Lib_AtlasAiDev;
58 use TTA\TTA_Cache;
59
60 /**
61 * Is plugin active
62 */
63 function is_pro_plugin_exists()
64 {
65 $plugin_path = \WP_PLUGIN_DIR;
66 $pro_plugins = [
67 '/text-to-speech-pro/text-to-audio-pro.php',
68 '/text-to-speech-pro-premium/text-to-audio-pro.php',
69 '/text-to-audio-pro/text-to-audio-pro.php',
70 '/text-to-audio-pro-premium/text-to-audio-pro.php'
71 ];
72
73 foreach ($pro_plugins as $pro_plugin) {
74 if (file_exists($plugin_path . $pro_plugin)) {
75 return true;
76 }
77 }
78
79 return false;
80 }
81
82
83 /**
84 * Currently plugin version.
85 * Start at version 1.0.0 and use SemVer - https://semver.org
86 * Rename this for your plugin and update it as you release new versions.
87 */
88
89 if (!defined('TEXT_TO_AUDIO_NONCE')) {
90
91 define('TEXT_TO_AUDIO_NONCE', 'TEXT_TO_AUDIO_NONCE');
92 }
93
94 if (!defined('TEXT_TO_AUDIO_TEXT_DOMAIN')) {
95
96 define('TEXT_TO_AUDIO_TEXT_DOMAIN', 'text-to-audio');
97 }
98
99 if (!defined('TEXT_TO_AUDIO_ROOT_FILE')) {
100
101 define('TEXT_TO_AUDIO_ROOT_FILE', __FILE__);
102 }
103
104 if (!defined('TTA_ROOT_FILE_NAME')) {
105 $path = explode(DIRECTORY_SEPARATOR, TEXT_TO_AUDIO_ROOT_FILE);
106 $file = end($path);
107 define('TTA_ROOT_FILE_NAME', $file);
108 }
109
110 if (!defined('TTA_LIBS_PATH')) {
111
112 define('TTA_LIBS_PATH', dirname(TEXT_TO_AUDIO_ROOT_FILE) . '/libs/');
113 }
114
115 if (!defined('TTA_ADMIN_PATH')) {
116
117 define('TTA_ADMIN_PATH', plugin_dir_url(__FILE__) . 'admin/');
118 }
119
120 if (!defined('TTA_DEBUG_MODE')) {
121
122 define('TTA_DEBUG_MODE', 0);
123 }
124
125 if (!defined('TTA_ENABLE_RESET_UI')) {
126 define('TTA_ENABLE_RESET_UI', false);
127 }
128
129 if (!defined('TTA_REQUIRED_PRO_VERSION')) {
130 define('TTA_REQUIRED_PRO_VERSION', '3.3.1');
131 }
132
133
134 if (!defined('TTA_PLUGIN_URL')) {
135 /**
136 * Plugin Directory URL
137 *
138 * @var string
139 * @since 1.2.2
140 */
141 define('TTA_PLUGIN_URL', trailingslashit(plugin_dir_url(TEXT_TO_AUDIO_ROOT_FILE)));
142 }
143
144 if (!defined('TTA_PLUGIN_PATH')) {
145 /**
146 * Plugin Directory PATH
147 *
148 * @var string
149 * @since 1.2.2
150 */
151 define('TTA_PLUGIN_PATH', trailingslashit(plugin_dir_path(TEXT_TO_AUDIO_ROOT_FILE)));
152 }
153
154 if (TTA_DEBUG_MODE && defined('WP_SITEURL') && WP_SITEURL) {
155 $rest_url = WP_SITEURL . '/wp-json/';
156 update_option('tts_rest_api_url', $rest_url, false);
157 TTA_Cache::set('tts_rest_api_url', $rest_url);
158 }
159
160 /**
161 * Begins execution of the plugin.
162 *
163 * Since everything within the plugin is registered via hooks,
164 * then kicking off the plugin from this point in the file does
165 * not affect the page life cycle.
166 *
167 * @since 1.0.0
168 */
169 class TTA_Init
170 {
171
172 public function __construct()
173 {
174 if (!defined('TEXT_TO_AUDIO_VERSION')) {
175 define('TEXT_TO_AUDIO_VERSION', apply_filters('tts_version', '2.3.13'));
176 }
177
178 if (!defined('TEXT_TO_AUDIO_PLUGIN_NAME')) {
179 define('TEXT_TO_AUDIO_PLUGIN_NAME', apply_filters('tts_plugin_name', 'AtlasVoice'));
180 }
181
182 $this->run();
183 }
184
185 public function run()
186 {
187 // TTS-238 v5 §14 D0c — single hook-based entry into the
188 // AtlasVoice subsystem. Wires cron, meta boxes, REST routes,
189 // localise-data filters, and (later) the regen-guard. All
190 // individual feature modules self-gate on Layer 1 opt-in so
191 // this call is safe even when the admin has not opted in.
192 //
193 // CRITICAL ORDERING: must run BEFORE `new TTA()` below, because
194 // TTA::run() → TTA_Admin::__construct() invokes the
195 // `atlasvoice_localize_data` filter during construction. The
196 // LocalizeData::inject callback must already be registered by
197 // then, otherwise the filter fires against an empty hook chain
198 // and no AtlasVoice fields make it into ttsObj.
199 if ( class_exists( '\\TTA\\AtlasVoice\\Bootstrap' ) ) {
200 \TTA\AtlasVoice\Bootstrap::register();
201 }
202
203 $plugin = new TTA();
204 $plugin->run();
205
206 add_action('init', function () {
207 // TTS-262: init() now runs in BOTH states. Audience-targeted
208 // promotions run always (so 'pro'/'all' promos can reach Pro users);
209 // telemetry/Insights stays free-only, gated inside init().
210 TTA_Lib_AtlasAiDev::instance()->init();
211 if (!TTA_Cache::get('tts_rest_api_url')) {
212 $rest_url = esc_url_raw(rest_url());
213 update_option('tts_rest_api_url', $rest_url, false);
214 TTA_Cache::set('tts_rest_api_url', $rest_url);
215 }
216 TTA_Notices::instance();
217 //Rest api init.
218 new TTA_Api_Routes();
219 }, 9999);
220
221 //add plugins action links.
222 if (is_admin()) {
223 $basename = plugin_basename(__FILE__);
224 $prefix = is_network_admin() ? 'network_admin_' : '';
225 add_filter(
226 "{$prefix}plugin_action_links_$basename",
227 array($this, 'add_action_links'),
228 10, // priority
229 4 // parameters
230 );
231 }
232 }
233
234 /**
235 * add action list to plugin.
236 */
237 public function add_action_links($actions, $plugin_file, $plugin_data, $context)
238 {
239 $plugin_url = esc_url(admin_url() . 'admin.php?page=text-to-audio');
240 $doc_url = esc_url(admin_url() . 'admin.php?page=text-to-audio#/faq');
241 $support = esc_url('https://atlasaidev.com/contact-us/');
242 $review = esc_url('https://wordpress.org/support/plugin/text-to-audio/reviews/');
243 $custom_actions = array(
244 'settings' => sprintf('<a href="%s" target="_blank">%s</a>', $plugin_url, __('Settings', 'text-to-audio')),
245 'faq' => sprintf('<a href="%s" target="_blank">%s</a>', $doc_url, __('Docs', 'text-to-audio')),
246 'support' => sprintf('<a href="%s" target="_blank">%s</a>', $support, __('Support', 'text-to-audio')),
247 'review' => sprintf('<a href="%s" target="_blank">%s</a>', $review, __('Write a Review', 'text-to-audio')),
248 );
249
250 // TTS-264: free-only "Go Pro" action link -> the internal Pricing page.
251 // Prepended and colour-accented so it stands out on the Plugins screen.
252 if (!is_atlasvoice_addon_functional()) {
253 $pricing_url = esc_url(admin_url() . 'admin.php?page=atlasvoice-pricing');
254 $custom_actions = array_merge(
255 array('go_pro' => sprintf('<a href="%s" style="color:#184c53;font-weight:600;">%s</a>', $pricing_url, __('Go Pro', 'text-to-audio'))),
256 $custom_actions
257 );
258 }
259
260 // add the links to the front of the actions list
261 return array_merge($custom_actions, $actions);
262
263 }
264
265 }
266
267
268 // TTS-247: load_plugin_textdomain() has been discouraged since WP 4.6 for
269 // wp.org-hosted plugins -- WordPress loads translations automatically from
270 // translate.wordpress.org. Removed per the Plugin Check warning.
271
272 add_action('plugins_loaded', function () {
273 //Rest api init.
274 new TTA_Init();
275 }, 9999);
276
277 /**
278 * Register custom cron schedule intervals
279 */
280 add_filter('cron_schedules', function ($schedules) {
281 $schedules['weekly'] = array(
282 'interval' => 604800, // 7 days in seconds
283 'display' => 'Once Weekly',
284 );
285 $schedules['monthly'] = array(
286 'interval' => 2592000, // 30 days in seconds
287 'display' => 'Once Monthly',
288 );
289 return $schedules;
290 });
291
292 /**
293 * Hook for scheduled analytics report
294 */
295 add_action('tta_send_scheduled_report', function () {
296 // Email sending is a Pro feature — delegate to Pro Report Email class.
297 if (class_exists('TTA_Pro\TTA_Pro_Report_Email')) {
298 $reporter = new \TTA_Pro\TTA_Pro_Report_Email();
299 $reporter->generate_and_send_report();
300 }
301 });
302
303 /**
304 * TTS-236: Register cron hook for the chunked play_count migration.
305 * Scheduled by TTA_Activator::create_analytics_table_if_not_exists() on upgrade,
306 * and by TTA_Notices::query_total_plays() if the large-table guard trips.
307 */
308 add_action('tta_migrate_play_count_column', array('\TTA\TTA_Activator', 'migrate_play_count_batch'));
309
310
311 /**
312 * The code that runs during plugin activation.
313 * This action is documented in includes/TTA_Activator.php
314 */
315 register_activation_hook(__FILE__, function () {
316 TTA_Activator::activate();
317 });
318
319 /**
320 * TTS-287: seed plugin defaults on a subsite created AFTER network activation.
321 *
322 * register_activation_hook() fires once, for the site that activates. On a
323 * network-activated install every subsite created later starts with no
324 * tta_settings_data and no tta_customize_settings, so every option-driven gate
325 * in should_load_button() reads an empty array and the player never renders --
326 * not auto-insert, not the [atlasvoice] shortcode, in either mode, for admins
327 * or visitors. The site looks installed and is silently inert.
328 *
329 * Verified on a fresh subsite: making the individual gates default-permissive
330 * is NOT sufficient on its own, because several independent options are
331 * missing at once. The defaults have to exist.
332 *
333 * wp_initialize_site runs after the new site's tables exist, so switch_to_blog()
334 * is safe here. Priority 20 leaves room for core to finish provisioning.
335 */
336 add_action('wp_initialize_site', function ($new_site) {
337 if (!function_exists('is_plugin_active_for_network')) {
338 require_once ABSPATH . 'wp-admin/includes/plugin.php';
339 }
340
341 if (!is_plugin_active_for_network(plugin_basename(TEXT_TO_AUDIO_ROOT_FILE))) {
342 return;
343 }
344
345 $blog_id = ($new_site instanceof WP_Site) ? (int) $new_site->blog_id : (int) $new_site;
346 if (!$blog_id) {
347 return;
348 }
349
350 switch_to_blog($blog_id);
351 TTA_Activator::activate();
352 restore_current_blog();
353 }, 20, 1);
354
355 /**
356 * TTS-247 — grandfather existing installs onto the new staging/live mode.
357 * Runs early (front + admin) so an upgraded site keeps its live player on
358 * the very first request, before should_load_button's staging gate runs.
359 * Self-disables after one pass via the tta_mode_default_migrated flag.
360 */
361 add_action('plugins_loaded', ['TTA\\TTA_Activator', 'maybe_set_default_mode'], 1);
362
363 /**
364 * Redirect to settings page on first activation.
365 * Uses a transient set in TTA_Activator::activate() to detect first-time activation.
366 *
367 * @since 2.1.8
368 */
369 add_action('admin_init', function () {
370 // One-time migration (2.1.10): enable analytics for existing free users.
371 // TTS-250: track every post by default (the "all" sentinel) instead of the
372 // latest 20 — the old 20-post cap was an artificial limit on a shipped
373 // feature (wp.org Guideline 5).
374 if ( ! get_option( 'tta_analytics_migrated_2_1_10' ) ) {
375 $analytics = (array) get_option( 'tta_analytics_settings' );
376 if ( empty( $analytics['tts_enable_analytics'] ) && empty( $analytics['tts_trackable_post_ids'] ) ) {
377 $analytics['tts_enable_analytics'] = true;
378 $analytics['tts_trackable_post_ids'] = array( 'all' );
379 update_option( 'tta_analytics_settings', $analytics, false );
380 }
381 update_option( 'tta_analytics_migrated_2_1_10', true, false );
382 }
383
384 // Allow resetting onboarding via ?page=text-to-audio&reset_onboard=true
385 // phpcs:disable WordPress.Security.NonceVerification.Recommended -- admin-only flow gated by current_user_can(manage_options); read-only routing check
386 if ( isset( $_GET['page'] ) && 'text-to-audio' === $_GET['page']
387 && isset( $_GET['reset_onboard'] ) && 'true' === $_GET['reset_onboard']
388 && current_user_can( 'manage_options' )
389 ) {
390 // phpcs:enable WordPress.Security.NonceVerification.Recommended
391 delete_option( 'tta_onboarding_completed' );
392 delete_option( 'tta_pro_onboarding_completed' );
393 wp_safe_redirect( admin_url( 'admin.php?page=text-to-audio&welcome=1' ) );
394 exit;
395 }
396
397 if ( get_transient('tta_activation_redirect') ) {
398 delete_transient('tta_activation_redirect');
399
400 // Don't redirect during bulk activation or if user can't manage options.
401 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- WP-core flag set by core during multi-activate; presence-only check
402 if ( isset($_GET['activate-multi']) || ! current_user_can('manage_options') ) {
403 return;
404 }
405
406 // Skip wizard if onboarding was already completed (e.g. reactivation).
407 if ( get_option( 'tta_onboarding_completed' ) ) {
408 wp_safe_redirect( admin_url( 'admin.php?page=text-to-audio' ) );
409 } else {
410 wp_safe_redirect( admin_url( 'admin.php?page=text-to-audio&welcome=1' ) );
411 }
412 exit;
413 }
414 });
415
416 /**
417 * The code that runs during plugin deactivation.
418 * This action is documented in includes/TTA_Deactivator.php
419 */
420 register_deactivation_hook(__FILE__, function () {
421 TTA_Deactivator::deactivate();
422 });
423
424
425 /**
426 *
427 * Create short code for qr code.
428 * Example [atlasvoice]
429 *
430 * @param $atts
431 *
432 * @return string
433 */
434 function tta_create_shortcode($atts, $content, $shortcode_tag)
435 {
436 // TTS-247: escape happens inside tta_get_button_content (wp_kses with
437 // a small allow-list around the tts__listening_button filter output).
438 return tta_get_button_content($atts, false, $content);
439 }
440
441
442 //update_post_meta(8, 'tts_mp3_file_urls', []);
443 add_shortcode('tta_listen_btn', 'tta_create_shortcode');
444 add_shortcode('atlasvoice', 'tta_create_shortcode');
445
446 // Filter to allow shortcodes in HTML tags
447 add_filter('do_shortcode_tag', 'allow_shortcode_in_html_tag', 10, 4);
448 function allow_shortcode_in_html_tag($output, $tag, $attr, $m)
449 {
450
451 if ($tag == 'tta_listen_btn' || $tag == 'atlasvoice' && (!empty($attr) || isset($m[5]))) {
452 if (isset($attr['position']) && $attr['position'] == 'before') {
453 // $content = tta_get_button_content( $attr, false, $m[5] ) . $m[5];
454 $content = $output . $m[5];
455 } else {
456 // $content = $m[5] . tta_get_button_content( $attr, false, $m[5] );
457 $content = $m[5] . $output;
458 }
459
460 //Get the content wrapped by the shortcode.
461 return $content;
462 }
463
464 return $output;
465 }