├── src ├── utils │ ├── moowoodle-all-course-table.js │ └── moowoodle-admin-frontend.js ├── assets │ └── images │ │ ├── dualcube.png │ │ ├── moowoodle.png │ │ ├── logo-moowoodle-pro.png │ │ └── manage-enrolment.jpg ├── commponents │ ├── CustomInputField │ │ ├── Section.jsx │ │ ├── TextBox.jsx │ │ ├── ToggleCheckbox.jsx │ │ ├── Log.jsx │ │ ├── MultipleCheckboxs.jsx │ │ ├── Select.jsx │ │ └── Button.jsx │ ├── SubMenuPage │ │ ├── Settings.jsx │ │ ├── Synchronization.jsx │ │ ├── ManageEnrolment.jsx │ │ └── AllCourses.jsx │ └── Common │ │ ├── Tabs.jsx │ │ ├── SideBanner.jsx │ │ ├── ProOverlay.jsx │ │ ├── TableWithPagination.jsx │ │ └── TabContent.jsx ├── index.js └── app.js ├── vendor ├── composer │ ├── installed.json │ ├── autoload_namespaces.php │ ├── autoload_psr4.php │ ├── autoload_classmap.php │ ├── installed.php │ ├── LICENSE │ ├── autoload_static.php │ ├── autoload_real.php │ ├── InstalledVersions.php │ └── ClassLoader.php └── autoload.php ├── assets ├── images │ └── logo-moowoodle-pro.png └── frontend │ └── css │ ├── frontend.min.css │ └── frontend.css ├── moowoodle.php ├── package.json ├── moowoodle-config.php ├── templates ├── emails │ ├── plain │ │ └── new-enrollment.php │ └── new-enrollment.php └── endpoints │ └── my-course.php └── classes ├── Helper.php ├── Emails.php ├── Template.php ├── Product.php ├── MyAccountEndPoint.php ├── Installer.php ├── Category.php ├── Emails └── Emails_New_Enrollment.php ├── ExternalService.php ├── Settings.php ├── RestAPI.php ├── MooWoodle.php ├── Enrollment.php ├── TestConnection.php ├── Course.php └── Library.php /src/utils/moowoodle-all-course-table.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/dualcube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kndnsow/moowoodle/HEAD/src/assets/images/dualcube.png -------------------------------------------------------------------------------- /src/assets/images/moowoodle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kndnsow/moowoodle/HEAD/src/assets/images/moowoodle.png -------------------------------------------------------------------------------- /vendor/composer/installed.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [], 3 | "dev": true, 4 | "dev-package-names": [] 5 | } 6 | -------------------------------------------------------------------------------- /assets/images/logo-moowoodle-pro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kndnsow/moowoodle/HEAD/assets/images/logo-moowoodle-pro.png -------------------------------------------------------------------------------- /src/assets/images/logo-moowoodle-pro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kndnsow/moowoodle/HEAD/src/assets/images/logo-moowoodle-pro.png -------------------------------------------------------------------------------- /src/assets/images/manage-enrolment.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kndnsow/moowoodle/HEAD/src/assets/images/manage-enrolment.jpg -------------------------------------------------------------------------------- /vendor/composer/autoload_namespaces.php: -------------------------------------------------------------------------------- 1 | array($baseDir . '/classes'), 10 | ); 11 | -------------------------------------------------------------------------------- /vendor/composer/autoload_classmap.php: -------------------------------------------------------------------------------- 1 | $vendorDir . '/composer/InstalledVersions.php', 10 | ); 11 | -------------------------------------------------------------------------------- /assets/frontend/css/frontend.min.css: -------------------------------------------------------------------------------- 1 | .instraction-tri{border:2px solid #ccc;width:max-content;padding:10px}.button-tri{background-color:#eee;border-color:#eee;color:#333}.button-tri a{text-decoration:none}.payment-tri{background-color:#eee;border-color:#eee;color:#333;padding:10px 5px;border-radius:5px;width:max-content} -------------------------------------------------------------------------------- /src/commponents/CustomInputField/Section.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const Section = (props) => { 3 | return ( 4 | <> 5 |
6 |
7 |

{props.label}

8 |
9 |
10 | 11 | ); 12 | }; 13 | export default Section; 14 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import { render } from '@wordpress/element'; 2 | import { BrowserRouter} from 'react-router-dom'; 3 | import App from './app.js'; 4 | 5 | /** 6 | * Import the stylesheet for the plugin. 7 | */ 8 | // import './style/main.scss'; 9 | // Render the App component into the DOM 10 | render(, document.getElementById('moowoodle_root')); 11 | -------------------------------------------------------------------------------- /assets/frontend/css/frontend.css: -------------------------------------------------------------------------------- 1 | .instraction-tri { 2 | border: 2px solid #ccc; 3 | width: max-content; 4 | padding: 10px; 5 | } 6 | .button-tri { 7 | background-color: #eeeeee; 8 | border-color: #eeeeee; 9 | color: #333333; 10 | } 11 | .button-tri a{ 12 | text-decoration: none; 13 | } 14 | .payment-tri { 15 | background-color: #eeeeee; 16 | border-color: #eeeeee; 17 | color: #333333; 18 | padding: 10px 5px; 19 | border-radius: 5px; 20 | width: max-content; 21 | } 22 | -------------------------------------------------------------------------------- /src/commponents/SubMenuPage/Settings.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Tabs from "./../Common/Tabs"; 3 | import TabContent from "./../Common/TabContent"; 4 | 5 | const Settings = () => { 6 | return ( 7 |
8 | 9 |
10 | {/* */} 11 |
12 | {/* */} 13 |
14 | 15 | 16 |
17 |
18 |
19 | ); 20 | } 21 | export default Settings; 22 | -------------------------------------------------------------------------------- /src/commponents/SubMenuPage/Synchronization.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Tabs from "./../Common/Tabs"; 3 | import TabContent from "./../Common/TabContent"; 4 | 5 | const Synchronization = () => { 6 | return ( 7 |
8 | 9 |
10 | {/* */} 11 |
12 | {/* */} 13 |
14 | 15 | 16 |
17 |
18 |
19 | ); 20 | } 21 | export default Synchronization; 22 | -------------------------------------------------------------------------------- /vendor/composer/installed.php: -------------------------------------------------------------------------------- 1 | array( 3 | 'name' => '__root__', 4 | 'pretty_version' => '1.0.0+no-version-set', 5 | 'version' => '1.0.0.0', 6 | 'reference' => NULL, 7 | 'type' => 'library', 8 | 'install_path' => __DIR__ . '/../../', 9 | 'aliases' => array(), 10 | 'dev' => true, 11 | ), 12 | 'versions' => array( 13 | '__root__' => array( 14 | 'pretty_version' => '1.0.0+no-version-set', 15 | 'version' => '1.0.0.0', 16 | 'reference' => NULL, 17 | 'type' => 'library', 18 | 'install_path' => __DIR__ . '/../../', 19 | 'aliases' => array(), 20 | 'dev_requirement' => false, 21 | ), 22 | ), 23 | ); 24 | -------------------------------------------------------------------------------- /moowoodle.php: -------------------------------------------------------------------------------- 1 | { 3 | const { field } = props; 4 | return ( 5 | <> 6 |
7 | { props.onChange?.(e) }} 18 | > 19 | {field.copy_text == "copy" && ( 20 | 23 | )} 24 |
25 | 26 | ); 27 | }; 28 | export default TextBox; 29 | -------------------------------------------------------------------------------- /src/commponents/CustomInputField/ToggleCheckbox.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const ToggleCheckbox = (props) => { 4 | const { field } = props; 5 | console.log(field.preSetting) 6 | return ( 7 | <> 8 |
9 | { 16 | props.onChange?.(e); 17 | }} 18 | disabled={field.is_pro === 'pro' && MooWoodleAppLocalizer.porAdv} 19 | /> 20 | 21 |
22 | 23 | ); 24 | }; 25 | 26 | export default ToggleCheckbox; 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "moowoodle", 3 | "version": "3.2.0", 4 | "description": "=== MooWoodle ===", 5 | "main": "index.js", 6 | "directories": { 7 | "lib": "lib" 8 | }, 9 | "scripts": { 10 | "build": "wp-scripts build", 11 | "start": "wp-scripts start" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/dualcube/moowoodle" 16 | }, 17 | "author": "", 18 | "license": "ISC", 19 | "bugs": { 20 | "url": "https://github.com/dualcube/moowoodleissues" 21 | }, 22 | "homepage": "https://github.com/dualcube/moowoodle#readme", 23 | "devDependencies": { 24 | "@wordpress/scripts": "^26.17.0" 25 | }, 26 | "dependencies": { 27 | "browser-router": "^0.2.0", 28 | "date-fns": "^3.4.0", 29 | "react": "^18.2.0", 30 | "react-data-table-component": "^7.6.2", 31 | "react-date-range": "^2.0.0-alpha.4", 32 | "react-paginate": "^8.2.0", 33 | "react-router-dom": "^6.22.1" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /moowoodle-config.php: -------------------------------------------------------------------------------- 1 | Pro' : '' ); 18 | -------------------------------------------------------------------------------- /vendor/composer/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) Nils Adermann, Jordi Boggiano 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is furnished 9 | to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /templates/emails/plain/new-enrollment.php: -------------------------------------------------------------------------------- 1 | data->ID, 'moowoodle_moodle_user_pwd', true); 17 | if (!get_user_meta($user_id, 'moowoodle_moodle_user_id')) { 18 | echo esc_html('Username : ', 'moowoodle') . esc_html($user_details->data->user_login) . '\n\n'; 19 | echo esc_html('Password : ', 'moowoodle') . esc_html($pwd) . '\n\n'; 20 | } 21 | echo esc_html('To enroll and access your course please click on the course link given below :', 'moowoodle') . '\n\n'; 22 | foreach ($enrollments['enrolments'] as $enrollment) { 23 | $enrollment_list[] = MooWoodle()->Course->get_moowoodle_course_url($enrollment['courseid'], $enrollment['course_name']); 24 | echo esc_html('You are enrolled in ' . $enrollment_list[$i]) . ' \n\n'; 25 | $i++; 26 | } 27 | if (!get_user_meta($user_id, 'moowoodle_moodle_user_id')) { 28 | echo esc_html('You need to change your password after first login.', 'moowoodle') . '\n\n'; 29 | } 30 | -------------------------------------------------------------------------------- /vendor/composer/autoload_static.php: -------------------------------------------------------------------------------- 1 | 11 | array ( 12 | 'MooWoodle\\' => 13, 13 | ), 14 | ); 15 | 16 | public static $prefixDirsPsr4 = array ( 17 | 'MooWoodle\\' => 18 | array ( 19 | 0 => __DIR__ . '/../..' . '/classes', 20 | ), 21 | ); 22 | 23 | public static $classMap = array ( 24 | 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', 25 | ); 26 | 27 | public static function getInitializer(ClassLoader $loader) 28 | { 29 | return \Closure::bind(function () use ($loader) { 30 | $loader->prefixLengthsPsr4 = ComposerStaticInitb759568308ece88c8e94825621f0ef67::$prefixLengthsPsr4; 31 | $loader->prefixDirsPsr4 = ComposerStaticInitb759568308ece88c8e94825621f0ef67::$prefixDirsPsr4; 32 | $loader->classMap = ComposerStaticInitb759568308ece88c8e94825621f0ef67::$classMap; 33 | 34 | }, null, ClassLoader::class); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /vendor/composer/autoload_real.php: -------------------------------------------------------------------------------- 1 | register(true); 33 | 34 | return $loader; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /classes/Helper.php: -------------------------------------------------------------------------------- 1 | get_contents(get_site_url(null, str_replace(ABSPATH, '', MW_LOGS) . "/error.txt")); 41 | if (!empty($existing_content)) { 42 | $log_entry = "\n" . $log_entry; 43 | } 44 | return $wp_filesystem->put_contents(MW_LOGS . "/error.txt", $existing_content . $log_entry ); 45 | } 46 | } 47 | return false; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /templates/emails/new-enrollment.php: -------------------------------------------------------------------------------- 1 | 17 |

18 | data->ID, 'moowoodle_moodle_user_pwd', true); 21 | if (!get_user_meta($user_id, 'moowoodle_moodle_user_id')) { 22 | echo esc_html__('Username : ', 'moowoodle') . esc_html__($user_details->data->user_login) . '

'; 23 | echo esc_html__('Password : ', 'moowoodle') . esc_html__($pwd) . '

'; 24 | } 25 | echo esc_html__('To access your course please click on the course link given below :', 'moowoodle') . '

'; 26 | ?> 27 |

28 | Course->get_moowoodle_course_url($enrollment['courseid'], $enrollment['course_name']); 31 | ?> 32 |

33 |
'; ?> 34 |

35 | 39 |

40 |
'; ?> 41 | 42 |

43 | mailer()->get_emails(); 29 | if (empty($email_key) || !array_key_exists($email_key, $emails)) { 30 | return; 31 | } 32 | $emails[$email_key]->trigger($email_data); 33 | } 34 | /** 35 | * Send confirmation for enrollment in moodle course 36 | * 37 | * @access public 38 | * @param array $enrolments 39 | * @return void 40 | */ 41 | public function send_moodle_enrollment_confirmation($enrolments) { 42 | $enrollment_datas = array(); 43 | $user_id = MooWoodle()->Enrollment->wc_order->get_user_id(); 44 | $user = get_userdata($user_id); 45 | $enrollment_datas['email'] = ($user == false) ? '' : $user->user_email; 46 | $enrollment_datas['enrolments'] = $enrolments; 47 | $this->send_email('Emails_New_Enrollment', $enrollment_datas); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/commponents/Common/Tabs.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { BrowserRouter as Router, Link, useLocation } from 'react-router-dom'; 3 | 4 | 5 | const Tabs = () => { 6 | const location = new URLSearchParams(useLocation().hash); 7 | const tabs = MooWoodleAppLocalizer.library[location.get('tab')]; 8 | let currentTab = location.get('sub-tab') ? location.get('sub-tab') : Object.keys(MooWoodleAppLocalizer.library[location.get('tab')])[0] ; 9 | const getTabs = () => { 10 | return Object.entries(tabs).map(([tabid , tab]) => { 11 | let active = ''; 12 | 13 | if(currentTab == tabid ){ 14 | active = ' nav-tab-active' 15 | } 16 | let icon = ''; 17 | if (tab['font_class']) { 18 | icon = tab['font_class']; 19 | } 20 | return ( 25 | {tab.label} 26 | { 27 | tab.is_pro && MooWoodleAppLocalizer.porAdv && 28 | Pro 29 | } 30 | ) 31 | }); 32 | } 33 | return ( 34 |
35 | {getTabs()} 36 | Upgrade to Pro for More Features 37 |
38 | ); 39 | } 40 | export default Tabs; 41 | -------------------------------------------------------------------------------- /src/commponents/CustomInputField/Log.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import axios from 'axios'; 3 | 4 | const Log = () => { 5 | const [logs, setLogs] = useState([]); 6 | const handleClearLog = async (event) => { 7 | if (!window.confirm("Are you sure?")) { 8 | event.preventDefault(); 9 | } else { 10 | await clearLogs(); 11 | await loadLogs(); 12 | } 13 | }; 14 | 15 | const clearLogs = async () => { 16 | // Implement logic to clear logs on the server 17 | }; 18 | 19 | const fetchLogs = async () => { 20 | try { 21 | const response = await axios.get( 22 | `${MooWoodleAppLocalizer.rest_url}moowoodle/v1/fetch-mw-log`, 23 | { 24 | headers: { "X-WP-Nonce": MooWoodleAppLocalizer.nonce }, 25 | } 26 | ); 27 | return response.data; 28 | } catch (error) { 29 | console.error("Error fetching logs:", error); 30 | return []; 31 | } 32 | }; 33 | 34 | const loadLogs = async () => { 35 | const logsData = await fetchLogs(); 36 | setLogs(logsData); 37 | }; 38 | 39 | useEffect(() => { 40 | loadLogs(); 41 | }, []); // Fetch logs on component mount 42 | 43 | return ( 44 |
45 |
46 |
47 | 50 |
51 |
52 | {logs.map((log, index) => ( 53 |

{log}

54 | ))} 55 |
56 |
57 |
58 | ); 59 | }; 60 | 61 | export default Log; 62 | -------------------------------------------------------------------------------- /src/commponents/Common/SideBanner.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const SideBanner = () => { 4 | return ( 5 | <> 6 |
7 |
8 | 9 | 10 | 11 |
12 | Unlock premium features and elevate your experience by upgrading to MooWoodle Pro! 13 |
With our Pro version, you can enjoy:
14 |

 

15 |

1. Convenient Single Sign-On for Moodle™ and WordPress Login

16 |

2. Create steady income through course subscriptions.

17 |

3. Increase earnings by offering courses in groups, variations, or individually.

18 |

4. Select and sync courses with flexibility

19 |

5. Easily synchronize courses in bulk

20 |

6. Seamless, One-Password Access to Moodle™ and WordPress.

21 |

7. Choose which user information to synchronize.

22 |

8. Automatic User Synchronization for Moodle™ and WordPress.

23 | 29 |
30 |
31 |
32 | 33 | ); 34 | } 35 | export default SideBanner; 36 | -------------------------------------------------------------------------------- /src/commponents/Common/ProOverlay.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const ProOverlay = () => { 4 | return ( 5 | <> 6 |
7 |
8 | 9 |

10 | Unlock Pro{" "} 11 |

12 |

Upgrade to Moowoodle Pro

13 |
14 | Boost to MooWoodle Pro to access premium features and enhancements! 15 |

16 |

1. Convenient Single Sign-On for Moodle™ and WordPress Login.

17 |

2. Create steady income through course subscriptions.

18 |

3. Increase earnings by offering courses in groups, variations, or individually.

19 |

4. Selectively sync courses with flexibility.

20 |

5. Effortlessly synchronize courses in bulk.

21 |

6. Automatic User Synchronization for Moodle™ and WordPress.

22 |

7. Choose which user information to synchronize.

23 |
24 |
Today's Offer
25 |
26 | Upto 15%Discount 27 |
28 |

29 | Seize the opportunity – upgrade now and unlock the full potential of our Pro features with a 15% discount using coupon code: 30 | UP15! 31 |

32 | 33 | Buy MooWoodle Pro 34 | 35 |
36 |
37 | 38 | ); 39 | } 40 | export default ProOverlay; 41 | -------------------------------------------------------------------------------- /src/commponents/Common/TableWithPagination.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | import DataTable from 'react-data-table-component'; 3 | import ReactPaginate from 'react-paginate'; 4 | 5 | const TableWithPagination = ( props ) => { 6 | const [itemsPerPage, setItemsPerPage] = useState( props.data.length ); 7 | 8 | useEffect(()=>{ 9 | setItemsPerPage(props.data.length); 10 | },[props.data.length]) 11 | 12 | // When current page is changed 13 | const handlePageChange = ( { selected } ) => { 14 | // When current page is changed currentPage = selected and itemPerPage = itemPerPage 15 | props.onPageChange( selected + 1, itemsPerPage ); 16 | }; 17 | 18 | // When perpage is changed 19 | const handleItemsPerPageChange = (event) => { 20 | setItemsPerPage( parseInt( event.target.value ) ); 21 | 22 | // When item perPage is changed currentPage = 0 and itemPerPage = event.target.value 23 | props.onPageChange(1, event.target.value); 24 | }; 25 | 26 | return ( 27 |
28 | 35 | 41 |
42 | { 43 | props.perPageOptions && 44 | <> 45 | Items per page: 46 | 53 | 54 | } 55 |
56 |
57 | ); 58 | }; 59 | 60 | export default TableWithPagination; 61 | -------------------------------------------------------------------------------- /src/commponents/CustomInputField/MultipleCheckboxs.jsx: -------------------------------------------------------------------------------- 1 | const MultipleCheckboxs = (props) => { 2 | const { field } = props; 3 | const getChecboxes = (option_values) => { 4 | return Object.entries(option_values).map(([checkboxTitle, checkboxOptions]) => { 5 | return(
9 |
10 |
11 | { 20 | props.onChange?.(e); 21 | }} 22 | /> 23 |

24 | {checkboxTitle} {checkboxOptions.is_pro && MooWoodleAppLocalizer.pro_sticker} 25 |

26 |
27 |
28 |

{checkboxOptions.desc}

29 |
30 |
31 |
) 32 | }); 33 | } 34 | 35 | return ( 36 | <> 37 |
38 | 41 |
42 | {getChecboxes(field.option_values)} 43 |
44 |
45 | 46 | ); 47 | }; 48 | 49 | export default MultipleCheckboxs; 50 | -------------------------------------------------------------------------------- /src/app.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import { useLocation } from 'react-router-dom'; 3 | import AllCourses from "./commponents/SubMenuPage/AllCourses"; 4 | import ManageEnrolment from "./commponents/SubMenuPage/ManageEnrolment"; 5 | import Settings from "./commponents/SubMenuPage/Settings"; 6 | import Synchronization from "./commponents/SubMenuPage/Synchronization"; 7 | import SideBanner from "./commponents/Common/SideBanner"; 8 | import ProOverlay from "./commponents/Common/ProOverlay"; 9 | import dualcubeLogo from "./assets/images/dualcube.png"; 10 | 11 | // css and scss file for global styling. 12 | import "./styles/admin.css"; 13 | 14 | // utils js file for global customisation. 15 | import "./utils/moowoodle-admin-frontend.js"; 16 | 17 | const App = () => { 18 | const { __ } = wp.i18n; 19 | const currentUrl = window.location.href; 20 | document.querySelectorAll('#toplevel_page_moowoodle>ul>li>a').forEach((element) => { 21 | element.parentNode.classList.remove('current'); 22 | if (currentUrl.includes(element.href)) { 23 | element.parentNode.classList.add('current'); 24 | } 25 | }); 26 | const location = new URLSearchParams(useLocation().hash); 27 | const [overlayVisible, setOverlayVisible] = useState(false); 28 | 29 | const handleOverlayClick = (event) => { 30 | console.log('hi') 31 | if (event.target.classList.contains('mw-pro-popup-overlay')) { 32 | setOverlayVisible(true); 33 | } 34 | }; 35 | const handleImageOverlayClick = () => { 36 | setOverlayVisible(false); 37 | }; 38 | // console.log('sub ' + location.get('sub-tab')); 39 | return ( 40 | <> 41 | 42 | {/*
*/} 43 |
MooWoodle
44 |
45 |
46 | { location.get('tab') === 'moowoodle-all-courses' && } 47 | { location.get('tab') === 'moowoodle-manage-enrolment' && } 48 | { location.get('tab') === 'moowoodle-settings' && } 49 | { location.get('tab') === 'moowoodle-synchronization' && } 50 | 51 | {!MooWoodleAppLocalizer.porAdv && } 52 |
53 |
54 | 57 | 58 | ); 59 | } 60 | export default App; 61 | -------------------------------------------------------------------------------- /src/commponents/CustomInputField/Select.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react'; 2 | 3 | const Select = (props) => { 4 | const { option_values, field } = props; 5 | const optionsData = []; 6 | 7 | let i = 0; 8 | for (const [k, v] of Object.entries(field.option_values)) { 9 | if (typeof(v) == 'object') { 10 | if (!i) { 11 | optionsData.push( 12 | 15 | ); 16 | i++; 17 | } 18 | optionsData.push( 19 | 27 | ); 28 | if (Number(field.preSetting?.[field.name]) === i) { 29 | field.sub_desc = v['desc']; 30 | } 31 | } else { 32 | if (!field[field.name]) { 33 | field[field.name] = ''; 34 | } 35 | optionsData.push( 36 | 39 | ); 40 | } 41 | i++; 42 | } 43 | useEffect(() => { 44 | const handleSelectChange = (event) => { 45 | const selectedOption = event.target.options[event.target.selectedIndex]; 46 | const description = selectedOption.getAttribute('data-desc'); 47 | document.querySelector('.mw-normal-checkbox-label').innerHTML = description; 48 | }; 49 | 50 | const selectElement = document.getElementById(field.id); 51 | selectElement.addEventListener('change', handleSelectChange); 52 | 53 | return () => { 54 | // Cleanup the event listener on component unmount 55 | selectElement.removeEventListener('change', handleSelectChange); 56 | }; 57 | }, [field.id]); 58 | 59 | return ( 60 | <> 61 | 69 | { 70 | field.is_pro && MooWoodleAppLocalizer.porAdv && 71 | Pro 72 | } 73 |
74 |
75 | 76 | ); 77 | }; 78 | 79 | export default Select; 80 | -------------------------------------------------------------------------------- /classes/Template.php: -------------------------------------------------------------------------------- 1 | template_url = 'moowoodle/'; 7 | } 8 | /** 9 | * Get other templates (e.g. product attributes) passing attributes and including the file. 10 | * 11 | * @access public 12 | * @param mixed $template_name 13 | * @param array $args (default: array()) 14 | * @param string $template_path (default: '') 15 | * @param string $default_path (default: '') 16 | * @return void 17 | */ 18 | public function get_template($template_name, $args = array(), $template_path = '', $default_path = '') { 19 | if ($args && is_array($args)) { 20 | extract($args); 21 | } 22 | 23 | $located = $this->locate_template($template_name, $template_path, $default_path); 24 | include $located; 25 | } 26 | /** 27 | * Locate a template and return the path for inclusion. 28 | * 29 | * This is the load order: 30 | * 31 | * yourtheme / $template_path / $template_name 32 | * yourtheme / $template_name 33 | * $default_path / $template_name 34 | * 35 | * @access public 36 | * @param mixed $template_name 37 | * @param string $template_path (default: '') 38 | * @param string $default_path (default: '') 39 | * @return string 40 | */ 41 | public function locate_template($template_name, $template_path = '', $default_path = '') { 42 | if (!$template_path) { 43 | $template_path = $this->template_url; 44 | } 45 | 46 | if (!$default_path) { 47 | $default_path = MOOWOODLE_PLUGIN_PUTH . '/templates/'; 48 | } 49 | 50 | // Look within passed path within the theme - this is priority 51 | $template = locate_template(array(trailingslashit($template_path) . $template_name, $template_name)); 52 | // Get default template 53 | if (!$template) { 54 | $template = $default_path . $template_name; 55 | } 56 | 57 | // Return what we found 58 | return $template; 59 | } 60 | /** 61 | * Get template part (for templates like the shop-loop). 62 | * 63 | * @access public 64 | * @param mixed $slug 65 | * @param string $name (default: '') 66 | * @return void 67 | */ 68 | public function get_template_part($slug, $name = '') { 69 | $template = ''; 70 | // Look in yourtheme/slug-name.php and yourtheme/woocommerce/slug-name.php 71 | if ($name) { 72 | $template = $this->locate_template(array("{$slug}-{$name}.php", "{$this->template_url}{$slug}-{$name}.php")); 73 | } 74 | 75 | // Get default slug-name.php 76 | if (!$template && $name && file_exists(MOOWOODLE_PLUGIN_PUTH . "templates/{$slug}-{$name}.php")) { 77 | $template = MOOWOODLE_PLUGIN_PUTH . "templates/{$slug}-{$name}.php"; 78 | } 79 | 80 | // If template file doesn't exist, look in yourtheme/slug.php and yourtheme/woocommerce/slug.php 81 | if (!$template) { 82 | $template = $this->locate_template(array("{$slug}.php", "{$this->template_url}{$slug}.php")); 83 | } 84 | 85 | echo $template; 86 | if ($template) { 87 | load_template($template, false); 88 | } 89 | 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /classes/Product.php: -------------------------------------------------------------------------------- 1 | [ 21 | [ 22 | 'key'=> 'moodle_course_id', 23 | 'value' => $course['id'], 24 | ] 25 | ] 26 | ] 27 | ); 28 | 29 | // create a new product if not exist. 30 | if(empty($products)) { 31 | $product = new \WC_Product_Simple(); 32 | } else { // take the 1st one if exist. 33 | $product = $products[0]; 34 | } 35 | 36 | // get category term 37 | $term = MooWoodle()->Category->get_category($course['id'], 'product_cat'); 38 | 39 | // Set product properties 40 | $product->set_name($course['fullname']); 41 | $product->set_slug($course['shortname']); 42 | $product->set_description($course['summary']); 43 | $product->set_status('publish'); 44 | $product->set_sold_individually(true); 45 | $product->set_category_ids([$term]); 46 | $product->set_virtual(true); 47 | $product->set_catalog_visibility($course['visible'] ? 'visible' : 'hidden'); 48 | // $product->set_sku(); // need to set if need 49 | 50 | 51 | 52 | // get the course id linked with moodle. 53 | $linked_course_id = MooWoodle()->Course->get_courses( 54 | [ 55 | 'meta_key' => 'moodle_course_id', 56 | 'meta_value' => $course['id'], 57 | 'meta_compare' => '=', 58 | 'fields' => 'ids' 59 | ] 60 | )[0]; 61 | 62 | 63 | // Set product meta data. 64 | $product->update_meta_data('_course_startdate', $course['startdate']); 65 | $product->update_meta_data('_course_enddate', $course['enddate']); 66 | $product->update_meta_data('moodle_course_id', (int) $course['id']); 67 | $product->update_meta_data('linked_course_id', $linked_course_id); 68 | 69 | return $product->get_id(); 70 | } 71 | 72 | /** 73 | * Delete all the product which id is not prasent in $exclude_ids array. 74 | * 75 | * @access public 76 | * @param array $exclude_ids (product ids) 77 | * @return void 78 | */ 79 | public static function remove_exclude_ids($exclude_ids) { 80 | 81 | // get all product except $exclude_ids array 82 | $product_ids = \wc_get_products( 83 | [ 84 | 'exclude' => $exclude_ids, 85 | 'status' => 'publish', 86 | 'return' => 'ids', 87 | ] 88 | ); 89 | 90 | // delete product. 91 | foreach ($product_ids as $product_id) { 92 | \wh_deleteProduct($product_id, false); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /templates/endpoints/my-course.php: -------------------------------------------------------------------------------- 1 | 0) { 14 | ?> 15 |

16 |

17 | 18 | 19 | 20 | $value_heading) : ?> 21 | 22 | 23 | 24 | 25 | 26 | get_meta('_course_unenroled', true); 29 | $unenrolled_courses = $unenrolled_course ? explode(',', $unenrolled_course) : []; 30 | foreach ($order->get_items() as $enrolment) { 31 | $moodle_course_id = get_post_meta($enrolment->get_product_id(), 'moodle_course_id', true); 32 | $enrolment_date = $order->get_meta('moodle_user_enrolment_date', true); 33 | $linked_course_id = get_post_meta($enrolment->get_product_id(), 'linked_course_id', true); 34 | 35 | if ($linked_course_id && !in_array($moodle_course_id, $unenrolled_courses)) : 36 | ?> 37 | 38 | 39 | 40 | 41 | 42 | 43 | 50 | 56 | 57 | 62 | 63 |
get_product_id())); ?>user_login); ?> 44 | 49 | 51 | 55 |
64 |
65 |

