PluginProbe
WP Courses LMS – Online Courses Builder, eLearning Courses, Courses Solution, Education Courses / 3.2.30
WP Courses LMS – Online Courses Builder, eLearning Courses, Courses Solution, Education Courses v3.2.30
3.2.30 trunk 3.1.40 3.1.41 3.1.42 3.1.43 3.2.0 3.2.1 3.2.10 3.2.11 3.2.12 3.2.13 3.2.14 3.2.15 3.2.16 3.2.17 3.2.18 3.2.19 3.2.2 3.2.20 3.2.21 3.2.22 3.2.23 3.2.24 3.2.25 All 36 releases
wp-courses / wp-courses.php

wp-courses.php in WP Courses LMS – Online Courses Builder, eLearning Courses, Courses Solution, Education Courses 3.2.30, at wp-courses.php

674 lines 22.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Plugin Name: WP Courses LMS
5 * Description: Create unlimited online courses on your WordPress website with WP Courses LMS.
6 * Version: 3.2.30
7 * Author: WP Courses
8 * Plugin URI: https://wpcoursesplugin.com
9 * Author URI: https://wpcoursesplugin.com
10 * Text Domain: wp-courses
11 * Domain Path: /lang
12 * License: GPL2
13 */
14
15 defined('ABSPATH') or die("No script kiddies please!");
16 define("WPC_PLUGIN_URL", plugin_dir_url(__FILE__));
17
18 function wpc_is_premium_active()
19 {
20
21 if (!defined('WPCP_VERSION')) {
22 define('WPCP_VERSION', false);
23 }
24
25 if (function_exists('wpc_woo_has_bought') || function_exists('wpcp_ext_admin_notice_failure')) {
26 define('WPCP_ACTIVE', true);
27 } else {
28 define('WPCP_ACTIVE', false);
29 }
30 }
31
32 add_action('plugins_loaded', 'wpc_is_premium_active');
33
34 unregister_post_type('wpc-quiz');
35
36 include 'functions/functions.php';
37 include 'functions/security.php';
38 include 'functions/requirements.php';
39 include 'functions/tracking.php';
40 include 'functions/connections.php';
41 include 'functions/output.php';
42 include 'functions/quizzes.php';
43 include 'functions/render-ajax-components.php';
44 include 'integrations/pmpro.php';
45 include 'integrations/woo.php';
46 include 'legacy/update.php';
47 include 'legacy/depricated.php';
48 include 'db/db-tables.php';
49 include 'init/cp-types.php';
50 include 'init/taxonomies.php';
51 include 'init/enqueue.php';
52 include 'classes/WPC_Ajax.php';
53 include 'classes/WPC_Ajax_Components.php';
54 include 'classes/WPCQ_Ajax.php';
55 include 'classes/WPC_Shortcodes.php';
56 include 'init/templates.php';
57 include 'init/style-options.php';
58 include 'admin/wpc-options.php';
59 include 'admin/lesson-meta.php';
60 include 'admin/course-meta.php';
61 include 'admin/requirements-meta.php';
62 include 'admin/admin-menu.php';
63 include 'admin/columns.php';
64 include 'admin/front-end-editor.php';
65 include 'admin/widgets.php';
66 include 'admin/quiz-meta.php';
67 include 'cron/cron.php';
68 include 'ajax/ajax.php';
69 include 'ajax/ajax-survey.php';
70 include 'ajax/ajax-lesson-order.php';
71 include 'ajax/ajax-lesson-change-restriction.php';
72 include 'ajax/ajax-course-order.php';
73 include 'ajax/ajax-course-change.php';
74 include 'ajax/ajax-user-meta.php';
75
76 // Redirect on activation to welcome page
77 register_activation_hook(__FILE__, 'wpc_plugin_activate');
78 add_action('admin_init', 'wpc_plugin_redirect');
79
80 function wpc_plugin_activate()
81 {
82 set_transient('wpc_dismiss_survey_short', 'true', 86400); // Skip rating screen for plugin activation
83 add_option('wpc_plugin_do_activation_redirect', true);
84 }
85
86 function wpc_plugin_redirect()
87 {
88 if (get_option('wpc_plugin_do_activation_redirect', false)) {
89 delete_option('wpc_plugin_do_activation_redirect');
90 if (!isset($_GET['activate-multi'])) {
91 wp_redirect("admin.php?page=wpc_help");
92 }
93 }
94 }
95
96 function wpc_old_woo_admin_notice_failure()
97 {
98 // Check if PMPro is active
99 if (is_plugin_active('wp-courses-woocommerce/wp-courses-woocommerce.php')) { ?>
100 <div class="notice notice-error is-dismissible">
101 <p>WP Courses WooCommerce Integration is not fully compatible with your version of WP Courses. All add-ons for WP
102 Courses now reside in one add-on called WP Courses Premium. <a href="https://wpcoursesplugin.com/lesson/upgrading-wp-courses-woocommerce-integration-for-3-0/?course_id=958">Update
103 instructions can be found here</a>.</p>
104 </div>
105 <?php
106 }
107 }
108 add_action('admin_notices', 'wpc_old_woo_admin_notice_failure');
109
110 // AJAX compatibility with DIVI
111 add_filter('et_builder_load_requests', function ($builder_load_requests) {
112 $builder_load_requests['action'][] = 'wpc_lesson';
113 $builder_load_requests['action'][] = 'wpc_teacher';
114 $builder_load_requests['action'][] = 'wpc_course';
115 return $builder_load_requests;
116 });
117
118 // Append course_id GET to post edit link
119 function wpc_append_query_string($url, $post)
120 {
121 if (is_admin() == true) {
122 $post_type = get_post_type($post->ID);
123 if ('lesson' == $post_type || 'wpc-quiz' == $post_type) {
124 $last_viewed_course_id = get_user_meta(get_current_user_id(), 'wpc-last-viewed-course', true);
125 if (isset($_GET['course_id'])) {
126 $course_id = $_GET['course_id'];
127 } else {
128 $course_id = wpc_get_first_connected_course($post->ID);
129 }
130
131 if (!empty($course_id)) {
132 return add_query_arg(array('course_id' => $course_id), $url);
133 } else {
134 return $url;
135 }
136 }
137 return $url;
138 } else {
139 return $url;
140 }
141 }
142 add_filter('post_type_link', 'wpc_append_query_string', 10, 2);
143
144 // Changing excerpt more
145 function wpc_remove_read_more_excerpt($more)
146 {
147 global $post;
148 if (get_post_type($post->ID) === 'course') {
149 remove_filter('excerpt_more', 'new_excerpt_more');
150 return '';
151 } else {
152 return $more;
153 }
154 }
155 add_filter('excerpt_more', 'wpc_remove_read_more_excerpt', 11);
156
157 // Add links below plugin on plugins page
158 function wpc_action_links($links)
159 {
160 $premium_button = '<a style="font-weight:bold; color: #e21772;" href="' . esc_url(admin_url('/admin.php?page=wpc_premium')) . '">' . __('Upgrade to Premium', 'wp-courses') . '</a>';
161 $links = array_merge(
162 array(
163 '<a href="' . esc_url(admin_url('/admin.php?page=wpc_help')) . '">' . __('Setup and Help', 'wp-courses') . '</a>',
164 '<a href="' . esc_url(admin_url('/edit.php?post_type=course')) . '">' . __('All Courses', 'wp-courses') . '</a>',
165 '<a href="' . esc_url(admin_url('/edit.php?post_type=lesson')) . '">' . __('All Lessons', 'wp-courses') . '</a>',
166 ),
167 $links
168 );
169
170 if (WPCP_ACTIVE === false) {
171 array_unshift($links, $premium_button);
172 }
173
174 return $links;
175 }
176 add_action('plugin_action_links_' . plugin_basename(__FILE__), 'wpc_action_links');
177
178 // Use ajax in the front-end
179 add_action('wp_head', 'wp_courses_ajaxurl');
180
181 function wp_courses_ajaxurl()
182 {
183 echo '<script type="text/javascript">
184 var ajaxurl = "' . admin_url('admin-ajax.php') . '";
185 </script>';
186 }
187
188 // Add empty lightbox and ajax save icon to footer
189 add_action('wp_footer', 'wpc_ui_components');
190
191 add_action('admin_footer', 'wpc_ui_components');
192
193 function wpc_ui_components()
194 { ?>
195 <div id="wpc-right-toggle-sidebar" class="wpc-right-toggle-sidebar" data-visible="false">
196 <div class="wpc-toggle-sidebar-header"><i class="fa-solid fa-xmark wpc-toggle-sidebar"></i></div>
197 <div class="wpc-toggle-sidebar-content"></div>
198 </div>
199 <div id="wpc-bottom-toggle-sidebar" class="wpc-bottom-toggle-sidebar" data-visible="false">
200 <div class="wpc-bottom-toggle-sidebar-header"><i class="fa-solid fa-xmark wpc-close-bottom-sidebar"></i></div>
201 <div class="wpc-toggle-bottom-sidebar-content"></div>
202 </div>
203 <div style="display:none;" id="wpc-full-screen-loader">
204 <div id="wpc-full-screen-loader-inner"><span class="plus-loader">Loading&#8230;</span></div>
205 </div>
206
207 <div class="wpc-lightbox-wrapper" style="display: none;">
208 <div class="wpc-lightbox">
209 <div class="wpc-lightbox-close-wrapper">
210 <h2 class="wpc-lightbox-title"></h2>
211 <div class="wpc-lightbox-close"><i class="fa fa-times"></i></div>
212 </div>
213 <div class="wpc-lightbox-content">
214
215 </div>
216 <div style="display: none;" class="wpc-pagination wpc-lightbox-pagination"></div>
217 </div>
218 </div>
219
220 <div id="wpc-ajax-save" class="fa-2x" style="display: none;"><i></i></div>
221 <?php }
222
223 // Admin lesson course filter
224 add_action('restrict_manage_posts', 'wpc_course_filter_select');
225
226 function wpc_course_filter_select()
227 {
228 if (!empty($_GET['post_type'])) {
229 $post_type = sanitize_title_with_dashes($_GET['post_type']);
230 if ($post_type == 'lesson') {
231 global $wpdb;
232 $sql = 'SELECT DISTINCT ID, post_title, post_status FROM ' . $wpdb->posts . ' WHERE post_type = "course" AND post_status = "publish" OR post_type = "course" AND post_status = "draft" ORDER By post_title';
233 $results = $wpdb->get_results($sql);
234
235 echo '<select name="wpc-course-filter" class="wpc-admin-select">';
236
237 echo '<option value="all">' . __('All Courses', 'wp-courses') . '</option>';
238 echo '<option value="none">' . __('None', 'wp-courses') . '</option>';
239
240 foreach ($results as $result) {
241 echo '<option value="' . (int) $result->ID . '">' . esc_html($result->post_title) . '</option>';
242 }
243
244 echo '</select>';
245 }
246 }
247 }
248
249 add_action('pre_get_posts', 'wpc_admin_filter_lessons_by_course');
250
251 function wpc_admin_filter_lessons_by_course($query)
252 {
253
254 if (is_post_type_archive('lesson')) {
255
256 if (isset($_GET['wpc-course-filter'])) {
257
258 $value = sanitize_title_with_dashes($_GET['wpc-course-filter']);
259
260 if ($value === 'none' || $value === 'all') {
261 return;
262 }
263
264 $args = array(
265 'post_to' => $value,
266 'connection_type' => array('lesson-to-course'),
267 'order_by' => 'menu_order',
268 'order' => 'asc',
269 );
270
271 $lessons = wpc_get_connected($args);
272 $lesson_ids = array();
273
274 if (!empty($lessons)) {
275 foreach ($lessons as $lesson) {
276 $lesson_ids[] = $lesson->post_from;
277 }
278 $query->set('post__in', $lesson_ids);
279 }
280 }
281 }
282 };
283
284 // Courses and teachers per page
285 function wpc_num_posts($query)
286 {
287
288 $wpc_teachers_per_page = (int) get_option('wpc_teachers_per_page');
289
290 if (is_post_type_archive('teacher') && !is_admin() && !empty($wpc_teachers_per_page)) {
291 $query->set('posts_per_page', $wpc_teachers_per_page);
292 }
293
294 if (is_post_type_archive('course') || is_tax('course-category')) {
295 $wpc_courses_per_page = (int) get_option('wpc_courses_per_page');
296 if (!is_admin() && !empty($wpc_courses_per_page)) {
297 $query->set('posts_per_page', $wpc_courses_per_page);
298 }
299 }
300
301 return $query;
302 }
303 add_filter('pre_get_posts', 'wpc_num_posts', 100);
304
305 // Add localization
306 add_action('plugins_loaded', 'wpc_load_textdomain');
307 function wpc_load_textdomain()
308 {
309 load_plugin_textdomain('wp-courses', false, dirname(plugin_basename(__FILE__)) . '/lang/');
310 }
311
312 function wpc_remove_lesson_rest_api_data($data, $post, $context)
313 {
314
315 $can_edit = current_user_can('edit_posts');
316
317 if ($can_edit != true) {
318
319 $wpc_enable_rest_lesson = get_option('wpc_enable_rest_lesson');
320
321 if ($wpc_enable_rest_lesson != 'true') {
322 unset($data->data['content']);
323 unset($data->data['excerpt']);
324 }
325 }
326
327 return $data;
328 }
329
330 add_filter('rest_prepare_lesson', 'wpc_remove_lesson_rest_api_data', 12, 3);
331
332 // Order courses by menu order in course archive and coures category archive unless different order selected by user
333 add_action('pre_get_posts', 'wpc_change_courses_sort_order');
334
335 function wpc_change_courses_sort_order($query)
336 {
337
338 if (is_post_type_archive('course') && $query->is_main_query() || is_tax() == 'course-category' && $query->is_main_query()) {
339
340 if (isset($_GET['order'])) {
341 $value = sanitize_title_with_dashes($_GET['order']);
342
343 if ($value == 'default') {
344 $query->set('order', 'ASC');
345 $query->set('orderby', 'menu_order');
346 } elseif ($value == 'newest') {
347 $query->set('orderby', 'date');
348 $query->set('order', 'desc');
349 } elseif ($value == 'oldest') {
350 $query->set('orderby', 'date');
351 $query->set('order', 'asc');
352 } elseif ($value == 'alphabetical') {
353 $query->set('orderby', 'title');
354 $query->set('order', 'asc');
355 }
356 } else {
357 $query->set('orderby', 'title');
358 $query->set('order', 'asc');
359 }
360
361 if (isset($_GET['search'])) {
362 $search = sanitize_text_field($_GET['search']);
363 $query->set('s', $search);
364 }
365 }
366 }
367
368 // Order lessons by menu order in lesson archive unless different order selected by user
369 add_action('pre_get_posts', 'wpc_change_lesson_archive_sort_order');
370
371 function wpc_change_lesson_archive_sort_order($query)
372 {
373
374 if (is_post_type_archive('lesson') && $query->is_main_query()) {
375
376 if (isset($_GET['order'])) {
377 $value = sanitize_title_with_dashes($_GET['order']);
378
379 if ($value == 'default') {
380 $query->set('order', 'ASC');
381 $query->set('orderby', 'menu_order');
382 } elseif ($value == 'newest') {
383 $query->set('orderby', 'date');
384 $query->set('order', 'desc');
385 } elseif ($value == 'oldest') {
386 $query->set('orderby', 'date');
387 $query->set('order', 'asc');
388 } elseif ($value == 'alphabetical') {
389 $query->set('orderby', 'title');
390 $query->set('order', 'asc');
391 }
392 } else {
393 $query->set('orderby', 'title');
394 $query->set('order', 'asc');
395 }
396
397 if (isset($_GET['search'])) {
398 $search = sanitize_text_field($_GET['search']);
399 $query->set('s', $search);
400 }
401 }
402 }
403
404 // Order quizzes by menu order in lesson archive unless different order selected by user
405 add_action('pre_get_posts', 'wpc_change_quiz_archive_sort_order');
406
407 function wpc_change_quiz_archive_sort_order($query)
408 {
409
410 if (is_post_type_archive('wpc-quiz') && $query->is_main_query()) {
411
412 if (isset($_GET['order'])) {
413 $value = sanitize_title_with_dashes($_GET['order']);
414
415 if ($value == 'default') {
416 $query->set('order', 'ASC');
417 $query->set('orderby', 'menu_order');
418 } elseif ($value == 'newest') {
419 $query->set('orderby', 'date');
420 $query->set('order', 'desc');
421 } elseif ($value == 'oldest') {
422 $query->set('orderby', 'date');
423 $query->set('order', 'asc');
424 } elseif ($value == 'alphabetical') {
425 $query->set('orderby', 'title');
426 $query->set('order', 'asc');
427 }
428 } else {
429 $query->set('orderby', 'title');
430 $query->set('order', 'asc');
431 }
432
433 if (isset($_GET['search'])) {
434 $search = sanitize_text_field($_GET['search']);
435 $query->set('s', $search);
436 }
437 }
438 }
439
440 // Order teachers by menu order in lesson archive unless different order selected by user
441 add_action('pre_get_posts', 'wpc_change_teacher_archive_sort_order');
442
443 function wpc_change_teacher_archive_sort_order($query)
444 {
445
446 if (is_post_type_archive('teacher') && $query->is_main_query()) {
447
448 if (isset($_GET['order'])) {
449 $value = sanitize_title_with_dashes($_GET['order']);
450
451 if ($value == 'default') {
452 $query->set('order', 'ASC');
453 $query->set('orderby', 'menu_order');
454 } elseif ($value == 'newest') {
455 $query->set('orderby', 'date');
456 $query->set('order', 'desc');
457 } elseif ($value == 'oldest') {
458 $query->set('orderby', 'date');
459 $query->set('order', 'asc');
460 } elseif ($value == 'alphabetical') {
461 $query->set('orderby', 'title');
462 $query->set('order', 'asc');
463 }
464 } else {
465 $query->set('orderby', 'title');
466 $query->set('order', 'asc');
467 }
468
469 if (isset($_GET['search'])) {
470 $search = sanitize_text_field($_GET['search']);
471 $query->set('s', $search);
472 }
473 }
474 }
475
476 // Add video to content in single lessons. This way PMPro can filter the lesson content including the video.
477 add_filter('the_content', 'wpc_filter_content', 1);
478
479 function wpc_filter_content($content)
480 {
481
482 if (get_post_type() == 'lesson' && is_single()) {
483 $lesson_id = get_the_ID();
484 $video = wpc_get_video($lesson_id);
485 return '<div id="video-wrapper" class="wpc-vid-wrapper" style="margin: 0; width: 100%;">' . wpc_sanitize_video($video) . '</div>' . $content;
486 } elseif (get_post_type() === 'wpc-quiz') {
487 return $content . '<div id="wpc-fe-quiz-container"></div>';
488 } else {
489 return $content;
490 }
491 }
492
493 add_filter('the_content', 'wpc_content_restriction_filter');
494
495 function wpc_content_restriction_filter($content)
496 {
497
498 $post_type = get_post_type();
499
500 if ($post_type !== 'lesson' && $post_type !== 'wpc-quiz') {
501 return $content;
502 }
503
504 $restriction = get_post_meta(get_the_ID(), 'wpc-lesson-restriction', true);
505 $custom_logged_out_message = get_option('wpc_logged_out_message');
506 $login_url = wp_login_url(get_permalink());
507 $register_url = wp_registration_url();
508
509 $restricted_message = '<p class="wpc-content-restricted wpc-free-account-required wpc-alert-message">';
510 $restricted_message .= !empty($custom_logged_out_message) ? $custom_logged_out_message : '<a href="' . $login_url . '">' . __('Log in', 'wp-courses') . ' </a> or <a href="' . $register_url . '">' . __('Register', 'wp-courses') . '</a> to view this lesson';
511 $restricted_message .= '</p>';
512
513 if ($restriction == 'free-account' && !is_user_logged_in()) {
514 return wp_kses($restricted_message, 'post');
515 } else {
516 return $content;
517 }
518 }
519
520 // Show top admin nav menu across differen cp types
521 function wpc_admin_nav_menu_display_logic()
522 {
523 $show = false;
524
525 if (isset($_GET['taxonomy'])) {
526 if ($_GET['taxonomy'] == 'course-difficulty' || $_GET['taxonomy'] == 'course-category') {
527 $show = true;
528 }
529 }
530
531 $post_type = get_post_type();
532
533 if ($post_type == 'course' || $post_type == 'lesson' || $post_type == 'wpc-quiz' || $post_type == 'teacher' || $post_type == 'wpc-email' || $post_type == 'wpc-badge' || $post_type == 'wpc-certificate') {
534 $show = true;
535 }
536
537 $post_type_query_string = isset($_GET['post_type']) ? $_GET['post_type'] : false;
538
539 if ($post_type_query_string == 'course' || $post_type_query_string == 'lesson' || $post_type_query_string == 'wpc-quiz' || $post_type_query_string == 'teacher' || $post_type_query_string == 'wpc-email' || $post_type_query_string == 'wpc-badge' || $post_type_query_string == 'wpc-certificate') {
540 $show = true;
541 }
542
543 if (!is_admin()) {
544 $show = false;
545 }
546
547 return $show;
548 }
549
550 add_action('in_admin_header', 'wpc_admin_nav_menu');
551
552 function wpc_admin_nav_menu()
553 {
554 $show = wpc_admin_nav_menu_display_logic();
555 if ($show == true) {
556 include 'admin/admin-nav-menu.php';
557 }
558 }
559
560 // Shows the admin nav menu after screen options
561 add_action('admin_footer', 'wpc_admin_screen_options_styling');
562
563 function wpc_admin_screen_options_styling()
564 {
565 $show = wpc_admin_nav_menu_display_logic();
566 if ($show == true) {
567 echo '<script>
568 jQuery(document).ready(function($){
569 var nav = $(".wpc-admin-nav-menu");
570 var navClone = nav.clone();
571 nav.remove();
572 $("#screen-meta-links").after(nav);
573 });
574
575 </script>';
576 }
577 }
578
579 // Display license expiration notice
580 add_action('admin_notices', 'wpc_show_admin_notices');
581
582 function wpc_show_admin_notices()
583 {
584 $wpc_admin_notice_dismissed = get_option('wpc_admin_notice_dismissed');
585 if ($wpc_admin_notice_dismissed == 'true') {
586 return;
587 }
588
589 if (is_plugin_active('wp-courses-premium/wp-courses-premium.php')) {
590 $plugin_data = get_plugin_data(plugin_dir_path(__DIR__) . 'wp-courses-premium/wp-courses-premium.php', false, false);
591
592 if (!empty($plugin_data['Version'])) {
593 if (version_compare('3.2.10', $plugin_data['Version'], '>')) {
594 $output = 'You are using an outdated version of WP Courses LMS Premium. Please update to the latest version to ensure compatibility and security.';
595
596 $output2 = 'a) If your license is still valid, insert your license key and email address under WP Courses > Settings > Plugin Updates (update check might take up to 24 hours)';
597
598 $output3 = 'b) If your license has expired, you can get a new license ';
599
600 $output4 = 'https://wpcoursesplugin.com/cart/?add-to-cart=829';
601
602 $output5 = 'here';
603 } else {
604 return; // Premium plugin does not need to be updated
605 }
606 } else {
607 return; // Premium plugin did not return version
608 }
609 } else {
610 return; // Premium plugin not installed
611 }
612
613 printf(
614 '<div class="notice notice-warning is-dismissible wpc-admin-notice">
615 <p>%1$s</p>
616 <p>%2$s</p>
617 <p>%3$s<a target= "_blank" href="%4$s">%5$s</a></p>
618 </div>',
619 $output,
620 $output2,
621 $output3,
622 $output4,
623 $output5
624 );
625 }
626
627 add_action('wp_ajax_wpc_admin_notice_dismiss', 'wpc_dismiss_admin_notice');
628
629 function wpc_dismiss_admin_notice()
630 {
631 check_ajax_referer('wpc_nonce', 'security');
632
633 update_option('wpc_admin_notice_dismissed', 'true');
634
635 wp_die();
636 }
637
638 // Helper
639 function wpc_log($object = null)
640 {
641 try {
642 $pluginlog = plugin_dir_path(__FILE__) . 'debug.log';
643
644 ob_start();
645 var_dump($object);
646 $contents = ob_get_contents();
647 ob_end_clean();
648
649 $date = new DateTime();
650 $date_string = $date->format('Y-m-d H:i:s');
651
652 error_log($date_string . ' ' . $contents, 3, $pluginlog);
653 } catch (\Error $e) {
654 }
655 }
656
657 function wpc_array_insert_after($key, array &$array, $new_key, $new_value)
658 {
659 if (array_key_exists($key, $array)) {
660 $new = array();
661
662 foreach ($array as $k => $value) {
663 $new[$k] = $value;
664
665 if ($k === $key) {
666 $new[$new_key] = $new_value;
667 }
668 }
669
670 return $new;
671 }
672
673 return FALSE;
674 }