66 | 69 |

70 |

71 | add_my_courses_endpoint(); 8 | // Resister 'my_course' end point page in WooCommerce 'my_account'. 9 | add_filter('woocommerce_account_menu_items', array($this, 'my_courses_page_link')); 10 | // Put endpoint containt. 11 | add_action('woocommerce_account_' . $this->endpoint_slug . '_endpoint', array($this, 'woocommerce_account_my_courses_endpoint')); 12 | } 13 | /** 14 | *Adds my-courses endpoints table heade 15 | * 16 | * @access private 17 | * @return void 18 | */ 19 | private function add_my_courses_endpoint() { 20 | $this->endpoint_slug = 'my-courses'; 21 | add_rewrite_endpoint($this->endpoint_slug, EP_ROOT | EP_PAGES); 22 | flush_rewrite_rules(); 23 | } 24 | /** 25 | * resister my course to my-account WooCommerce menu. 26 | * 27 | * @access public 28 | * @return void 29 | */ 30 | public function my_courses_page_link($menu_links) { 31 | $name = __('My Courses', 'moowoodle'); 32 | $new = array($this->endpoint_slug => $name); 33 | $display_settings = get_option('moowoodle_display_settings'); 34 | if (isset($display_settings['my_courses_priority'])) { 35 | $priority_below = $display_settings['my_courses_priority']; 36 | } else { 37 | $priority_below = 0; 38 | } 39 | $menu_links = array_slice($menu_links, 0, $priority_below + 1, true) 40 | + $new 41 | + array_slice($menu_links, $priority_below + 1, NULL, true); 42 | return $menu_links; 43 | } 44 | /** 45 | * Add meta box panal. 46 | * 47 | * @access public 48 | * @return void 49 | */ 50 | public function woocommerce_account_my_courses_endpoint() { 51 | $customer = wp_get_current_user(); 52 | $customer_orders = wc_get_orders([ 53 | 'numberposts' => -1, 54 | 'orderby' => 'date', 55 | 'order' => 'DESC', 56 | 'type' => 'shop_order', 57 | 'status' => 'wc-completed', 58 | 'customer_id' => $customer->ID, 59 | ]); 60 | $table_heading = array( 61 | __("Course Name", 'moowoodle'), 62 | __("Moodle User Name", 'moowoodle'), 63 | __("Enrolment Date", 'moowoodle'), 64 | __("Course Link", 'moowoodle'), 65 | ); 66 | $pwd = get_user_meta($customer->ID, 'moowoodle_moodle_user_pwd', true); 67 | if ($pwd) { 68 | array_splice($table_heading, 2, 0, __("Password (First Time use Only)", 'moowoodle')); 69 | } 70 | // Render my-course template. 71 | MooWoodle()->Template->get_template( 72 | apply_filters('moowoodle_my_course_template_path', 'endpoints/my-course.php'), 73 | array( 74 | 'table_heading' => $table_heading, 75 | 'customer_orders' => $customer_orders, 76 | 'customer' => $customer, 77 | 'pwd' => $pwd, 78 | ) 79 | ); 80 | // load css for admin panel. 81 | add_action('wp_enqueue_scripts', array($this, 'frontend_styles')); 82 | } 83 | /** 84 | * Add meta box panal. 85 | * 86 | * @access public 87 | * @return void 88 | */ 89 | public function frontend_styles() { 90 | $suffix = defined('MOOWOODLE_SCRIPT_DEBUG') && MOOWOODLE_SCRIPT_DEBUG ? '' : '.min'; 91 | wp_enqueue_style('frontend_css', MOOWOODLE_PLUGIN_URL . 'assets/frontend/css/frontend' . $suffix . '.css', array(), MOOWOODLE_PLUGIN_VERSION); 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /classes/Installer.php: -------------------------------------------------------------------------------- 1 | migration(); 24 | $this->set_options(); 25 | do_action('moowoodle_updated'); 26 | } 27 | } 28 | /** 29 | * Plugin migration. 30 | * 31 | * @access public 32 | * @return void 33 | */ 34 | public static function migration() { 35 | $version = get_option('dc_moowoodle_plugin_db_version'); 36 | if ($version) { 37 | // in update 3.1.4 migrate 'moowoodle_synchronize_settings' to moowoodle_synchronize_now. 38 | if (version_compare($version, '3.1.3' ,'<=')) { 39 | $old_settings = get_option('moowoodle_synchronize_settings'); 40 | if ($old_settings) { 41 | update_option('moowoodle_synchronize_now', $old_settings); 42 | delete_option('moowoodle_synchronize_settings'); 43 | } 44 | } 45 | // in update 3.1.9 product meta changed from single to array. 46 | if(version_compare($version, '3.1.9' ,'=')){ 47 | foreach (wc_get_products(array('return' => 'ids')) as $product_id) { 48 | $moodle_course_id = get_post_meta($product_id, 'moodle_course_id', true); 49 | if (is_array($moodle_course_id) && !empty($moodle_course_id)) { 50 | update_post_meta($product_id, 'moodle_course_id', $moodle_course_id[0]); 51 | } 52 | } 53 | } 54 | // in update 3.1.11 change chackbox settings data from 'Enable' to true/flase. 55 | if(version_compare($version, '3.1.12' ,'<')){ 56 | $options =[ 57 | 'moowoodle_general_settings' => [ 'update_moodle_user', 'moowoodle_adv_log' ], 58 | 'moowoodle_display_settings' => [ 'start_end_date' ], 59 | 'moowoodle_sso_settings' => [ 'moowoodle_sso_eneble' ], 60 | 'moowoodle_notification_settings' => [ 'moowoodle_create_user_custom_mail' ], 61 | 'moowoodle_synchronize_settings' => [ 'realtime_sync_moodle_users', 'realtime_sync_wordpress_users', 62 | 'sync_user_first_name', 'sync_user_last_name', 'sync_username', 'sync_password', ], 63 | 'moowoodle_synchronize_now' => [ 'sync_courses', 'sync_courses_category', 'sync_all_product', 64 | 'sync_new_products', 'sync_exist_product', 'sync_image', ], 65 | ]; 66 | foreach($options as $option_key => $option_value){ 67 | $settings = get_option($option_key); 68 | $settings = $settings ? $settings : []; 69 | foreach($option_value as $index => $settings_key){ 70 | $settings[$settings_key] = $settings[$settings_key] ? true : false; 71 | } 72 | update_option($option_key, $settings); 73 | } 74 | } 75 | update_option('dc_moowoodle_plugin_db_version', MOOWOODLE_PLUGIN_VERSION); 76 | } 77 | } 78 | /** 79 | * Create and Update options. 80 | * 81 | * @access public 82 | * @return void 83 | */ 84 | private function set_options() { 85 | add_option('moowoodle_version', MOOWOODLE_PLUGIN_VERSION); 86 | update_option('woocommerce_registration_generate_username', 'no'); 87 | update_option('woocommerce_enable_guest_checkout', 'no'); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /classes/Category.php: -------------------------------------------------------------------------------- 1 | $taxonomy, 22 | 'hide_empty' => false, 23 | 'meta_query' => [ 24 | 'key' => '_category_id', 25 | 'value' => $category_id 26 | ] 27 | ] 28 | ); 29 | 30 | // Check no category found. 31 | if ( is_wp_error( $terms ) ) { 32 | return null; 33 | } 34 | 35 | return $terms[0]; 36 | } 37 | /** 38 | * Update moodle course categories in Wordpress site. 39 | * 40 | * @access private 41 | * @param array $categories 42 | * @param string $taxonomy 43 | * @param string $meta_key 44 | * @return void 45 | */ 46 | public static function update_categories($categories, $taxonomy) { 47 | if (empty($taxonomy) || !taxonomy_exists($taxonomy)) { 48 | return; 49 | } 50 | 51 | $category_ids = array(); 52 | if (!empty($categories)) { 53 | foreach ($categories as $category) { 54 | // find and getthe term id for category. 55 | $term = self::get_category($category['id'], $taxonomy); 56 | 57 | // If term is exist update it. 58 | if ($term) { 59 | $term = wp_update_term( 60 | $term->term_id, 61 | $taxonomy, 62 | [ 63 | 'name' => $category['name'], 64 | 'slug' => "{$category['name']} {$category['id']}", 65 | 'description' => $category['description'] 66 | ] 67 | ); 68 | } else { // term not exist create it. 69 | $term = wp_insert_term( 70 | $category['name'], 71 | $taxonomy, 72 | [ 73 | 'description' => $category['description'], 74 | 'slug' => "{$category['name']} {$category['id']}" 75 | ] 76 | ); 77 | if (!is_wp_error($term)) add_term_meta($term['term_id'], '_category_id', $category['id'], false); 78 | } 79 | 80 | // In success on update or insert sync meta data. 81 | if ( ! is_wp_error($term)) { 82 | update_term_meta($term['term_id'], '_parent', $category['parent'], ''); 83 | update_term_meta($term['term_id'], '_category_path', $category['path'], false); 84 | 85 | // Store category id to link with parent or delete term. 86 | $category_ids[] = $category['id']; 87 | } else { 88 | MooWoodle()->Helper->MW_log( "\n moowoodle url:" . $term->get_error_message() . "\n"); 89 | } 90 | } 91 | } 92 | 93 | // get all term for texonomy ( product_cat, course_cat ) 94 | $terms = get_terms(array('taxonomy' => $taxonomy, 'hide_empty' => false )); 95 | 96 | // if term not exist. 97 | if ( is_wp_error( $terms ) ) return; 98 | 99 | // Link with parent or delete term 100 | foreach ($terms as $term) { 101 | $category_id = get_term_meta($term->term_id, '_category_id', true); 102 | 103 | if (in_array($category_id, $category_ids)) { 104 | // get parent category id and continue if not exist 105 | $parent_category_id = get_term_meta($term->term_id, '_parent', true); 106 | if ( empty($parent) ) continue; 107 | // get parent term id and continue if not exist 108 | $parent_term =self::get_category($parent_category_id, $taxonomy); 109 | if( empty($parent_term) ) continue; 110 | // sync parent term with term 111 | wp_update_term($term->term_id, $taxonomy, array('parent' => $parent_term->term_id)); 112 | } else { // delete term if category is not moodle category. 113 | wp_delete_term($term->term_id, $taxonomy); 114 | } 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /classes/Emails/Emails_New_Enrollment.php: -------------------------------------------------------------------------------- 1 | id = 'new_moodle_enrollment'; 22 | $this->title = __('New Moodle Enrollment', 'moowoodle'); 23 | $this->description = __('This is a notification email sent to the enrollees for new enrollment.', 'moowoodle'); 24 | $this->customer_email = true; 25 | $this->heading = __('New Enrollment', 'moowoodle'); 26 | $this->subject = __('{site_title} New Enrollment', 'moowoodle'); 27 | $this->template_html = 'emails/new-enrollment.php'; 28 | $this->template_plain = 'emails/plain/new-enrollment.php'; 29 | // Call parent constructor 30 | parent::__construct(); 31 | $this->template_base = MOOWOODLE_PLUGIN_PUTH . '/templates/'; 32 | } 33 | /** 34 | * trigger function. 35 | * 36 | * @access public 37 | * @return void 38 | */ 39 | public function trigger($email_data) { 40 | $this->recipient = $email_data['email']; 41 | $this->object = $email_data; 42 | if (!$this->is_enabled() || !$this->get_recipient()) { 43 | return; 44 | } 45 | $this->send($this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments()); 46 | } 47 | /** 48 | * get_content_html function. 49 | * 50 | * @access public 51 | * @return string 52 | */ 53 | function get_content_html() { 54 | ob_start(); 55 | MooWoodle()->Template->get_template( 56 | $this->template_html, 57 | array( 58 | 'enrollments' => $this->object, 59 | 'user_data' => $this->recipient, 60 | 'email_heading' => $this->get_heading(), 61 | 'sent_to_admin' => false, 62 | 'plain_text' => false, 63 | ) 64 | ); 65 | return ob_get_clean(); 66 | } 67 | /** 68 | * get_content_plain function. 69 | * 70 | * @access public 71 | * @return string 72 | */ 73 | function get_content_plain() { 74 | ob_start(); 75 | MooWoodle()->Template->get_template( 76 | $this->template_plain, 77 | array( 78 | 'enrollments' => $this->object, 79 | 'email_heading' => $this->get_heading(), 80 | 'sent_to_admin' => false, 81 | 'plain_text' => true, 82 | ) 83 | ); 84 | return ob_get_clean(); 85 | } 86 | /** 87 | * Initialise Settings Form Fields 88 | * 89 | * @access public 90 | * @return void 91 | */ 92 | function init_form_fields() { 93 | $this->form_fields = array( 94 | 'enabled' => array( 95 | 'title' => __('Enable/Disable', 'moowoodle'), 96 | 'type' => 'checkbox', 97 | 'label' => __('Enable this email notification', 'moowoodle'), 98 | 'default' => 'yes', 99 | ), 100 | 'subject' => array( 101 | 'title' => __('Subject', 'moowoodle'), 102 | 'type' => 'text', 103 | 'description' => sprintf(__('This controls the email subject line. Leave blank to use the default subject: %s.', 'moowoodle'), $this->subject), 104 | 'placeholder' => '', 105 | 'default' => '', 106 | ), 107 | 'heading' => array( 108 | 'title' => __('Email Heading', 'moowoodle'), 109 | 'type' => 'text', 110 | 'description' => sprintf(__('This controls the main heading contained within the email notification. Leave blank to use the default heading: %s.', 'moowoodle'), $this->heading), 111 | 'placeholder' => '', 112 | 'default' => '', 113 | ), 114 | 'email_type' => array( 115 | 'title' => __('Email type', 'moowoodle'), 116 | 'type' => 'select', 117 | 'description' => __('Choose which format of email to send.', 'moowoodle'), 118 | 'default' => 'html', 119 | 'class' => 'email_type', 120 | 'options' => array( 121 | 'plain' => __('Plain text', 'moowoodle'), 122 | 'html' => __('HTML', 'moowoodle'), 123 | 'multipart' => __('Multipart', 'moowoodle'), 124 | ), 125 | ), 126 | ); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /classes/ExternalService.php: -------------------------------------------------------------------------------- 1 | 'core_course_get_categories', 27 | 'get_courses' => 'core_course_get_courses', 28 | 'get_moodle_users' => 'core_user_get_users', 29 | 'create_users' => 'core_user_create_users', 30 | 'update_users' => 'core_user_update_users', 31 | 'enrol_users' => 'enrol_manual_enrol_users', 32 | 'get_course_image' => 'core_course_get_courses_by_field', 33 | 'unenrol_users' => 'enrol_manual_unenrol_users', 34 | 'sync_users_data' => 'auth_moowoodle_user_sync', 35 | ]; 36 | 37 | if (array_key_exists($key, $moodle_core_functions)) { 38 | $function_name = $moodle_core_functions[$key]; 39 | } 40 | 41 | $connection_settings = get_option('moowoodle_general_settings'); 42 | $moodle_base_url = $connection_settings['moodle_url']; 43 | $moodle_access_token = $connection_settings['moodle_access_token']; 44 | $request_url = rtrim($moodle_base_url, '/') . '/webservice/rest/server.php?wstoken=' . $moodle_access_token . '&wsfunction=' . $function_name . '&moodlewsrestformat=json'; 45 | 46 | // need to remove. 47 | if ($function_name == 'core_user_get_users') { 48 | $request_url = $request_url . '&criteria[0][key]=email&criteria[0][value]=%%'; 49 | } 50 | 51 | if (!empty($moodle_base_url) && !empty($moodle_access_token) && $function_name != '') { 52 | $request_query = http_build_query($request_param); 53 | $response = wp_remote_post($request_url, array('body' => $request_query, 'timeout' => $connection_settings['moodle_timeout'])); 54 | 55 | // Log the response relult. 56 | if($connection_settings['moowoodle_adv_log']){ 57 | MooWoodle()->Helper->MW_log( "\n\n moowoodle moodle_url:" . $request_url . '&' . $request_query . "\n moowoodle response:" . wp_json_encode($response) . "\n\n"); 58 | } 59 | } 60 | 61 | // check the response containe error. 62 | $response = self::check_connection($response); 63 | 64 | // log the error 65 | if(isset($response['error'])){ 66 | MooWoodle()->Helper->MW_log( "\n moowoodle error:" . $error_massage . "\n"); 67 | return null; 68 | } 69 | 70 | // return response on success. 71 | return $response; 72 | } 73 | 74 | /** 75 | * check server resposne result . 76 | * 77 | * @access private 78 | * @param string | null $response 79 | * @return array $response 80 | */ 81 | private function check_connection( $response ) { 82 | 83 | // if server response containe error 84 | if (!$response || is_wp_error($response) || $response['response']['code'] != 200) { 85 | 86 | // if response is object and multiple error codes 87 | if(is_object($response) && is_array($response->get_error_code())) { 88 | return ['error' => implode(' | ', $response->get_error_code()) . $response->get_error_message()]; 89 | } 90 | 91 | // if response is associative array. 92 | if (is_array($response)) { 93 | return ['error' => $response['response']['code'] . $response['response']['message']]; 94 | } 95 | 96 | return ['error' => $response->get_error_code() . $response->get_error_message()]; 97 | } 98 | 99 | // convert moodle response to array. 100 | $response = json_decode($response['body'], true); 101 | 102 | // if array convertion failed 103 | if(json_last_error() !== JSON_ERROR_NONE){ 104 | return ['error' => __('Response is not JSON decodeable', 'moowoodle')]; 105 | } 106 | 107 | // if moodle response containe error. 108 | if ($response && array_key_exists('exception', $response)) { 109 | if (str_contains($response['message'], 'Access control exception')) { 110 | return ['error' => $response['message'] . ' ' . 'Link']; 111 | } 112 | if (str_contains($response['message'], 'Invalid moodle_access_token')) { 113 | return ['error' => $response['message'] . ' ' . 'Link']; 114 | } 115 | } 116 | 117 | // success 118 | return $response; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/commponents/CustomInputField/Button.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import axios from 'axios'; 3 | const Button = (props) => { 4 | const { __ } = wp.i18n; 5 | let course_id = ''; 6 | let user_id = ''; 7 | let message = ''; 8 | const [emptyDivContaint, setEmptyDivContaint] = useState(''); 9 | const handleButtonClick = async (event, route) => { 10 | event.target.classList.add("active"); 11 | const testConnectionActions = { 12 | get_site_info: __('Connecting to Moodle'), 13 | get_catagory: __('Course Category Sync'), 14 | get_course_by_fuild: __('Course Data Sync'), 15 | get_course: __('Course Sync'), 16 | create_user: __('User Creation'), 17 | get_user: __('User Data Sync'), 18 | update_user: __('User Data Update'), 19 | enrol_users: __('User Enrolment'), 20 | unenrol_users: __('User Unenrolment'), 21 | delete_users: __('All Test'), 22 | }; 23 | 24 | console.log(event.currentTarget.parentElement.parentElement.querySelector('.test-connection-contains')) 25 | switch (route) { 26 | case "test-connection": 27 | await testCunnection(Object.keys(testConnectionActions), testConnectionActions, route, message ); 28 | event.target.classList.remove("active"); 29 | break; 30 | case "sync-course-options": 31 | await syncCourse(route); 32 | break; 33 | case "sync-all-user-options": 34 | await syncUser(); 35 | break; // Add case with fieldid if any button is added. 36 | default: 37 | 38 | } 39 | }; 40 | const testCunnection = async(actions, actions_desc, route, message) => { 41 | const action = actions.shift(); 42 | if(!action)return; 43 | const data = { 44 | action: action, 45 | user_id: user_id, 46 | course_id: course_id, 47 | }; 48 | try { 49 | const response = await handleAxios(data, route); 50 | if (response.data.message) { 51 | message = ( 52 | <> 53 | {message} 54 |
55 | {actions_desc[action]} : 56 | 57 | {response.data.message === 'success' ? ( 58 | 59 | ) : ( 60 | <> 61 | 62 | 63 | 64 | )} 65 | 66 |
67 | 68 | ); 69 | setEmptyDivContaint( () => { 70 | return (message); 71 | }); 72 | user_id= response.data.user_id; 73 | course_id= response.data.course_id; 74 | console.log(response.data); 75 | if (response.data.course_empty) { 76 | console.log(response.data.course_empty); 77 | } 78 | if (action === 'get_site_info' && response.data.message !== 'success') { 79 | console.log('Setup Problem.'); 80 | } else if (action === 'update_user' && !course_id) { 81 | console.log('Course not found.'); 82 | } else if (action === 'update_user' && response.data.user_id === null) { 83 | console.log('User not found.'); 84 | } else if (action) { 85 | await testCunnection(actions, actions_desc, route, message); 86 | } 87 | } 88 | }catch(error){ 89 | console.log(error); 90 | }; 91 | } 92 | const syncCourse = async(route) => { 93 | console.log(props.field.preSetting) 94 | try { 95 | await handleAxios({preSetting: props.field.preSetting}, route); 96 | } catch(error){ 97 | console.log(error); 98 | }; 99 | } 100 | const syncUser = (route) => { 101 | try { 102 | handleAxios({preSetting: props.field.preSetting}, route); 103 | } catch(error){ 104 | console.log(error); 105 | }; 106 | } 107 | 108 | const handleAxios = async(data, route) => { 109 | try { 110 | const response = await axios({ 111 | method: 'post', 112 | url: `${MooWoodleAppLocalizer.rest_url}moowoodle/v1/${route}`, 113 | headers: { "X-WP-Nonce": MooWoodleAppLocalizer.nonce }, 114 | data: { 115 | data: data, 116 | } 117 | }) 118 | return response; 119 | }catch(error){ 120 | console.log(error); 121 | }; 122 | }; 123 | return ( 124 | <> 125 | { 126 | props.emptyDiv &&
{emptyDivContaint}
127 | } 128 |

129 | 138 |

139 | 140 | ); 141 | }; 142 | export default Button; 143 | -------------------------------------------------------------------------------- /classes/Settings.php: -------------------------------------------------------------------------------- 1 | $menu_names) { 32 | add_submenu_page( 33 | 'moowoodle', 34 | $menu_names['name'], 35 | $menu_names['name'], 36 | 'manage_options', 37 | 'moowoodle#&tab=' . $menu_slug . '&sub-tab=' . $menu_names['default_tab'], 38 | '_-return_null' 39 | ); 40 | } 41 | remove_submenu_page('moowoodle', 'moowoodle'); 42 | wp_enqueue_style( 43 | 'moowoodle_admin_css', 44 | MOOWOODLE_PLUGIN_URL . 'build/index.css', array(), 45 | MOOWOODLE_PLUGIN_VERSION 46 | ); 47 | wp_enqueue_script( 48 | 'mwd-build-admin-frontend', 49 | MOOWOODLE_PLUGIN_URL . 'build/index.js', 50 | ['wp-element', 'wp-i18n'], 51 | time(), 52 | true 53 | ); 54 | wp_localize_script( 55 | 'mwd-build-admin-frontend', 56 | 'MooWoodleAppLocalizer', 57 | [ 58 | 'admin_url' => get_admin_url(), 59 | 'side_banner_img' => esc_url(plugins_url()) .'/moowoodle/assets/images/logo-moowoodle-pro.png', 60 | 'library' => Library::moowoodle_get_options(), 61 | 'porAdv' => MOOWOODLE_PRO_ADV, 62 | 'preSettings' => [ 63 | 'moowoodle_general_settings' => get_option('moowoodle_general_settings'), 64 | 'moowoodle_display_settings' => get_option('moowoodle_display_settings'), 65 | 'moowoodle_sso_settings' => get_option('moowoodle_sso_settings'), 66 | 'moowoodle_synchronize_settings' => get_option('moowoodle_synchronize_settings'), 67 | 'moowoodle_synchronize_now' => get_option('moowoodle_synchronize_now'), 68 | ], 69 | 'MW_Log' => MW_LOGS.'/error.txt', 70 | 'rest_url' => esc_url_raw(rest_url()), 71 | 'nonce' => wp_create_nonce('wp_rest'), 72 | 'pro_sticker' => MOOWOOLE_PRO_STICKER, 73 | 'pro_popup_overlay' => MOOWOODLE_PRO_ADV ? ' mw-pro-popup-overlay ' : '', 74 | 'shop_url' => MOOWOODLE_PRO_SHOP_URL, 75 | 'manage_enrolment_img_url' => esc_url(plugins_url())."/moowoodle/assets/images/manage-enrolment.jpg", 76 | 'lang' => [ 77 | 'warning_to_force_checked' => esc_html__('The \'Sync now\' option requires \'Moodle Courses\' to be enabled.', 'moowoodle'), 78 | 'Copy' => 'Copy', 79 | 'Copied' => 'Copied', 80 | ], 81 | ], 82 | ); 83 | do_action('moowoodle_upgrade_to_pro_admin_menu_hide'); 84 | if (MOOWOODLE_PRO_ADV) { 85 | add_submenu_page( 86 | 'moowoodle', 87 | __("Upgrade to Pro", 'moowoodle'), 88 | '
' . esc_html__("Upgrade to Pro", 'moowoodle') . '
', 89 | 'manage_options', 90 | '', 91 | array($this, 'handle_external_redirects') 92 | ); 93 | } 94 | } 95 | // create the root page for load react. 96 | public static function create_settings_page() { 97 | 98 | $page = filter_input(INPUT_GET, 'page', FILTER_DEFAULT) !== null ? filter_input(INPUT_GET, 'page', FILTER_DEFAULT) : '';?> 99 |
100 |
101 | 104 | 105 |
106 |

107 |

108 |
    109 |
  1. ">
  2. 110 |
  3. 111 |
  4. 112 |
113 |

114 |
115 | 119 |
120 |
121 | { 13 | const { __ } = wp.i18n; 14 | const location = new URLSearchParams(useLocation().hash); 15 | const tabValue = MooWoodleAppLocalizer.library[location.get('tab')][location.get('sub-tab')]; 16 | const [successMsg, setSuccessMsg] = useState(''); 17 | const [Setting, setSetting] = useState(MooWoodleAppLocalizer.preSettings); 18 | const settingChanged = useRef(false); 19 | const handleChange = (event) => { 20 | settingChanged.current = true; 21 | setSetting((currentSetting) => { 22 | const newSetting = { ...currentSetting, }; 23 | if(!newSetting[tabValue.setting]){ 24 | newSetting[tabValue.setting] = {}; 25 | } 26 | console.log(event.target.type); 27 | if(event.target.type === 'checkbox'){ 28 | newSetting[tabValue.setting][event.target.name] = event.target.checked; 29 | } else { 30 | newSetting[tabValue.setting][event.target.name] = event.target.value; 31 | } 32 | return newSetting; 33 | }); 34 | } 35 | useEffect(() => { 36 | let timeoutId; 37 | timeoutId = setTimeout(() => { 38 | if(!tabValue) return; 39 | if(Setting[tabValue.setting] && settingChanged.current){ 40 | settingChanged.current = false; 41 | axios({ 42 | method: 'post', 43 | url: `${MooWoodleAppLocalizer.rest_url}moowoodle/v1/save-moowoodle-setting`, 44 | headers: { 'X-WP-Nonce' : MooWoodleAppLocalizer.nonce }, 45 | data: { 46 | setting: Setting[tabValue.setting], 47 | settingid: tabValue.setting, 48 | }, 49 | }).then((response) => { 50 | setSuccessMsg("Settings Saved"); 51 | setTimeout(() => { 52 | setSuccessMsg(''); 53 | }, 2050); 54 | }).catch((error) => { 55 | console.error('Error:', error); 56 | }); 57 | } 58 | }, 2000); 59 | return () => { 60 | clearTimeout(timeoutId); 61 | }; 62 | }, [Setting]); 63 | const getFieldContent = (fields) => { 64 | if(!fields) return ( 65 | <>{__('No souch Tab Exist.')} 66 | ); 67 | return Object.entries(fields).map(([fieldid, field]) => { 68 | field['id'] = fieldid; 69 | field['settingid'] = tabValue.setting; 70 | field['preSetting'] = Setting[tabValue.setting]; 71 | return ( 72 | <> 73 | { field.type === 'section' &&
} 74 |
75 | {field.label && field.type !== 'section' && ()} 76 |
77 | { 78 | field.desc_posi === 'up' && 79 |

80 | } 81 | {field.type === 'textbox' && { handleChange(e) }}/>} 82 | {field.type === 'toggle-checkbox' && { handleChange(e) }}/>} 83 | {field.type === 'select' && { console.log(e); }} placeholder="Search Course" aria-controls="moowoodle_table" /> 178 |
179 |
180 |
181 |
182 |
183 |
184 | 185 |
186 |
187 |
188 | {/* setState([item.selection])} 190 | showSelectionPreview={true} 191 | moveRangeOnFirstSelection={false} 192 | months={2} 193 | ranges={datePicked} 194 | direction="horizontal" 195 | preventSnapRefocus={true} 196 | calendarFocus="backwards" 197 | /> */} 198 |
199 |
200 | { 201 | MooWoodleAppLocalizer.porAdv ? 202 |

203 | 204 | 205 | 206 |

207 | : 208 | <> 209 | {ManageEnrolTable()} 210 | 211 | } 212 |
213 |
214 |
215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | ); 225 | } 226 | export default ManageEnrolment; 227 | -------------------------------------------------------------------------------- /classes/Enrollment.php: -------------------------------------------------------------------------------- 1 | get_meta( 'moodle_user_enrolled', true) != "true") { 23 | $this->wc_order = $order; 24 | $moodle_user_id = $this->get_moodle_user_id(); 25 | $this->enrol_moodle_user(intval($moodle_user_id)); 26 | } 27 | } 28 | 29 | /** 30 | * Perform enrollment to moodle 31 | * 32 | * @access private 33 | * @return void 34 | */ 35 | private function process_enrollment() { 36 | } 37 | 38 | /** 39 | * Get moodle user id. If the user does not exist in moodle then creats an user in moodle. 40 | * 41 | * @access private 42 | * @param bool $create_moodle_user (default: bool) 43 | * @return int 44 | */ 45 | private function get_moodle_user_id() { 46 | $user_id = $this->wc_order->get_user_id(); 47 | 48 | // if user is a guest user return. 49 | if ( ! $user_id ) return $user_id; 50 | 51 | // get moodle user id 52 | $moodle_user_id = get_user_meta( $user_id, 'moowoodle_moodle_user_id', true ); 53 | 54 | // Filter before moodle user create or update. 55 | $moodle_user_id = apply_filters('moowoodle_get_moodle_user_id_before_enrollment', $moodle_user_id, $user_id); 56 | 57 | // If moodle user id exist then return it. 58 | if ( $moodle_user_id ) return $moodle_user_id; 59 | 60 | // Get user id from moodle database. 61 | $moodle_user_id = $this->search_for_moodle_user( 'email', $this->wc_order->get_billing_email() ); 62 | 63 | // If user id not avialable in moodle databse then create it 64 | if ( ! $moodle_user_id ) { 65 | $moodle_user_id = $this->create_moodle_user(); 66 | } else { 67 | // User id is availeble update user id. 68 | 69 | $conn_settings = get_option('moowoodle_general_settings'); 70 | $should_user_update = $conn_settings['update_moodle_user'] ?? ''; 71 | 72 | if ( $should_user_update ) { 73 | $this->update_moodle_user( $moodle_user_id ); 74 | } 75 | } 76 | 77 | update_user_meta( $user_id, 'moowoodle_moodle_user_id', $moodle_user_id ); 78 | 79 | return $moodle_user_id; 80 | } 81 | /** 82 | * Searches for an user in moodle by a specific field. 83 | * 84 | * @access private 85 | * @param string $field 86 | * @param string $values 87 | * @return int 88 | */ 89 | private function search_for_moodle_user($field, $values) { 90 | // find user on moodle with moodle externel function. 91 | $users = MooWoodle()->ExternalService->do_request('get_moodle_users', array('criteria' => array(array('key' => $field, 'value' => $values)))); 92 | if (!empty($users) && !empty($users['users'])) { 93 | return $users['users'][0]['id']; 94 | } 95 | return 0; 96 | } 97 | /** 98 | * Creates an user in moodle. 99 | * 100 | * @access private 101 | * @param int $moodle_user_id (default: int) 102 | * @return int 103 | */ 104 | private function create_moodle_user($moodle_user_id = 0) { 105 | $user_data = $this->get_user_data(); 106 | // create user on moodle with moodle externel function. 107 | $moodle_user = MooWoodle()->ExternalService->do_request('create_users', array('users' => array($user_data))); 108 | if (!empty($moodle_user) && array_key_exists(0, $moodle_user)) { 109 | $moodle_user_id = $moodle_user[0]['id']; 110 | // send email with credentials 111 | do_action('moowoodle_after_create_moodle_user', $user_data); 112 | } 113 | return $moodle_user_id; 114 | } 115 | /** 116 | * Info about an user to be created/updated in moodle. 117 | * 118 | * @access private 119 | * @param int $moodle_user_id (default: int) 120 | * @return array 121 | */ 122 | private function get_user_data($moodle_user_id = 0) { 123 | $user_id = $this->wc_order->get_user_id(); 124 | $user = ($user_id != 0) ? get_userdata($user_id) : false; 125 | $billing_email = $this->wc_order->get_billing_email(); 126 | $username = $billing_email; 127 | if ($user) { 128 | $username = $user->user_login; 129 | } else { 130 | $user = get_user_by('email', $billing_email); 131 | if ($user) { 132 | $username = $user->data->user_login; 133 | } 134 | } 135 | $username = str_replace(' ', '', $username); 136 | $username = strtolower($username); 137 | $moodle_pwd_meta = get_user_meta($user_id, 'moowoodle_moodle_user_pwd', true); 138 | $pwd = ''; 139 | if (empty($moodle_pwd_meta) || $moodle_pwd_meta == null) { 140 | $pwd = $this->password_generator(); 141 | add_user_meta($user_id, 'moowoodle_moodle_user_pwd', $pwd); 142 | } else { 143 | $pwd = $moodle_pwd_meta; 144 | } 145 | $user_data = array(); 146 | if ($moodle_user_id) { 147 | $user_data['id'] = $moodle_user_id; 148 | } else { 149 | $user_data['email'] = ($user && $user->user_email != $billing_email) ? $user->user_email : $billing_email; 150 | $user_data['username'] = $username; 151 | $user_data['password'] = $pwd; 152 | $user_data['auth'] = 'manual'; 153 | $a = get_locale(); 154 | $b = strtolower($a); 155 | $user_data['lang'] = substr($b, 0, 2); 156 | } 157 | $user_data['firstname'] = $this->wc_order->get_billing_first_name(); 158 | $user_data['lastname'] = $this->wc_order->get_billing_last_name(); 159 | $user_data['city'] = $this->wc_order->get_billing_city(); 160 | $user_data['country'] = $this->wc_order->get_billing_country(); 161 | $user_data['preferences'][0]['type'] = "auth_forcepasswordchange"; 162 | $user_data['preferences'][0]['value'] = 1; 163 | return apply_filters('moowoodle_moodle_users_data', $user_data, $this->wc_order); 164 | } 165 | /** 166 | * Updates an user info in moodle. 167 | * 168 | * @access private 169 | * @param int $moodle_user_id (default: int) 170 | * @return int 171 | */ 172 | private function update_moodle_user($moodle_user_id = 0) { 173 | $user_data = $this->get_user_data($moodle_user_id); 174 | // update user data on moodle with moodle externel function. 175 | MooWoodle()->ExternalService->do_request('update_users', array('users' => array($user_data))); 176 | return $moodle_user_id; 177 | } 178 | /** 179 | * Enrollment/suspend enrollment of an user in moodle. 180 | * 181 | * @access private 182 | * @param int $moodle_user_id (default: int) 183 | * @param int $suspend (default: int) 184 | * @return void 185 | */ 186 | private function enrol_moodle_user($moodle_user_id, $suspend = 0) { 187 | if (empty($moodle_user_id) || !is_int($moodle_user_id)) { 188 | return; 189 | } 190 | $enrolments = $this->get_enrollment_data($moodle_user_id, $suspend); 191 | if (empty($enrolments)) { 192 | return; 193 | } 194 | $enrolment_data = $enrolments; 195 | // remove course meta not need on enrol. 196 | foreach ($enrolments as $key => $value) { 197 | unset($enrolments[$key]['linked_course_id']); 198 | unset($enrolments[$key]['course_name']); 199 | } 200 | // enroll user to moodle course by core external function. 201 | MooWoodle()->ExternalService->do_request('enrol_users', array('enrolments' => $enrolments)); 202 | $this->wc_order->update_meta_data('moodle_user_enrolled', "true"); 203 | $this->wc_order->update_meta_data('moodle_user_enrolment_date', time()); 204 | $this->wc_order->save(); 205 | // send confirmation email 206 | do_action('moowoodle_after_enrol_moodle_user', $enrolment_data); 207 | } 208 | /** 209 | * Data required for enrollment. 210 | * 211 | * @access private 212 | * @param int $moodle_user_id (default: int) 213 | * @param int $suspend (default: int) 214 | * @return array 215 | */ 216 | private function get_enrollment_data($moodle_user_id, $suspend = 0) { 217 | $enrolments = array(); 218 | $items = $this->wc_order->get_items(); 219 | $role_id = apply_filters('moowoodle_enrolled_user_role_id', 5); 220 | if (!empty($items)) { 221 | foreach ($items as $item) { 222 | $course_id = get_post_meta($item->get_product_id(), 'moodle_course_id', true); 223 | if (!empty($course_id)) { 224 | $enrolment = array(); 225 | $enrolment['courseid'] = intval($course_id); 226 | $enrolment['userid'] = $moodle_user_id; 227 | $enrolment['roleid'] = $role_id; 228 | $enrolment['suspend'] = $suspend; 229 | $enrolment['linked_course_id'] = get_post_meta($item->get_product_id(), 'linked_course_id', true); 230 | $enrolment['course_name'] = get_the_title($item->get_product_id()); 231 | $enrolments[] = $enrolment; 232 | } 233 | } 234 | } 235 | return apply_filters('moowoodle_moodle_enrolments_data', $enrolments); 236 | } 237 | /** 238 | * Display WC order thankyou page containt. 239 | * 240 | * @access public 241 | * @param void 242 | * @return void 243 | */ 244 | public function enrollment_modified_details($order_id) { 245 | $order = wc_get_order($order_id); 246 | if ($order->get_status() == 'completed') { 247 | echo esc_html_e('Please check your mail or go to My Courses page to access your courses.', 'moowoodle'); 248 | } else { 249 | echo esc_html_e('Order status is :- ', 'moowoodle') . $order->get_status() . '
'; 250 | } 251 | } 252 | /** 253 | * Display course start and end date. 254 | * 255 | * @access public 256 | * @param void 257 | * @return void 258 | */ 259 | public function add_dates_with_product() { 260 | global $product; 261 | $startdate = get_post_meta($product->get_id(), '_course_startdate', true); 262 | $enddate = get_post_meta($product->get_id(), '_course_enddate', true); 263 | $display_settings = get_option('moowoodle_display_settings'); 264 | if (isset($display_settings['start_end_date']) && $display_settings['start_end_date'] == "Enable") { 265 | if ($startdate) { 266 | echo esc_html_e("Start Date : ", 'moowoodle') . esc_html_e(gmdate('Y-m-d', $startdate), 'moowoodle'); 267 | print_r("
"); 268 | } 269 | if ($enddate) { 270 | echo esc_html_e("End Date : ", 'moowoodle') . esc_html_e(gmdate('Y-m-d', $enddate), 'moowoodle'); 271 | } 272 | } 273 | } 274 | /** 275 | * Generate random password. 276 | * 277 | * @access private 278 | * @param void 279 | * @return void 280 | */ 281 | private function password_generator() { 282 | $length = 8; 283 | $sets = array(); 284 | $sets[] = 'ABCDEFGHJKLMNPQRSTUVWXYZ'; 285 | $sets[] = 'abcdefghjkmnpqrstuvwxyz'; 286 | $sets[] = '23456789'; 287 | $sets[] = '~!@#$%^&*(){}[],./?'; 288 | $password = ''; 289 | //append a character from each set - gets first 4 characters 290 | foreach ($sets as $set) { 291 | $password .= $set[array_rand(str_split($set))]; 292 | } 293 | //use all characters to fill up to $length 294 | while (strlen($password) < $length) { 295 | //get a random set 296 | $randomSet = $sets[array_rand($sets)]; 297 | //add a random char from the random set 298 | $password .= $randomSet[array_rand(str_split($randomSet))]; 299 | } 300 | //shuffle the password string before returning! 301 | return str_shuffle($password); 302 | } 303 | } 304 | -------------------------------------------------------------------------------- /classes/TestConnection.php: -------------------------------------------------------------------------------- 1 | ' . __('error log', 'moowoodle') . ' '; 8 | self::$user_data['email'] = 'moowoodletestuser@gmail.com'; 9 | self::$user_data['username'] = 'moowoodletestuser'; 10 | self::$user_data['password'] = 'Moowoodle@123'; 11 | self::$user_data['auth'] = 'manual'; 12 | $a = get_locale(); 13 | $b = strtolower($a); 14 | self::$user_data['lang'] = substr($b, 0, 2); 15 | self::$user_data['firstname'] = 'moowoodle'; 16 | self::$user_data['lastname'] = 'testuser'; 17 | self::$user_data['city'] = 'moowoodlecity'; 18 | self::$user_data['country'] = 'IN'; 19 | self::$user_data['preferences'][0]['type'] = "auth_forcepasswordchange"; 20 | self::$user_data['preferences'][0]['value'] = 1; 21 | } 22 | //test get site info 23 | public static function get_site_info($response_data) { 24 | $response = self::moowoodle_moodle_test_connection_callback('get_site_info'); 25 | if ($response != null) { 26 | if (self::check_connection($response) == 'success') { 27 | $response_arr = json_decode($response['body'], true); 28 | $web_service_functions = array( 29 | 'core_user_get_users', 30 | 'core_user_update_users', 31 | 'enrol_manual_enrol_users', 32 | 'core_user_delete_users', 33 | 'enrol_manual_unenrol_users', 34 | 'core_course_get_courses_by_field', 35 | 'core_course_get_courses', 36 | 'core_user_create_users', 37 | 'core_course_get_categories', 38 | 'core_webservice_get_site_info', 39 | ); 40 | $response_functions = array_map(function ($function) { 41 | return $function['name']; 42 | }, $response_arr['functions']); 43 | $missing_functions = array_diff($web_service_functions, $response_functions); 44 | if (!empty($missing_functions)) { 45 | MooWoodle()->Helper->MW_log( "\n\n It seems that certain Moodle external web service functions are not configured correctly.\n The missing functions following:" . wp_json_encode($missing_functions) . "\n\n"); 46 | } else if (!MOOWOODLE_PRO_ADV) { 47 | if (!in_array('auth_moowoodle_user_sync_get_all_users_data', $response_functions) && defined( 'MOOWOODLE_PRO_PLUGIN_VERSION' ) && version_compare( MOOWOODLE_PRO_PLUGIN_VERSION, '1.0.5', '<' ) ) { 48 | MooWoodle()->Helper->MW_log( "\n\n It seems that you are using MooWoodle Pro but Moodle external web service functions 'auth_moowoodle_user_sync_get_all_users_data' is not configured correctly.\n\n"); 49 | } else if (!in_array('auth_moowoodle_user_sync', $response_functions) && defined( 'MOOWOODLE_PRO_PLUGIN_VERSION' ) && version_compare( MOOWOODLE_PRO_PLUGIN_VERSION, '1.0.5', '>=' ) ) { 50 | MooWoodle()->dMW_log( "\n\n It seems that you are using MooWoodle Pro but Moodle external web service functions 'auth_moowoodle_user_sync' is not configured correctly.\n\n"); 51 | } else if ($response_arr['downloadfiles'] != 1) { 52 | MooWoodle()->Helper->MW_log( "\n\n It seems that you are using MooWoodle Pro but Moodle external web service is not configured correctly. Please edit your Moodle External service and enable 'Can download files' (you can find it from 'Show more...' options)\n\n"); 53 | } else { 54 | $response_data['message'] = 'success'; 55 | } 56 | } else { 57 | $response_data['message'] = 'success'; 58 | } 59 | update_option('moowoodle_moodle_site_name', $response_arr['sitename']); 60 | } 61 | } 62 | return $response_data; 63 | } 64 | //test get course 65 | public static function get_course($response_data) { 66 | $response = self::moowoodle_moodle_test_connection_callback('get_courses'); 67 | if ($response != null) { 68 | if (self::check_connection($response) == 'success') { 69 | $response_data['message'] = 'success'; 70 | if($response_data['course_id']){ 71 | $response_arr = json_decode($response['body'], true); 72 | if (!empty($response_arr)) { 73 | foreach ($response_arr as $course) { 74 | if ($course['format'] != 'site') { 75 | $response_data['course_id'] = $course['id']; 76 | $response_data['course_empty'] = ''; 77 | break; 78 | } 79 | $response_data['course_empty'] = __('Set up a Moodle course to conduct the connection test.', 'moowoodle'); 80 | } 81 | } 82 | } 83 | } 84 | } 85 | return $response_data; 86 | } 87 | // test get category 88 | public static function get_catagory($response_data) { 89 | $response = self::moowoodle_moodle_test_connection_callback('get_categories'); 90 | if ($response != null && self::check_connection($response) == 'success') { 91 | $response_data['message'] = 'success'; 92 | } 93 | return $response_data; 94 | } 95 | // test get course by fuild 96 | public static function get_course_by_fuild($response_data) { 97 | $response = self::moowoodle_moodle_test_connection_callback('get_course_by_fuild'); 98 | if ($response != null && self::check_connection($response) == 'success') { 99 | $response_arr = json_decode($response['body'], true); 100 | $response_data['message'] = 'success'; 101 | if (!empty($response_arr)) { 102 | foreach ($response_arr['courses'] as $course) { 103 | if ($course['format'] != 'site') { 104 | $response_data['course_id'] = $course['id']; 105 | $response_data['course_empty'] = ''; 106 | break; 107 | } 108 | } 109 | } 110 | } 111 | return $response_data; 112 | } 113 | public static function create_user($response_data) { 114 | $response = self::moowoodle_moodle_test_connection_callback('create_users', array('users' => array(self::$user_data))); 115 | $response_data['message'] = esc_html(__('Failed, please check the', 'moowoodle')) . ' ' . esc_html(__('error log', 'moowoodle')) . ' '; 116 | if ($response != null && (self::check_connection($response) == 'success' || strpos(self::check_connection($response), 'Username already exists'))) { 117 | $response_data['message'] = 'success'; 118 | } 119 | return $response_data; 120 | } 121 | // test get user 122 | public static function get_user($response_data) { 123 | 124 | $response = self::moowoodle_moodle_test_connection_callback('get_moodle_users', array('criteria' => array(array('key' => 'email', 'value' => 'moowoodletestuser@gmail.com')))); 125 | if ($response != null && self::check_connection($response) == 'success') { 126 | $response_arr = json_decode($response['body'], true); 127 | $response_data['user_id'] = $response_arr['users'][0]['id']; 128 | $response_data['message'] = 'success'; 129 | } 130 | return $response_data; 131 | } 132 | // test user update 133 | public static function update_user($response_data) { 134 | self::$user_data['id'] = $response_data['user_id']; 135 | self::$user_data['city'] = 'citymoowoodle'; 136 | if(self::$user_data){ 137 | $response = self::moowoodle_moodle_test_connection_callback('update_users', array('users' => array(self::$user_data))); 138 | if ($response != null && self::check_connection($response) == 'success') { 139 | $response_data['message'] = 'success'; 140 | } 141 | } 142 | return $response_data; 143 | } 144 | // test enrol users 145 | public static function enrol_users($response_data) { 146 | 147 | $enrolment['courseid'] = $response_data['course_id']; 148 | $enrolment['userid'] = $response_data['user_id']; 149 | $enrolment['roleid'] = '5'; 150 | if($enrolment['courseid'] && $enrolment['userid']){ 151 | $response = self::moowoodle_moodle_test_connection_callback('enrol_users', array('enrolments' => array($enrolment))); 152 | if ($response != null && self::check_connection($response) == 'success') { 153 | $response_data['message'] = 'success'; 154 | } 155 | } 156 | return $response_data; 157 | } 158 | // test unenrol users 159 | public static function unenrol_users($response_data) { 160 | $enrolment['courseid'] = $response_data['course_id']; 161 | $enrolment['userid'] = $response_data['user_id']; 162 | if($enrolment['courseid'] && $enrolment['userid']){ 163 | $response = self::moowoodle_moodle_test_connection_callback('unenrol_users', array('enrolments' => array($enrolment))); 164 | if ($response != null && self::check_connection($response) == 'success') { 165 | $response_data['message'] = 'success'; 166 | } 167 | } 168 | return $response_data; 169 | } 170 | // test delete users 171 | public static function delete_users($response_data) { 172 | self::$user_data['id'] = $response_data['user_id']; 173 | if(self::$user_data['id']){ 174 | $response = self::moowoodle_moodle_test_connection_callback('delete_users', array('userids' => array(self::$user_data['id']))); 175 | if ($response != null && self::check_connection($response) == 'success') { 176 | $response_data['message'] = 'success'; 177 | } 178 | } 179 | return $response_data; 180 | } 181 | /** 182 | * get server resposne from moodle with externel service. 183 | * 184 | * @access private 185 | * @param string $function_name (default: null) 186 | * @param string $request_param (default: null) 187 | * @return mixed 188 | */ 189 | private static function moowoodle_moodle_test_connection_callback($key = '', $request_param = array()) { 190 | $response = null; 191 | $function_name = ""; 192 | $moodle_core_functions = array( 193 | 'get_site_info' => 'core_webservice_get_site_info', 194 | 'get_categories' => 'core_course_get_categories', 195 | 'get_courses' => 'core_course_get_courses', 196 | 'get_moodle_users' => 'core_user_get_users', 197 | 'create_users' => 'core_user_create_users', 198 | 'update_users' => 'core_user_update_users', 199 | 'enrol_users' => 'enrol_manual_enrol_users', 200 | 'get_course_by_fuild' => 'core_course_get_courses_by_field', 201 | 'unenrol_users' => 'enrol_manual_unenrol_users', 202 | 'delete_users' => 'core_user_delete_users', 203 | ); 204 | if (array_key_exists($key, $moodle_core_functions)) { 205 | $function_name = $moodle_core_functions[$key]; 206 | } 207 | $conn_settings = get_option('moowoodle_general_settings'); 208 | $url = $conn_settings['moodle_url']; 209 | $token = $conn_settings['moodle_access_token']; 210 | $request_url = $url . '/webservice/rest/server.php?wstoken=' . $token . '&wsfunction=' . $function_name . '&moodlewsrestformat=json'; 211 | if ($function_name == 'core_user_get_users') { 212 | $request_url = $request_url . '&criteria[0][key]=email&criteria[0][value]=%%'; 213 | } 214 | if (!empty($url) && !empty($token) && $function_name != '') { 215 | $request_query = http_build_query($request_param); 216 | $response = wp_remote_post($request_url, array('body' => $request_query, 'timeout' => get_option('moowoodle_general_settings')['moodle_timeout'])); 217 | if ($conn_settings['moowoodle_adv_log']) { 218 | MooWoodle()->Helper->MW_log( "\n\n moowoodle url:" . $request_url . '&' . $request_query . "\n moowoodle response:" . wp_json_encode($response) . "\n\n"); 219 | } 220 | } 221 | return $response; 222 | } 223 | /** 224 | * check server resposne result . 225 | * 226 | * @access private 227 | * @param string $response (default: null) 228 | * @return string 229 | */ 230 | private static function check_connection($response) { 231 | $conn_settings = get_option('moowoodle_general_settings'); 232 | $url_check = $error_massage = ''; 233 | if ($response && !is_wp_error($response) && $response['response']['code'] == 200) { 234 | if (is_string($response['body'])) { 235 | $response_arr = json_decode($response['body'], true); 236 | if (json_last_error() === JSON_ERROR_NONE) { 237 | if (is_null($response_arr) || !array_key_exists('exception', $response_arr)) { 238 | return $response_arr; 239 | } else { 240 | if (str_contains($response_arr['message'], 'Access control exception')) { 241 | $url_check = 'Link'; 242 | } 243 | if (str_contains($response_arr['message'], 'Invalid token')) { 244 | $url_check = 'Link'; 245 | } 246 | $error_massage = $response_arr['message'] . ' ' . $url_check; 247 | } 248 | } else { 249 | $error_massage = __('Response is not JSON decodeable', 'moowoodle'); 250 | } 251 | } else { 252 | $error_massage = __('Not String response', 'moowoodle'); 253 | } 254 | } else { 255 | // if response is object and multiple error codes 256 | if(is_object($response) && is_array($response->get_error_code())) { 257 | $error_massage = implode(' | ', $response->get_error_code()); 258 | $error_massage .= $response->get_error_message(); 259 | } elseif (is_array($response)) { // if response is associative array. 260 | $error_massage = $response['response']['code'] . $response['response']['message']; 261 | } else { 262 | $error_massage = $response->get_error_code() . $response->get_error_message(); 263 | } 264 | } 265 | MooWoodle()->Helper->MW_log( "\n moowoodle error:" . $error_massage . "\n"); 266 | return $error_massage; 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /src/commponents/SubMenuPage/AllCourses.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import axios from "axios"; 3 | import Tabs from "./../Common/Tabs"; 4 | import logo from "./../../assets/images/logo-moowoodle-pro.png"; 5 | import DataTable from 'react-data-table-component'; 6 | const LoadingSpinner = () => ( 7 | 8 | 11 |
12 | 13 |
14 | 15 | 16 | ); 17 | 18 | const AllCourses = () => { 19 | const { __ } = wp.i18n; 20 | const [successMsg, setSuccessMsg] = useState(''); 21 | const [courses, setCourses] = useState([]); 22 | const [selectedRows, setSelectedRows] = useState([]); 23 | const [loading, setLoading] = useState(true); 24 | 25 | const columns = [ 26 | { 27 | name: __('Course Name'), 28 | selector: row => row.course_name, 29 | cell: (row) => ( 30 | 31 | {row.course_name} 32 | 33 | ), 34 | sortable: true, 35 | }, 36 | { 37 | name: __('Short Name'), 38 | selector: row => row.course_short_name, 39 | sortable: true, 40 | }, 41 | { 42 | name: 'Product Name', 43 | selector: row => row.product, 44 | cell: (row) => ( 45 | Object.keys(row.product).length !== 0 ? ( 46 | Object.entries(row.product).map(([productName, productURL], index) => ( 47 | <> 48 | 49 | {productName} 50 |
51 | 52 | )) 53 | ) : ( 54 | '-' 55 | ) 56 | ), 57 | sortable: true, 58 | }, 59 | { 60 | name: __('Category Name'), 61 | selector: row => row.catagory_name, 62 | cell: (row) => ( 63 | 64 | {row.catagory_name} 65 | 66 | ), 67 | sortable: true, 68 | }, 69 | { 70 | name: __('Enrolled Users'), 71 | selector: row => row.enroled_user, 72 | sortable: true, 73 | }, 74 | { 75 | name: __('Date'), 76 | selector: row => row.date, 77 | }, 78 | { 79 | name:
, 80 | selector: row => row.course_name, 81 | cell: (row, rowIndex) => ( 82 |
83 |
84 | 100 | { 101 | Object.keys(row.product).length !== 0 ? 102 | 118 | : 119 | 135 | } 136 |
137 |
138 | ), 139 | }, 140 | ]; 141 | useEffect(() => { 142 | // Fetch data from the WordPress REST API 143 | const fetchData = async () => { 144 | try { 145 | const response = await axios.get( 146 | `${MooWoodleAppLocalizer.rest_url}moowoodle/v1/fetch-all-courses`, 147 | { 148 | headers: { "X-WP-Nonce": MooWoodleAppLocalizer.nonce }, 149 | } 150 | ); 151 | setCourses(response.data); 152 | setLoading(false); 153 | } catch (error) { 154 | console.error("Error fetching data:", error); 155 | setLoading(false); 156 | } 157 | }; 158 | 159 | fetchData(); 160 | }, []); 161 | const handleSingleSyncCourse = async (action, moodleCourseIds, CourseIds,rowIndex) => { 162 | if(!MooWoodleAppLocalizer.porAdv){ 163 | axios({ 164 | method: 'post', 165 | url: `${MooWoodleAppLocalizer.rest_url}moowoodle/v1/all-course-bulk-action`, 166 | headers: { 'X-WP-Nonce' : MooWoodleAppLocalizer.nonce }, 167 | data: { 168 | selectedAction: action, 169 | moodleCourseIds: [moodleCourseIds], 170 | CourseIds: [CourseIds] 171 | }, 172 | }).then((response) => { 173 | const updatedCourses = [...courses]; 174 | console.log(updatedCourses) 175 | updatedCourses[rowIndex] = response.data[0]; 176 | console.log(updatedCourses) 177 | setCourses(updatedCourses); 178 | setSuccessMsg("Synced"); 179 | setTimeout(() => { 180 | setSuccessMsg(''); 181 | }, 2050); 182 | }).catch((error) => { 183 | console.error('Error:', error); 184 | }); 185 | } 186 | }; 187 | const handleSelectedRowsChange = ( selecteRowsData ) => { 188 | // You can set state or dispatch with something like Redux so we can use the retrieved data 189 | setSelectedRows(selecteRowsData.selectedRows); 190 | }; 191 | 192 | const handleBulkAction = async () => { 193 | // Get the selected option from the dropdown 194 | const selectedAction = document.getElementById("bulk-action-selector-top").value; 195 | console.log('Selected action:', selectedAction); 196 | const CourseIds = selectedRows.map(row => row.id); 197 | // Extract moodle_course_id from selectedRows 198 | const moodleCourseIds = selectedRows.map(row => row.moodle_course_id); 199 | console.log(moodleCourseIds); 200 | 201 | if(!MooWoodleAppLocalizer.porAdv){ 202 | axios({ 203 | method: 'post', 204 | url: `${MooWoodleAppLocalizer.rest_url}moowoodle/v1/all-course-bulk-action`, 205 | headers: { 'X-WP-Nonce' : MooWoodleAppLocalizer.nonce }, 206 | data: { 207 | selectedAction: selectedAction, 208 | moodleCourseIds: moodleCourseIds, 209 | CourseIds: CourseIds 210 | }, 211 | }).then((response) => { 212 | const updatedCourses = courses.map(course => { 213 | const updatedCourse = response.data.find(data => data.moodle_course_id === course.moodle_course_id); 214 | if (updatedCourse) { 215 | return updatedCourse; // Replace the course data with updatedCourse data 216 | } else { 217 | return course; // If not found, keep the original course data 218 | } 219 | }); 220 | setCourses(updatedCourses) 221 | console.log(updatedCourses) 222 | // setCourses(updatedCourses); 223 | setSuccessMsg("Synced"); 224 | setTimeout(() => { 225 | setSuccessMsg(''); 226 | }, 2050); 227 | }).catch((error) => { 228 | console.error('Error:', error); 229 | }); 230 | } 231 | } 232 | 233 | 234 | return ( 235 | <> 236 |
237 | 238 |
239 |
240 |
241 | { 242 | successMsg && 243 |
244 | 245 | { successMsg } 246 |
247 | } 248 | 331 |
332 |
333 |
334 |
335 | 336 | ); 337 | }; 338 | export default AllCourses; 339 | -------------------------------------------------------------------------------- /classes/Course.php: -------------------------------------------------------------------------------- 1 | labels = array( 9 | 'singular' => __('Course', 'moowoodle'), 10 | 'plural' => __('Courses', 'moowoodle'), 11 | 'menu' => __('Courses', 'moowoodle'), 12 | ); 13 | // Register 'course' in post DB. 14 | $this->register_course_post_type(); 15 | // Register 'course_cat' in taxonomy DB. 16 | $this->register_course_cat_taxonomy(); 17 | //add Link Moodle Course in WooCommerce edit product tab. 18 | add_filter('woocommerce_product_data_tabs', array(&$this, 'moowoodle_linked_course_tab'), 99, 1); 19 | add_action('woocommerce_product_data_panels', array(&$this, 'moowoodle_linked_course_panals')); 20 | // add subcription product notice . 21 | add_filter('woocommerce_product_class', array(&$this, 'product_type_subcription_warning'), 10, 2); 22 | // Course meta save with WooCommerce product save 23 | add_action('woocommerce_process_product_meta', array(&$this, 'save_product_meta_data')); 24 | } 25 | /** 26 | * get function for Courses from post. 27 | * 28 | * @access public 29 | * @param array $args 30 | * @return array $courses 31 | */ 32 | public static function get_courses ($args = []) { 33 | $args = array_merge(['post_type' => 'course', 'post_status' => 'publish'],$args); 34 | return get_posts($args); 35 | } 36 | 37 | /** 38 | * Update moodle courses data in Wordpress post. 39 | * if not exist create new post. 40 | * 41 | * @access public 42 | * @param array $course (moodle course data) 43 | * @return int course id 44 | */ 45 | public static function update_course($course) { 46 | if (empty($courses) || $course['format'] == 'site') return 0; 47 | 48 | // get the course id linked with moodle. 49 | $post_id = self::get_courses( 50 | [ 51 | 'meta_key' => 'moodle_course_id', 52 | 'meta_value' => $course['id'], 53 | 'meta_compare' => '=', 54 | 'fields' => 'ids' 55 | ] 56 | )[0]; 57 | 58 | //prepare argument for update or create course. 59 | $args = [ 60 | 'post_title' => $course['fullname'], 61 | 'post_name' => $course['shortname'], 62 | 'post_content' => $course['summary'], 63 | 'post_status' => 'publish', 64 | 'post_type' => 'course', 65 | ]; 66 | 67 | // if course already exist update course 68 | // otherwise create new course. 69 | if ($post_id > 0) { 70 | $args['ID'] = $post_id; 71 | $new_post_id = wp_update_post($args); 72 | } else { 73 | $new_post_id = wp_insert_post($args); 74 | } 75 | 76 | // update course meta data. 77 | update_post_meta( $new_post_id, '_course_short_name', sanitize_text_field($course['shortname'])); 78 | update_post_meta( $new_post_id, '_course_idnumber', sanitize_text_field($course['idnumber'])); 79 | update_post_meta( $new_post_id, '_course_startdate', $course['startdate']); 80 | update_post_meta( $new_post_id, '_course_enddate', $course['enddate']); 81 | update_post_meta( $new_post_id, 'moodle_course_id', (int) $course['id']); 82 | update_post_meta( $new_post_id, '_category_id', (int) $course['categoryid']); 83 | update_post_meta( $new_post_id, '_visibility', $course['visible']) ? 'visible' : 'hidden'; 84 | 85 | // set course category id. 86 | $term = MooWoodle()->Category->get_category($course['id'], 'course_cat'); 87 | if ($term) \wp_set_post_terms($new_post_id, $term->term_id, 'course_cat'); 88 | 89 | return $new_post_id; 90 | } 91 | 92 | /** 93 | * Delete all the courses which id is not prasent in $exclude_ids array. 94 | * 95 | * @access public 96 | * @param array $exclude_ids (course post ids) 97 | * @return void 98 | */ 99 | public static function remove_exclude_ids($exclude_ids) { 100 | $posts = get_posts( 101 | [ 102 | 'post_type' => 'course', 103 | 'numberposts' => -1, 104 | 'post_status' => 'publish', 105 | 'post__not_in' => $exclude_ids 106 | ] 107 | ); 108 | 109 | // delete posts. 110 | foreach ($posts as $post) { 111 | wp_delete_post($post->ID, false); 112 | } 113 | } 114 | public static function get_moowoodle_course_url($moodle_course_id, $course_name) { 115 | $course = $moodle_course_id; 116 | $class = "moowoodle"; 117 | $target = '_blank'; 118 | $content = $course_name; 119 | $conn_settings = get_option('moowoodle_general_settings'); 120 | $redirect_uri = $conn_settings['moodle_url'] . "/course/view.php?id=" . $course; 121 | $url = '' . $content . ''; 122 | return $url; 123 | } 124 | /** 125 | * Register 'course' in post DB. 126 | * 127 | * @access private 128 | * @return void 129 | */ 130 | private function register_course_post_type() { 131 | $args = array( 132 | 'labels' => array( 133 | 'name' => sprintf(_x('%s', 'post type general name', 'moowoodle'), $this->labels['plural']), 134 | 'singular_name' => sprintf(_x('%s', 'post type singular name', 'moowoodle'), $this->labels['singular']), 135 | 'add_new' => sprintf(_x('Add New %s', 'course', 'moowoodle'), $this->labels['singular']), 136 | 'add_new_item' => sprintf(__('Add New %s', 'moowoodle'), $this->labels['singular']), 137 | 'edit_item' => sprintf(__('Edit %s', 'moowoodle'), $this->labels['singular']), 138 | 'new_item' => sprintf(__('New %s', 'moowoodle'), $this->labels['singular']), 139 | 'all_items' => sprintf(__('%s', 'moowoodle'), $this->labels['plural']), 140 | 'view_item' => sprintf(__('View %s', 'moowoodle'), $this->labels['singular']), 141 | 'search_items' => sprintf(__('Search %s', 'moowoodle'), $this->labels['plural']), 142 | 'not_found' => sprintf(__('No %s found', 'moowoodle'), strtolower($this->labels['plural'])), 143 | 'not_found_in_trash' => sprintf(__('No %s found in Trash', 'moowoodle'), strtolower($this->labels['plural'])), 144 | ), 145 | 'public' => false, 146 | 'publicly_queryable' => false, 147 | 'show_ui' => true, 148 | 'query_var' => true, 149 | 'rewrite' => true, 150 | 'has_archive' => false, 151 | 'hierarchical' => false, 152 | 'show_in_menu' => false, 153 | 'supports' => array('title', 'editor'), 154 | 'capability_type' => 'post', 155 | 'capabilities' => array('create_posts' => false, 156 | 'delete_posts' => false, 157 | ), 158 | ); 159 | register_post_type('course', $args); 160 | } 161 | /** 162 | * Register 'course_cat' in taxonomy DB. 163 | * 164 | * @access private 165 | * @return void 166 | */ 167 | private function register_course_cat_taxonomy() { 168 | register_taxonomy('course_cat', 'course', 169 | array( 170 | 'labels' => array( 171 | 'name' => sprintf(_x('%s category', 'moowoodle'), $this->labels['singular']), 172 | 'singular_name' => sprintf(_x('%s category', 'moowoodle'), $this->labels['singular']), 173 | 'add_new_item' => sprintf(_x('Add new %s category', 'moowoodle'), $this->labels['singular']), 174 | 'new_item_name' => sprintf(_x('New %s category', 'moowoodle'), $this->labels['singular']), 175 | 'menu_name' => sprintf(_x('%s category', 'moowoodle'), $this->labels['singular']), //'Categories', 176 | 'search_items' => sprintf(_x('Search %s categories', 'moowoodle'), $this->labels['singular']), //'Search Course Categories', 177 | 'all_items' => sprintf(_x('All %s categories', 'moowoodle'), $this->labels['singular']), //'All Course Categories', 178 | 'parent_item' => sprintf(_x('Parent %s category', 'moowoodle'), $this->labels['singular']), //'Parent Course Category', 179 | 'parent_item_colon' => sprintf(_x('Parent %s category', 'moowoodle'), $this->labels['singular']), //'Parent Course Category:', 180 | 'edit_item' => sprintf(_x('Edit %s category', 'moowoodle'), $this->labels['singular']), //'Edit Course Category', 181 | 'update_item' => sprintf(_x('New %s category name', 'moowoodle'), $this->labels['singular']), //'New Course Category Name' 182 | ), 183 | 'show_ui' => false, 184 | 'show_tagcloud' => false, 185 | 'hierarchical' => true, 186 | 'query_var' => true, 187 | ) 188 | ); 189 | } 190 | /** 191 | * Creates custom tab for product types. 192 | * 193 | * @access public 194 | * @param array $product_data_tabs 195 | * @return void 196 | */ 197 | public function moowoodle_linked_course_tab($product_data_tabs) { 198 | $product_data_tabs['moowoodle'] = array( 199 | 'label' => __('Moodle Linked Course', 'moowoodle'), // translatable 200 | 'target' => 'moowoodle_course_link_tab', // translatable 201 | ); 202 | return $product_data_tabs; 203 | } 204 | /** 205 | * Add meta box panal. 206 | * 207 | * @access public 208 | * @return void 209 | */ 210 | public function moowoodle_linked_course_panals() { 211 | global $post; 212 | $linked_course_id = get_post_meta($post->ID, 'linked_course_id', true); 213 | $courses = $this->get_courses(['numberposts' => -1, 'fields' => 'ids']); 214 | ?> 215 | '; 244 | } 245 | /** 246 | * Add meta box panal. 247 | * 248 | * @access public 249 | * @return void 250 | */ 251 | public function product_type_subcription_warning($php_classname, $product_type) { 252 | $active_plugins = (array) get_option('active_plugins', array()); 253 | if (is_multisite()) { 254 | $active_plugins = array_merge($active_plugins, get_site_option('active_sitewide_plugins', array())); 255 | } 256 | 257 | if (in_array('woocommerce-subscriptions/woocommerce-subscriptions.php', $active_plugins) || array_key_exists('woocommerce-product/woocommerce-subscriptions.php', $active_plugins) || in_array('woocommerce-product-bundles/woocommerce-product-bundles.php', $active_plugins) || array_key_exists('woocommerce-product-bundles/woocommerce-product-bundles.php', $active_plugins)) { 258 | add_action('admin_notices', function(){ 259 | if (MOOWOODLE_PRO_ADV) { 260 | echo '

' . __('WooComerce Subbcription and WooComerce Product Bundles is supported only with ', 'moowoodle') . '' . __('MooWoodle Pro', 'moowoodle') . '

'; 261 | } 262 | }); 263 | } 264 | return $php_classname; 265 | } 266 | /** 267 | * Save product meta. 268 | * 269 | * @access public 270 | * @param int $post_id 271 | * @return void 272 | */ 273 | public function save_product_meta_data($post_id) { 274 | // Security check 275 | if (!filter_input(INPUT_POST, 'product_meta_nonce', FILTER_DEFAULT) === null || !wp_verify_nonce(filter_input(INPUT_POST, 'product_meta_nonce', FILTER_DEFAULT)) || !current_user_can('edit_product', $post_id)) { 276 | return $post_id; 277 | } 278 | $course_id = filter_input(INPUT_POST, 'course_id', FILTER_DEFAULT); 279 | if ($course_id) { 280 | update_post_meta($post_id, 'linked_course_id', wp_kses_post($course_id)); 281 | update_post_meta($post_id, '_sku', 'course-' . get_post_meta($course_id, '_sku', true)); 282 | update_post_meta($post_id, 'moodle_course_id', get_post_meta($course_id, 'moodle_course_id', true)); 283 | } 284 | } 285 | /** 286 | * Get All Caurse data. 287 | * @return \WP_Error| \WP_REST_Response 288 | */ 289 | public function fetch_all_courses( $args = [] ) { 290 | // get courses from post 291 | $courses = $this->get_courses($args); 292 | $formatted_courses = []; 293 | foreach ($courses as $course_id) { 294 | // get course all post meta. 295 | $course_meta = array_map('current', get_post_meta($course_id,'',true)); 296 | $course_enddate = $course_meta['_course_enddate']; 297 | //get term object by course category id. 298 | $term = MooWoodle()->Category->get_category($course_meta['_category_id'], 'course_cat'); 299 | $moodle_course_id = $course_meta['moodle_course_id']; 300 | $synced_products = []; 301 | // get all products lincked with course. 302 | $products = get_posts(['post_type' => 'product', 'numberposts' => -1, 'post_status' => 'publish', 'meta_key' => 'linked_course_id', 'meta_value' => $course_id]); 303 | $count_enrolment = 0; 304 | foreach ($products as $product) { 305 | $synced_products[esc_html(get_the_title($product))] = add_query_arg( [ 'post' => $product->ID , 'action' => 'edit'],admin_url('post.php')); 306 | $count_enrolment = $count_enrolment + (int) get_post_meta($product->ID, 'total_sales', true); 307 | } 308 | $date = wp_date('M j, Y', $course_meta['_course_startdate']); 309 | if ($course_enddate) { 310 | $date .= ' - ' . wp_date('M j, Y ', $course_enddate); 311 | } 312 | $formatted_courses[] = [ 313 | 'id' => $course_id, 314 | 'moodle_course_id' => $moodle_course_id, 315 | 'moodle_url' => esc_url(get_option('moowoodle_general_settings')["moodle_url"]) . 'course/edit.php?id=' . $moodle_course_id, 316 | 'course_name' => esc_html(get_the_title($course_id)), 317 | 'course_short_name' => $course_meta['_course_short_name'], 318 | 'product' => $synced_products, 319 | 'catagory_name' => esc_html($term->name), 320 | 'catagory_url' => add_query_arg(['course_cat' => $term->slug, 'post_type' => 'course'], admin_url('edit.php')), 321 | 'enroled_user' => $count_enrolment, 322 | 'date' => $date, 323 | ]; 324 | } 325 | return $formatted_courses; 326 | } 327 | } 328 | -------------------------------------------------------------------------------- /vendor/composer/InstalledVersions.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer; 14 | 15 | use Composer\Autoload\ClassLoader; 16 | use Composer\Semver\VersionParser; 17 | 18 | /** 19 | * This class is copied in every Composer installed project and available to all 20 | * 21 | * See also https://getcomposer.org/doc/07-runtime.md#installed-versions 22 | * 23 | * To require its presence, you can require `composer-runtime-api ^2.0` 24 | * 25 | * @final 26 | */ 27 | class InstalledVersions 28 | { 29 | /** 30 | * @var mixed[]|null 31 | * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null 32 | */ 33 | private static $installed; 34 | 35 | /** 36 | * @var bool|null 37 | */ 38 | private static $canGetVendors; 39 | 40 | /** 41 | * @var array[] 42 | * @psalm-var array}> 43 | */ 44 | private static $installedByVendor = array(); 45 | 46 | /** 47 | * Returns a list of all package names which are present, either by being installed, replaced or provided 48 | * 49 | * @return string[] 50 | * @psalm-return list 51 | */ 52 | public static function getInstalledPackages() 53 | { 54 | $packages = array(); 55 | foreach (self::getInstalled() as $installed) { 56 | $packages[] = array_keys($installed['versions']); 57 | } 58 | 59 | if (1 === \count($packages)) { 60 | return $packages[0]; 61 | } 62 | 63 | return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); 64 | } 65 | 66 | /** 67 | * Returns a list of all package names with a specific type e.g. 'library' 68 | * 69 | * @param string $type 70 | * @return string[] 71 | * @psalm-return list 72 | */ 73 | public static function getInstalledPackagesByType($type) 74 | { 75 | $packagesByType = array(); 76 | 77 | foreach (self::getInstalled() as $installed) { 78 | foreach ($installed['versions'] as $name => $package) { 79 | if (isset($package['type']) && $package['type'] === $type) { 80 | $packagesByType[] = $name; 81 | } 82 | } 83 | } 84 | 85 | return $packagesByType; 86 | } 87 | 88 | /** 89 | * Checks whether the given package is installed 90 | * 91 | * This also returns true if the package name is provided or replaced by another package 92 | * 93 | * @param string $packageName 94 | * @param bool $includeDevRequirements 95 | * @return bool 96 | */ 97 | public static function isInstalled($packageName, $includeDevRequirements = true) 98 | { 99 | foreach (self::getInstalled() as $installed) { 100 | if (isset($installed['versions'][$packageName])) { 101 | return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false; 102 | } 103 | } 104 | 105 | return false; 106 | } 107 | 108 | /** 109 | * Checks whether the given package satisfies a version constraint 110 | * 111 | * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: 112 | * 113 | * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') 114 | * 115 | * @param VersionParser $parser Install composer/semver to have access to this class and functionality 116 | * @param string $packageName 117 | * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package 118 | * @return bool 119 | */ 120 | public static function satisfies(VersionParser $parser, $packageName, $constraint) 121 | { 122 | $constraint = $parser->parseConstraints((string) $constraint); 123 | $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); 124 | 125 | return $provided->matches($constraint); 126 | } 127 | 128 | /** 129 | * Returns a version constraint representing all the range(s) which are installed for a given package 130 | * 131 | * It is easier to use this via isInstalled() with the $constraint argument if you need to check 132 | * whether a given version of a package is installed, and not just whether it exists 133 | * 134 | * @param string $packageName 135 | * @return string Version constraint usable with composer/semver 136 | */ 137 | public static function getVersionRanges($packageName) 138 | { 139 | foreach (self::getInstalled() as $installed) { 140 | if (!isset($installed['versions'][$packageName])) { 141 | continue; 142 | } 143 | 144 | $ranges = array(); 145 | if (isset($installed['versions'][$packageName]['pretty_version'])) { 146 | $ranges[] = $installed['versions'][$packageName]['pretty_version']; 147 | } 148 | if (array_key_exists('aliases', $installed['versions'][$packageName])) { 149 | $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); 150 | } 151 | if (array_key_exists('replaced', $installed['versions'][$packageName])) { 152 | $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); 153 | } 154 | if (array_key_exists('provided', $installed['versions'][$packageName])) { 155 | $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); 156 | } 157 | 158 | return implode(' || ', $ranges); 159 | } 160 | 161 | throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); 162 | } 163 | 164 | /** 165 | * @param string $packageName 166 | * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present 167 | */ 168 | public static function getVersion($packageName) 169 | { 170 | foreach (self::getInstalled() as $installed) { 171 | if (!isset($installed['versions'][$packageName])) { 172 | continue; 173 | } 174 | 175 | if (!isset($installed['versions'][$packageName]['version'])) { 176 | return null; 177 | } 178 | 179 | return $installed['versions'][$packageName]['version']; 180 | } 181 | 182 | throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); 183 | } 184 | 185 | /** 186 | * @param string $packageName 187 | * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present 188 | */ 189 | public static function getPrettyVersion($packageName) 190 | { 191 | foreach (self::getInstalled() as $installed) { 192 | if (!isset($installed['versions'][$packageName])) { 193 | continue; 194 | } 195 | 196 | if (!isset($installed['versions'][$packageName]['pretty_version'])) { 197 | return null; 198 | } 199 | 200 | return $installed['versions'][$packageName]['pretty_version']; 201 | } 202 | 203 | throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); 204 | } 205 | 206 | /** 207 | * @param string $packageName 208 | * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference 209 | */ 210 | public static function getReference($packageName) 211 | { 212 | foreach (self::getInstalled() as $installed) { 213 | if (!isset($installed['versions'][$packageName])) { 214 | continue; 215 | } 216 | 217 | if (!isset($installed['versions'][$packageName]['reference'])) { 218 | return null; 219 | } 220 | 221 | return $installed['versions'][$packageName]['reference']; 222 | } 223 | 224 | throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); 225 | } 226 | 227 | /** 228 | * @param string $packageName 229 | * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. 230 | */ 231 | public static function getInstallPath($packageName) 232 | { 233 | foreach (self::getInstalled() as $installed) { 234 | if (!isset($installed['versions'][$packageName])) { 235 | continue; 236 | } 237 | 238 | return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; 239 | } 240 | 241 | throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); 242 | } 243 | 244 | /** 245 | * @return array 246 | * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} 247 | */ 248 | public static function getRootPackage() 249 | { 250 | $installed = self::getInstalled(); 251 | 252 | return $installed[0]['root']; 253 | } 254 | 255 | /** 256 | * Returns the raw installed.php data for custom implementations 257 | * 258 | * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. 259 | * @return array[] 260 | * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} 261 | */ 262 | public static function getRawData() 263 | { 264 | @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); 265 | 266 | if (null === self::$installed) { 267 | // only require the installed.php file if this file is loaded from its dumped location, 268 | // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 269 | if (substr(__DIR__, -8, 1) !== 'C') { 270 | self::$installed = include __DIR__ . '/installed.php'; 271 | } else { 272 | self::$installed = array(); 273 | } 274 | } 275 | 276 | return self::$installed; 277 | } 278 | 279 | /** 280 | * Returns the raw data of all installed.php which are currently loaded for custom implementations 281 | * 282 | * @return array[] 283 | * @psalm-return list}> 284 | */ 285 | public static function getAllRawData() 286 | { 287 | return self::getInstalled(); 288 | } 289 | 290 | /** 291 | * Lets you reload the static array from another file 292 | * 293 | * This is only useful for complex integrations in which a project needs to use 294 | * this class but then also needs to execute another project's autoloader in process, 295 | * and wants to ensure both projects have access to their version of installed.php. 296 | * 297 | * A typical case would be PHPUnit, where it would need to make sure it reads all 298 | * the data it needs from this class, then call reload() with 299 | * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure 300 | * the project in which it runs can then also use this class safely, without 301 | * interference between PHPUnit's dependencies and the project's dependencies. 302 | * 303 | * @param array[] $data A vendor/composer/installed.php data set 304 | * @return void 305 | * 306 | * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data 307 | */ 308 | public static function reload($data) 309 | { 310 | self::$installed = $data; 311 | self::$installedByVendor = array(); 312 | } 313 | 314 | /** 315 | * @return array[] 316 | * @psalm-return list}> 317 | */ 318 | private static function getInstalled() 319 | { 320 | if (null === self::$canGetVendors) { 321 | self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); 322 | } 323 | 324 | $installed = array(); 325 | 326 | if (self::$canGetVendors) { 327 | foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { 328 | if (isset(self::$installedByVendor[$vendorDir])) { 329 | $installed[] = self::$installedByVendor[$vendorDir]; 330 | } elseif (is_file($vendorDir.'/composer/installed.php')) { 331 | /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ 332 | $required = require $vendorDir.'/composer/installed.php'; 333 | $installed[] = self::$installedByVendor[$vendorDir] = $required; 334 | if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { 335 | self::$installed = $installed[count($installed) - 1]; 336 | } 337 | } 338 | } 339 | } 340 | 341 | if (null === self::$installed) { 342 | // only require the installed.php file if this file is loaded from its dumped location, 343 | // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 344 | if (substr(__DIR__, -8, 1) !== 'C') { 345 | /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ 346 | $required = require __DIR__ . '/installed.php'; 347 | self::$installed = $required; 348 | } else { 349 | self::$installed = array(); 350 | } 351 | } 352 | 353 | if (self::$installed !== array()) { 354 | $installed[] = self::$installed; 355 | } 356 | 357 | return $installed; 358 | } 359 | } 360 | -------------------------------------------------------------------------------- /vendor/composer/ClassLoader.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Autoload; 14 | 15 | /** 16 | * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. 17 | * 18 | * $loader = new \Composer\Autoload\ClassLoader(); 19 | * 20 | * // register classes with namespaces 21 | * $loader->add('Symfony\Component', __DIR__.'/component'); 22 | * $loader->add('Symfony', __DIR__.'/framework'); 23 | * 24 | * // activate the autoloader 25 | * $loader->register(); 26 | * 27 | * // to enable searching the include path (eg. for PEAR packages) 28 | * $loader->setUseIncludePath(true); 29 | * 30 | * In this example, if you try to use a class in the Symfony\Component 31 | * namespace or one of its children (Symfony\Component\Console for instance), 32 | * the autoloader will first look for the class under the component/ 33 | * directory, and it will then fallback to the framework/ directory if not 34 | * found before giving up. 35 | * 36 | * This class is loosely based on the Symfony UniversalClassLoader. 37 | * 38 | * @author Fabien Potencier 39 | * @author Jordi Boggiano 40 | * @see https://www.php-fig.org/psr/psr-0/ 41 | * @see https://www.php-fig.org/psr/psr-4/ 42 | */ 43 | class ClassLoader 44 | { 45 | /** @var \Closure(string):void */ 46 | private static $includeFile; 47 | 48 | /** @var string|null */ 49 | private $vendorDir; 50 | 51 | // PSR-4 52 | /** 53 | * @var array> 54 | */ 55 | private $prefixLengthsPsr4 = array(); 56 | /** 57 | * @var array> 58 | */ 59 | private $prefixDirsPsr4 = array(); 60 | /** 61 | * @var list 62 | */ 63 | private $fallbackDirsPsr4 = array(); 64 | 65 | // PSR-0 66 | /** 67 | * List of PSR-0 prefixes 68 | * 69 | * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2'))) 70 | * 71 | * @var array>> 72 | */ 73 | private $prefixesPsr0 = array(); 74 | /** 75 | * @var list 76 | */ 77 | private $fallbackDirsPsr0 = array(); 78 | 79 | /** @var bool */ 80 | private $useIncludePath = false; 81 | 82 | /** 83 | * @var array 84 | */ 85 | private $classMap = array(); 86 | 87 | /** @var bool */ 88 | private $classMapAuthoritative = false; 89 | 90 | /** 91 | * @var array 92 | */ 93 | private $missingClasses = array(); 94 | 95 | /** @var string|null */ 96 | private $apcuPrefix; 97 | 98 | /** 99 | * @var array 100 | */ 101 | private static $registeredLoaders = array(); 102 | 103 | /** 104 | * @param string|null $vendorDir 105 | */ 106 | public function __construct($vendorDir = null) 107 | { 108 | $this->vendorDir = $vendorDir; 109 | self::initializeIncludeClosure(); 110 | } 111 | 112 | /** 113 | * @return array> 114 | */ 115 | public function getPrefixes() 116 | { 117 | if (!empty($this->prefixesPsr0)) { 118 | return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); 119 | } 120 | 121 | return array(); 122 | } 123 | 124 | /** 125 | * @return array> 126 | */ 127 | public function getPrefixesPsr4() 128 | { 129 | return $this->prefixDirsPsr4; 130 | } 131 | 132 | /** 133 | * @return list 134 | */ 135 | public function getFallbackDirs() 136 | { 137 | return $this->fallbackDirsPsr0; 138 | } 139 | 140 | /** 141 | * @return list 142 | */ 143 | public function getFallbackDirsPsr4() 144 | { 145 | return $this->fallbackDirsPsr4; 146 | } 147 | 148 | /** 149 | * @return array Array of classname => path 150 | */ 151 | public function getClassMap() 152 | { 153 | return $this->classMap; 154 | } 155 | 156 | /** 157 | * @param array $classMap Class to filename map 158 | * 159 | * @return void 160 | */ 161 | public function addClassMap(array $classMap) 162 | { 163 | if ($this->classMap) { 164 | $this->classMap = array_merge($this->classMap, $classMap); 165 | } else { 166 | $this->classMap = $classMap; 167 | } 168 | } 169 | 170 | /** 171 | * Registers a set of PSR-0 directories for a given prefix, either 172 | * appending or prepending to the ones previously set for this prefix. 173 | * 174 | * @param string $prefix The prefix 175 | * @param list|string $paths The PSR-0 root directories 176 | * @param bool $prepend Whether to prepend the directories 177 | * 178 | * @return void 179 | */ 180 | public function add($prefix, $paths, $prepend = false) 181 | { 182 | $paths = (array) $paths; 183 | if (!$prefix) { 184 | if ($prepend) { 185 | $this->fallbackDirsPsr0 = array_merge( 186 | $paths, 187 | $this->fallbackDirsPsr0 188 | ); 189 | } else { 190 | $this->fallbackDirsPsr0 = array_merge( 191 | $this->fallbackDirsPsr0, 192 | $paths 193 | ); 194 | } 195 | 196 | return; 197 | } 198 | 199 | $first = $prefix[0]; 200 | if (!isset($this->prefixesPsr0[$first][$prefix])) { 201 | $this->prefixesPsr0[$first][$prefix] = $paths; 202 | 203 | return; 204 | } 205 | if ($prepend) { 206 | $this->prefixesPsr0[$first][$prefix] = array_merge( 207 | $paths, 208 | $this->prefixesPsr0[$first][$prefix] 209 | ); 210 | } else { 211 | $this->prefixesPsr0[$first][$prefix] = array_merge( 212 | $this->prefixesPsr0[$first][$prefix], 213 | $paths 214 | ); 215 | } 216 | } 217 | 218 | /** 219 | * Registers a set of PSR-4 directories for a given namespace, either 220 | * appending or prepending to the ones previously set for this namespace. 221 | * 222 | * @param string $prefix The prefix/namespace, with trailing '\\' 223 | * @param list|string $paths The PSR-4 base directories 224 | * @param bool $prepend Whether to prepend the directories 225 | * 226 | * @throws \InvalidArgumentException 227 | * 228 | * @return void 229 | */ 230 | public function addPsr4($prefix, $paths, $prepend = false) 231 | { 232 | $paths = (array) $paths; 233 | if (!$prefix) { 234 | // Register directories for the root namespace. 235 | if ($prepend) { 236 | $this->fallbackDirsPsr4 = array_merge( 237 | $paths, 238 | $this->fallbackDirsPsr4 239 | ); 240 | } else { 241 | $this->fallbackDirsPsr4 = array_merge( 242 | $this->fallbackDirsPsr4, 243 | $paths 244 | ); 245 | } 246 | } elseif (!isset($this->prefixDirsPsr4[$prefix])) { 247 | // Register directories for a new namespace. 248 | $length = strlen($prefix); 249 | if ('\\' !== $prefix[$length - 1]) { 250 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); 251 | } 252 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; 253 | $this->prefixDirsPsr4[$prefix] = $paths; 254 | } elseif ($prepend) { 255 | // Prepend directories for an already registered namespace. 256 | $this->prefixDirsPsr4[$prefix] = array_merge( 257 | $paths, 258 | $this->prefixDirsPsr4[$prefix] 259 | ); 260 | } else { 261 | // Append directories for an already registered namespace. 262 | $this->prefixDirsPsr4[$prefix] = array_merge( 263 | $this->prefixDirsPsr4[$prefix], 264 | $paths 265 | ); 266 | } 267 | } 268 | 269 | /** 270 | * Registers a set of PSR-0 directories for a given prefix, 271 | * replacing any others previously set for this prefix. 272 | * 273 | * @param string $prefix The prefix 274 | * @param list|string $paths The PSR-0 base directories 275 | * 276 | * @return void 277 | */ 278 | public function set($prefix, $paths) 279 | { 280 | if (!$prefix) { 281 | $this->fallbackDirsPsr0 = (array) $paths; 282 | } else { 283 | $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; 284 | } 285 | } 286 | 287 | /** 288 | * Registers a set of PSR-4 directories for a given namespace, 289 | * replacing any others previously set for this namespace. 290 | * 291 | * @param string $prefix The prefix/namespace, with trailing '\\' 292 | * @param list|string $paths The PSR-4 base directories 293 | * 294 | * @throws \InvalidArgumentException 295 | * 296 | * @return void 297 | */ 298 | public function setPsr4($prefix, $paths) 299 | { 300 | if (!$prefix) { 301 | $this->fallbackDirsPsr4 = (array) $paths; 302 | } else { 303 | $length = strlen($prefix); 304 | if ('\\' !== $prefix[$length - 1]) { 305 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); 306 | } 307 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; 308 | $this->prefixDirsPsr4[$prefix] = (array) $paths; 309 | } 310 | } 311 | 312 | /** 313 | * Turns on searching the include path for class files. 314 | * 315 | * @param bool $useIncludePath 316 | * 317 | * @return void 318 | */ 319 | public function setUseIncludePath($useIncludePath) 320 | { 321 | $this->useIncludePath = $useIncludePath; 322 | } 323 | 324 | /** 325 | * Can be used to check if the autoloader uses the include path to check 326 | * for classes. 327 | * 328 | * @return bool 329 | */ 330 | public function getUseIncludePath() 331 | { 332 | return $this->useIncludePath; 333 | } 334 | 335 | /** 336 | * Turns off searching the prefix and fallback directories for classes 337 | * that have not been registered with the class map. 338 | * 339 | * @param bool $classMapAuthoritative 340 | * 341 | * @return void 342 | */ 343 | public function setClassMapAuthoritative($classMapAuthoritative) 344 | { 345 | $this->classMapAuthoritative = $classMapAuthoritative; 346 | } 347 | 348 | /** 349 | * Should class lookup fail if not found in the current class map? 350 | * 351 | * @return bool 352 | */ 353 | public function isClassMapAuthoritative() 354 | { 355 | return $this->classMapAuthoritative; 356 | } 357 | 358 | /** 359 | * APCu prefix to use to cache found/not-found classes, if the extension is enabled. 360 | * 361 | * @param string|null $apcuPrefix 362 | * 363 | * @return void 364 | */ 365 | public function setApcuPrefix($apcuPrefix) 366 | { 367 | $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; 368 | } 369 | 370 | /** 371 | * The APCu prefix in use, or null if APCu caching is not enabled. 372 | * 373 | * @return string|null 374 | */ 375 | public function getApcuPrefix() 376 | { 377 | return $this->apcuPrefix; 378 | } 379 | 380 | /** 381 | * Registers this instance as an autoloader. 382 | * 383 | * @param bool $prepend Whether to prepend the autoloader or not 384 | * 385 | * @return void 386 | */ 387 | public function register($prepend = false) 388 | { 389 | spl_autoload_register(array($this, 'loadClass'), true, $prepend); 390 | 391 | if (null === $this->vendorDir) { 392 | return; 393 | } 394 | 395 | if ($prepend) { 396 | self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; 397 | } else { 398 | unset(self::$registeredLoaders[$this->vendorDir]); 399 | self::$registeredLoaders[$this->vendorDir] = $this; 400 | } 401 | } 402 | 403 | /** 404 | * Unregisters this instance as an autoloader. 405 | * 406 | * @return void 407 | */ 408 | public function unregister() 409 | { 410 | spl_autoload_unregister(array($this, 'loadClass')); 411 | 412 | if (null !== $this->vendorDir) { 413 | unset(self::$registeredLoaders[$this->vendorDir]); 414 | } 415 | } 416 | 417 | /** 418 | * Loads the given class or interface. 419 | * 420 | * @param string $class The name of the class 421 | * @return true|null True if loaded, null otherwise 422 | */ 423 | public function loadClass($class) 424 | { 425 | if ($file = $this->findFile($class)) { 426 | $includeFile = self::$includeFile; 427 | $includeFile($file); 428 | 429 | return true; 430 | } 431 | 432 | return null; 433 | } 434 | 435 | /** 436 | * Finds the path to the file where the class is defined. 437 | * 438 | * @param string $class The name of the class 439 | * 440 | * @return string|false The path if found, false otherwise 441 | */ 442 | public function findFile($class) 443 | { 444 | // class map lookup 445 | if (isset($this->classMap[$class])) { 446 | return $this->classMap[$class]; 447 | } 448 | if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { 449 | return false; 450 | } 451 | if (null !== $this->apcuPrefix) { 452 | $file = apcu_fetch($this->apcuPrefix.$class, $hit); 453 | if ($hit) { 454 | return $file; 455 | } 456 | } 457 | 458 | $file = $this->findFileWithExtension($class, '.php'); 459 | 460 | // Search for Hack files if we are running on HHVM 461 | if (false === $file && defined('HHVM_VERSION')) { 462 | $file = $this->findFileWithExtension($class, '.hh'); 463 | } 464 | 465 | if (null !== $this->apcuPrefix) { 466 | apcu_add($this->apcuPrefix.$class, $file); 467 | } 468 | 469 | if (false === $file) { 470 | // Remember that this class does not exist. 471 | $this->missingClasses[$class] = true; 472 | } 473 | 474 | return $file; 475 | } 476 | 477 | /** 478 | * Returns the currently registered loaders keyed by their corresponding vendor directories. 479 | * 480 | * @return array 481 | */ 482 | public static function getRegisteredLoaders() 483 | { 484 | return self::$registeredLoaders; 485 | } 486 | 487 | /** 488 | * @param string $class 489 | * @param string $ext 490 | * @return string|false 491 | */ 492 | private function findFileWithExtension($class, $ext) 493 | { 494 | // PSR-4 lookup 495 | $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; 496 | 497 | $first = $class[0]; 498 | if (isset($this->prefixLengthsPsr4[$first])) { 499 | $subPath = $class; 500 | while (false !== $lastPos = strrpos($subPath, '\\')) { 501 | $subPath = substr($subPath, 0, $lastPos); 502 | $search = $subPath . '\\'; 503 | if (isset($this->prefixDirsPsr4[$search])) { 504 | $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); 505 | foreach ($this->prefixDirsPsr4[$search] as $dir) { 506 | if (file_exists($file = $dir . $pathEnd)) { 507 | return $file; 508 | } 509 | } 510 | } 511 | } 512 | } 513 | 514 | // PSR-4 fallback dirs 515 | foreach ($this->fallbackDirsPsr4 as $dir) { 516 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { 517 | return $file; 518 | } 519 | } 520 | 521 | // PSR-0 lookup 522 | if (false !== $pos = strrpos($class, '\\')) { 523 | // namespaced class name 524 | $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) 525 | . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); 526 | } else { 527 | // PEAR-like class name 528 | $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; 529 | } 530 | 531 | if (isset($this->prefixesPsr0[$first])) { 532 | foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { 533 | if (0 === strpos($class, $prefix)) { 534 | foreach ($dirs as $dir) { 535 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { 536 | return $file; 537 | } 538 | } 539 | } 540 | } 541 | } 542 | 543 | // PSR-0 fallback dirs 544 | foreach ($this->fallbackDirsPsr0 as $dir) { 545 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { 546 | return $file; 547 | } 548 | } 549 | 550 | // PSR-0 include paths. 551 | if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { 552 | return $file; 553 | } 554 | 555 | return false; 556 | } 557 | 558 | /** 559 | * @return void 560 | */ 561 | private static function initializeIncludeClosure() 562 | { 563 | if (self::$includeFile !== null) { 564 | return; 565 | } 566 | 567 | /** 568 | * Scope isolated include. 569 | * 570 | * Prevents access to $this/self from included files. 571 | * 572 | * @param string $file 573 | * @return void 574 | */ 575 | self::$includeFile = \Closure::bind(static function($file) { 576 | include $file; 577 | }, null, null); 578 | } 579 | } 580 | -------------------------------------------------------------------------------- /classes/Library.php: -------------------------------------------------------------------------------- 1 | Pro' : '' ; 5 | public static function get_settings_menu() { 6 | $moowoodle_menu = [ 7 | "moowoodle-all-courses" => ['name' => __("All Courses", 'moowoodle'), 'default_tab' => 'moowoodle-linked-courses'], 8 | "moowoodle-manage-enrolment" => ['name' => __("Manage Enrolment", 'moowoodle') . MOOWOOLE_PRO_STICKER, 'default_tab' => 'moowoodle-manage-enrolment'], 9 | "moowoodle-settings" => ['name' => __("Settings", 'moowoodle'), 'default_tab' => 'moowoodle-general'], 10 | "moowoodle-synchronization" => ['name' => __("Synchronization", 'moowoodle'), 'default_tab' => 'moowoodle-sync-options'], 11 | ]; 12 | return $moowoodle_menu; 13 | } 14 | public static function moowoodle_get_options() { 15 | $user_sync_running_cron_batch = apply_filters('moowoodle_sync_user_corn_info', ''); 16 | $sync_wordpress_users = apply_filters('add_moowoodle_sync_wordpress_users_roles',''); 17 | $conn_settings = get_option('moowoodle_general_settings'); 18 | $url = isset($conn_settings['moodle_url']) ? $conn_settings['moodle_url'] : ''; 19 | $woocom_new_user_mail = 'here!'; 20 | if ($url != null) { 21 | $moodle_tokens_url = ' ' . __('Manage tokens', 'moowoodle') . ''; 22 | $moodle_sso_url = ' ' . __('Moodle', 'moowoodle') . ''; 23 | $moowoodle_sync_setting_url = ' ' . __('Synchronization Settings', 'moowoodle') . ''; 24 | } else { 25 | $moodle_tokens_url = __('Manage tokens', 'moowoodle'); 26 | $moodle_sso_url = __('Moodle', 'moowoodle'); 27 | $moowoodle_sync_setting_url = __('Moodle', 'moowoodle'); 28 | } 29 | $account_menu_array = array(); 30 | $i = 0; 31 | foreach ( wc_get_account_menu_items() as $key => $value) { 32 | $account_menu_array[$i] = $value; 33 | $i++; 34 | } 35 | $moowoodle_options = array( 36 | "moowoodle-all-courses" => array( 37 | "moowoodle-linked-courses" => array( 38 | "label" => __("Moodle Courses", 'moowoodle'), 39 | "font_class" => "dashicons-welcome-learn-more", 40 | "setting" => "moowoodle_course_settings", 41 | "field_types" => array( 42 | "moowoodle-link-course-table" => array( 43 | "type" => "section", 44 | "label" => __("Courses", 'moowoodle'), 45 | ), 46 | "all_course_nolabel" => array( 47 | "type" => "all-course-nolabel", 48 | "label" => __("", 'moowoodle'), 49 | "desc" => __("", 'moowoodle'), 50 | "option_values" => array( 51 | 'Enable' => __('', 'moowoodle'), 52 | ), 53 | ), 54 | ), 55 | ), 56 | ), 57 | "moowoodle-manage-enrolment" => array( 58 | "moowoodle-manage-enrolment" => array( 59 | "label" => __("Enrolment", 'moowoodle'), 60 | "font_class" => "dashicons-analytics", 61 | "setting" => "manage_enrolmente_settings", 62 | "field_types" => array( 63 | "moowoodle-manage-enrolment" => array( 64 | "type" => "section", 65 | "label" => __("All Enrolments", 'moowoodle'), 66 | ), 67 | "manage_enrolment_nolabel" => array( 68 | "type" => "manage-enrolment-nolabel", 69 | "is_pro" => true, 70 | "label" => __("", 'moowoodle'), 71 | "desc" => __("", 'moowoodle'), 72 | "option_values" => array( 73 | 'Enable' => __('', 'moowoodle'), 74 | ), 75 | ), 76 | ), 77 | ), 78 | ), 79 | "moowoodle-settings" => array( 80 | "moowoodle-general" => array( 81 | "label" => __("General", 'moowoodle'), 82 | "font_class" => "dashicons-admin-generic", 83 | "setting" => "moowoodle_general_settings", 84 | "field_types" => array( 85 | "moowoodle-connection" => array( 86 | "type" => "section", 87 | "label" => __("Connection Settings", 'moowoodle'), 88 | ), 89 | "moodle-url" => array( 90 | "type" => "textbox", 91 | 'name' => "moodle_url", 92 | "label" => __("Moodle Site URL", 'moowoodle'), 93 | "desc" => __('Enter the Moodle Site URL', 'moowoodle'), 94 | ), 95 | "moodle-access-token" => array( 96 | "type" => "textbox", 97 | "name" => "moodle_access_token", 98 | "label" => __("Moodle Access Token", 'moowoodle'), 99 | "desc" => __('Enter Moodle Access Token. You can generate the Access Token from - Dashboard => Site administration => Server => Web services => ' . $moodle_tokens_url, 'moowoodle'), 100 | ), 101 | "test-connection" => array( 102 | "type" => "empty-div", 103 | "desc_posi" => "up", 104 | "name" => "test_connection", 105 | "submit_btn_value" => __('Test Connection', 'moowoodle'), 106 | "label" => __("Mooowoodle Test Connection", 'moowoodle'), 107 | "desc" => __("Refer to the", 'moowoodle') . ' ' . esc_html__('setup guide', 'moowoodle') . ' ' . esc_html__('to complete all necessary configurations on the Moodle site, and subsequently, perform a Test Connection to verify the functionality of all services.', 'moowoodle'), 108 | "option_values" => array( 109 | 'Enable' => __('', 'moowoodle'), 110 | ), 111 | ), 112 | "moowoodle-user-information" => array( 113 | "type" => "section", 114 | "label" => __("User Information Exchange Settings", 'moowoodle'), 115 | ), 116 | "update-moodle-user" => array( 117 | "type" => "toggle-checkbox", 118 | "name" => "update_moodle_user", 119 | "label" => __("Force Override Moodle User Profile", 'moowoodle'), 120 | "desc" => __('If enabled, all moodle user\'s profile data (first name, last name, city, address, etc.) will be updated as per their wordpress profile data. Explicitly, for existing user, their data will be overwritten on moodle.', 'moowoodle'), 121 | "option_values" => array( 122 | 'Enable' => __('', 'moowoodle'), 123 | ), 124 | ), 125 | "moowoodle-system-settings" => array( 126 | "type" => "section", 127 | "label" => __("System Settings", 'moowoodle'), 128 | ), 129 | "moodle-timeout" => array( 130 | "type" => "textbox", 131 | "name" => "moodle_timeout", 132 | "label" => __("Timeout", 'moowoodle'), 133 | "desc" => __('Set Curl connection time out in sec.', 'moowoodle'), 134 | ), 135 | "moowoodle-adv-log" => array( 136 | "type" => "toggle-checkbox", 137 | "name" => "moowoodle_adv_log", 138 | "label" => __("Advance Log", 'moowoodle'), 139 | "desc" => __('These setting will record all advanced error informations. Please don\'t Enable it if not required, because it will create a large log file.', 'moowoodle'), 140 | "option_values" => array( 141 | 'Enable' => __('', 'moowoodle'), 142 | ), 143 | ), 144 | ), 145 | ), 146 | "moowoodle-display" => array( 147 | "id" => "moowoodle-display", 148 | "label" => __("Display", 'moowoodle'), 149 | "font_class" => "dashicons-welcome-view-site", 150 | "setting" => "moowoodle_display_settings", 151 | "field_types" => array( 152 | "moowoodle-display" => array( 153 | "type" => "section", 154 | "label" => __("Display Settings", 'moowoodle'), 155 | ), 156 | "start-end-date" => array( 157 | "type" => "toggle-checkbox", 158 | "name" => "start_end_date", 159 | "label" => __("Display Start Date and End Date in Shop Page", 'moowoodle'), 160 | "desc" => __('If enabled display start date and end date in shop page.', 'moowoodle'), 161 | "option_values" => array( 162 | 'Enable' => __('', 'moowoodle'), 163 | ), 164 | ), 165 | "my-courses-priority" => array( 166 | "type" => "select", 167 | "name" => "my_courses_priority", 168 | "label" => __("My Courses Menu Position", 'moowoodle'), 169 | "desc" => __('Select below which menu the My Courses Menu will be displayed', 'moowoodle'), 170 | "option_values" => $account_menu_array, 171 | ), 172 | ), 173 | ), 174 | "moowoodle-SSO" => array( 175 | "is_pro" => true, 176 | "label" => __("SSO ", 'moowoodle'), 177 | "font_class" => "dashicons-admin-multisite", 178 | "setting" => "moowoodle_sso_settings", 179 | "field_types" => array( 180 | "moowoodle-sso" => array( 181 | "type" => "section", 182 | "label" => __("Single Sing On Settings", 'moowoodle'), 183 | ), 184 | "moowoodle-sso-eneble" => array( 185 | "type" => "toggle-checkbox", 186 | 'name' => "moowoodle_sso_eneble", 187 | "is_pro" => true, 188 | "label" => __("Single Sing On", 'moowoodle'), 189 | "desc" => __('If enabled Moodle user\'s will login by WordPress user', 'moowoodle'), 190 | "option_values" => array( 191 | 'Enable' => __('', 'moowoodle'), 192 | ), 193 | ), 194 | "moowoodle-sso-secret-key" => array( 195 | "type" => "textbox", 196 | "name" => "moowoodle_sso_secret_key", 197 | "is_pro" => true, 198 | "copy_text" => "copy", 199 | "label" => __("SSO Secret Key", 'moowoodle'), 200 | "desc" => __('Enter SSO Secret Key it should be same as ' . $moodle_sso_url . ' SSO Secret Key', 'moowoodle'), 201 | ), 202 | ), 203 | ), 204 | "moowoodle-notification" => array( 205 | "is_pro" => true, 206 | "label" => __("Notification ", 'moowoodle'), 207 | "font_class" => "dashicons-bell", 208 | "setting" => "moowoodle_notification_settings", 209 | "field_types" => array( 210 | "moowoodle-notification" => array( 211 | "type" => "section", 212 | "label" => __("Manage Notification", 'moowoodle'), 213 | ), 214 | "moowoodle-create-user-custom-mail-eneble" => array( 215 | "type" => "toggle-checkbox", 216 | 'name' => "moowoodle_create_user_custom_mail", 217 | "is_pro" => true, 218 | "label" => __("Customize New User Registration Email", 'moowoodle'), 219 | "desc" => __('If this option is enabled, default WordPress new user registration emails will be disabled for both admin and user. Our custom New User Registration email will be sent to the newly registered user. You can personalize the content of the MooWoodle New User email from ', 'moowoodle') . $woocom_new_user_mail, 220 | "option_values" => array( 221 | 'Enable' => __('', 'moowoodle'), 222 | ), 223 | ), 224 | ), 225 | ), 226 | "moowoodle-log" => array( 227 | "id" => "moowoodle-log", 228 | "label" => __("Log", 'moowoodle'), 229 | "font_class" => "dashicons-welcome-write-blog", 230 | "setting" => "moowoodle_log", 231 | "field_types" => array( 232 | "moowoodle-log-table" => array( 233 | "type" => "section", 234 | "label" => __("Log", 'moowoodle'), 235 | ), 236 | "log" => array( 237 | "type" => "log", 238 | "label" => __("", 'moowoodle'), 239 | "desc" => __("", 'moowoodle'), 240 | "option_values" => array( 241 | 'Enable' => __('', 'moowoodle'), 242 | ), 243 | ), 244 | ), 245 | ), 246 | ), 247 | "moowoodle-synchronization" => array( 248 | "moowoodle-sync-options" => array( 249 | "label" => __("Synchronization Settings", 'moowoodle'), 250 | "font_class" => "dashicons-admin-links", 251 | "setting" => "moowoodle_synchronize_settings", 252 | "field_types" => array( 253 | "moowoodle-sync-settings" => array( 254 | "type" => "section", 255 | "label" => __("Synchronization Options", 'moowoodle'), 256 | ), 257 | "sync-real-time-user-options" => array( 258 | "type" => "multiple-checkboxs", 259 | "label" => __("Realtime User Sync", 'moowoodle'), 260 | "desc" => __("Activate this feature for effortless user synchronization between Moodle and WordPress. As soon as a new user is added on one platform, our system dynamically syncs their profile to the other, accompanied by email notifications. This ensures users are promptly informed, creating a seamlessly unified experience across both platforms.", 'moowoodle') , 261 | "option_values" => array( 262 | 'Moodle ⇒ WordPress' => array( 263 | "id" => "realtime-sync-moodle-users", 264 | "name" => "realtime_sync_moodle_users", 265 | "desc" => __("", 'moowoodle'), 266 | "is_pro" => true, 267 | ), 268 | 'WordPress ⇒ Moodle' => array( 269 | "id" => "realtime-sync-wordpress-users", 270 | "name" => "realtime_sync_wordpress_users", 271 | "desc" => __("", 'moowoodle'), 272 | "is_pro" => true, 273 | ), 274 | ), 275 | ), 276 | "sync-user-options" => array( 277 | "type" => "multiple-checkboxs", 278 | "label" => __("User Information", 'moowoodle'), 279 | "desc" => __("Determine User Information to Synchronize in Moodle-WordPress User synchronization. Please be aware that this setting does not apply to newly created users.", 'moowoodle'), 280 | "desc_posi" => "up", 281 | "note" => "Note: We're updating the WordPress password hashing method to ensure compatibility with Moodle. Rest assured, no user data is compromised, and this won't impact the login procedure on your site.", 282 | "option_values" => array( 283 | 'First Name' => array( 284 | "id" => "sync-user-first-name", 285 | "name" => "sync_user_first_name", 286 | "desc" => __("", 'moowoodle'), 287 | "is_pro" => true, 288 | ), 289 | 'Last Name' => array( 290 | "id" => "sync-user-last-name", 291 | "name" => "sync_user_last_name", 292 | "desc" => __("", 'moowoodle'), 293 | "is_pro" => true, 294 | ), 295 | 'Username' => array( 296 | "id" => "sync-username", 297 | "name" => "sync_username", 298 | "desc" => __("", 'moowoodle'), 299 | "is_pro" => true, 300 | ), 301 | 'Password' => array( 302 | "id" => "sync-password", 303 | "name" => "sync_password", 304 | "desc" => __("", 'moowoodle'), 305 | "is_pro" => true, 306 | ), 307 | 308 | ), 309 | ), 310 | ), 311 | ), 312 | "moowoodle-sync-now" => array( 313 | "label" => __("Synchronize Now", 'moowoodle'), 314 | "font_class" => "dashicons-admin-links", 315 | "setting" => "moowoodle_synchronize_now", 316 | "field_types" => array( 317 | "moowoodle-sync-now" => array( 318 | "type" => "section", 319 | "label" => __("Synchronize Option", 'moowoodle'), 320 | ), 321 | "sync-all-user-options" => array( 322 | "type" => "select", 323 | "name" => "sync_users_now", 324 | "submit_btn_value" => __('Sync All Users Now', 'moowoodle'), 325 | "label" => __("Existing Users", 'moowoodle'), 326 | "desc" => __("Prior to updating existing user info, you must select the user info to be synchronized at ", 'moowoodle') . $moowoodle_sync_setting_url . __("

While synchronizing user information, we use the email address as the unique identifier for each user. We check the username associated with that email address, and if we find the same username in the other instance but with a different email address, the user's information cannot be synchronized.", 'moowoodle') , 327 | "desc_posi" => "up", 328 | "is_pro" => true, 329 | "option_values" => array( 330 | 'Moodle ⇒ WordPress' => array( 331 | "id" => "sync-moodle-users", 332 | "name" => "sync_moodle_users", 333 | "desc" =>$user_sync_running_cron_batch . __("", 'moowoodle'), 334 | ), 335 | 'WordPress ⇒ Moodle' => array( 336 | "id" => "sync-wordpress-users", 337 | "name" => "sync_wordpress_users", 338 | "desc" => $user_sync_running_cron_batch . $sync_wordpress_users . __("
To update passwords for users created before activating the plugin, they must log into WorPress site to migrate their passwords to the new hashing method. After this step, it will synchronize their passwords from WordPress to Moodle.If the user doesn't log in, all other fields will be synchronized except for the password.", 'moowoodle'), 339 | ), 340 | ), 341 | ), 342 | "sync-course-options" => array( 343 | "type" => "multiple-checkboxs", 344 | "label" => __("Courses", 'moowoodle'), 345 | "name" => "sync_course_now", 346 | "submit_btn_value" => __('Sync Courses Now', 'moowoodle'), 347 | "desc" => __("Choose the category you wish to synchronize from Moodle to your WordPress site. During synchronization, if a course is found deleted in Moodle, it will likewise remove the corresponding course and product data from WordPress.", 'moowoodle'), 348 | "option_values" => array( 349 | 'Moodle Courses' => array( 350 | "id" => "sync-courses", 351 | "name" => "sync_courses", 352 | "desc" => __("This function will retrieve all Moodle course data and synchronize it with the courses listed in WordPress.", 'moowoodle'), 353 | "checked" => "forced", 354 | ), 355 | 'Moodle Course Categories' => array( 356 | "id" => "sync-course-category", 357 | "name" => "sync_courses_category", 358 | "desc" => __("This feature will scan the entire Moodle course category structure and synchronize it with the WordPress category listings.", 'moowoodle'), 359 | ), 360 | 'Create and Update Products' => array( 361 | "id" => "sync-all-product", 362 | "name" => "sync_all_product", 363 | "desc" => __("This feature allows you to update previously created product information using Moodle course data. NOTE: This action will overwrite all existing product details with those from Moodle course details.", 'moowoodle'), 364 | ), 365 | 'Create New Products' => array( 366 | "id" => "sync-new-products", 367 | "name" => "sync_new_products", 368 | "desc" => __("This functionality enables automatic creation of new products based on Moodle course data if they do not already exist in WordPress.", 'moowoodle'), 369 | "is_pro" => true, 370 | ), 371 | 'Update Existing Products' => array( 372 | "id" => "sync-exist-product", 373 | "name" => "sync_exist_product", 374 | "desc" => __("This feature allows you to update previously created product information using Moodle course data. NOTE: This action will overwrite all existing product details with those from Moodle course details.", 'moowoodle'), 375 | "is_pro" => true, 376 | ), 377 | 'Course Images' => array( 378 | "id" => "sync-image", 379 | "name" => "sync_image", 380 | "desc" => __("This function copies course images and sets them as WooCommerce product images.", 'moowoodle'), 381 | "is_pro" => true, 382 | ), 383 | ), 384 | ), 385 | ), 386 | ), 387 | ), 388 | ); 389 | return apply_filters('moowoodle_fileds_options', $moowoodle_options); 390 | } 391 | } 392 | --------------------------------------------------------------------------------