diff --git a/CHANGELOG.md b/CHANGELOG.md index a58a1df09..8b058b8ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines. +## [0.1.45](https://github.com/CodingBlackFemales/wordpress/compare/v0.1.44...v0.1.45) (2026-04-22) + ## [0.1.44](https://github.com/CodingBlackFemales/wordpress/compare/v0.1.43...v0.1.44) (2026-04-20) ## [0.1.43](https://github.com/CodingBlackFemales/wordpress/compare/v0.1.42...v0.1.43) (2026-04-17) diff --git a/composer.json b/composer.json index d2d7c8f0f..922194588 100644 --- a/composer.json +++ b/composer.json @@ -76,6 +76,7 @@ "wp-plugin/code-profiler": "^1.8.2", "wp-plugin/conditional-blocks": "^3.3.1", "wp-plugin/drip": "^1.1.9", + "wp-plugin/easy-table-of-contents": "^2.0", "wp-plugin/facebook-for-woocommerce": "^3.5.15", "wp-plugin/header-footer-code-manager": "^1.1.44", "wp-plugin/import-meetup-events": "^1.6.9", diff --git a/composer.lock b/composer.lock index 78c513127..36b280578 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "938f186d4804aa78b2e97175eb4c8df2", + "content-hash": "0138df2bd02f57736c2b5ad2843a6222", "packages": [ { "name": "aws/aws-crt-php", @@ -62,16 +62,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.379.4", + "version": "3.379.7", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "606d812d3e9289147e2c801d51b916c45c92de39" + "reference": "2c338cb3f2bcb9e8616ffbac7a36d66034f2ceef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/606d812d3e9289147e2c801d51b916c45c92de39", - "reference": "606d812d3e9289147e2c801d51b916c45c92de39", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/2c338cb3f2bcb9e8616ffbac7a36d66034f2ceef", + "reference": "2c338cb3f2bcb9e8616ffbac7a36d66034f2ceef", "shasum": "" }, "require": { @@ -153,9 +153,9 @@ "support": { "forum": "https://github.com/aws/aws-sdk-php/discussions", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.379.4" + "source": "https://github.com/aws/aws-sdk-php/tree/3.379.7" }, - "time": "2026-04-21T20:01:34+00:00" + "time": "2026-04-24T18:17:06+00:00" }, { "name": "composer/installers", @@ -1317,10 +1317,10 @@ }, { "name": "koodimonni-plugin-language/akismet-en_gb", - "version": "5.6", + "version": "5.7", "dist": { "type": "zip", - "url": "https://downloads.wordpress.org/translation/plugin/akismet/5.6/en_GB.zip" + "url": "https://downloads.wordpress.org/translation/plugin/akismet/5.7/en_GB.zip" }, "require": { "koodimonni/composer-dropin-installer": ">=0.2.3" @@ -2011,16 +2011,16 @@ }, { "name": "mck89/peast", - "version": "v1.17.5", + "version": "v1.17.6", "source": { "type": "git", "url": "https://github.com/mck89/peast.git", - "reference": "e19a8bd896b7f04941a38fd38a140c9a6531c84f" + "reference": "b8b4184b1e6912669f9af155caef9050509d9f18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mck89/peast/zipball/e19a8bd896b7f04941a38fd38a140c9a6531c84f", - "reference": "e19a8bd896b7f04941a38fd38a140c9a6531c84f", + "url": "https://api.github.com/repos/mck89/peast/zipball/b8b4184b1e6912669f9af155caef9050509d9f18", + "reference": "b8b4184b1e6912669f9af155caef9050509d9f18", "shasum": "" }, "require": { @@ -2033,7 +2033,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.17.5-dev" + "dev-master": "1.17.6-dev" } }, "autoload": { @@ -2054,9 +2054,9 @@ "description": "Peast is PHP library that generates AST for JavaScript code", "support": { "issues": "https://github.com/mck89/peast/issues", - "source": "https://github.com/mck89/peast/tree/v1.17.5" + "source": "https://github.com/mck89/peast/tree/v1.17.6" }, - "time": "2026-03-15T10:47:07+00:00" + "time": "2026-04-24T08:04:05+00:00" }, { "name": "mtdowling/jmespath.php", @@ -3884,12 +3884,12 @@ "source": { "type": "git", "url": "https://github.com/wp-cli/ai-command.git", - "reference": "370d1b4e75b839791b298b3feeedd8308c75725b" + "reference": "badad2fa92d17b8fb87ed9727db0fcfd08f95d33" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wp-cli/ai-command/zipball/370d1b4e75b839791b298b3feeedd8308c75725b", - "reference": "370d1b4e75b839791b298b3feeedd8308c75725b", + "url": "https://api.github.com/repos/wp-cli/ai-command/zipball/badad2fa92d17b8fb87ed9727db0fcfd08f95d33", + "reference": "badad2fa92d17b8fb87ed9727db0fcfd08f95d33", "shasum": "" }, "require": { @@ -3936,7 +3936,7 @@ "issues": "https://github.com/wp-cli/ai-command/issues", "source": "https://github.com/wp-cli/ai-command/tree/main" }, - "time": "2026-04-20T09:45:39+00:00" + "time": "2026-04-22T08:45:32+00:00" }, { "name": "wp-cli/block-command", @@ -6040,12 +6040,12 @@ "source": { "type": "git", "url": "https://github.com/wp-cli/wp-cli.git", - "reference": "abcfe295c630e44ef7805371464b687225b57a42" + "reference": "43a6ef34888bf07f1a6751423082604343ea7a5b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wp-cli/wp-cli/zipball/abcfe295c630e44ef7805371464b687225b57a42", - "reference": "abcfe295c630e44ef7805371464b687225b57a42", + "url": "https://api.github.com/repos/wp-cli/wp-cli/zipball/43a6ef34888bf07f1a6751423082604343ea7a5b", + "reference": "43a6ef34888bf07f1a6751423082604343ea7a5b", "shasum": "" }, "require": { @@ -6116,7 +6116,7 @@ "issues": "https://github.com/wp-cli/wp-cli/issues", "source": "https://github.com/wp-cli/wp-cli" }, - "time": "2026-04-17T07:15:32+00:00" + "time": "2026-04-22T08:46:30+00:00" }, { "name": "wp-cli/wp-cli-bundle", @@ -6124,12 +6124,12 @@ "source": { "type": "git", "url": "https://github.com/wp-cli/wp-cli-bundle.git", - "reference": "303e528ff821a1cdc558e97dd06f5302785c0a04" + "reference": "3eb2dd73b2974eb6b91ad5cc7ef2f329591d6b36" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wp-cli/wp-cli-bundle/zipball/303e528ff821a1cdc558e97dd06f5302785c0a04", - "reference": "303e528ff821a1cdc558e97dd06f5302785c0a04", + "url": "https://api.github.com/repos/wp-cli/wp-cli-bundle/zipball/3eb2dd73b2974eb6b91ad5cc7ef2f329591d6b36", + "reference": "3eb2dd73b2974eb6b91ad5cc7ef2f329591d6b36", "shasum": "" }, "require": { @@ -6195,7 +6195,7 @@ "issues": "https://github.com/wp-cli/wp-cli-bundle/issues", "source": "https://github.com/wp-cli/wp-cli-bundle" }, - "time": "2026-04-18T06:10:02+00:00" + "time": "2026-04-24T04:17:36+00:00" }, { "name": "wp-cli/wp-config-transformer", @@ -6248,15 +6248,15 @@ }, { "name": "wp-plugin/akismet", - "version": "5.6", + "version": "5.7", "source": { "type": "svn", "url": "https://plugins.svn.wordpress.org/akismet/", - "reference": "tags/5.6" + "reference": "tags/5.7" }, "dist": { "type": "zip", - "url": "https://downloads.wordpress.org/plugin/akismet.5.6.zip" + "url": "https://downloads.wordpress.org/plugin/akismet.5.7.zip" }, "require": { "composer/installers": "~1.0|~2.0" @@ -6275,7 +6275,7 @@ "issues": "https://wordpress.org/support/plugin/akismet", "source": "https://plugins.svn.wordpress.org/akismet" }, - "time": "2026-04-22T02:21:04+00:00" + "time": "2026-04-23T22:36:15+00:00" }, { "name": "wp-plugin/breadcrumb-navxt", @@ -6310,15 +6310,15 @@ }, { "name": "wp-plugin/code-profiler", - "version": "1.9.1", + "version": "1.9.2", "source": { "type": "svn", "url": "https://plugins.svn.wordpress.org/code-profiler/", - "reference": "tags/1.9.1" + "reference": "tags/1.9.2" }, "dist": { "type": "zip", - "url": "https://downloads.wordpress.org/plugin/code-profiler.1.9.1.zip" + "url": "https://downloads.wordpress.org/plugin/code-profiler.1.9.2.zip" }, "require": { "composer/installers": "~1.0|~2.0" @@ -6337,7 +6337,7 @@ "issues": "https://wordpress.org/support/plugin/code-profiler", "source": "https://plugins.svn.wordpress.org/code-profiler" }, - "time": "2026-03-23T19:23:21+00:00" + "time": "2026-04-24T09:51:35+00:00" }, { "name": "wp-plugin/conditional-blocks", @@ -6400,6 +6400,37 @@ }, "time": "2026-03-23T19:23:21+00:00" }, + { + "name": "wp-plugin/easy-table-of-contents", + "version": "2.0.82.2", + "source": { + "type": "svn", + "url": "https://plugins.svn.wordpress.org/easy-table-of-contents/", + "reference": "tags/2.0.82.2" + }, + "dist": { + "type": "zip", + "url": "https://downloads.wordpress.org/plugin/easy-table-of-contents.2.0.82.2.zip" + }, + "require": { + "composer/installers": "~1.0|~2.0" + }, + "type": "wordpress-plugin", + "notification-url": "https://wp-packages.org/downloads", + "authors": [ + { + "name": "Magazine3" + } + ], + "description": "Adds a user friendly and fully automatic way to create and display a table of contents generated from the page content.", + "homepage": "https://tocwp.com/", + "support": { + "changelog": "https://wordpress.org/plugins/easy-table-of-contents/#developers", + "issues": "https://wordpress.org/support/plugin/easy-table-of-contents", + "source": "https://plugins.svn.wordpress.org/easy-table-of-contents" + }, + "time": "2026-03-26T06:55:40+00:00" + }, { "name": "wp-plugin/facebook-for-woocommerce", "version": "3.6.3", @@ -6680,15 +6711,15 @@ }, { "name": "wp-plugin/otter-blocks", - "version": "3.1.8", + "version": "3.1.9", "source": { "type": "svn", "url": "https://plugins.svn.wordpress.org/otter-blocks/", - "reference": "tags/3.1.8" + "reference": "tags/3.1.9" }, "dist": { "type": "zip", - "url": "https://downloads.wordpress.org/plugin/otter-blocks.3.1.8.zip" + "url": "https://downloads.wordpress.org/plugin/otter-blocks.3.1.9.zip" }, "require": { "composer/installers": "~1.0|~2.0" @@ -6707,7 +6738,7 @@ "issues": "https://wordpress.org/support/plugin/otter-blocks", "source": "https://plugins.svn.wordpress.org/otter-blocks" }, - "time": "2026-04-01T13:11:04+00:00" + "time": "2026-04-24T12:05:37+00:00" }, { "name": "wp-plugin/pdf-embedder", @@ -6959,15 +6990,15 @@ }, { "name": "wp-plugin/woocommerce-gateway-stripe", - "version": "10.6.0", + "version": "10.6.1", "source": { "type": "svn", "url": "https://plugins.svn.wordpress.org/woocommerce-gateway-stripe/", - "reference": "tags/10.6.0" + "reference": "tags/10.6.1" }, "dist": { "type": "zip", - "url": "https://downloads.wordpress.org/plugin/woocommerce-gateway-stripe.10.6.0.zip" + "url": "https://downloads.wordpress.org/plugin/woocommerce-gateway-stripe.10.6.1.zip" }, "require": { "composer/installers": "~1.0|~2.0" @@ -6986,7 +7017,7 @@ "issues": "https://wordpress.org/support/plugin/woocommerce-gateway-stripe", "source": "https://plugins.svn.wordpress.org/woocommerce-gateway-stripe" }, - "time": "2026-04-21T18:40:50+00:00" + "time": "2026-04-23T11:21:08+00:00" }, { "name": "wp-plugin/woocommerce-paypal-payments", @@ -7052,15 +7083,15 @@ }, { "name": "wp-plugin/wp-graphql", - "version": "2.11.2", + "version": "2.12.0", "source": { "type": "svn", "url": "https://plugins.svn.wordpress.org/wp-graphql/", - "reference": "tags/2.11.2" + "reference": "tags/2.12.0" }, "dist": { "type": "zip", - "url": "https://downloads.wordpress.org/plugin/wp-graphql.2.11.2.zip" + "url": "https://downloads.wordpress.org/plugin/wp-graphql.2.12.0.zip" }, "require": { "composer/installers": "~1.0|~2.0" @@ -7079,7 +7110,7 @@ "issues": "https://wordpress.org/support/plugin/wp-graphql", "source": "https://plugins.svn.wordpress.org/wp-graphql" }, - "time": "2026-04-13T18:10:57+00:00" + "time": "2026-04-23T21:16:09+00:00" }, { "name": "wp-plugin/wp-job-manager", @@ -8047,12 +8078,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "f41f65e527608a9a76cfbafd873756ed76c5452d" + "reference": "08cd07f04fb07fb4d316e956801d57b700cf7096" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/f41f65e527608a9a76cfbafd873756ed76c5452d", - "reference": "f41f65e527608a9a76cfbafd873756ed76c5452d", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/08cd07f04fb07fb4d316e956801d57b700cf7096", + "reference": "08cd07f04fb07fb4d316e956801d57b700cf7096", "shasum": "" }, "conflict": { @@ -8075,6 +8106,7 @@ "alextselegidis/easyappointments": "<=1.5.2", "alexusmai/laravel-file-manager": "<=3.3.1", "algolia/algoliasearch-magento-2": "<=3.16.1|>=3.17.0.0-beta1,<=3.17.1", + "almirhodzic/nova-toggle-5": "<1.3", "alt-design/alt-redirect": "<1.6.4", "altcha-org/altcha": "<1.3.1", "alterphp/easyadmin-extension-bundle": ">=1.2,<1.2.11|>=1.3,<1.3.1", @@ -8166,12 +8198,12 @@ "cesnet/simplesamlphp-module-proxystatistics": "<3.1", "chriskacerguis/codeigniter-restserver": "<=2.7.1", "chrome-php/chrome": "<1.14", - "ci4-cms-erp/ci4ms": "<=0.31.3", + "ci4-cms-erp/ci4ms": "<0.31.5", "civicrm/civicrm-core": ">=4.2,<4.2.9|>=4.3,<4.3.3", "ckeditor/ckeditor": "<4.25", "clickstorm/cs-seo": ">=6,<6.8|>=7,<7.5|>=8,<8.4|>=9,<9.3", "co-stack/fal_sftp": "<0.2.6", - "cockpit-hq/cockpit": "<2.13.5", + "cockpit-hq/cockpit": "<2.14", "code16/sharp": "<9.20", "codeception/codeception": "<3.1.3|>=4,<4.1.22", "codeigniter/framework": "<3.1.10", @@ -8334,7 +8366,7 @@ "fisharebest/webtrees": "<=2.1.18", "fixpunkt/fp-masterquiz": "<2.2.1|>=3,<3.5.2", "fixpunkt/fp-newsletter": "<1.1.1|>=1.2,<2.1.2|>=2.2,<3.2.6", - "flarum/core": "<1.8.10", + "flarum/core": "<=1.8.15|>=2.0.0.0-beta1,<=2.0.0.0-beta8", "flarum/flarum": "<0.1.0.0-beta8", "flarum/framework": "<1.8.10", "flarum/mentions": "<1.6.3", @@ -8371,7 +8403,7 @@ "geshi/geshi": "<=1.0.9.1", "getformwork/formwork": "<=2.3.3", "getgrav/grav": "<1.11.0.0-beta1", - "getkirby/cms": "<=5.2.1", + "getkirby/cms": "<5.4", "getkirby/kirby": "<3.9.8.3-dev|>=3.10,<3.10.1.2-dev|>=4,<4.7.1", "getkirby/panel": "<2.5.14", "getkirby/starterkit": "<=3.7.0.2", @@ -8469,7 +8501,7 @@ "kelvinmo/simplexrd": "<3.1.1", "kevinpapst/kimai2": "<1.16.7", "khodakhah/nodcms": "<=3.4.1", - "kimai/kimai": "<=2.53", + "kimai/kimai": "<2.54", "kitodo/presentation": "<3.2.3|>=3.3,<3.3.4", "klaviyo/magento2-extension": ">=1,<3", "knplabs/knp-snappy": "<=1.4.2", @@ -8913,7 +8945,7 @@ "twig/twig": "<3.11.2|>=3.12,<3.14.1|>=3.16,<3.19", "typicms/core": "<16.1.7", "typo3/cms": "<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2", - "typo3/cms-backend": "<4.1.14|>=4.2,<4.2.15|>=4.3,<4.3.7|>=4.4,<4.4.4|>=7,<=7.6.50|>=8,<=8.7.39|>=9,<9.5.55|>=10,<=10.4.54|>=11,<=11.5.48|>=12,<=12.4.40|>=13,<=13.4.22|>=14,<=14.0.1", + "typo3/cms-backend": "<4.1.14|>=4.2,<4.2.15|>=4.3,<4.3.7|>=4.4,<4.4.4|>=7,<=7.6.50|>=8,<=8.7.39|>=9,<9.5.55|>=10,<=10.4.54|>=11,<=11.5.48|>=12,<=12.4.40|>=13,<=13.4.22|>=14,<=14.0.1|==14.2", "typo3/cms-belog": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", "typo3/cms-beuser": ">=9,<9.5.55|>=10,<10.4.54|>=11,<11.5.48|>=12,<12.4.37|>=13,<13.4.18", "typo3/cms-core": "<=8.7.56|>=9,<9.5.55|>=10,<=10.4.54|>=11,<=11.5.48|>=12,<=12.4.40|>=13,<=13.4.22|>=14,<=14.0.1", @@ -9095,7 +9127,7 @@ "type": "tidelift" } ], - "time": "2026-04-21T17:25:01+00:00" + "time": "2026-04-24T17:22:29+00:00" }, { "name": "slevomat/coding-standard", @@ -9690,12 +9722,12 @@ "source": { "type": "git", "url": "https://github.com/WordPress/WordPress-Coding-Standards.git", - "reference": "5196e8683358d41f8751f9485e2699b2ec5c02d3" + "reference": "1f6e18395c227a5f56306b1fc893cb60bacdc720" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/5196e8683358d41f8751f9485e2699b2ec5c02d3", - "reference": "5196e8683358d41f8751f9485e2699b2ec5c02d3", + "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/1f6e18395c227a5f56306b1fc893cb60bacdc720", + "reference": "1f6e18395c227a5f56306b1fc893cb60bacdc720", "shasum": "" }, "require": { @@ -9749,7 +9781,7 @@ "type": "custom" } ], - "time": "2026-04-21T06:00:44+00:00" + "time": "2026-04-23T14:13:38+00:00" } ], "aliases": [], diff --git a/package-lock.json b/package-lock.json index 27c862f82..28a18735e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cbf-wordpress", - "version": "0.1.44", + "version": "0.1.45", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cbf-wordpress", - "version": "0.1.44", + "version": "0.1.45", "devDependencies": { "@commitlint/cli": "^19.0", "@commitlint/config-conventional": "^19.0", diff --git a/package.json b/package.json index c0b2ab5d2..2a99ad139 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cbf-wordpress", - "version": "0.1.44", + "version": "0.1.45", "description": "[![Packagist](https://img.shields.io/packagist/v/roots/bedrock.svg?style=flat-square)](https://packagist.org/packages/roots/bedrock) [![Build Status](https://img.shields.io/travis/roots/bedrock.svg?style=flat-square)](https://travis-ci.org/roots/bedrock)", "devDependencies": { "@commitlint/cli": "^19.0", diff --git a/web/app/plugins/ld-content-cloner/LICENSE.txt b/web/app/plugins/ld-content-cloner/LICENSE.txt deleted file mode 100644 index ecbc05937..000000000 --- a/web/app/plugins/ld-content-cloner/LICENSE.txt +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. \ No newline at end of file diff --git a/web/app/plugins/ld-content-cloner/admin/class-ldcc-admin.php b/web/app/plugins/ld-content-cloner/admin/class-ldcc-admin.php deleted file mode 100644 index 9720cd51f..000000000 --- a/web/app/plugins/ld-content-cloner/admin/class-ldcc-admin.php +++ /dev/null @@ -1,214 +0,0 @@ - - */ - -namespace LDCC_Admin; - -/** - * This class is used to implement the admin functionality of the plugin. - */ -class LDCC_Admin { - - - /** - * The ID of this plugin. - * - * @since 1.0.0 - * @access private - * @var string $plugin_name The ID of this plugin. - */ - private $plugin_name; - - /** - * The version of this plugin. - * - * @since 1.0.0 - * @access private - * @var string $version The current version of this plugin. - */ - private $version; - - /** - * Initialize the class and set its properties. - * - * @since 1.0.0 - * @param string $plugin_name The name of this plugin. - * @param string $version The version of this plugin. - */ - public function __construct( $plugin_name, $version ) { - $this->plugin_name = $plugin_name; - $this->version = $version; - } - - /** - * Register the stylesheets for the admin area. - * - * @since 1.0.0 - */ - public function enqueue_styles() { - - /** - * This function is provided for demonstration purposes only. - * - * An instance of this class should be passed to the run() function - * defined in Ld_Content_Cloner_Loader as all of the hooks are defined - * in that particular class. - * - * The Ld_Content_Cloner_Loader will then create the relationship - * between the defined hooks and the functions defined in this - * class. - */ - - global $current_screen; - - wp_register_style( - 'ldbr-bootstrap-css', - plugin_dir_url( __FILE__ ) . 'css/bootstrap.min.css', - array(), - $this->version, - 'all' - ); - if ( isset( $current_screen ) && 'edit' === $current_screen->base && in_array( $current_screen->id, array( 'edit-sfwd-courses', 'edit-groups' ), true ) ) { - wp_enqueue_style( - $this->plugin_name, - plugin_dir_url( __FILE__ ) . 'css/ld-content-cloner-admin.css', - array(), - $this->version, - 'all' - ); - - wp_enqueue_style( - $this->plugin_name . 'jquery-ui', - plugin_dir_url( __FILE__ ) . 'css/jquery-ui.min.css', - array(), - $this->version, - 'all' - ); - - wp_enqueue_style( - $this->plugin_name . 'jquery-ui-structure', - plugin_dir_url( __FILE__ ) . 'css/jquery-ui.structure.min.css', - array(), - $this->version, - 'all' - ); - - wp_enqueue_style( - $this->plugin_name . 'jquery-ui-theme', - plugin_dir_url( __FILE__ ) . 'css/jquery-ui.theme.min.css', - array(), - $this->version, - 'all' - ); - wp_enqueue_style( 'ldbr-bootstrap-css' ); - } - if ( isset( $current_screen ) && sanitize_title( __( 'LearnDash LMS', 'learndash' ) ) . '_page_learndash-course-bulk-rename' === $current_screen->id ) { - wp_enqueue_style( - 'ldbr-admin-css', - plugin_dir_url( __FILE__ ) . 'css/ldbr-admin.css', - array(), - $this->version, - 'all' - ); - wp_enqueue_style( 'ldbr-bootstrap-css' ); - } - } - - /** - * Register the JavaScript for the admin area. - * - * @since 1.0.0 - */ - public function enqueue_scripts() { - - /** - * This function is provided for demonstration purposes only. - * - * An instance of this class should be passed to the run() function - * defined in Ld_Content_Cloner_Loader as all of the hooks are defined - * in that particular class. - * - * The Ld_Content_Cloner_Loader will then create the relationship - * between the defined hooks and the functions defined in this - * class. - */ - global $current_screen; - - wp_register_script( - 'ldbr-bootstrap-js', - plugin_dir_url( __FILE__ ) . 'js/bootstrap.min.js', - array( 'jquery' ), - $this->version, - false - ); - if ( isset( $current_screen ) && 'edit' === $current_screen->base && in_array( $current_screen->id, array( 'edit-sfwd-courses', 'edit-groups' ), true ) ) { - wp_enqueue_script( - $this->plugin_name, - plugin_dir_url( __FILE__ ) . 'js/ld-content-cloner-admin.js', - array( 'jquery' ), - $this->version, - false - ); - - wp_enqueue_script( 'jquery-ui-core' ); - - wp_enqueue_script( 'jquery-ui-dialog' ); - - $ld_builder_settings = array(); - if ( class_exists( '\LearnDash_Settings_Section' ) ) { - $ld_builder_settings = array( - 'shared_steps_course' => \LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Courses_Builder', 'shared_steps' ), - 'course_builder' => \LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Courses_Builder', 'enabled' ), - 'shared_steps_quiz' => \LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Quizzes_Builder', 'shared_questions' ), - 'quiz_builder' => \LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Quizzes_Builder', 'enabled' ), - ); - } - - wp_localize_script( - $this->plugin_name, - 'ldcc_js_data', - array( - 'adm_ajax_url' => admin_url( 'admin-ajax.php' ), - 'adm_post_url' => admin_url( 'post.php' ), - 'adm_ldbr_url' => admin_url( 'admin.php?page=learndash-course-bulk-rename' ), - 'image_base_url' => plugin_dir_url( __FILE__ ) . 'images/', - 'ld_builder_settings' => $ld_builder_settings, - 'course_label' => \LearnDash_Custom_Label::get_label( 'course' ), - 'lesson_label' => \LearnDash_Custom_Label::get_label( 'lesson' ), - 'topic_label' => \LearnDash_Custom_Label::get_label( 'topic' ), - 'quiz_label' => \LearnDash_Custom_Label::get_label( 'quiz' ), - 'no_content_text' => sprintf( __( 'No content in %s. %s duplication complete.', 'ld-content-cloner' ), \LearnDash_Custom_Label::label_to_lower( 'course' ), \LearnDash_Custom_Label::get_label( 'course' ) ) - ) - ); - wp_enqueue_script( 'ldbr-bootstrap-js' ); - } - - if ( isset( $current_screen ) && sanitize_title( __( 'LearnDash LMS', 'learndash' ) ) . '_page_learndash-course-bulk-rename' === $current_screen->id ) { - wp_enqueue_script( - 'ldbr-admin-js', - plugin_dir_url( __FILE__ ) . 'js/ldbr-admin.js', - array( 'jquery' ), - $this->version, - false - ); - - wp_localize_script( - 'ldbr-admin-js', - 'ldbr_js_data', - array( - 'adm_ajax_url' => admin_url( 'admin-ajax.php' ), - 'image_base_url' => plugin_dir_url( __FILE__ ) . 'images/', - ) - ); - wp_enqueue_script( 'ldbr-bootstrap-js' ); - } - } -} diff --git a/web/app/plugins/ld-content-cloner/admin/css/bootstrap.min.css b/web/app/plugins/ld-content-cloner/admin/css/bootstrap.min.css deleted file mode 100644 index b21d2fb13..000000000 --- a/web/app/plugins/ld-content-cloner/admin/css/bootstrap.min.css +++ /dev/null @@ -1,6 +0,0 @@ -@charset "UTF-8";/*! - * Bootstrap v5.0.2 (https://getbootstrap.com/) - * Copyright 2011-2021 The Bootstrap Authors - * Copyright 2011-2021 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0))}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-font-sans-serif);font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:#6c757d}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{width:100%;padding-right:var(--bs-gutter-x,.75rem);padding-left:var(--bs-gutter-x,.75rem);margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(var(--bs-gutter-y) * -1);margin-right:calc(var(--bs-gutter-x) * -.5);margin-left:calc(var(--bs-gutter-x) * -.5)}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0%}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.6666666667%}@media (min-width:576px){.col-sm{flex:1 0 0%}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.6666666667%}}@media (min-width:768px){.col-md{flex:1 0 0%}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.6666666667%}}@media (min-width:992px){.col-lg{flex:1 0 0%}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.6666666667%}}@media (min-width:1200px){.col-xl{flex:1 0 0%}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.6666666667%}}@media (min-width:1400px){.col-xxl{flex:1 0 0%}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.6666666667%}}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}.g-0,.gx-0{--bs-gutter-x:0}.g-0,.gy-0{--bs-gutter-y:0}.g-1,.gx-1{--bs-gutter-x:0.25rem}.g-1,.gy-1{--bs-gutter-y:0.25rem}.g-2,.gx-2{--bs-gutter-x:0.5rem}.g-2,.gy-2{--bs-gutter-y:0.5rem}.g-3,.gx-3{--bs-gutter-x:1rem}.g-3,.gy-3{--bs-gutter-y:1rem}.g-4,.gx-4{--bs-gutter-x:1.5rem}.g-4,.gy-4{--bs-gutter-y:1.5rem}.g-5,.gx-5{--bs-gutter-x:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}@media (min-width:576px){.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x:0}.g-sm-0,.gy-sm-0{--bs-gutter-y:0}.g-sm-1,.gx-sm-1{--bs-gutter-x:0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y:0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x:0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y:0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x:1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y:1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x:1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y:1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}}@media (min-width:768px){.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x:0}.g-md-0,.gy-md-0{--bs-gutter-y:0}.g-md-1,.gx-md-1{--bs-gutter-x:0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y:0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x:0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y:0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x:1rem}.g-md-3,.gy-md-3{--bs-gutter-y:1rem}.g-md-4,.gx-md-4{--bs-gutter-x:1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y:1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}}@media (min-width:992px){.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x:0}.g-lg-0,.gy-lg-0{--bs-gutter-y:0}.g-lg-1,.gx-lg-1{--bs-gutter-x:0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y:0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x:0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y:0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x:1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y:1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x:1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y:1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}}@media (min-width:1200px){.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x:0}.g-xl-0,.gy-xl-0{--bs-gutter-y:0}.g-xl-1,.gx-xl-1{--bs-gutter-x:0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y:0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x:0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y:0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x:1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y:1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x:1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y:1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}}@media (min-width:1400px){.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.33333333%}.offset-xxl-2{margin-left:16.66666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.33333333%}.offset-xxl-5{margin-left:41.66666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.33333333%}.offset-xxl-8{margin-left:66.66666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.33333333%}.offset-xxl-11{margin-left:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x:0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y:0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x:0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y:0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x:0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y:0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x:1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y:1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x:1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y:1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}}.table{--bs-table-bg:transparent;--bs-table-accent-bg:transparent;--bs-table-striped-color:#212529;--bs-table-striped-bg:rgba(0, 0, 0, 0.05);--bs-table-active-color:#212529;--bs-table-active-bg:rgba(0, 0, 0, 0.1);--bs-table-hover-color:#212529;--bs-table-hover-bg:rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;color:#212529;vertical-align:top;border-color:#dee2e6}.table>:not(caption)>*>*{padding:.5rem .5rem;background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-accent-bg)}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table>:not(:last-child)>:last-child>*{border-bottom-color:currentColor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:1px 0}.table-bordered>:not(caption)>*>*{border-width:0 1px}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-striped>tbody>tr:nth-of-type(odd){--bs-table-accent-bg:var(--bs-table-striped-bg);color:var(--bs-table-striped-color)}.table-active{--bs-table-accent-bg:var(--bs-table-active-bg);color:var(--bs-table-active-color)}.table-hover>tbody>tr:hover{--bs-table-accent-bg:var(--bs-table-hover-bg);color:var(--bs-table-hover-color)}.table-primary{--bs-table-bg:#cfe2ff;--bs-table-striped-bg:#c5d7f2;--bs-table-striped-color:#000;--bs-table-active-bg:#bacbe6;--bs-table-active-color:#000;--bs-table-hover-bg:#bfd1ec;--bs-table-hover-color:#000;color:#000;border-color:#bacbe6}.table-secondary{--bs-table-bg:#e2e3e5;--bs-table-striped-bg:#d7d8da;--bs-table-striped-color:#000;--bs-table-active-bg:#cbccce;--bs-table-active-color:#000;--bs-table-hover-bg:#d1d2d4;--bs-table-hover-color:#000;color:#000;border-color:#cbccce}.table-success{--bs-table-bg:#d1e7dd;--bs-table-striped-bg:#c7dbd2;--bs-table-striped-color:#000;--bs-table-active-bg:#bcd0c7;--bs-table-active-color:#000;--bs-table-hover-bg:#c1d6cc;--bs-table-hover-color:#000;color:#000;border-color:#bcd0c7}.table-info{--bs-table-bg:#cff4fc;--bs-table-striped-bg:#c5e8ef;--bs-table-striped-color:#000;--bs-table-active-bg:#badce3;--bs-table-active-color:#000;--bs-table-hover-bg:#bfe2e9;--bs-table-hover-color:#000;color:#000;border-color:#badce3}.table-warning{--bs-table-bg:#fff3cd;--bs-table-striped-bg:#f2e7c3;--bs-table-striped-color:#000;--bs-table-active-bg:#e6dbb9;--bs-table-active-color:#000;--bs-table-hover-bg:#ece1be;--bs-table-hover-color:#000;color:#000;border-color:#e6dbb9}.table-danger{--bs-table-bg:#f8d7da;--bs-table-striped-bg:#eccccf;--bs-table-striped-color:#000;--bs-table-active-bg:#dfc2c4;--bs-table-active-color:#000;--bs-table-hover-bg:#e5c7ca;--bs-table-hover-color:#000;color:#000;border-color:#dfc2c4}.table-light{--bs-table-bg:#f8f9fa;--bs-table-striped-bg:#ecedee;--bs-table-striped-color:#000;--bs-table-active-bg:#dfe0e1;--bs-table-active-color:#000;--bs-table-hover-bg:#e5e6e7;--bs-table-hover-color:#000;color:#000;border-color:#dfe0e1}.table-dark{--bs-table-bg:#212529;--bs-table-striped-bg:#2c3034;--bs-table-striped-color:#fff;--bs-table-active-bg:#373b3e;--bs-table-active-color:#fff;--bs-table-hover-bg:#323539;--bs-table-hover-color:#fff;color:#fff;border-color:#373b3e}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width:575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:#6c757d}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:#212529;background-color:#fff;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{height:1.5em}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}.form-control::file-selector-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:#dde0e3}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:#dde0e3}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + (.5rem + 2px));padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + (1rem + 2px));padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + (.75rem + 2px))}textarea.form-control-sm{min-height:calc(1.5em + (.5rem + 2px))}textarea.form-control-lg{min-height:calc(1.5em + (1rem + 2px))}.form-control-color{max-width:3rem;height:auto;padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{height:1.5em;border-radius:.25rem}.form-control-color::-webkit-color-swatch{height:1.5em;border-radius:.25rem}.form-select{display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;-moz-padding-start:calc(0.75rem - 3px);font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:#e9ecef}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #212529}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-input{width:1em;height:1em;margin-top:.25em;vertical-align:top;background-color:#fff;background-repeat:no-repeat;background-position:center;background-size:contain;border:1px solid rgba(0,0,0,.25);-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-print-color-adjust:exact;color-adjust:exact}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{width:2em;margin-left:-2.5em;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check:disabled+.btn,.btn-check[disabled]+.btn{pointer-events:none;filter:none;opacity:.65}.form-range{width:100%;height:1.5rem;padding:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#0d6efd;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#0d6efd;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-range::-moz-range-thumb{-moz-transition:none;transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.form-range:disabled::-moz-range-thumb{background-color:#adb5bd}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-select{height:calc(3.5rem + 2px);line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;height:100%;padding:1rem .75rem;pointer-events:none;border:1px solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion:reduce){.form-floating>label{transition:none}}.form-floating>.form-control{padding:1rem .75rem}.form-floating>.form-control::-moz-placeholder{color:transparent}.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control:not(:-moz-placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:not(:-moz-placeholder-shown)~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:-webkit-autofill~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus{z-index:3}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:3}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-lg>.btn,.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.input-group-sm>.btn,.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu){border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:-1px;border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:#198754}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:rgba(25,135,84,.9);border-radius:.25rem}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:#198754;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-valid,.was-validated .form-select:valid{border-color:#198754}.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"],.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-valid:focus,.was-validated .form-select:valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.form-check-input.is-valid,.was-validated .form-check-input:valid{border-color:#198754}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:#198754}.form-check-input.is-valid:focus,.was-validated .form-check-input:valid:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#198754}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.input-group .form-control.is-valid,.input-group .form-select.is-valid,.was-validated .input-group .form-control:valid,.was-validated .input-group .form-select:valid{z-index:1}.input-group .form-control.is-valid:focus,.input-group .form-select.is-valid:focus,.was-validated .input-group .form-control:valid:focus,.was-validated .input-group .form-select:valid:focus{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:rgba(220,53,69,.9);border-radius:.25rem}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:#dc3545;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-invalid,.was-validated .form-select:invalid{border-color:#dc3545}.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"],.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-invalid:focus,.was-validated .form-select:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.form-check-input.is-invalid,.was-validated .form-check-input:invalid{border-color:#dc3545}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:#dc3545}.form-check-input.is-invalid:focus,.was-validated .form-check-input:invalid:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.input-group .form-control.is-invalid,.input-group .form-select.is-invalid,.was-validated .input-group .form-control:invalid,.was-validated .input-group .form-select:invalid{z-index:2}.input-group .form-control.is-invalid:focus,.input-group .form-select.is-invalid:focus,.was-validated .input-group .form-control:invalid:focus,.was-validated .input-group .form-select:invalid:focus{z-index:3}.btn{display:inline-block;font-weight:400;line-height:1.5;color:#212529;text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:#212529}.btn-check:focus+.btn,.btn:focus{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.btn.disabled,.btn:disabled,fieldset:disabled .btn{pointer-events:none;opacity:.65}.btn-primary{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-primary:hover{color:#fff;background-color:#0b5ed7;border-color:#0a58ca}.btn-check:focus+.btn-primary,.btn-primary:focus{color:#fff;background-color:#0b5ed7;border-color:#0a58ca;box-shadow:0 0 0 .25rem rgba(49,132,253,.5)}.btn-check:active+.btn-primary,.btn-check:checked+.btn-primary,.btn-primary.active,.btn-primary:active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0a58ca;border-color:#0a53be}.btn-check:active+.btn-primary:focus,.btn-check:checked+.btn-primary:focus,.btn-primary.active:focus,.btn-primary:active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(49,132,253,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5c636a;border-color:#565e64}.btn-check:focus+.btn-secondary,.btn-secondary:focus{color:#fff;background-color:#5c636a;border-color:#565e64;box-shadow:0 0 0 .25rem rgba(130,138,145,.5)}.btn-check:active+.btn-secondary,.btn-check:checked+.btn-secondary,.btn-secondary.active,.btn-secondary:active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#565e64;border-color:#51585e}.btn-check:active+.btn-secondary:focus,.btn-check:checked+.btn-secondary:focus,.btn-secondary.active:focus,.btn-secondary:active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(130,138,145,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-success{color:#fff;background-color:#198754;border-color:#198754}.btn-success:hover{color:#fff;background-color:#157347;border-color:#146c43}.btn-check:focus+.btn-success,.btn-success:focus{color:#fff;background-color:#157347;border-color:#146c43;box-shadow:0 0 0 .25rem rgba(60,153,110,.5)}.btn-check:active+.btn-success,.btn-check:checked+.btn-success,.btn-success.active,.btn-success:active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#146c43;border-color:#13653f}.btn-check:active+.btn-success:focus,.btn-check:checked+.btn-success:focus,.btn-success.active:focus,.btn-success:active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(60,153,110,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#198754;border-color:#198754}.btn-info{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-info:hover{color:#000;background-color:#31d2f2;border-color:#25cff2}.btn-check:focus+.btn-info,.btn-info:focus{color:#000;background-color:#31d2f2;border-color:#25cff2;box-shadow:0 0 0 .25rem rgba(11,172,204,.5)}.btn-check:active+.btn-info,.btn-check:checked+.btn-info,.btn-info.active,.btn-info:active,.show>.btn-info.dropdown-toggle{color:#000;background-color:#3dd5f3;border-color:#25cff2}.btn-check:active+.btn-info:focus,.btn-check:checked+.btn-info:focus,.btn-info.active:focus,.btn-info:active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(11,172,204,.5)}.btn-info.disabled,.btn-info:disabled{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-warning{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#000;background-color:#ffca2c;border-color:#ffc720}.btn-check:focus+.btn-warning,.btn-warning:focus{color:#000;background-color:#ffca2c;border-color:#ffc720;box-shadow:0 0 0 .25rem rgba(217,164,6,.5)}.btn-check:active+.btn-warning,.btn-check:checked+.btn-warning,.btn-warning.active,.btn-warning:active,.show>.btn-warning.dropdown-toggle{color:#000;background-color:#ffcd39;border-color:#ffc720}.btn-check:active+.btn-warning:focus,.btn-check:checked+.btn-warning:focus,.btn-warning.active:focus,.btn-warning:active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(217,164,6,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#bb2d3b;border-color:#b02a37}.btn-check:focus+.btn-danger,.btn-danger:focus{color:#fff;background-color:#bb2d3b;border-color:#b02a37;box-shadow:0 0 0 .25rem rgba(225,83,97,.5)}.btn-check:active+.btn-danger,.btn-check:checked+.btn-danger,.btn-danger.active,.btn-danger:active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#b02a37;border-color:#a52834}.btn-check:active+.btn-danger:focus,.btn-check:checked+.btn-danger:focus,.btn-danger.active:focus,.btn-danger:active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(225,83,97,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-light{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:focus+.btn-light,.btn-light:focus{color:#000;background-color:#f9fafb;border-color:#f9fafb;box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-check:active+.btn-light,.btn-check:checked+.btn-light,.btn-light.active,.btn-light:active,.show>.btn-light.dropdown-toggle{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:active+.btn-light:focus,.btn-check:checked+.btn-light:focus,.btn-light.active:focus,.btn-light:active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-light.disabled,.btn-light:disabled{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-dark{color:#fff;background-color:#212529;border-color:#212529}.btn-dark:hover{color:#fff;background-color:#1c1f23;border-color:#1a1e21}.btn-check:focus+.btn-dark,.btn-dark:focus{color:#fff;background-color:#1c1f23;border-color:#1a1e21;box-shadow:0 0 0 .25rem rgba(66,70,73,.5)}.btn-check:active+.btn-dark,.btn-check:checked+.btn-dark,.btn-dark.active,.btn-dark:active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1a1e21;border-color:#191c1f}.btn-check:active+.btn-dark:focus,.btn-check:checked+.btn-dark:focus,.btn-dark.active:focus,.btn-dark:active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(66,70,73,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#212529;border-color:#212529}.btn-outline-primary{color:#0d6efd;border-color:#0d6efd}.btn-outline-primary:hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-check:focus+.btn-outline-primary,.btn-outline-primary:focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.5)}.btn-check:active+.btn-outline-primary,.btn-check:checked+.btn-outline-primary,.btn-outline-primary.active,.btn-outline-primary.dropdown-toggle.show,.btn-outline-primary:active{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-check:active+.btn-outline-primary:focus,.btn-check:checked+.btn-outline-primary:focus,.btn-outline-primary.active:focus,.btn-outline-primary.dropdown-toggle.show:focus,.btn-outline-primary:active:focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#0d6efd;background-color:transparent}.btn-outline-secondary{color:#6c757d;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-check:focus+.btn-outline-secondary,.btn-outline-secondary:focus{box-shadow:0 0 0 .25rem rgba(108,117,125,.5)}.btn-check:active+.btn-outline-secondary,.btn-check:checked+.btn-outline-secondary,.btn-outline-secondary.active,.btn-outline-secondary.dropdown-toggle.show,.btn-outline-secondary:active{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-check:active+.btn-outline-secondary:focus,.btn-check:checked+.btn-outline-secondary:focus,.btn-outline-secondary.active:focus,.btn-outline-secondary.dropdown-toggle.show:focus,.btn-outline-secondary:active:focus{box-shadow:0 0 0 .25rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-success{color:#198754;border-color:#198754}.btn-outline-success:hover{color:#fff;background-color:#198754;border-color:#198754}.btn-check:focus+.btn-outline-success,.btn-outline-success:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.5)}.btn-check:active+.btn-outline-success,.btn-check:checked+.btn-outline-success,.btn-outline-success.active,.btn-outline-success.dropdown-toggle.show,.btn-outline-success:active{color:#fff;background-color:#198754;border-color:#198754}.btn-check:active+.btn-outline-success:focus,.btn-check:checked+.btn-outline-success:focus,.btn-outline-success.active:focus,.btn-outline-success.dropdown-toggle.show:focus,.btn-outline-success:active:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#198754;background-color:transparent}.btn-outline-info{color:#0dcaf0;border-color:#0dcaf0}.btn-outline-info:hover{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-check:focus+.btn-outline-info,.btn-outline-info:focus{box-shadow:0 0 0 .25rem rgba(13,202,240,.5)}.btn-check:active+.btn-outline-info,.btn-check:checked+.btn-outline-info,.btn-outline-info.active,.btn-outline-info.dropdown-toggle.show,.btn-outline-info:active{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-check:active+.btn-outline-info:focus,.btn-check:checked+.btn-outline-info:focus,.btn-outline-info.active:focus,.btn-outline-info.dropdown-toggle.show:focus,.btn-outline-info:active:focus{box-shadow:0 0 0 .25rem rgba(13,202,240,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#0dcaf0;background-color:transparent}.btn-outline-warning{color:#ffc107;border-color:#ffc107}.btn-outline-warning:hover{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-check:focus+.btn-outline-warning,.btn-outline-warning:focus{box-shadow:0 0 0 .25rem rgba(255,193,7,.5)}.btn-check:active+.btn-outline-warning,.btn-check:checked+.btn-outline-warning,.btn-outline-warning.active,.btn-outline-warning.dropdown-toggle.show,.btn-outline-warning:active{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-check:active+.btn-outline-warning:focus,.btn-check:checked+.btn-outline-warning:focus,.btn-outline-warning.active:focus,.btn-outline-warning.dropdown-toggle.show:focus,.btn-outline-warning:active:focus{box-shadow:0 0 0 .25rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-danger{color:#dc3545;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-check:focus+.btn-outline-danger,.btn-outline-danger:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.5)}.btn-check:active+.btn-outline-danger,.btn-check:checked+.btn-outline-danger,.btn-outline-danger.active,.btn-outline-danger.dropdown-toggle.show,.btn-outline-danger:active{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-check:active+.btn-outline-danger:focus,.btn-check:checked+.btn-outline-danger:focus,.btn-outline-danger.active:focus,.btn-outline-danger.dropdown-toggle.show:focus,.btn-outline-danger:active:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-light{color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:hover{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:focus+.btn-outline-light,.btn-outline-light:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-check:active+.btn-outline-light,.btn-check:checked+.btn-outline-light,.btn-outline-light.active,.btn-outline-light.dropdown-toggle.show,.btn-outline-light:active{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:active+.btn-outline-light:focus,.btn-check:checked+.btn-outline-light:focus,.btn-outline-light.active:focus,.btn-outline-light.dropdown-toggle.show:focus,.btn-outline-light:active:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-dark{color:#212529;border-color:#212529}.btn-outline-dark:hover{color:#fff;background-color:#212529;border-color:#212529}.btn-check:focus+.btn-outline-dark,.btn-outline-dark:focus{box-shadow:0 0 0 .25rem rgba(33,37,41,.5)}.btn-check:active+.btn-outline-dark,.btn-check:checked+.btn-outline-dark,.btn-outline-dark.active,.btn-outline-dark.dropdown-toggle.show,.btn-outline-dark:active{color:#fff;background-color:#212529;border-color:#212529}.btn-check:active+.btn-outline-dark:focus,.btn-check:checked+.btn-outline-dark:focus,.btn-outline-dark.active:focus,.btn-outline-dark.dropdown-toggle.show:focus,.btn-outline-dark:active:focus{box-shadow:0 0 0 .25rem rgba(33,37,41,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#212529;background-color:transparent}.btn-link{font-weight:400;color:#0d6efd;text-decoration:underline}.btn-link:hover{color:#0a58ca}.btn-link.disabled,.btn-link:disabled{color:#6c757d}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.dropdown,.dropend,.dropstart,.dropup{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;z-index:1000;display:none;min-width:10rem;padding:.5rem 0;margin:0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:.125rem}.dropdown-menu-start{--bs-position:start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position:end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-start{--bs-position:start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position:end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-start{--bs-position:start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position:end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-start{--bs-position:start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position:end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-start{--bs-position:start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position:end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1400px){.dropdown-menu-xxl-start{--bs-position:start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position:end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid rgba(0,0,0,.15)}.dropdown-item{display:block;width:100%;padding:.25rem 1rem;clear:both;font-weight:400;color:#212529;text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#1e2125;background-color:#e9ecef}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#0d6efd}.dropdown-item.disabled,.dropdown-item:disabled{color:#adb5bd;pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1rem;color:#212529}.dropdown-menu-dark{color:#dee2e6;background-color:#343a40;border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item{color:#dee2e6}.dropdown-menu-dark .dropdown-item:focus,.dropdown-menu-dark .dropdown-item:hover{color:#fff;background-color:rgba(255,255,255,.15)}.dropdown-menu-dark .dropdown-item.active,.dropdown-menu-dark .dropdown-item:active{color:#fff;background-color:#0d6efd}.dropdown-menu-dark .dropdown-item.disabled,.dropdown-menu-dark .dropdown-item:disabled{color:#adb5bd}.dropdown-menu-dark .dropdown-divider{border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item-text{color:#dee2e6}.dropdown-menu-dark .dropdown-header{color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn-group:not(:first-child),.btn-group>.btn:not(:first-child){margin-left:-1px}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn~.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem;color:#0d6efd;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion:reduce){.nav-link{transition:none}}.nav-link:focus,.nav-link:hover{color:#0a58ca}.nav-link.disabled{color:#6c757d;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-link{margin-bottom:-1px;background:0 0;border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6;isolation:isolate}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{background:0 0;border:0;border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#0d6efd}.nav-fill .nav-item,.nav-fill>.nav-link{flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{flex-basis:0;flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding-top:.5rem;padding-bottom:.5rem}.navbar>.container,.navbar>.container-fluid,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;text-decoration:none;white-space:nowrap}.navbar-nav{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem;transition:box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 .25rem}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height,75vh);overflow-y:auto}@media (min-width:576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (min-width:768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (min-width:992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (min-width:1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}@media (min-width:1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.55)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.55);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%280, 0, 0, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:rgba(0,0,0,.55)}.navbar-light .navbar-text a,.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.55)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.55);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:rgba(255,255,255,.55)}.navbar-dark .navbar-text a,.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:flex;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:1rem 1rem}.card-title{margin-bottom:.5rem}.card-subtitle{margin-top:-.25rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1rem}.card-header{padding:.5rem 1rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-footer{padding:.5rem 1rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.5rem;margin-bottom:-.5rem;margin-left:-.5rem;border-bottom:0}.card-header-pills{margin-right:-.5rem;margin-left:-.5rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom,.card-img-top{width:100%}.card-img,.card-img-top{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-group>.card{margin-bottom:.75rem}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:1rem 1.25rem;font-size:1rem;color:#212529;text-align:left;background-color:#fff;border:0;border-radius:0;overflow-anchor:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,border-radius .15s ease}@media (prefers-reduced-motion:reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:#0c63e4;background-color:#e7f1ff;box-shadow:inset 0 -1px 0 rgba(0,0,0,.125)}.accordion-button:not(.collapsed)::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%230c63e4'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");transform:rotate(-180deg)}.accordion-button::after{flex-shrink:0;width:1.25rem;height:1.25rem;margin-left:auto;content:"";background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-size:1.25rem;transition:transform .2s ease-in-out}@media (prefers-reduced-motion:reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.accordion-header{margin-bottom:0}.accordion-item{background-color:#fff;border:1px solid rgba(0,0,0,.125)}.accordion-item:first-of-type{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.accordion-item:first-of-type .accordion-button{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.accordion-item:last-of-type .accordion-button.collapsed{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.accordion-item:last-of-type .accordion-collapse{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.accordion-body{padding:1rem 1.25rem}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}.accordion-flush .accordion-item .accordion-button{border-radius:0}.breadcrumb{display:flex;flex-wrap:wrap;padding:0 0;margin-bottom:1rem;list-style:none}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:.5rem;color:#6c757d;content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:#6c757d}.pagination{display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;color:#0d6efd;text-decoration:none;background-color:#fff;border:1px solid #dee2e6;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:#0a58ca;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:3;color:#0a58ca;background-color:#e9ecef;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.page-item:not(:first-child) .page-link{margin-left:-1px}.page-item.active .page-link{z-index:3;color:#fff;background-color:#0d6efd;border-color:#0d6efd}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;background-color:#fff;border-color:#dee2e6}.page-link{padding:.375rem .75rem}.page-item:first-child .page-link{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.35em .65em;font-size:.75em;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{position:relative;padding:1rem 1rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{color:#084298;background-color:#cfe2ff;border-color:#b6d4fe}.alert-primary .alert-link{color:#06357a}.alert-secondary{color:#41464b;background-color:#e2e3e5;border-color:#d3d6d8}.alert-secondary .alert-link{color:#34383c}.alert-success{color:#0f5132;background-color:#d1e7dd;border-color:#badbcc}.alert-success .alert-link{color:#0c4128}.alert-info{color:#055160;background-color:#cff4fc;border-color:#b6effb}.alert-info .alert-link{color:#04414d}.alert-warning{color:#664d03;background-color:#fff3cd;border-color:#ffecb5}.alert-warning .alert-link{color:#523e02}.alert-danger{color:#842029;background-color:#f8d7da;border-color:#f5c2c7}.alert-danger .alert-link{color:#6a1a21}.alert-light{color:#636464;background-color:#fefefe;border-color:#fdfdfe}.alert-light .alert-link{color:#4f5050}.alert-dark{color:#141619;background-color:#d3d3d4;border-color:#bcbebf}.alert-dark .alert-link{color:#101214}@-webkit-keyframes progress-bar-stripes{0%{background-position-x:1rem}}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress{display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:#fff;text-align:center;white-space:nowrap;background-color:#0d6efd;transition:width .6s ease}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:1s linear infinite progress-bar-stripes;animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion:reduce){.progress-bar-animated{-webkit-animation:none;animation:none}}.list-group{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:.25rem}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>li::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.5rem 1rem;color:#212529;text-decoration:none;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#0d6efd;border-color:#0d6efd}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{color:#084298;background-color:#cfe2ff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#084298;background-color:#bacbe6}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#084298;border-color:#084298}.list-group-item-secondary{color:#41464b;background-color:#e2e3e5}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#41464b;background-color:#cbccce}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#41464b;border-color:#41464b}.list-group-item-success{color:#0f5132;background-color:#d1e7dd}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#0f5132;background-color:#bcd0c7}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#0f5132;border-color:#0f5132}.list-group-item-info{color:#055160;background-color:#cff4fc}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#055160;background-color:#badce3}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#055160;border-color:#055160}.list-group-item-warning{color:#664d03;background-color:#fff3cd}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#664d03;background-color:#e6dbb9}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#664d03;border-color:#664d03}.list-group-item-danger{color:#842029;background-color:#f8d7da}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#842029;background-color:#dfc2c4}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#842029;border-color:#842029}.list-group-item-light{color:#636464;background-color:#fefefe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#636464;background-color:#e5e5e5}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#636464;border-color:#636464}.list-group-item-dark{color:#141619;background-color:#d3d3d4}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#141619;background-color:#bebebf}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#141619;border-color:#141619}.btn-close{box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:#000;background:transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat;border:0;border-radius:.25rem;opacity:.5}.btn-close:hover{color:#000;text-decoration:none;opacity:.75}.btn-close:focus{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25);opacity:1}.btn-close.disabled,.btn-close:disabled{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;opacity:.25}.btn-close-white{filter:invert(1) grayscale(100%) brightness(200%)}.toast{width:350px;max-width:100%;font-size:.875rem;pointer-events:auto;background-color:rgba(255,255,255,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .5rem 1rem rgba(0,0,0,.15);border-radius:.25rem}.toast:not(.showing):not(.show){opacity:0}.toast.hide{display:none}.toast-container{width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:.75rem}.toast-header{display:flex;align-items:center;padding:.5rem .75rem;color:#6c757d;background-color:rgba(255,255,255,.85);background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05);border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.toast-header .btn-close{margin-right:-.375rem;margin-left:.75rem}.toast-body{padding:.75rem;word-wrap:break-word}.modal{position:fixed;top:0;left:0;z-index:1060;display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - 1rem)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:flex;flex-shrink:0;align-items:center;justify-content:space-between;padding:1rem 1rem;border-bottom:1px solid #dee2e6;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.modal-header .btn-close{padding:.5rem .5rem;margin:-.5rem -.5rem -.5rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:1 1 auto;padding:1rem}.modal-footer{display:flex;flex-wrap:wrap;flex-shrink:0;align-items:center;justify-content:flex-end;padding:.75rem;border-top:1px solid #dee2e6;border-bottom-right-radius:calc(.3rem - 1px);border-bottom-left-radius:calc(.3rem - 1px)}.modal-footer>*{margin:.25rem}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{height:calc(100% - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{max-width:800px}}@media (min-width:1200px){.modal-xl{max-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-header{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}.modal-fullscreen .modal-footer{border-radius:0}@media (max-width:575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-header{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}.modal-fullscreen-sm-down .modal-footer{border-radius:0}}@media (max-width:767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-header{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}.modal-fullscreen-md-down .modal-footer{border-radius:0}}@media (max-width:991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-header{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}.modal-fullscreen-lg-down .modal-footer{border-radius:0}}@media (max-width:1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-header{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}.modal-fullscreen-xl-down .modal-footer{border-radius:0}}@media (max-width:1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-header{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}.modal-fullscreen-xxl-down .modal-footer{border-radius:0}}.tooltip{position:absolute;z-index:1080;display:block;margin:0;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .tooltip-arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[data-popper-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow,.bs-tooltip-top .tooltip-arrow{bottom:0}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before,.bs-tooltip-top .tooltip-arrow::before{top:-1px;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[data-popper-placement^=right],.bs-tooltip-end{padding:0 .4rem}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow,.bs-tooltip-end .tooltip-arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before,.bs-tooltip-end .tooltip-arrow::before{right:-1px;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[data-popper-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow,.bs-tooltip-bottom .tooltip-arrow{top:0}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before,.bs-tooltip-bottom .tooltip-arrow::before{bottom:-1px;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[data-popper-placement^=left],.bs-tooltip-start{padding:0 .4rem}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow,.bs-tooltip-start .tooltip-arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before,.bs-tooltip-start .tooltip-arrow::before{left:-1px;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1070;display:block;max-width:276px;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .popover-arrow{position:absolute;display:block;width:1rem;height:.5rem}.popover .popover-arrow::after,.popover .popover-arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow,.bs-popover-top>.popover-arrow{bottom:calc(-.5rem - 1px)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-top>.popover-arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#fff}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow,.bs-popover-end>.popover-arrow{left:calc(-.5rem - 1px);width:.5rem;height:1rem}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-end>.popover-arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#fff}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow,.bs-popover-bottom>.popover-arrow{top:calc(-.5rem - 1px)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#fff}.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f0f0f0}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow,.bs-popover-start>.popover-arrow{right:calc(-.5rem - 1px);width:.5rem;height:1rem}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-start>.popover-arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#fff}.popover-header{padding:.5rem 1rem;margin-bottom:0;font-size:1rem;background-color:#f0f0f0;border-bottom:1px solid rgba(0,0,0,.2);border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:1rem 1rem;color:#212529}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-end,.carousel-item-next:not(.carousel-item-start){transform:translateX(100%)}.active.carousel-item-start,.carousel-item-prev:not(.carousel-item-end){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:0 0;border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%;list-style:none}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-next-icon,.carousel-dark .carousel-control-prev-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}@-webkit-keyframes spinner-border{to{transform:rotate(360deg)}}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;border:.25em solid currentColor;border-right-color:transparent;border-radius:50%;-webkit-animation:.75s linear infinite spinner-border;animation:.75s linear infinite spinner-border}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@-webkit-keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;background-color:currentColor;border-radius:50%;opacity:0;-webkit-animation:.75s linear infinite spinner-grow;animation:.75s linear infinite spinner-grow}.spinner-grow-sm{width:1rem;height:1rem}@media (prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{-webkit-animation-duration:1.5s;animation-duration:1.5s}}.offcanvas{position:fixed;bottom:0;z-index:1050;display:flex;flex-direction:column;max-width:100%;visibility:hidden;background-color:#fff;background-clip:padding-box;outline:0;transition:transform .3s ease-in-out}@media (prefers-reduced-motion:reduce){.offcanvas{transition:none}}.offcanvas-header{display:flex;align-items:center;justify-content:space-between;padding:1rem 1rem}.offcanvas-header .btn-close{padding:.5rem .5rem;margin-top:-.5rem;margin-right:-.5rem;margin-bottom:-.5rem}.offcanvas-title{margin-bottom:0;line-height:1.5}.offcanvas-body{flex-grow:1;padding:1rem 1rem;overflow-y:auto}.offcanvas-start{top:0;left:0;width:400px;border-right:1px solid rgba(0,0,0,.2);transform:translateX(-100%)}.offcanvas-end{top:0;right:0;width:400px;border-left:1px solid rgba(0,0,0,.2);transform:translateX(100%)}.offcanvas-top{top:0;right:0;left:0;height:30vh;max-height:100%;border-bottom:1px solid rgba(0,0,0,.2);transform:translateY(-100%)}.offcanvas-bottom{right:0;left:0;height:30vh;max-height:100%;border-top:1px solid rgba(0,0,0,.2);transform:translateY(100%)}.offcanvas.show{transform:none}.clearfix::after{display:block;clear:both;content:""}.link-primary{color:#0d6efd}.link-primary:focus,.link-primary:hover{color:#0a58ca}.link-secondary{color:#6c757d}.link-secondary:focus,.link-secondary:hover{color:#565e64}.link-success{color:#198754}.link-success:focus,.link-success:hover{color:#146c43}.link-info{color:#0dcaf0}.link-info:focus,.link-info:hover{color:#3dd5f3}.link-warning{color:#ffc107}.link-warning:focus,.link-warning:hover{color:#ffcd39}.link-danger{color:#dc3545}.link-danger:focus,.link-danger:hover{color:#b02a37}.link-light{color:#f8f9fa}.link-light:focus,.link-light:hover{color:#f9fafb}.link-dark{color:#212529}.link-dark:focus,.link-dark:hover{color:#1a1e21}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio:100%}.ratio-4x3{--bs-aspect-ratio:calc(3 / 4 * 100%)}.ratio-16x9{--bs-aspect-ratio:calc(9 / 16 * 100%)}.ratio-21x9{--bs-aspect-ratio:calc(9 / 21 * 100%)}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}@media (min-width:576px){.sticky-sm-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:768px){.sticky-md-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:992px){.sticky-lg-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:1200px){.sticky-xl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:1400px){.sticky-xxl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:left!important}.float-end{float:right!important}.float-none{float:none!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translateX(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:1px solid #dee2e6!important}.border-0{border:0!important}.border-top{border-top:1px solid #dee2e6!important}.border-top-0{border-top:0!important}.border-end{border-right:1px solid #dee2e6!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:1px solid #dee2e6!important}.border-start-0{border-left:0!important}.border-primary{border-color:#0d6efd!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#198754!important}.border-info{border-color:#0dcaf0!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#212529!important}.border-white{border-color:#fff!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.375rem + 1.5vw)!important}.fs-2{font-size:calc(1.325rem + .9vw)!important}.fs-3{font-size:calc(1.3rem + .6vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!important}.fs-6{font-size:1rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-light{font-weight:300!important}.fw-lighter{font-weight:lighter!important}.fw-normal{font-weight:400!important}.fw-bold{font-weight:700!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-primary{color:#0d6efd!important}.text-secondary{color:#6c757d!important}.text-success{color:#198754!important}.text-info{color:#0dcaf0!important}.text-warning{color:#ffc107!important}.text-danger{color:#dc3545!important}.text-light{color:#f8f9fa!important}.text-dark{color:#212529!important}.text-white{color:#fff!important}.text-body{color:#212529!important}.text-muted{color:#6c757d!important}.text-black-50{color:rgba(0,0,0,.5)!important}.text-white-50{color:rgba(255,255,255,.5)!important}.text-reset{color:inherit!important}.bg-primary{background-color:#0d6efd!important}.bg-secondary{background-color:#6c757d!important}.bg-success{background-color:#198754!important}.bg-info{background-color:#0dcaf0!important}.bg-warning{background-color:#ffc107!important}.bg-danger{background-color:#dc3545!important}.bg-light{background-color:#f8f9fa!important}.bg-dark{background-color:#212529!important}.bg-body{background-color:#fff!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:.25rem!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:.2rem!important}.rounded-2{border-radius:.25rem!important}.rounded-3{border-radius:.3rem!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:50rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-end{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-start{border-bottom-left-radius:.25rem!important;border-top-left-radius:.25rem!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media (min-width:576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}}@media (min-width:1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}}@media (min-width:1200px){.fs-1{font-size:2.5rem!important}.fs-2{font-size:2rem!important}.fs-3{font-size:1.75rem!important}.fs-4{font-size:1.5rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}} \ No newline at end of file diff --git a/web/app/plugins/ld-content-cloner/admin/css/images/ui-bg_flat_0_111111_40x100.png b/web/app/plugins/ld-content-cloner/admin/css/images/ui-bg_flat_0_111111_40x100.png deleted file mode 100644 index 07cfc4938..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/css/images/ui-bg_flat_0_111111_40x100.png and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/css/images/ui-bg_flat_0_aaaaaa_40x100.png b/web/app/plugins/ld-content-cloner/admin/css/images/ui-bg_flat_0_aaaaaa_40x100.png deleted file mode 100644 index b956ac587..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/css/images/ui-bg_flat_0_aaaaaa_40x100.png and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/css/images/ui-bg_flat_100_1b7aa6_40x100.png b/web/app/plugins/ld-content-cloner/admin/css/images/ui-bg_flat_100_1b7aa6_40x100.png deleted file mode 100644 index 692e5ebf9..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/css/images/ui-bg_flat_100_1b7aa6_40x100.png and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/css/images/ui-bg_flat_100_1e8cbe_40x100.png b/web/app/plugins/ld-content-cloner/admin/css/images/ui-bg_flat_100_1e8cbe_40x100.png deleted file mode 100644 index 03e304261..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/css/images/ui-bg_flat_100_1e8cbe_40x100.png and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/css/images/ui-bg_flat_100_2ea2cc_40x100.png b/web/app/plugins/ld-content-cloner/admin/css/images/ui-bg_flat_100_2ea2cc_40x100.png deleted file mode 100644 index 7b319da15..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/css/images/ui-bg_flat_100_2ea2cc_40x100.png and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/css/images/ui-bg_flat_100_ffffff_40x100.png b/web/app/plugins/ld-content-cloner/admin/css/images/ui-bg_flat_100_ffffff_40x100.png deleted file mode 100644 index d7451dde9..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/css/images/ui-bg_flat_100_ffffff_40x100.png and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/css/images/ui-bg_glass_55_fbf9ee_1x400.png b/web/app/plugins/ld-content-cloner/admin/css/images/ui-bg_glass_55_fbf9ee_1x400.png deleted file mode 100644 index 22d4b94ff..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/css/images/ui-bg_glass_55_fbf9ee_1x400.png and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/css/images/ui-bg_glass_95_fef1ec_1x400.png b/web/app/plugins/ld-content-cloner/admin/css/images/ui-bg_glass_95_fef1ec_1x400.png deleted file mode 100644 index 98fa292e7..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/css/images/ui-bg_glass_95_fef1ec_1x400.png and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_2e83ff_256x240.png b/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_2e83ff_256x240.png deleted file mode 100644 index f2bf83883..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_2e83ff_256x240.png and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_333333_256x240.png b/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_333333_256x240.png deleted file mode 100644 index 58a4aa862..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_333333_256x240.png and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_444444_256x240.png b/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_444444_256x240.png deleted file mode 100644 index 38a1d86d7..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_444444_256x240.png and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_555555_256x240.png b/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_555555_256x240.png deleted file mode 100644 index ab6b11480..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_555555_256x240.png and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_777620_256x240.png b/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_777620_256x240.png deleted file mode 100644 index b7b4309c2..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_777620_256x240.png and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_777777_256x240.png b/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_777777_256x240.png deleted file mode 100644 index 8a7b96baa..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_777777_256x240.png and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_cc0000_256x240.png b/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_cc0000_256x240.png deleted file mode 100644 index c8bc4ce7a..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_cc0000_256x240.png and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_cd0a0a_256x240.png b/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_cd0a0a_256x240.png deleted file mode 100644 index 493701892..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_cd0a0a_256x240.png and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_ffffff_256x240.png b/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_ffffff_256x240.png deleted file mode 100644 index c803999c5..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/css/images/ui-icons_ffffff_256x240.png and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/css/jquery-ui.min.css b/web/app/plugins/ld-content-cloner/admin/css/jquery-ui.min.css deleted file mode 100644 index 55f4c19e8..000000000 --- a/web/app/plugins/ld-content-cloner/admin/css/jquery-ui.min.css +++ /dev/null @@ -1,7 +0,0 @@ -/*! jQuery UI - v1.11.4 - 2015-09-15 -* http://jqueryui.com -* Includes: core.css, draggable.css, resizable.css, button.css, dialog.css, theme.css -* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Segoe%20UI%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=6px&bgColorHeader=333333&bgTextureHeader=gloss_wave&bgImgOpacityHeader=25&borderColorHeader=333333&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=000000&bgTextureContent=inset_soft&bgImgOpacityContent=25&borderColorContent=666666&fcContent=ffffff&iconColorContent=cccccc&bgColorDefault=555555&bgTextureDefault=glass&bgImgOpacityDefault=20&borderColorDefault=666666&fcDefault=eeeeee&iconColorDefault=cccccc&bgColorHover=0078a3&bgTextureHover=glass&bgImgOpacityHover=40&borderColorHover=59b4d4&fcHover=ffffff&iconColorHover=ffffff&bgColorActive=f58400&bgTextureActive=inset_soft&bgImgOpacityActive=30&borderColorActive=ffaf0f&fcActive=ffffff&iconColorActive=222222&bgColorHighlight=eeeeee&bgTextureHighlight=highlight_soft&bgImgOpacityHighlight=80&borderColorHighlight=cccccc&fcHighlight=2e7db2&iconColorHighlight=4b8e0b&bgColorError=ffc73d&bgTextureError=glass&bgImgOpacityError=40&borderColorError=ffb73d&fcError=111111&iconColorError=a83300&bgColorOverlay=5c5c5c&bgTextureOverlay=flat&bgImgOpacityOverlay=50&opacityOverlay=80&bgColorShadow=cccccc&bgTextureShadow=flat&bgImgOpacityShadow=30&opacityShadow=60&thicknessShadow=7px&offsetTopShadow=-7px&offsetLeftShadow=-7px&cornerRadiusShadow=8px -* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */ - -.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block;-ms-touch-action:none;touch-action:none}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-button{display:inline-block;position:relative;padding:0;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:normal}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-dialog{overflow:hidden;position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:12px;height:12px;right:-5px;bottom:-5px;background-position:16px 16px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-widget{font-family:Segoe UI,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Segoe UI,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #666;background:#000 url("images/ui-bg_inset-soft_25_000000_1x100.png") 50% bottom repeat-x;color:#fff}.ui-widget-content a{color:#fff}.ui-widget-header{border:1px solid #333;background:#333 url("images/ui-bg_gloss-wave_25_333333_500x100.png") 50% 50% repeat-x;color:#fff;font-weight:bold}.ui-widget-header a{color:#fff}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #666;background:#555 url("images/ui-bg_glass_20_555555_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#eee}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#eee;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #59b4d4;background:#0078a3 url("images/ui-bg_glass_40_0078a3_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#fff}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited{color:#fff;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #ffaf0f;background:#f58400 url("images/ui-bg_inset-soft_30_f58400_1x100.png") 50% 50% repeat-x;font-weight:bold;color:#fff}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#fff;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #ccc;background:#eee url("images/ui-bg_highlight-soft_80_eeeeee_1x100.png") 50% top repeat-x;color:#2e7db2}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#2e7db2}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #ffb73d;background:#ffc73d url("images/ui-bg_glass_40_ffc73d_1x400.png") 50% 50% repeat-x;color:#111}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#111}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#111}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_cccccc_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-default .ui-icon{background-image:url("images/ui-icons_cccccc_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-active .ui-icon{background-image:url("images/ui-icons_222222_256x240.png")}.ui-state-highlight .ui-icon{background-image:url("images/ui-icons_4b8e0b_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_a83300_256x240.png")}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:6px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:6px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:6px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:6px}.ui-widget-overlay{background:#5c5c5c url("images/ui-bg_flat_50_5c5c5c_40x100.png") 50% 50% repeat-x;opacity:.8;filter:Alpha(Opacity=80)}.ui-widget-shadow{margin:-7px 0 0 -7px;padding:7px;background:#ccc url("images/ui-bg_flat_30_cccccc_40x100.png") 50% 50% repeat-x;opacity:.6;filter:Alpha(Opacity=60);border-radius:8px} \ No newline at end of file diff --git a/web/app/plugins/ld-content-cloner/admin/css/jquery-ui.structure.min.css b/web/app/plugins/ld-content-cloner/admin/css/jquery-ui.structure.min.css deleted file mode 100644 index 934109be9..000000000 --- a/web/app/plugins/ld-content-cloner/admin/css/jquery-ui.structure.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.11.4 - 2015-09-15 -* http://jqueryui.com -* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */ - -.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block;-ms-touch-action:none;touch-action:none}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-button{display:inline-block;position:relative;padding:0;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:normal}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-dialog{overflow:hidden;position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:12px;height:12px;right:-5px;bottom:-5px;background-position:16px 16px}.ui-draggable .ui-dialog-titlebar{cursor:move} \ No newline at end of file diff --git a/web/app/plugins/ld-content-cloner/admin/css/jquery-ui.theme.min.css b/web/app/plugins/ld-content-cloner/admin/css/jquery-ui.theme.min.css deleted file mode 100644 index c9e8879b1..000000000 --- a/web/app/plugins/ld-content-cloner/admin/css/jquery-ui.theme.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.11.4 - 2015-10-21 -* http://jqueryui.com -* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */ - -.ui-widget{font-family:"Open Sans",sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:"Open Sans",sans-serif;font-size:1em}.ui-widget-content{border:1px solid #e5e5e5;background:#fff url("images/ui-bg_flat_100_ffffff_40x100.png") 50% 50% repeat-x;color:#555}.ui-widget-content a{color:#555}.ui-widget-header{border:1px solid #e1e1e1;background:#fff url("images/ui-bg_flat_100_ffffff_40x100.png") 50% 50% repeat-x;color:#333;font-weight:bold}.ui-widget-header a{color:#333}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #0074a2;background:#2ea2cc url("images/ui-bg_flat_100_2ea2cc_40x100.png") 50% 50% repeat-x;font-weight:normal;color:#fff}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#fff;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #0074a2;background:#1e8cbe url("images/ui-bg_flat_100_1e8cbe_40x100.png") 50% 50% repeat-x;font-weight:normal;color:#fff}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited{color:#fff;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #005684;background:#1b7aa6 url("images/ui-bg_flat_100_1b7aa6_40x100.png") 50% 50% repeat-x;font-weight:normal;color:#fff}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#fff;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fcefa1;background:#fbf9ee url("images/ui-bg_glass_55_fbf9ee_1x400.png") 50% 50% repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#fef1ec url("images/ui-bg_glass_95_fef1ec_1x400.png") 50% 50% repeat-x;color:#cd0a0a}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#cd0a0a}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#cd0a0a}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_555555_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_333333_256x240.png")}.ui-state-default .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-active .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-highlight .ui-icon{background-image:url("images/ui-icons_2e83ff_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_cd0a0a_256x240.png")}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:0}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:0}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:0}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:0}.ui-widget-overlay{background:#111 url("images/ui-bg_flat_0_111111_40x100.png") 50% 50% repeat-x;opacity:.65;filter:Alpha(Opacity=65)}.ui-widget-shadow{margin:-8px 0 0 -8px;padding:8px;background:#aaa url("images/ui-bg_flat_0_aaaaaa_40x100.png") 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30);border-radius:8px} \ No newline at end of file diff --git a/web/app/plugins/ld-content-cloner/admin/css/ld-content-cloner-admin.css b/web/app/plugins/ld-content-cloner/admin/css/ld-content-cloner-admin.css deleted file mode 100644 index b5f0d7989..000000000 --- a/web/app/plugins/ld-content-cloner/admin/css/ld-content-cloner-admin.css +++ /dev/null @@ -1,132 +0,0 @@ -/** - * All of the CSS for your admin-specific functionality should be - * included in this file. - */ -.ui-dialog { - z-index: 999999 !important; -} - -.ui-widget-overlay { - z-index: 99999 !important; -} - -.ui-dialog .ui-dialog-titlebar { - border-width: 0 0 1px; - margin-bottom: 10px; -} - -.ui-dialog .ui-dialog-content { - padding: 1em; -} -#ldcc-dialog, #ldcc-group-dialog { - clear: left; -} -#ldcc-dialog .ldcc-success, #ldcc-dialog .ldcc-notice, -#ldcc-group-dialog .ldcc-success, #ldcc-group-dialog .ldcc-notice { - display: none; -} - -#ldcc-dialog .ldcc-success,#ldcc-group-dialog .ldcc-success { - background-color: #c0e3cf; - font-size: 15px; - margin: 20px 0; - padding: 10px; -} - -#ldcc-dialog .ldcc-success > div,#ldcc-group-dialog .ldcc-success > div { - margin-bottom: 5px; -} - -#ldcc-dialog .ldcc-notice,#ldcc-group-dialog .ldcc-notice { - font-weight: 600; -} - -.ldcc-course-link, -.ldcc-group-link, -.ldcc-course-rename-link { - font-weight: 600; -} - -.ldcc-course-link:hover, -.ldcc-course-rename-link:hover { - color: #333; -} - -#ldcc-dialog .ldcc-error, #ldcc-group-dialog .ldcc-error { - background-color: #e3c0c0; - font-size: 15px; - margin: 20px 0; - padding: 10px; -} - -.ldcc-course-progress::before, -#ldcc-dialog div[class^="ldcc-lesson-"]:before, -#ldcc-dialog div[class^="ldcc-quiz-"]:before { - content: ""; - display: table; -} -.ldcc-course-progress::after, -#ldcc-dialog div[class^="ldcc-lesson-"]:before, -#ldcc-dialog div[class^="ldcc-quiz-"]:before { - clear: both; - content: ""; - display: table; -} - -.ldcc-course-progress { - border-bottom: 1px dotted #ddd; - padding: 0 0 5px; -} - -.ldcc-course-progress > span { - display: inline-block; - font-size: 16px; - padding: 5px 0; -} - -.ldcc-course-progress > img { - float: right; - height: 30px; - width: 30px; -} - -#ldcc-dialog div[class^="ldcc-lesson-"], -#ldcc-dialog div[class^="ldcc-quiz-"] { - border-bottom: 1px dotted #ddd; - padding: 10px 0; -} - - -#ldcc-dialog div[class^="ldcc-lesson-"] img, -#ldcc-dialog div[class^="ldcc-quiz-"] img { - float: right; - height: 20px; - width: 20px; -} - -#ldcc-dialog div[class^="ldcc-lesson-"] span, -#ldcc-dialog div[class^="ldcc-quiz-"] span, -#ldcc-dialog div.ldcc-course-progress span { - width: 90%; -} - -#ldcc-dialog #ldcc_clone_status { - max-height: 220px; - overflow-y: auto; - padding-right: 10px; -} - -.hide_extra_close.ui-dialog-titlebar-close { - background-color: transparent; - border: none; - top: 25% !important; - right: 1em !important; -} - -.ui-button.ui-dialog-titlebar-close { - overflow: visible !important; -} - -.ui-widget-header .ui-icon { - display: none; -} diff --git a/web/app/plugins/ld-content-cloner/admin/css/ldbr-admin.css b/web/app/plugins/ld-content-cloner/admin/css/ldbr-admin.css deleted file mode 100644 index 50fd335d9..000000000 --- a/web/app/plugins/ld-content-cloner/admin/css/ldbr-admin.css +++ /dev/null @@ -1,96 +0,0 @@ -#ldbr-select-form { - margin-bottom: 15px; -} - -.ldbr-table { - border-collapse: separate; - border-spacing: 0; - border: 1px solid #0061a7; - -moz-border-radius: 6px; - -webkit-border-radius: 6px; - border-radius: 6px; - font-family: 'trebuchet MS', 'Lucida sans', Arial; - font-size: 14px; - color: #444444; - background: #ffffff; - width: 100%; -} - -.ldbr-table tr.ldbr-head-row > th { - background-color: #dce9f9; - background-image: -webkit-gradient(linear, left top, left bottom, from(#ebf3fc), to(#dce9f9)); - background-image: -webkit-linear-gradient(top, #ebf3fc, #dce9f9); - background-image: -moz-linear-gradient(top, #ebf3fc, #dce9f9); - background-image: -ms-linear-gradient(top, #ebf3fc, #dce9f9); - background-image: -o-linear-gradient(top, #ebf3fc, #dce9f9); - background-image: linear-gradient(to bottom, #ebf3fc, #dce9f9); - -webkit-box-shadow: 0 1px 0 rgba(255, 255, 255, 0.8) inset; - -moz-box-shadow: 0 1px 0 rgba(255, 255, 255, 0.8) inset; - box-shadow: 0 1px 0 rgba(255, 255, 255, 0.8) inset; - border: 1px solid #0061a7; - color: #000; - padding: 20px 10px; - text-align: left; - text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); -} - -.ldbr-table tr.ldbr-head-row > th:first-child { - border-radius: 6px 0 0; -} - -.ldbr-table tr.ldbr-head-row > th:last-child { - border-radius: 0 6px 0 0; -} - -.ldbr-table .ldbr-row td { - border-left: 1px solid #cccccc; - border-top: 1px solid #cccccc; - padding: 20px 10px; - text-align: left; -} - -.ldbr-table .ldbr-row:hover { - background-color: #fbf8e9; -} - -.ldbr-table th:nth-child(2), -.ldbr-table td:nth-child(2), -.ldbr-table th:nth-child(3), -.ldbr-table td:nth-child(3) { - width: 40%; -} - -.ldbr-post-new-title { - width: 100%; -} - -.ldbr-table .ldbr-foot-row > td { - background-color: #dce9f9; - background-image: -webkit-gradient(linear, left top, left bottom, from(#ebf3fc), to(#dce9f9)); - background-image: -webkit-linear-gradient(top, #ebf3fc, #dce9f9); - background-image: -moz-linear-gradient(top, #ebf3fc, #dce9f9); - background-image: -ms-linear-gradient(top, #ebf3fc, #dce9f9); - background-image: -o-linear-gradient(top, #ebf3fc, #dce9f9); - background-image: linear-gradient(to bottom, #ebf3fc, #dce9f9); - -webkit-box-shadow: 0 1px 0 rgba(255, 255, 255, 0.8) inset; - -moz-box-shadow: 0 1px 0 rgba(255, 255, 255, 0.8) inset; - box-shadow: 0 1px 0 rgba(255, 255, 255, 0.8) inset; - border-radius: 0 0 6px 6px; - border-top: 1px solid #cccccc; - text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); - padding: 20px 10px; -} - -.ldbr-foot-row img { - height: auto; - line-height: 0; - margin: 0 10px; - width: 25px; -} - -.ldbr-success { - background-color: #c0e3cf; - font-size: 15px; - margin: 20px 0; - padding: 10px; -} diff --git a/web/app/plugins/ld-content-cloner/admin/fonts/glyphicons-halflings-regular.eot b/web/app/plugins/ld-content-cloner/admin/fonts/glyphicons-halflings-regular.eot deleted file mode 100644 index b93a4953f..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/fonts/glyphicons-halflings-regular.eot and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/fonts/glyphicons-halflings-regular.svg b/web/app/plugins/ld-content-cloner/admin/fonts/glyphicons-halflings-regular.svg deleted file mode 100644 index 94fb5490a..000000000 --- a/web/app/plugins/ld-content-cloner/admin/fonts/glyphicons-halflings-regular.svg +++ /dev/null @@ -1,288 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/web/app/plugins/ld-content-cloner/admin/fonts/glyphicons-halflings-regular.ttf b/web/app/plugins/ld-content-cloner/admin/fonts/glyphicons-halflings-regular.ttf deleted file mode 100644 index 1413fc609..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/fonts/glyphicons-halflings-regular.ttf and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/fonts/glyphicons-halflings-regular.woff b/web/app/plugins/ld-content-cloner/admin/fonts/glyphicons-halflings-regular.woff deleted file mode 100644 index 9e612858f..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/fonts/glyphicons-halflings-regular.woff and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/fonts/glyphicons-halflings-regular.woff2 b/web/app/plugins/ld-content-cloner/admin/fonts/glyphicons-halflings-regular.woff2 deleted file mode 100644 index 64539b54c..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/fonts/glyphicons-halflings-regular.woff2 and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/fonts/glyphicons-old-halflings-regular.eot b/web/app/plugins/ld-content-cloner/admin/fonts/glyphicons-old-halflings-regular.eot deleted file mode 100644 index b93a4953f..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/fonts/glyphicons-old-halflings-regular.eot and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/fonts/glyphicons-old-halflings-regular.ttf b/web/app/plugins/ld-content-cloner/admin/fonts/glyphicons-old-halflings-regular.ttf deleted file mode 100644 index 1413fc609..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/fonts/glyphicons-old-halflings-regular.ttf and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/fonts/glyphicons-old-halflings-regular.woff b/web/app/plugins/ld-content-cloner/admin/fonts/glyphicons-old-halflings-regular.woff deleted file mode 100644 index 9e612858f..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/fonts/glyphicons-old-halflings-regular.woff and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/images/loader.gif b/web/app/plugins/ld-content-cloner/admin/images/loader.gif deleted file mode 100644 index f3e45e056..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/images/loader.gif and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/images/tick.png b/web/app/plugins/ld-content-cloner/admin/images/tick.png deleted file mode 100644 index 3b4e0310e..000000000 Binary files a/web/app/plugins/ld-content-cloner/admin/images/tick.png and /dev/null differ diff --git a/web/app/plugins/ld-content-cloner/admin/index.php b/web/app/plugins/ld-content-cloner/admin/index.php deleted file mode 100644 index 530b88ff6..000000000 --- a/web/app/plugins/ld-content-cloner/admin/index.php +++ /dev/null @@ -1,6 +0,0 @@ -[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter(t=>t.matches(e)),parents(t,e){const s=[];let i=t.parentNode;for(;i&&i.nodeType===Node.ELEMENT_NODE&&3!==i.nodeType;)i.matches(e)&&s.push(i),i=i.parentNode;return s},prev(t,e){let s=t.previousElementSibling;for(;s;){if(s.matches(e))return[s];s=s.previousElementSibling}return[]},next(t,e){let s=t.nextElementSibling;for(;s;){if(s.matches(e))return[s];s=s.nextElementSibling}return[]}},n=t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t},o=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let s=t.getAttribute("href");if(!s||!s.includes("#")&&!s.startsWith("."))return null;s.includes("#")&&!s.startsWith("#")&&(s="#"+s.split("#")[1]),e=s&&"#"!==s?s.trim():null}return e},r=t=>{const e=o(t);return e&&document.querySelector(e)?e:null},a=t=>{const e=o(t);return e?document.querySelector(e):null},l=t=>{t.dispatchEvent(new Event("transitionend"))},c=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),h=t=>c(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?i.findOne(t):null,d=(t,e,s)=>{Object.keys(s).forEach(i=>{const n=s[i],o=e[i],r=o&&c(o)?"element":null==(a=o)?""+a:{}.toString.call(a).match(/\s([a-z]+)/i)[1].toLowerCase();var a;if(!new RegExp(n).test(r))throw new TypeError(`${t.toUpperCase()}: Option "${i}" provided type "${r}" but expected type "${n}".`)})},u=t=>!(!c(t)||0===t.getClientRects().length)&&"visible"===getComputedStyle(t).getPropertyValue("visibility"),g=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),p=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?p(t.parentNode):null},f=()=>{},m=t=>t.offsetHeight,_=()=>{const{jQuery:t}=window;return t&&!document.body.hasAttribute("data-bs-no-jquery")?t:null},b=[],v=()=>"rtl"===document.documentElement.dir,y=t=>{var e;e=()=>{const e=_();if(e){const s=t.NAME,i=e.fn[s];e.fn[s]=t.jQueryInterface,e.fn[s].Constructor=t,e.fn[s].noConflict=()=>(e.fn[s]=i,t.jQueryInterface)}},"loading"===document.readyState?(b.length||document.addEventListener("DOMContentLoaded",()=>{b.forEach(t=>t())}),b.push(e)):e()},w=t=>{"function"==typeof t&&t()},E=(t,e,s=!0)=>{if(!s)return void w(t);const i=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:s}=window.getComputedStyle(t);const i=Number.parseFloat(e),n=Number.parseFloat(s);return i||n?(e=e.split(",")[0],s=s.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(s))):0})(e)+5;let n=!1;const o=({target:s})=>{s===e&&(n=!0,e.removeEventListener("transitionend",o),w(t))};e.addEventListener("transitionend",o),setTimeout(()=>{n||l(e)},i)},A=(t,e,s,i)=>{let n=t.indexOf(e);if(-1===n)return t[!s&&i?t.length-1:0];const o=t.length;return n+=s?1:-1,i&&(n=(n+o)%o),t[Math.max(0,Math.min(n,o-1))]},T=/[^.]*(?=\..*)\.|.*/,C=/\..*/,k=/::\d+$/,L={};let O=1;const D={mouseenter:"mouseover",mouseleave:"mouseout"},I=/^(mouseenter|mouseleave)/i,N=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function S(t,e){return e&&`${e}::${O++}`||t.uidEvent||O++}function x(t){const e=S(t);return t.uidEvent=e,L[e]=L[e]||{},L[e]}function M(t,e,s=null){const i=Object.keys(t);for(let n=0,o=i.length;nfunction(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};i?i=t(i):s=t(s)}const[o,r,a]=P(e,s,i),l=x(t),c=l[a]||(l[a]={}),h=M(c,r,o?s:null);if(h)return void(h.oneOff=h.oneOff&&n);const d=S(r,e.replace(T,"")),u=o?function(t,e,s){return function i(n){const o=t.querySelectorAll(e);for(let{target:r}=n;r&&r!==this;r=r.parentNode)for(let a=o.length;a--;)if(o[a]===r)return n.delegateTarget=r,i.oneOff&&B.off(t,n.type,e,s),s.apply(r,[n]);return null}}(t,s,i):function(t,e){return function s(i){return i.delegateTarget=t,s.oneOff&&B.off(t,i.type,e),e.apply(t,[i])}}(t,s);u.delegationSelector=o?s:null,u.originalHandler=r,u.oneOff=n,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function H(t,e,s,i,n){const o=M(e[s],i,n);o&&(t.removeEventListener(s,o,Boolean(n)),delete e[s][o.uidEvent])}function R(t){return t=t.replace(C,""),D[t]||t}const B={on(t,e,s,i){j(t,e,s,i,!1)},one(t,e,s,i){j(t,e,s,i,!0)},off(t,e,s,i){if("string"!=typeof e||!t)return;const[n,o,r]=P(e,s,i),a=r!==e,l=x(t),c=e.startsWith(".");if(void 0!==o){if(!l||!l[r])return;return void H(t,l,r,o,n?s:null)}c&&Object.keys(l).forEach(s=>{!function(t,e,s,i){const n=e[s]||{};Object.keys(n).forEach(o=>{if(o.includes(i)){const i=n[o];H(t,e,s,i.originalHandler,i.delegationSelector)}})}(t,l,s,e.slice(1))});const h=l[r]||{};Object.keys(h).forEach(s=>{const i=s.replace(k,"");if(!a||e.includes(i)){const e=h[s];H(t,l,r,e.originalHandler,e.delegationSelector)}})},trigger(t,e,s){if("string"!=typeof e||!t)return null;const i=_(),n=R(e),o=e!==n,r=N.has(n);let a,l=!0,c=!0,h=!1,d=null;return o&&i&&(a=i.Event(e,s),i(t).trigger(a),l=!a.isPropagationStopped(),c=!a.isImmediatePropagationStopped(),h=a.isDefaultPrevented()),r?(d=document.createEvent("HTMLEvents"),d.initEvent(n,l,!0)):d=new CustomEvent(e,{bubbles:l,cancelable:!0}),void 0!==s&&Object.keys(s).forEach(t=>{Object.defineProperty(d,t,{get:()=>s[t]})}),h&&d.preventDefault(),c&&t.dispatchEvent(d),d.defaultPrevented&&void 0!==a&&a.preventDefault(),d}},$=new Map;var W={set(t,e,s){$.has(t)||$.set(t,new Map);const i=$.get(t);i.has(e)||0===i.size?i.set(e,s):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(i.keys())[0]}.`)},get:(t,e)=>$.has(t)&&$.get(t).get(e)||null,remove(t,e){if(!$.has(t))return;const s=$.get(t);s.delete(e),0===s.size&&$.delete(t)}};class q{constructor(t){(t=h(t))&&(this._element=t,W.set(this._element,this.constructor.DATA_KEY,this))}dispose(){W.remove(this._element,this.constructor.DATA_KEY),B.off(this._element,this.constructor.EVENT_KEY),Object.getOwnPropertyNames(this).forEach(t=>{this[t]=null})}_queueCallback(t,e,s=!0){E(t,e,s)}static getInstance(t){return W.get(t,this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.0.2"}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}static get DATA_KEY(){return"bs."+this.NAME}static get EVENT_KEY(){return"."+this.DATA_KEY}}class z extends q{static get NAME(){return"alert"}close(t){const e=t?this._getRootElement(t):this._element,s=this._triggerCloseEvent(e);null===s||s.defaultPrevented||this._removeElement(e)}_getRootElement(t){return a(t)||t.closest(".alert")}_triggerCloseEvent(t){return B.trigger(t,"close.bs.alert")}_removeElement(t){t.classList.remove("show");const e=t.classList.contains("fade");this._queueCallback(()=>this._destroyElement(t),t,e)}_destroyElement(t){t.remove(),B.trigger(t,"closed.bs.alert")}static jQueryInterface(t){return this.each((function(){const e=z.getOrCreateInstance(this);"close"===t&&e[t](this)}))}static handleDismiss(t){return function(e){e&&e.preventDefault(),t.close(this)}}}B.on(document,"click.bs.alert.data-api",'[data-bs-dismiss="alert"]',z.handleDismiss(new z)),y(z);class F extends q{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=F.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}function U(t){return"true"===t||"false"!==t&&(t===Number(t).toString()?Number(t):""===t||"null"===t?null:t)}function K(t){return t.replace(/[A-Z]/g,t=>"-"+t.toLowerCase())}B.on(document,"click.bs.button.data-api",'[data-bs-toggle="button"]',t=>{t.preventDefault();const e=t.target.closest('[data-bs-toggle="button"]');F.getOrCreateInstance(e).toggle()}),y(F);const V={setDataAttribute(t,e,s){t.setAttribute("data-bs-"+K(e),s)},removeDataAttribute(t,e){t.removeAttribute("data-bs-"+K(e))},getDataAttributes(t){if(!t)return{};const e={};return Object.keys(t.dataset).filter(t=>t.startsWith("bs")).forEach(s=>{let i=s.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1,i.length),e[i]=U(t.dataset[s])}),e},getDataAttribute:(t,e)=>U(t.getAttribute("data-bs-"+K(e))),offset(t){const e=t.getBoundingClientRect();return{top:e.top+document.body.scrollTop,left:e.left+document.body.scrollLeft}},position:t=>({top:t.offsetTop,left:t.offsetLeft})},Q={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0,touch:!0},X={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean",touch:"boolean"},Y="next",G="prev",Z="left",J="right",tt={ArrowLeft:J,ArrowRight:Z};class et extends q{constructor(t,e){super(t),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this.touchStartX=0,this.touchDeltaX=0,this._config=this._getConfig(e),this._indicatorsElement=i.findOne(".carousel-indicators",this._element),this._touchSupported="ontouchstart"in document.documentElement||navigator.maxTouchPoints>0,this._pointerEvent=Boolean(window.PointerEvent),this._addEventListeners()}static get Default(){return Q}static get NAME(){return"carousel"}next(){this._slide(Y)}nextWhenVisible(){!document.hidden&&u(this._element)&&this.next()}prev(){this._slide(G)}pause(t){t||(this._isPaused=!0),i.findOne(".carousel-item-next, .carousel-item-prev",this._element)&&(l(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null}cycle(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config&&this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))}to(t){this._activeElement=i.findOne(".active.carousel-item",this._element);const e=this._getItemIndex(this._activeElement);if(t>this._items.length-1||t<0)return;if(this._isSliding)return void B.one(this._element,"slid.bs.carousel",()=>this.to(t));if(e===t)return this.pause(),void this.cycle();const s=t>e?Y:G;this._slide(s,this._items[t])}_getConfig(t){return t={...Q,...V.getDataAttributes(this._element),..."object"==typeof t?t:{}},d("carousel",t,X),t}_handleSwipe(){const t=Math.abs(this.touchDeltaX);if(t<=40)return;const e=t/this.touchDeltaX;this.touchDeltaX=0,e&&this._slide(e>0?J:Z)}_addEventListeners(){this._config.keyboard&&B.on(this._element,"keydown.bs.carousel",t=>this._keydown(t)),"hover"===this._config.pause&&(B.on(this._element,"mouseenter.bs.carousel",t=>this.pause(t)),B.on(this._element,"mouseleave.bs.carousel",t=>this.cycle(t))),this._config.touch&&this._touchSupported&&this._addTouchEventListeners()}_addTouchEventListeners(){const t=t=>{!this._pointerEvent||"pen"!==t.pointerType&&"touch"!==t.pointerType?this._pointerEvent||(this.touchStartX=t.touches[0].clientX):this.touchStartX=t.clientX},e=t=>{this.touchDeltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this.touchStartX},s=t=>{!this._pointerEvent||"pen"!==t.pointerType&&"touch"!==t.pointerType||(this.touchDeltaX=t.clientX-this.touchStartX),this._handleSwipe(),"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout(t=>this.cycle(t),500+this._config.interval))};i.find(".carousel-item img",this._element).forEach(t=>{B.on(t,"dragstart.bs.carousel",t=>t.preventDefault())}),this._pointerEvent?(B.on(this._element,"pointerdown.bs.carousel",e=>t(e)),B.on(this._element,"pointerup.bs.carousel",t=>s(t)),this._element.classList.add("pointer-event")):(B.on(this._element,"touchstart.bs.carousel",e=>t(e)),B.on(this._element,"touchmove.bs.carousel",t=>e(t)),B.on(this._element,"touchend.bs.carousel",t=>s(t)))}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=tt[t.key];e&&(t.preventDefault(),this._slide(e))}_getItemIndex(t){return this._items=t&&t.parentNode?i.find(".carousel-item",t.parentNode):[],this._items.indexOf(t)}_getItemByOrder(t,e){const s=t===Y;return A(this._items,e,s,this._config.wrap)}_triggerSlideEvent(t,e){const s=this._getItemIndex(t),n=this._getItemIndex(i.findOne(".active.carousel-item",this._element));return B.trigger(this._element,"slide.bs.carousel",{relatedTarget:t,direction:e,from:n,to:s})}_setActiveIndicatorElement(t){if(this._indicatorsElement){const e=i.findOne(".active",this._indicatorsElement);e.classList.remove("active"),e.removeAttribute("aria-current");const s=i.find("[data-bs-target]",this._indicatorsElement);for(let e=0;e{B.trigger(this._element,"slid.bs.carousel",{relatedTarget:r,direction:u,from:o,to:a})};if(this._element.classList.contains("slide")){r.classList.add(d),m(r),n.classList.add(h),r.classList.add(h);const t=()=>{r.classList.remove(h,d),r.classList.add("active"),n.classList.remove("active",d,h),this._isSliding=!1,setTimeout(g,0)};this._queueCallback(t,n,!0)}else n.classList.remove("active"),r.classList.add("active"),this._isSliding=!1,g();l&&this.cycle()}_directionToOrder(t){return[J,Z].includes(t)?v()?t===Z?G:Y:t===Z?Y:G:t}_orderToDirection(t){return[Y,G].includes(t)?v()?t===G?Z:J:t===G?J:Z:t}static carouselInterface(t,e){const s=et.getOrCreateInstance(t,e);let{_config:i}=s;"object"==typeof e&&(i={...i,...e});const n="string"==typeof e?e:i.slide;if("number"==typeof e)s.to(e);else if("string"==typeof n){if(void 0===s[n])throw new TypeError(`No method named "${n}"`);s[n]()}else i.interval&&i.ride&&(s.pause(),s.cycle())}static jQueryInterface(t){return this.each((function(){et.carouselInterface(this,t)}))}static dataApiClickHandler(t){const e=a(this);if(!e||!e.classList.contains("carousel"))return;const s={...V.getDataAttributes(e),...V.getDataAttributes(this)},i=this.getAttribute("data-bs-slide-to");i&&(s.interval=!1),et.carouselInterface(e,s),i&&et.getInstance(e).to(i),t.preventDefault()}}B.on(document,"click.bs.carousel.data-api","[data-bs-slide], [data-bs-slide-to]",et.dataApiClickHandler),B.on(window,"load.bs.carousel.data-api",()=>{const t=i.find('[data-bs-ride="carousel"]');for(let e=0,s=t.length;et===this._element);null!==n&&o.length&&(this._selector=n,this._triggerArray.push(e))}this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}static get Default(){return st}static get NAME(){return"collapse"}toggle(){this._element.classList.contains("show")?this.hide():this.show()}show(){if(this._isTransitioning||this._element.classList.contains("show"))return;let t,e;this._parent&&(t=i.find(".show, .collapsing",this._parent).filter(t=>"string"==typeof this._config.parent?t.getAttribute("data-bs-parent")===this._config.parent:t.classList.contains("collapse")),0===t.length&&(t=null));const s=i.findOne(this._selector);if(t){const i=t.find(t=>s!==t);if(e=i?nt.getInstance(i):null,e&&e._isTransitioning)return}if(B.trigger(this._element,"show.bs.collapse").defaultPrevented)return;t&&t.forEach(t=>{s!==t&&nt.collapseInterface(t,"hide"),e||W.set(t,"bs.collapse",null)});const n=this._getDimension();this._element.classList.remove("collapse"),this._element.classList.add("collapsing"),this._element.style[n]=0,this._triggerArray.length&&this._triggerArray.forEach(t=>{t.classList.remove("collapsed"),t.setAttribute("aria-expanded",!0)}),this.setTransitioning(!0);const o="scroll"+(n[0].toUpperCase()+n.slice(1));this._queueCallback(()=>{this._element.classList.remove("collapsing"),this._element.classList.add("collapse","show"),this._element.style[n]="",this.setTransitioning(!1),B.trigger(this._element,"shown.bs.collapse")},this._element,!0),this._element.style[n]=this._element[o]+"px"}hide(){if(this._isTransitioning||!this._element.classList.contains("show"))return;if(B.trigger(this._element,"hide.bs.collapse").defaultPrevented)return;const t=this._getDimension();this._element.style[t]=this._element.getBoundingClientRect()[t]+"px",m(this._element),this._element.classList.add("collapsing"),this._element.classList.remove("collapse","show");const e=this._triggerArray.length;if(e>0)for(let t=0;t{this.setTransitioning(!1),this._element.classList.remove("collapsing"),this._element.classList.add("collapse"),B.trigger(this._element,"hidden.bs.collapse")},this._element,!0)}setTransitioning(t){this._isTransitioning=t}_getConfig(t){return(t={...st,...t}).toggle=Boolean(t.toggle),d("collapse",t,it),t}_getDimension(){return this._element.classList.contains("width")?"width":"height"}_getParent(){let{parent:t}=this._config;t=h(t);const e=`[data-bs-toggle="collapse"][data-bs-parent="${t}"]`;return i.find(e,t).forEach(t=>{const e=a(t);this._addAriaAndCollapsedClass(e,[t])}),t}_addAriaAndCollapsedClass(t,e){if(!t||!e.length)return;const s=t.classList.contains("show");e.forEach(t=>{s?t.classList.remove("collapsed"):t.classList.add("collapsed"),t.setAttribute("aria-expanded",s)})}static collapseInterface(t,e){let s=nt.getInstance(t);const i={...st,...V.getDataAttributes(t),..."object"==typeof e&&e?e:{}};if(!s&&i.toggle&&"string"==typeof e&&/show|hide/.test(e)&&(i.toggle=!1),s||(s=new nt(t,i)),"string"==typeof e){if(void 0===s[e])throw new TypeError(`No method named "${e}"`);s[e]()}}static jQueryInterface(t){return this.each((function(){nt.collapseInterface(this,t)}))}}B.on(document,"click.bs.collapse.data-api",'[data-bs-toggle="collapse"]',(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();const e=V.getDataAttributes(this),s=r(this);i.find(s).forEach(t=>{const s=nt.getInstance(t);let i;s?(null===s._parent&&"string"==typeof e.parent&&(s._config.parent=e.parent,s._parent=s._getParent()),i="toggle"):i=e,nt.collapseInterface(t,i)})})),y(nt);const ot=new RegExp("ArrowUp|ArrowDown|Escape"),rt=v()?"top-end":"top-start",at=v()?"top-start":"top-end",lt=v()?"bottom-end":"bottom-start",ct=v()?"bottom-start":"bottom-end",ht=v()?"left-start":"right-start",dt=v()?"right-start":"left-start",ut={offset:[0,2],boundary:"clippingParents",reference:"toggle",display:"dynamic",popperConfig:null,autoClose:!0},gt={offset:"(array|string|function)",boundary:"(string|element)",reference:"(string|element|object)",display:"string",popperConfig:"(null|object|function)",autoClose:"(boolean|string)"};class pt extends q{constructor(t,e){super(t),this._popper=null,this._config=this._getConfig(e),this._menu=this._getMenuElement(),this._inNavbar=this._detectNavbar(),this._addEventListeners()}static get Default(){return ut}static get DefaultType(){return gt}static get NAME(){return"dropdown"}toggle(){g(this._element)||(this._element.classList.contains("show")?this.hide():this.show())}show(){if(g(this._element)||this._menu.classList.contains("show"))return;const t=pt.getParentFromElement(this._element),e={relatedTarget:this._element};if(!B.trigger(this._element,"show.bs.dropdown",e).defaultPrevented){if(this._inNavbar)V.setDataAttribute(this._menu,"popper","none");else{if(void 0===s)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");let e=this._element;"parent"===this._config.reference?e=t:c(this._config.reference)?e=h(this._config.reference):"object"==typeof this._config.reference&&(e=this._config.reference);const i=this._getPopperConfig(),n=i.modifiers.find(t=>"applyStyles"===t.name&&!1===t.enabled);this._popper=s.createPopper(e,this._menu,i),n&&V.setDataAttribute(this._menu,"popper","static")}"ontouchstart"in document.documentElement&&!t.closest(".navbar-nav")&&[].concat(...document.body.children).forEach(t=>B.on(t,"mouseover",f)),this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.toggle("show"),this._element.classList.toggle("show"),B.trigger(this._element,"shown.bs.dropdown",e)}}hide(){if(g(this._element)||!this._menu.classList.contains("show"))return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_addEventListeners(){B.on(this._element,"click.bs.dropdown",t=>{t.preventDefault(),this.toggle()})}_completeHide(t){B.trigger(this._element,"hide.bs.dropdown",t).defaultPrevented||("ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach(t=>B.off(t,"mouseover",f)),this._popper&&this._popper.destroy(),this._menu.classList.remove("show"),this._element.classList.remove("show"),this._element.setAttribute("aria-expanded","false"),V.removeDataAttribute(this._menu,"popper"),B.trigger(this._element,"hidden.bs.dropdown",t))}_getConfig(t){if(t={...this.constructor.Default,...V.getDataAttributes(this._element),...t},d("dropdown",t,this.constructor.DefaultType),"object"==typeof t.reference&&!c(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError("dropdown".toUpperCase()+': Option "reference" provided type "object" without a required "getBoundingClientRect" method.');return t}_getMenuElement(){return i.next(this._element,".dropdown-menu")[0]}_getPlacement(){const t=this._element.parentNode;if(t.classList.contains("dropend"))return ht;if(t.classList.contains("dropstart"))return dt;const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?at:rt:e?ct:lt}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map(t=>Number.parseInt(t,10)):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return"static"===this._config.display&&(t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,..."function"==typeof this._config.popperConfig?this._config.popperConfig(t):this._config.popperConfig}}_selectMenuItem({key:t,target:e}){const s=i.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter(u);s.length&&A(s,e,"ArrowDown"===t,!s.includes(e)).focus()}static dropdownInterface(t,e){const s=pt.getOrCreateInstance(t,e);if("string"==typeof e){if(void 0===s[e])throw new TypeError(`No method named "${e}"`);s[e]()}}static jQueryInterface(t){return this.each((function(){pt.dropdownInterface(this,t)}))}static clearMenus(t){if(t&&(2===t.button||"keyup"===t.type&&"Tab"!==t.key))return;const e=i.find('[data-bs-toggle="dropdown"]');for(let s=0,i=e.length;sthis.matches('[data-bs-toggle="dropdown"]')?this:i.prev(this,'[data-bs-toggle="dropdown"]')[0];return"Escape"===t.key?(s().focus(),void pt.clearMenus()):"ArrowUp"===t.key||"ArrowDown"===t.key?(e||s().click(),void pt.getInstance(s())._selectMenuItem(t)):void(e&&"Space"!==t.key||pt.clearMenus())}}B.on(document,"keydown.bs.dropdown.data-api",'[data-bs-toggle="dropdown"]',pt.dataApiKeydownHandler),B.on(document,"keydown.bs.dropdown.data-api",".dropdown-menu",pt.dataApiKeydownHandler),B.on(document,"click.bs.dropdown.data-api",pt.clearMenus),B.on(document,"keyup.bs.dropdown.data-api",pt.clearMenus),B.on(document,"click.bs.dropdown.data-api",'[data-bs-toggle="dropdown"]',(function(t){t.preventDefault(),pt.dropdownInterface(this)})),y(pt);class ft{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,"paddingRight",e=>e+t),this._setElementAttributes(".fixed-top, .fixed-bottom, .is-fixed, .sticky-top","paddingRight",e=>e+t),this._setElementAttributes(".sticky-top","marginRight",e=>e-t)}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,s){const i=this.getWidth();this._applyManipulationCallback(t,t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+i)return;this._saveInitialAttribute(t,e);const n=window.getComputedStyle(t)[e];t.style[e]=s(Number.parseFloat(n))+"px"})}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,"paddingRight"),this._resetElementAttributes(".fixed-top, .fixed-bottom, .is-fixed, .sticky-top","paddingRight"),this._resetElementAttributes(".sticky-top","marginRight")}_saveInitialAttribute(t,e){const s=t.style[e];s&&V.setDataAttribute(t,e,s)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,t=>{const s=V.getDataAttribute(t,e);void 0===s?t.style.removeProperty(e):(V.removeDataAttribute(t,e),t.style[e]=s)})}_applyManipulationCallback(t,e){c(t)?e(t):i.find(t,this._element).forEach(e)}isOverflowing(){return this.getWidth()>0}}const mt={isVisible:!0,isAnimated:!1,rootElement:"body",clickCallback:null},_t={isVisible:"boolean",isAnimated:"boolean",rootElement:"(element|string)",clickCallback:"(function|null)"};class bt{constructor(t){this._config=this._getConfig(t),this._isAppended=!1,this._element=null}show(t){this._config.isVisible?(this._append(),this._config.isAnimated&&m(this._getElement()),this._getElement().classList.add("show"),this._emulateAnimation(()=>{w(t)})):w(t)}hide(t){this._config.isVisible?(this._getElement().classList.remove("show"),this._emulateAnimation(()=>{this.dispose(),w(t)})):w(t)}_getElement(){if(!this._element){const t=document.createElement("div");t.className="modal-backdrop",this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_getConfig(t){return(t={...mt,..."object"==typeof t?t:{}}).rootElement=h(t.rootElement),d("backdrop",t,_t),t}_append(){this._isAppended||(this._config.rootElement.appendChild(this._getElement()),B.on(this._getElement(),"mousedown.bs.backdrop",()=>{w(this._config.clickCallback)}),this._isAppended=!0)}dispose(){this._isAppended&&(B.off(this._element,"mousedown.bs.backdrop"),this._element.remove(),this._isAppended=!1)}_emulateAnimation(t){E(t,this._getElement(),this._config.isAnimated)}}const vt={backdrop:!0,keyboard:!0,focus:!0},yt={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean"};class wt extends q{constructor(t,e){super(t),this._config=this._getConfig(e),this._dialog=i.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._isShown=!1,this._ignoreBackdropClick=!1,this._isTransitioning=!1,this._scrollBar=new ft}static get Default(){return vt}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||B.trigger(this._element,"show.bs.modal",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isAnimated()&&(this._isTransitioning=!0),this._scrollBar.hide(),document.body.classList.add("modal-open"),this._adjustDialog(),this._setEscapeEvent(),this._setResizeEvent(),B.on(this._element,"click.dismiss.bs.modal",'[data-bs-dismiss="modal"]',t=>this.hide(t)),B.on(this._dialog,"mousedown.dismiss.bs.modal",()=>{B.one(this._element,"mouseup.dismiss.bs.modal",t=>{t.target===this._element&&(this._ignoreBackdropClick=!0)})}),this._showBackdrop(()=>this._showElement(t)))}hide(t){if(t&&["A","AREA"].includes(t.target.tagName)&&t.preventDefault(),!this._isShown||this._isTransitioning)return;if(B.trigger(this._element,"hide.bs.modal").defaultPrevented)return;this._isShown=!1;const e=this._isAnimated();e&&(this._isTransitioning=!0),this._setEscapeEvent(),this._setResizeEvent(),B.off(document,"focusin.bs.modal"),this._element.classList.remove("show"),B.off(this._element,"click.dismiss.bs.modal"),B.off(this._dialog,"mousedown.dismiss.bs.modal"),this._queueCallback(()=>this._hideModal(),this._element,e)}dispose(){[window,this._dialog].forEach(t=>B.off(t,".bs.modal")),this._backdrop.dispose(),super.dispose(),B.off(document,"focusin.bs.modal")}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new bt({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_getConfig(t){return t={...vt,...V.getDataAttributes(this._element),..."object"==typeof t?t:{}},d("modal",t,yt),t}_showElement(t){const e=this._isAnimated(),s=i.findOne(".modal-body",this._dialog);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.appendChild(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0,s&&(s.scrollTop=0),e&&m(this._element),this._element.classList.add("show"),this._config.focus&&this._enforceFocus(),this._queueCallback(()=>{this._config.focus&&this._element.focus(),this._isTransitioning=!1,B.trigger(this._element,"shown.bs.modal",{relatedTarget:t})},this._dialog,e)}_enforceFocus(){B.off(document,"focusin.bs.modal"),B.on(document,"focusin.bs.modal",t=>{document===t.target||this._element===t.target||this._element.contains(t.target)||this._element.focus()})}_setEscapeEvent(){this._isShown?B.on(this._element,"keydown.dismiss.bs.modal",t=>{this._config.keyboard&&"Escape"===t.key?(t.preventDefault(),this.hide()):this._config.keyboard||"Escape"!==t.key||this._triggerBackdropTransition()}):B.off(this._element,"keydown.dismiss.bs.modal")}_setResizeEvent(){this._isShown?B.on(window,"resize.bs.modal",()=>this._adjustDialog()):B.off(window,"resize.bs.modal")}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide(()=>{document.body.classList.remove("modal-open"),this._resetAdjustments(),this._scrollBar.reset(),B.trigger(this._element,"hidden.bs.modal")})}_showBackdrop(t){B.on(this._element,"click.dismiss.bs.modal",t=>{this._ignoreBackdropClick?this._ignoreBackdropClick=!1:t.target===t.currentTarget&&(!0===this._config.backdrop?this.hide():"static"===this._config.backdrop&&this._triggerBackdropTransition())}),this._backdrop.show(t)}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(B.trigger(this._element,"hidePrevented.bs.modal").defaultPrevented)return;const{classList:t,scrollHeight:e,style:s}=this._element,i=e>document.documentElement.clientHeight;!i&&"hidden"===s.overflowY||t.contains("modal-static")||(i||(s.overflowY="hidden"),t.add("modal-static"),this._queueCallback(()=>{t.remove("modal-static"),i||this._queueCallback(()=>{s.overflowY=""},this._dialog)},this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),s=e>0;(!s&&t&&!v()||s&&!t&&v())&&(this._element.style.paddingLeft=e+"px"),(s&&!t&&!v()||!s&&t&&v())&&(this._element.style.paddingRight=e+"px")}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const s=wt.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===s[t])throw new TypeError(`No method named "${t}"`);s[t](e)}}))}}B.on(document,"click.bs.modal.data-api",'[data-bs-toggle="modal"]',(function(t){const e=a(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),B.one(e,"show.bs.modal",t=>{t.defaultPrevented||B.one(e,"hidden.bs.modal",()=>{u(this)&&this.focus()})}),wt.getOrCreateInstance(e).toggle(this)})),y(wt);const Et={backdrop:!0,keyboard:!0,scroll:!1},At={backdrop:"boolean",keyboard:"boolean",scroll:"boolean"};class Tt extends q{constructor(t,e){super(t),this._config=this._getConfig(e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._addEventListeners()}static get NAME(){return"offcanvas"}static get Default(){return Et}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||B.trigger(this._element,"show.bs.offcanvas",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._element.style.visibility="visible",this._backdrop.show(),this._config.scroll||((new ft).hide(),this._enforceFocusOnElement(this._element)),this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add("show"),this._queueCallback(()=>{B.trigger(this._element,"shown.bs.offcanvas",{relatedTarget:t})},this._element,!0))}hide(){this._isShown&&(B.trigger(this._element,"hide.bs.offcanvas").defaultPrevented||(B.off(document,"focusin.bs.offcanvas"),this._element.blur(),this._isShown=!1,this._element.classList.remove("show"),this._backdrop.hide(),this._queueCallback(()=>{this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._element.style.visibility="hidden",this._config.scroll||(new ft).reset(),B.trigger(this._element,"hidden.bs.offcanvas")},this._element,!0)))}dispose(){this._backdrop.dispose(),super.dispose(),B.off(document,"focusin.bs.offcanvas")}_getConfig(t){return t={...Et,...V.getDataAttributes(this._element),..."object"==typeof t?t:{}},d("offcanvas",t,At),t}_initializeBackDrop(){return new bt({isVisible:this._config.backdrop,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:()=>this.hide()})}_enforceFocusOnElement(t){B.off(document,"focusin.bs.offcanvas"),B.on(document,"focusin.bs.offcanvas",e=>{document===e.target||t===e.target||t.contains(e.target)||t.focus()}),t.focus()}_addEventListeners(){B.on(this._element,"click.dismiss.bs.offcanvas",'[data-bs-dismiss="offcanvas"]',()=>this.hide()),B.on(this._element,"keydown.dismiss.bs.offcanvas",t=>{this._config.keyboard&&"Escape"===t.key&&this.hide()})}static jQueryInterface(t){return this.each((function(){const e=Tt.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}B.on(document,"click.bs.offcanvas.data-api",'[data-bs-toggle="offcanvas"]',(function(t){const e=a(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),g(this))return;B.one(e,"hidden.bs.offcanvas",()=>{u(this)&&this.focus()});const s=i.findOne(".offcanvas.show");s&&s!==e&&Tt.getInstance(s).hide(),Tt.getOrCreateInstance(e).toggle(this)})),B.on(window,"load.bs.offcanvas.data-api",()=>i.find(".offcanvas.show").forEach(t=>Tt.getOrCreateInstance(t).show())),y(Tt);const Ct=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),kt=/^(?:(?:https?|mailto|ftp|tel|file):|[^#&/:?]*(?:[#/?]|$))/i,Lt=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i,Ot=(t,e)=>{const s=t.nodeName.toLowerCase();if(e.includes(s))return!Ct.has(s)||Boolean(kt.test(t.nodeValue)||Lt.test(t.nodeValue));const i=e.filter(t=>t instanceof RegExp);for(let t=0,e=i.length;t{Ot(t,a)||s.removeAttribute(t.nodeName)})}return i.body.innerHTML}const It=new RegExp("(^|\\s)bs-tooltip\\S+","g"),Nt=new Set(["sanitize","allowList","sanitizeFn"]),St={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(array|string|function)",container:"(string|element|boolean)",fallbackPlacements:"array",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",allowList:"object",popperConfig:"(null|object|function)"},xt={AUTO:"auto",TOP:"top",RIGHT:v()?"left":"right",BOTTOM:"bottom",LEFT:v()?"right":"left"},Mt={animation:!0,template:'',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:[0,0],container:!1,fallbackPlacements:["top","right","bottom","left"],boundary:"clippingParents",customClass:"",sanitize:!0,sanitizeFn:null,allowList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},Pt={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"};class jt extends q{constructor(t,e){if(void 0===s)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this._config=this._getConfig(e),this.tip=null,this._setListeners()}static get Default(){return Mt}static get NAME(){return"tooltip"}static get Event(){return Pt}static get DefaultType(){return St}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(t){if(this._isEnabled)if(t){const e=this._initializeOnDelegatedTarget(t);e._activeTrigger.click=!e._activeTrigger.click,e._isWithActiveTrigger()?e._enter(null,e):e._leave(null,e)}else{if(this.getTipElement().classList.contains("show"))return void this._leave(null,this);this._enter(null,this)}}dispose(){clearTimeout(this._timeout),B.off(this._element.closest(".modal"),"hide.bs.modal",this._hideModalHandler),this.tip&&this.tip.remove(),this._popper&&this._popper.destroy(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this.isWithContent()||!this._isEnabled)return;const t=B.trigger(this._element,this.constructor.Event.SHOW),e=p(this._element),i=null===e?this._element.ownerDocument.documentElement.contains(this._element):e.contains(this._element);if(t.defaultPrevented||!i)return;const o=this.getTipElement(),r=n(this.constructor.NAME);o.setAttribute("id",r),this._element.setAttribute("aria-describedby",r),this.setContent(),this._config.animation&&o.classList.add("fade");const a="function"==typeof this._config.placement?this._config.placement.call(this,o,this._element):this._config.placement,l=this._getAttachment(a);this._addAttachmentClass(l);const{container:c}=this._config;W.set(o,this.constructor.DATA_KEY,this),this._element.ownerDocument.documentElement.contains(this.tip)||(c.appendChild(o),B.trigger(this._element,this.constructor.Event.INSERTED)),this._popper?this._popper.update():this._popper=s.createPopper(this._element,o,this._getPopperConfig(l)),o.classList.add("show");const h="function"==typeof this._config.customClass?this._config.customClass():this._config.customClass;h&&o.classList.add(...h.split(" ")),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach(t=>{B.on(t,"mouseover",f)});const d=this.tip.classList.contains("fade");this._queueCallback(()=>{const t=this._hoverState;this._hoverState=null,B.trigger(this._element,this.constructor.Event.SHOWN),"out"===t&&this._leave(null,this)},this.tip,d)}hide(){if(!this._popper)return;const t=this.getTipElement();if(B.trigger(this._element,this.constructor.Event.HIDE).defaultPrevented)return;t.classList.remove("show"),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach(t=>B.off(t,"mouseover",f)),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1;const e=this.tip.classList.contains("fade");this._queueCallback(()=>{this._isWithActiveTrigger()||("show"!==this._hoverState&&t.remove(),this._cleanTipClass(),this._element.removeAttribute("aria-describedby"),B.trigger(this._element,this.constructor.Event.HIDDEN),this._popper&&(this._popper.destroy(),this._popper=null))},this.tip,e),this._hoverState=""}update(){null!==this._popper&&this._popper.update()}isWithContent(){return Boolean(this.getTitle())}getTipElement(){if(this.tip)return this.tip;const t=document.createElement("div");return t.innerHTML=this._config.template,this.tip=t.children[0],this.tip}setContent(){const t=this.getTipElement();this.setElementContent(i.findOne(".tooltip-inner",t),this.getTitle()),t.classList.remove("fade","show")}setElementContent(t,e){if(null!==t)return c(e)?(e=h(e),void(this._config.html?e.parentNode!==t&&(t.innerHTML="",t.appendChild(e)):t.textContent=e.textContent)):void(this._config.html?(this._config.sanitize&&(e=Dt(e,this._config.allowList,this._config.sanitizeFn)),t.innerHTML=e):t.textContent=e)}getTitle(){let t=this._element.getAttribute("data-bs-original-title");return t||(t="function"==typeof this._config.title?this._config.title.call(this._element):this._config.title),t}updateAttachment(t){return"right"===t?"end":"left"===t?"start":t}_initializeOnDelegatedTarget(t,e){const s=this.constructor.DATA_KEY;return(e=e||W.get(t.delegateTarget,s))||(e=new this.constructor(t.delegateTarget,this._getDelegateConfig()),W.set(t.delegateTarget,s,e)),e}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map(t=>Number.parseInt(t,10)):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"onChange",enabled:!0,phase:"afterWrite",fn:t=>this._handlePopperPlacementChange(t)}],onFirstUpdate:t=>{t.options.placement!==t.placement&&this._handlePopperPlacementChange(t)}};return{...e,..."function"==typeof this._config.popperConfig?this._config.popperConfig(e):this._config.popperConfig}}_addAttachmentClass(t){this.getTipElement().classList.add("bs-tooltip-"+this.updateAttachment(t))}_getAttachment(t){return xt[t.toUpperCase()]}_setListeners(){this._config.trigger.split(" ").forEach(t=>{if("click"===t)B.on(this._element,this.constructor.Event.CLICK,this._config.selector,t=>this.toggle(t));else if("manual"!==t){const e="hover"===t?this.constructor.Event.MOUSEENTER:this.constructor.Event.FOCUSIN,s="hover"===t?this.constructor.Event.MOUSELEAVE:this.constructor.Event.FOCUSOUT;B.on(this._element,e,this._config.selector,t=>this._enter(t)),B.on(this._element,s,this._config.selector,t=>this._leave(t))}}),this._hideModalHandler=()=>{this._element&&this.hide()},B.on(this._element.closest(".modal"),"hide.bs.modal",this._hideModalHandler),this._config.selector?this._config={...this._config,trigger:"manual",selector:""}:this._fixTitle()}_fixTitle(){const t=this._element.getAttribute("title"),e=typeof this._element.getAttribute("data-bs-original-title");(t||"string"!==e)&&(this._element.setAttribute("data-bs-original-title",t||""),!t||this._element.getAttribute("aria-label")||this._element.textContent||this._element.setAttribute("aria-label",t),this._element.setAttribute("title",""))}_enter(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusin"===t.type?"focus":"hover"]=!0),e.getTipElement().classList.contains("show")||"show"===e._hoverState?e._hoverState="show":(clearTimeout(e._timeout),e._hoverState="show",e._config.delay&&e._config.delay.show?e._timeout=setTimeout(()=>{"show"===e._hoverState&&e.show()},e._config.delay.show):e.show())}_leave(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusout"===t.type?"focus":"hover"]=e._element.contains(t.relatedTarget)),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState="out",e._config.delay&&e._config.delay.hide?e._timeout=setTimeout(()=>{"out"===e._hoverState&&e.hide()},e._config.delay.hide):e.hide())}_isWithActiveTrigger(){for(const t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1}_getConfig(t){const e=V.getDataAttributes(this._element);return Object.keys(e).forEach(t=>{Nt.has(t)&&delete e[t]}),(t={...this.constructor.Default,...e,..."object"==typeof t&&t?t:{}}).container=!1===t.container?document.body:h(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),d("tooltip",t,this.constructor.DefaultType),t.sanitize&&(t.template=Dt(t.template,t.allowList,t.sanitizeFn)),t}_getDelegateConfig(){const t={};if(this._config)for(const e in this._config)this.constructor.Default[e]!==this._config[e]&&(t[e]=this._config[e]);return t}_cleanTipClass(){const t=this.getTipElement(),e=t.getAttribute("class").match(It);null!==e&&e.length>0&&e.map(t=>t.trim()).forEach(e=>t.classList.remove(e))}_handlePopperPlacementChange(t){const{state:e}=t;e&&(this.tip=e.elements.popper,this._cleanTipClass(),this._addAttachmentClass(this._getAttachment(e.placement)))}static jQueryInterface(t){return this.each((function(){const e=jt.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}y(jt);const Ht=new RegExp("(^|\\s)bs-popover\\S+","g"),Rt={...jt.Default,placement:"right",offset:[0,8],trigger:"click",content:"",template:''},Bt={...jt.DefaultType,content:"(string|element|function)"},$t={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"};class Wt extends jt{static get Default(){return Rt}static get NAME(){return"popover"}static get Event(){return $t}static get DefaultType(){return Bt}isWithContent(){return this.getTitle()||this._getContent()}getTipElement(){return this.tip||(this.tip=super.getTipElement(),this.getTitle()||i.findOne(".popover-header",this.tip).remove(),this._getContent()||i.findOne(".popover-body",this.tip).remove()),this.tip}setContent(){const t=this.getTipElement();this.setElementContent(i.findOne(".popover-header",t),this.getTitle());let e=this._getContent();"function"==typeof e&&(e=e.call(this._element)),this.setElementContent(i.findOne(".popover-body",t),e),t.classList.remove("fade","show")}_addAttachmentClass(t){this.getTipElement().classList.add("bs-popover-"+this.updateAttachment(t))}_getContent(){return this._element.getAttribute("data-bs-content")||this._config.content}_cleanTipClass(){const t=this.getTipElement(),e=t.getAttribute("class").match(Ht);null!==e&&e.length>0&&e.map(t=>t.trim()).forEach(e=>t.classList.remove(e))}static jQueryInterface(t){return this.each((function(){const e=Wt.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}y(Wt);const qt={offset:10,method:"auto",target:""},zt={offset:"number",method:"string",target:"(string|element)"};class Ft extends q{constructor(t,e){super(t),this._scrollElement="BODY"===this._element.tagName?window:this._element,this._config=this._getConfig(e),this._selector=`${this._config.target} .nav-link, ${this._config.target} .list-group-item, ${this._config.target} .dropdown-item`,this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,B.on(this._scrollElement,"scroll.bs.scrollspy",()=>this._process()),this.refresh(),this._process()}static get Default(){return qt}static get NAME(){return"scrollspy"}refresh(){const t=this._scrollElement===this._scrollElement.window?"offset":"position",e="auto"===this._config.method?t:this._config.method,s="position"===e?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),i.find(this._selector).map(t=>{const n=r(t),o=n?i.findOne(n):null;if(o){const t=o.getBoundingClientRect();if(t.width||t.height)return[V[e](o).top+s,n]}return null}).filter(t=>t).sort((t,e)=>t[0]-e[0]).forEach(t=>{this._offsets.push(t[0]),this._targets.push(t[1])})}dispose(){B.off(this._scrollElement,".bs.scrollspy"),super.dispose()}_getConfig(t){if("string"!=typeof(t={...qt,...V.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}}).target&&c(t.target)){let{id:e}=t.target;e||(e=n("scrollspy"),t.target.id=e),t.target="#"+e}return d("scrollspy",t,zt),t}_getScrollTop(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop}_getScrollHeight(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)}_getOffsetHeight(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height}_process(){const t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),s=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=s){const t=this._targets[this._targets.length-1];this._activeTarget!==t&&this._activate(t)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(let e=this._offsets.length;e--;)this._activeTarget!==this._targets[e]&&t>=this._offsets[e]&&(void 0===this._offsets[e+1]||t`${e}[data-bs-target="${t}"],${e}[href="${t}"]`),s=i.findOne(e.join(","));s.classList.contains("dropdown-item")?(i.findOne(".dropdown-toggle",s.closest(".dropdown")).classList.add("active"),s.classList.add("active")):(s.classList.add("active"),i.parents(s,".nav, .list-group").forEach(t=>{i.prev(t,".nav-link, .list-group-item").forEach(t=>t.classList.add("active")),i.prev(t,".nav-item").forEach(t=>{i.children(t,".nav-link").forEach(t=>t.classList.add("active"))})})),B.trigger(this._scrollElement,"activate.bs.scrollspy",{relatedTarget:t})}_clear(){i.find(this._selector).filter(t=>t.classList.contains("active")).forEach(t=>t.classList.remove("active"))}static jQueryInterface(t){return this.each((function(){const e=Ft.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}B.on(window,"load.bs.scrollspy.data-api",()=>{i.find('[data-bs-spy="scroll"]').forEach(t=>new Ft(t))}),y(Ft);class Ut extends q{static get NAME(){return"tab"}show(){if(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&this._element.classList.contains("active"))return;let t;const e=a(this._element),s=this._element.closest(".nav, .list-group");if(s){const e="UL"===s.nodeName||"OL"===s.nodeName?":scope > li > .active":".active";t=i.find(e,s),t=t[t.length-1]}const n=t?B.trigger(t,"hide.bs.tab",{relatedTarget:this._element}):null;if(B.trigger(this._element,"show.bs.tab",{relatedTarget:t}).defaultPrevented||null!==n&&n.defaultPrevented)return;this._activate(this._element,s);const o=()=>{B.trigger(t,"hidden.bs.tab",{relatedTarget:this._element}),B.trigger(this._element,"shown.bs.tab",{relatedTarget:t})};e?this._activate(e,e.parentNode,o):o()}_activate(t,e,s){const n=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?i.children(e,".active"):i.find(":scope > li > .active",e))[0],o=s&&n&&n.classList.contains("fade"),r=()=>this._transitionComplete(t,n,s);n&&o?(n.classList.remove("show"),this._queueCallback(r,t,!0)):r()}_transitionComplete(t,e,s){if(e){e.classList.remove("active");const t=i.findOne(":scope > .dropdown-menu .active",e.parentNode);t&&t.classList.remove("active"),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}t.classList.add("active"),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),m(t),t.classList.contains("fade")&&t.classList.add("show");let n=t.parentNode;if(n&&"LI"===n.nodeName&&(n=n.parentNode),n&&n.classList.contains("dropdown-menu")){const e=t.closest(".dropdown");e&&i.find(".dropdown-toggle",e).forEach(t=>t.classList.add("active")),t.setAttribute("aria-expanded",!0)}s&&s()}static jQueryInterface(t){return this.each((function(){const e=Ut.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}B.on(document,"click.bs.tab.data-api",'[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),g(this)||Ut.getOrCreateInstance(this).show()})),y(Ut);const Kt={animation:"boolean",autohide:"boolean",delay:"number"},Vt={animation:!0,autohide:!0,delay:5e3};class Qt extends q{constructor(t,e){super(t),this._config=this._getConfig(e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get DefaultType(){return Kt}static get Default(){return Vt}static get NAME(){return"toast"}show(){B.trigger(this._element,"show.bs.toast").defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove("hide"),m(this._element),this._element.classList.add("showing"),this._queueCallback(()=>{this._element.classList.remove("showing"),this._element.classList.add("show"),B.trigger(this._element,"shown.bs.toast"),this._maybeScheduleHide()},this._element,this._config.animation))}hide(){this._element.classList.contains("show")&&(B.trigger(this._element,"hide.bs.toast").defaultPrevented||(this._element.classList.remove("show"),this._queueCallback(()=>{this._element.classList.add("hide"),B.trigger(this._element,"hidden.bs.toast")},this._element,this._config.animation)))}dispose(){this._clearTimeout(),this._element.classList.contains("show")&&this._element.classList.remove("show"),super.dispose()}_getConfig(t){return t={...Vt,...V.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}},d("toast",t,this.constructor.DefaultType),t}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout(()=>{this.hide()},this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const s=t.relatedTarget;this._element===s||this._element.contains(s)||this._maybeScheduleHide()}_setListeners(){B.on(this._element,"click.dismiss.bs.toast",'[data-bs-dismiss="toast"]',()=>this.hide()),B.on(this._element,"mouseover.bs.toast",t=>this._onInteraction(t,!0)),B.on(this._element,"mouseout.bs.toast",t=>this._onInteraction(t,!1)),B.on(this._element,"focusin.bs.toast",t=>this._onInteraction(t,!0)),B.on(this._element,"focusout.bs.toast",t=>this._onInteraction(t,!1))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=Qt.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return y(Qt),{Alert:z,Button:F,Carousel:et,Collapse:nt,Dropdown:pt,Modal:wt,Offcanvas:Tt,Popover:Wt,ScrollSpy:Ft,Tab:Ut,Toast:Qt,Tooltip:jt}})); -//# sourceMappingURL=bootstrap.min.js.map \ No newline at end of file diff --git a/web/app/plugins/ld-content-cloner/admin/js/ld-content-cloner-admin.js b/web/app/plugins/ld-content-cloner/admin/js/ld-content-cloner-admin.js deleted file mode 100644 index fc332f679..000000000 --- a/web/app/plugins/ld-content-cloner/admin/js/ld-content-cloner-admin.js +++ /dev/null @@ -1,314 +0,0 @@ -/** - * This file is used to implement the successive AJAX functionality for the content cloner plugin. - * - * @package Content Cloner. - */ - -(function($) { - 'use strict'; - - $( document ).ready( - function() { - - $( '.carousel' ).carousel( - { - interval: 1000 * 10 - } - ); - var old_course_id = 0; - var new_course_id = 0; - var og_course_id = 0; - var action = ""; - - var og_group_id = 0; - var new_group_id = 0; - - var curriculum_data = ""; - - var curr_lesson_ind = 0; - var next_lesson = 0; - - var curr_quiz_ind = 0; - var next_quiz = 0; - function setCookie(cname, cvalue, exdays) { - var d = new Date(); - d.setTime( d.getTime() + (exdays * 24 * 60 * 60 * 1000) ); - var expires = "expires=" + d.toUTCString(); - document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/"; - } - function getCookie(cname) { - var name = cname + "="; - var decodedCookie = decodeURIComponent( document.cookie ); - var ca = decodedCookie.split( ';' ); - var cookie_length = ca.length; - for (var i = 0; i < cookie_length; i++) { - var c = ca[i]; - while (c.charAt( 0 ) == ' ') { - c = c.substring( 1 ); - } - if (c.indexOf( name ) == 0) { - return c.substring( name.length, c.length ); - } - } - return ""; - } - $( '.ldcc-clone-course' ).click( - function(e) { - $( '.wdm_leftwrap' ).removeAttr( 'style' ); - e.preventDefault(); - if ("" === getCookie( 'show_data_upgrade_notice' )) { - alert( "If you face any issues after cloning the course. \n(1) Go to LearnDash LMS > Settings > Data Upgrades \n(2) Uncheck the Process Mismatched Questions only? checkbox. \n(3) Now run all of the upgrades on the page.\n(4) Try Cloning the course again." ); - setCookie( 'show_data_upgrade_notice', 'yes' ); - } - var originalContent; - $( '#ldcc-dialog' ).dialog( - { - modal: true, - closeOnEscape: false, - draggable: false, - resizable: false, - minWidth: 500, - // minHeight: 400,//. - open: function(event, ui) { - originalContent = $( "#ldcc-dialog" ).html(); - $( "#ldcc-dialog" ).removeClass( 'hidden' ); - $( ".ui-dialog-titlebar-close", ui.dialog | ui ).addClass( 'hide_extra_close' ); - // var win = $(window); - // $(this).parent().css({ - // position: 'fixed', - // left: (win.width() - $(this).parent().outerWidth()) / 2, - // top: (win.height() - $(this).parent().outerHeight()) / 2 - // }); - }, - close: function(event, ui) { - $( "#ldcc-dialog" ).html( originalContent ); - $( "#ldcc-dialog" ).addClass( 'hidden' ); - // window.location.reload();//. - } - } - ); - var course_id = og_course_id = $( this ).data( 'course-id' ); - var course = $( this ).data( 'course' ); - - var course_title = $( this ).parents( 'td.title.column-title' ).find( 'strong a.row-title' ).text(); - - $( '#ldcc-dialog #ldcc_clone_status' ).append( "
" + ldcc_js_data.course_label + " - " + course_title + "
" ); - action = "duplicate_course_new"; - $.ajax( - { - method: "POST", - url: ldcc_js_data.adm_ajax_url, - data: { - course: course, - course_id: course_id, - action: action, - }, - success: function(result) { - var res = JSON.parse( result ); - if (res.success) { - new_course_id = res.success.new_course_id; - old_course_id = res.success.old_course_id; - curriculum_data = res.success.c_data; - $( '#ldcc-dialog .ldcc-course-progress img' ).attr( "src", ldcc_js_data.image_base_url + "tick.png" ); - $( '#ldcc-dialog' ).trigger( "course_post_created" ); - } else { - $( '#ldcc-dialog #ldcc_clone_status' ).append( "
" + res.error + "
" ); - } - } - } - ); - } - ); - - $( '.ldcc-clone-group' ).click( - function(e) { - $( '.wdm_leftwrap' ).removeAttr( 'style' ); - e.preventDefault(); - $( '#ldcc-group-dialog' ).dialog( - { - modal: true, - closeOnEscape: false, - draggable: false, - resizable: false, - minWidth: 500, - // minHeight: 400,//. - open: function(event, ui) { - // Commented this as it was hiding the close button for group cloning. - // $(".ui-dialog-titlebar-close", ui.dialog | ui).hide();//. - $( "#ldcc-group-dialog" ).removeClass( 'hidden' ); - $( ".ui-dialog-titlebar-close", ui.dialog | ui ).addClass( 'hide_extra_close' ); - // var win = $(window); - // $(this).parent().css({ - // position: 'fixed', - // left: (win.width() - $(this).parent().outerWidth()) / 2, - // top: (win.height() - $(this).parent().outerHeight()) / 2 - // }); - }, - close: function(event, ui) { - $( "#ldcc-group-dialog" ).addClass( 'hidden' ); - // window.location.reload();//. - } - } - ); - var group_id = og_group_id = $( this ).data( 'group-id' ); - var group = $( this ).data( 'group' ); - - var group_title = $( this ).parents( 'td.title.column-title' ).find( 'strong a.row-title' ).text(); - - $( '#ldcc-group-dialog #ldcc_clone_status' ).append( "
" + group_title + "
" ); - $.ajax( - { - method: "POST", - url: ldcc_js_data.adm_ajax_url, - data: { - group: group, - group_id: group_id, - action: "duplicate_group", - }, - success: function(result) { - var res = JSON.parse( result ); - if (res.success) { - new_group_id = res.success.new_group_id; - curriculum_data = res.success.c_data; - $( '#ldcc-group-dialog .ldcc-course-progress img' ).attr( "src", ldcc_js_data.image_base_url + "tick.png" ); - $( '#ldcc-group-dialog' ).trigger( "group_clone_completed" ); - } else { - $( '#ldcc-group-dialog #ldcc_clone_status' ).append( "
" + res.error + "
" ); - } - } - } - ); - } - ); - - $( '#ldcc-dialog' ).on( - "course_post_created", - function() { - - if ( ! $.isEmptyObject( curriculum_data )) { - if (curriculum_data.lesson.length || curriculum_data.quiz.length) { - curr_lesson_ind = 0; - next_lesson = 0; - if (curriculum_data.lesson.length) { - next_lesson = curriculum_data.lesson[0][0]; - } - $( '#ldcc-dialog' ).trigger( "create_lesson" ); - } else { - $( '#ldcc-dialog #ldcc_clone_status' ).append( "
" + ldcc_js_data.no_content_text + "
" ); - $( '#ldcc-dialog' ).trigger( "course_clone_completed" ); - } - } else { - $( '#ldcc-dialog #ldcc_clone_status' ).append( "
" + ldcc_js_data.no_content_text + "
" ); - $( '#ldcc-dialog' ).trigger( "course_clone_completed" ); - } - - } - ); - - $( '#ldcc-dialog' ).on( - "create_lesson", - function() { - if (curr_lesson_ind <= (curriculum_data.lesson.length - 1)) { - $( '#ldcc-dialog #ldcc_clone_status' ).append( "
" + curriculum_data.lesson[curr_lesson_ind][1] + "
" ); - - action = "duplicate_lesson_new"; - $.ajax( - { - method: "POST", - url: ldcc_js_data.adm_ajax_url, - data: { - lesson_id: curriculum_data.lesson[curr_lesson_ind][0], - new_lesson_id: curriculum_data.lesson[curr_lesson_ind][2], - topic_lesson_id: curriculum_data.lesson[curr_lesson_ind][3], - old_course_id: old_course_id, - course_id: new_course_id, - ld_builder_settings: ldcc_js_data.ld_builder_settings, - action: action, - }, - success: function(result) { - var res = JSON.parse( result ); - if (res.success) { - $( '#ldcc-dialog .ldcc-lesson-' + curriculum_data.lesson[curr_lesson_ind][0] + ' img' ).attr( "src", ldcc_js_data.image_base_url + "tick.png" ); - curr_lesson_ind += 1; - $( '#ldcc-dialog' ).trigger( "create_lesson" ); - } else { - $( '#ldcc-dialog #ldcc_clone_status' ).append( "
" + res.error + "
" ); - } - } - } - ); - } else { - curr_quiz_ind = 0; - next_quiz = 0; - if (curriculum_data.quiz.length) { - next_quiz = curriculum_data.quiz[0][0]; - } - if (next_quiz !== 0) { - $( '#ldcc-dialog' ).trigger( "create_quiz" ); - } else { - $( '#ldcc-dialog' ).trigger( "course_clone_completed" ); - } - } - } - ); - - $( '#ldcc-dialog' ).on( - "create_quiz", - function() { - if (curr_quiz_ind <= (curriculum_data.quiz.length - 1)) { - $( '#ldcc-dialog #ldcc_clone_status' ).append( "
" + curriculum_data.quiz[curr_quiz_ind][1] + "
" ); - action = "duplicate_quiz_new"; - $.ajax( - { - method: "POST", - url: ldcc_js_data.adm_ajax_url, - data: { - course_id: new_course_id, - old_course_id: old_course_id, - quiz_id: curriculum_data.quiz[curr_quiz_ind][0], - new_quiz_id: curriculum_data.quiz[curr_quiz_ind][2], - lesson_id: curriculum_data.quiz[curr_quiz_ind][3], - ld_builder_settings: ldcc_js_data.ld_builder_settings, - action: action, - }, - success: function(result) { - var res = JSON.parse( result ); - if (res.success) { - $( '#ldcc-dialog .ldcc-quiz-' + curriculum_data.quiz[curr_quiz_ind][0] + ' img' ).attr( "src", ldcc_js_data.image_base_url + "tick.png" ); - curr_quiz_ind += 1; - $( '#ldcc-dialog' ).trigger( "create_quiz" ); - } else { - $( '#ldcc-dialog #ldcc_clone_status' ).append( "
" + res.error + "
" ); - } - } - } - ); - } else { - $( '#ldcc-dialog' ).trigger( "course_clone_completed" ); - } - } - ); - - $( '#ldcc-dialog' ).on( - "course_clone_completed", - function() { - $( '#ldcc-dialog .ldcc-success .ldcc-course-link' ).attr( "href", ldcc_js_data.adm_post_url + "?action=edit&post=" + new_course_id ); - $( '#ldcc-dialog .ldcc-success .ldcc-course-rename-link' ).attr( "href", ldcc_js_data.adm_ldbr_url + "&ldbr-select-course=" + new_course_id ); - $( '#ldcc-dialog .ldcc-success' ).show(); - $( '#ldcc-dialog .ldcc-notice' ).show(); - } - ); - - $( '#ldcc-group-dialog' ).on( - "group_clone_completed", - function() { - $( '#ldcc-group-dialog .ldcc-success .ldcc-group-link' ).attr( "href", ldcc_js_data.adm_post_url + "?action=edit&post=" + new_group_id ); - $( '#ldcc-group-dialog .ldcc-success' ).show(); - $( '#ldcc-group-dialog .ldcc-notice' ).show(); - } - ); - - } - ); - -})( jQuery ); diff --git a/web/app/plugins/ld-content-cloner/admin/js/ldbr-admin.js b/web/app/plugins/ld-content-cloner/admin/js/ldbr-admin.js deleted file mode 100644 index d18399138..000000000 --- a/web/app/plugins/ld-content-cloner/admin/js/ldbr-admin.js +++ /dev/null @@ -1,96 +0,0 @@ -/** - * This file is used to show ads carousal and Bulk Rename. - * - * @package Content Cloner. - */ - -(function( $ ) { - 'use strict'; - /** - * All of the code for your admin-specific JavaScript source - * should reside in this file. - * - * Note that this assume you're going to use jQuery, so it prepares - * the $ function reference to be used within the scope of this - * function. - * - * From here, you're able to define handlers for when the DOM is - * ready: - * - * $(function() { - * - * }); - * - * Or when the window is loaded: - * - * $( window ).load(function() { - * - * }); - * - * ...and so on. - * - * Remember that ideally, we should not attach any more than a single DOM-ready or window-load handler - * for any particular page. Though other scripts in WordPress core, other plugins, and other themes may - * be doing this, we should try to minimize doing that in our own work. - */ - $( document ).ready( - function(){ - $( '.carousel' ).carousel( - { - interval: 1000 * 10 - } - ); - $( "#save_post_titles" ).click( - function(){ - var this_btn = $( this ); - if ( this_btn.data( "lock" ) == 0 ) { - this_btn.data( "lock", 1 ); - this_btn.after( "" ); - var array = {}; - $( ".ldbr-table .ldbr-row" ).each( - function( index, value ){ - var input_new_title = $( value ).find( ".ldbr-post-new-title" ); - array[ input_new_title.data( 'post-id' ) ] = input_new_title.val(); - } - ); - - $.ajax( - { - method: "POST", - url: ldbr_js_data.adm_ajax_url, - data: { - action: "ldbr_bulk_rename", - security: $( "#ldbr_security" ).val(), - course_data : JSON.stringify( array ), - }, - } - ). - success( - function( result ){ - this_btn.data( "lock", 0 ); - var res = JSON.parse( result ); - if ( res.success ) { - this_btn.parents( "td" ).find( "img" ).remove(); - this_btn.after( "" ); - $( ".ldbr-table" ).after( "
" + res.success + "
" ); - } else { - $( '.ldbr-table' ).after( "
" + res.error + "
" ); - } - } - ); - window.setTimeout( - function(){ - $( '.ldbr-success, .ldbr-error, .ldbr-foot-row img' ).hide( "slow" ); - }, - 3500 - ); - } else { - alert( "Please wait till the renaming process is completed." ); - } - } - ); - - } - ); - -})( jQuery ); diff --git a/web/app/plugins/ld-content-cloner/admin/partials/ld-content-cloner-admin-display.php b/web/app/plugins/ld-content-cloner/admin/partials/ld-content-cloner-admin-display.php deleted file mode 100644 index db1757e8a..000000000 --- a/web/app/plugins/ld-content-cloner/admin/partials/ld-content-cloner-admin-display.php +++ /dev/null @@ -1,16 +0,0 @@ - - - diff --git a/web/app/plugins/ld-content-cloner/includes/backslashhelper.php b/web/app/plugins/ld-content-cloner/includes/backslashhelper.php deleted file mode 100644 index 35e8641f2..000000000 --- a/web/app/plugins/ld-content-cloner/includes/backslashhelper.php +++ /dev/null @@ -1,29 +0,0 @@ - - */ -namespace LdContentCloner; - -class LdContentCloner { - - - /** - * The loader that's responsible for maintaining and registering all hooks that power - * the plugin. - * - * @since 1.0.0 - * @access protected - * @var Ld_Content_Cloner_Loader $loader Maintains and registers all hooks for the plugin. - */ - protected $loader; - - /** - * The unique identifier of this plugin. - * - * @since 1.0.0 - * @access protected - * @var string $plugin_name The string used to uniquely identify this plugin. - */ - protected $plugin_name; - - /** - * The current version of the plugin. - * - * @since 1.0.0 - * @access protected - * @var string $version The current version of the plugin. - */ - protected $version; - - /** - * Define the core functionality of the plugin. - * - * Set the plugin name and the plugin version that can be used throughout the plugin. - * Load the dependencies, define the locale, and set the hooks for the admin area and - * the public-facing side of the site. - * - * @since 1.0.0 - */ - public function __construct() { - $this->pluginName = 'ld-content-cloner'; - $this->version = '1.0.0'; - - $this->loadDependencies(); - $this->setLocale(); - $this->defineAdminHooks(); - $this->definePublicHooks(); - } - - /** - * Load the required dependencies for this plugin. - * - * Include the following files that make up the plugin: - * - * - Ld_Content_Cloner_Loader. Orchestrates the hooks of the plugin. - * - Ld_Content_Cloner_i18n. Defines internationalization functionality. - * - Ld_Content_Cloner_Admin. Defines all hooks for the admin area. - * - Ld_Content_Cloner_Public. Defines all hooks for the public side of the site. - * - * Create an instance of the loader which will be used to register the hooks - * with WordPress. - * - * @since 1.0.0 - * @access private - */ - private function loadDependencies() { - - /** - * The class responsible for orchestrating the actions and filters of the - * core plugin. - */ - require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-ldcc-loader.php'; - - /** - * The class responsible for defining internationalization functionality - * of the plugin. - */ - require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-ldcc-i18n.php'; - - /** - * The class responsible for defining all actions that occur in the admin area. - */ - require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/class-ldcc-admin.php'; - - /** - * The class responsible for defining all actions that occur in the public-facing - * side of the site. - */ - require_once plugin_dir_path( dirname( __FILE__ ) ) . 'public/class-ldcc-public.php'; - - /** - * The class responsible for defining LD course cloning functionality of the plugin. - */ - require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-ldcc-course.php'; - require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-ldcc-course-clone.php'; - - /** - * Helper file to induce backslashes. - */ - require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/backslashhelper.php'; - - /** - * The class responsible for defining LD group cloning functionality of the plugin. - */ - require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-ldcc-group.php'; - - /** - * The class responsible for defining LD course bulk renaming functionality of the plugin. - */ - require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-ldcc-bulk-rename.php'; - - $this->loader = new \LDCC_Loader\LDCC_Loader(); - } - - /** - * Define the locale for this plugin for internationalization. - * - * Uses the Ld_Content_Cloner_i18n class in order to set the domain and to register the hook - * with WordPress. - * - * @since 1.0.0 - * @access private - */ - private function setLocale() { - $plugin_i18n = new \LDCC_i18n\LDCC_I18n(); - $plugin_i18n->set_domain( $this->get_plugin_name() ); - - $this->loader->add_action( 'plugins_loaded', $plugin_i18n, 'ldcc_load_plugin_textdomain' ); - } - - /** - * Register all of the hooks related to the admin area functionality - * of the plugin. - * - * @since 1.0.0 - * @access private - */ - private function defineAdminHooks() { - $plugin_admin = new \LDCC_Admin\LDCC_Admin( $this->get_plugin_name(), $this->getVersion() ); - $ld_course = new \LDCC_Course\LDCC_Course(); - - $ld_course_new = new \LdccCourseClone\LdccCourse(); - - $ld_group = new \LDCC_Group\LDCC_Group(); - - $ld_bulk_rename = new \LDCC_Bulk_Rename\LDCC_Bulk_Rename(); - - $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' ); - $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' ); - - $this->loader->add_filter( 'post_row_actions', $ld_course, 'addCourseRowActions', 999, 2 ); - - $this->loader->add_filter( 'post_row_actions', $ld_group, 'add_group_row_actions', 10, 2 ); - $this->loader->add_action( 'wp_ajax_duplicate_group', $ld_group, 'create_duplicate_group' ); - - $this->loader->add_action( 'wp_ajax_duplicate_course_new', $ld_course_new, 'createDuplicateCourse' ); - $this->loader->add_action( 'wp_ajax_duplicate_lesson_new', $ld_course_new, 'createDuplicateLesson' ); - $this->loader->add_action( 'wp_ajax_duplicate_quiz_new', $ld_course_new, 'duplicateQuiz' ); - - $this->loader->add_filter( 'ir_filter_instructor_query', $ld_course_new, 'allowCourseAccessToInstructors', 10, 1 ); - - $this->loader->add_action( 'admin_footer', $ld_course, 'addModalStructure' ); - $this->loader->add_action( 'admin_footer', $ld_group, 'add_modal_structure' ); - - // for bulk rename functionality - $this->loader->add_action( 'admin_menu', $ld_bulk_rename, 'bulk_rename_submenu_page', 100 ); - - $this->loader->add_action( 'wp_ajax_ldbr_bulk_rename', $ld_bulk_rename, 'bulk_rename_callback' ); - } - - /** - * Register all of the hooks related to the public-facing functionality - * of the plugin. - * - * @since 1.0.0 - * @access private - */ - private function definePublicHooks() { - $plugin_public = new \LDCC_Public\LDCC_Public( $this->get_plugin_name(), $this->getVersion() ); - - $this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_styles' ); - $this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_scripts' ); - } - - /** - * Run the loader to execute all of the hooks with WordPress. - * - * @since 1.0.0 - */ - public function run() { - $this->loader->run(); - } - - /** - * The name of the plugin used to uniquely identify it within the context of - * WordPress and to define internationalization functionality. - * - * @since 1.0.0 - * @return string The name of the plugin. - */ - public function get_plugin_name() { - return $this->pluginName; - } - - /** - * The reference to the class that orchestrates the hooks with the plugin. - * - * @since 1.0.0 - * @return Ld_Content_Cloner_Loader Orchestrates the hooks of the plugin. - */ - public function getLoader() { - return $this->loader; - } - - /** - * Retrieve the version number of the plugin. - * - * @since 1.0.0 - * @return string The version number of the plugin. - */ - public function getVersion() { - return $this->version; - } -} diff --git a/web/app/plugins/ld-content-cloner/includes/class-ldcc-activator.php b/web/app/plugins/ld-content-cloner/includes/class-ldcc-activator.php deleted file mode 100644 index 6058dadca..000000000 --- a/web/app/plugins/ld-content-cloner/includes/class-ldcc-activator.php +++ /dev/null @@ -1,36 +0,0 @@ - - */ -class LDCC_Activator { - - - /** - * Short Description. (use period) - * - * Long Description. - * - * @since 1.0.0 - */ - public static function activate() { - } -} diff --git a/web/app/plugins/ld-content-cloner/includes/class-ldcc-bulk-rename.php b/web/app/plugins/ld-content-cloner/includes/class-ldcc-bulk-rename.php deleted file mode 100644 index 46f186edd..000000000 --- a/web/app/plugins/ld-content-cloner/includes/class-ldcc-bulk-rename.php +++ /dev/null @@ -1,283 +0,0 @@ - 'sfwd-courses', - 'post_status' => array( 'publish', 'draft' ), - 'posts_per_page' => -1, - ); - $user_id = get_current_user_id(); - $course_ids_shared = get_user_meta( $user_id, 'ir_shared_courses', 1 ); - $courses_shared = array(); - if ( ! empty( $course_ids_shared ) ) { - $course_ids_shared = explode( ',', $course_ids_shared ); - $courses_shared = array_map( - function( $course_id ) { - return get_post( $course_id ); - }, - $course_ids_shared - ); - } - $courses = get_posts( $args ); - $courses = array_merge( $courses, $courses_shared ); - $selected_course = filter_input( INPUT_GET, 'ldbr-select-course', FILTER_VALIDATE_INT ); - $selected = ''; - - $this->add_slider(); - - // disable topic transient. - add_filter( 'learndash_transients_disabled', array( $this, 'disable_topic_transient' ), 20, 2 ); - - ?> -
-

- add_course_list( $courses, $selected_course ); - ?> - -
- '; - - $c_quizzes = array(); - $l_quizzes = array(); - $t_quizzes = array(); - - $lessons = learndash_get_course_lessons_list( $selected_course, null, array( 'num' => 0 ) ); - - $c_quizzes = learndash_get_course_quiz_list( $selected_course ); - if ( ! empty( $lessons ) ) { - foreach ( $lessons as $lesson ) { - $lesson_ids[ $lesson['post']->ID ] = $lesson['post']->post_title; - - $topics = learndash_get_topic_list( $lesson['post']->ID, $selected_course ); - if ( ! empty( $topics ) ) { - foreach ( $topics as $topic ) { - $topic_ids[ $topic->ID ] = $topic->post_title; - $t_quizzes = array_merge( $t_quizzes, learndash_get_lesson_quiz_list( $topic->ID, '', $selected_course ) ); - } - } - unset( $topics ); - - $l_quizzes = array_merge( $l_quizzes, learndash_get_lesson_quiz_list( $lesson['post']->ID, '', $selected_course ) ); - } - } - - $quizzes = array_merge( $c_quizzes, $l_quizzes, $t_quizzes ); - if ( ! empty( $quizzes ) ) { - foreach ( $quizzes as $quiz ) { - $quiz_ids[ $quiz['post']->ID ] = $quiz['post']->post_title; - } - } - - echo ""; - echo ""; - $this->ldcc_display_renaming( $selected_course, get_the_title( $selected_course ) ); - - foreach ( $lesson_ids as $id => $title ) { - $this->ldcc_display_renaming( $id, $title ); - } - - foreach ( $topic_ids as $id => $title ) { - $this->ldcc_display_renaming( $id, $title ); - } - - foreach ( $quiz_ids as $id => $title ) { - $this->ldcc_display_renaming( $id, $title ); - } - - echo ' - - '; - echo '
" . __( 'Post Type', 'ld-content-cloner' ) . "" . __( 'Post Title', 'ld-content-cloner' ) . "" . __( "New Title", 'ld-content-cloner' ) . "
- - -
'; - } - ?> -
- -
- -
- - - -
- -
- -
- " . get_the_title( $lesson_id ) . ' -> '; - } - } - } - echo " - " . esc_html( $obj->labels->singular_name ) . " - " . $lesson_name . "" . esc_html( $title ) . " - - "; - } - - /** - * This method is used for implementing bulk rename. - */ - public function bulk_rename_callback() { - $security = filter_input( INPUT_POST, 'security', FILTER_SANITIZE_STRING ); - - if ( wp_verify_nonce( $security, 'bulk_renaming' ) ) { - $rename_data = filter_input( INPUT_POST, 'course_data' ); - $rename_data = (array) json_decode( $rename_data ); - foreach ( $rename_data as $post_id => $new_title ) { - if ( get_the_title( $post_id ) !== trim( $new_title ) ) { - $this->update_post( $post_id, $new_title ); - } - } - echo wp_json_encode( array( 'success' => __( 'All Post Titles Updated.', 'ld-content-cloner' ) ) ); - } else { - echo wp_json_encode( array( 'error' => __( 'Security check failed.', 'ld-content-cloner' ) ) ); - } - die(); - } - - /** - * This method is used to update post. - * - * @param integer $post_id Post ID. - * @param string $new_title New Post Title. - */ - public function update_post( $post_id, $new_title ) { - $post_arr = array( - 'ID' => $post_id, - 'post_title' => $new_title, - ); - - if ( ! empty( $post_id ) ) { - $post = get_post( $post_id ); - } - - if ( get_post_status( $post_id ) === 'publish' ) { - $new_slug = sanitize_title( $post->post_title ); - $post_arr['post_name'] = $new_slug; - } - - wp_update_post( $post_arr ); - unset( $post_id ); - unset( $post ); - } -} diff --git a/web/app/plugins/ld-content-cloner/includes/class-ldcc-course-clone.php b/web/app/plugins/ld-content-cloner/includes/class-ldcc-course-clone.php deleted file mode 100644 index 7119d0040..000000000 --- a/web/app/plugins/ld-content-cloner/includes/class-ldcc-course-clone.php +++ /dev/null @@ -1,628 +0,0 @@ - - */ - -namespace LdccCourseClone; - -class LdccCourse { - - /** - * - * @since 1.0.0 - */ - - public function __construct() { - } - /** - * IR Multiinstructor for shared steps doesn't return lessons list if instructor is not primary author because of author param added in Instructor Role plugin. - * This filter will fix this issue so that all the instructors will be able to clone the complete course. - * - * @param [type] $query [description] - * @return [type] [description] - */ - public function allowCourseAccessToInstructors( $query ) { - $course_id = filter_input( INPUT_POST, 'course_id', FILTER_VALIDATE_INT ); - if ( empty( $course_id ) ) { - return $query; - } - $course_nonce = filter_input( INPUT_POST, 'course' ); - if ( empty( $course_nonce ) ) { - return $query; - } - $nonce_check = wp_verify_nonce( $course_nonce, 'dup_course_' . $course_id ); - if ( false === $nonce_check ) { - return $query; - } - $query->set( 'author__in', array() ); - return $query; - } - - public static function createDuplicateCourse() { - $course_id = filter_input( INPUT_POST, 'course_id', FILTER_VALIDATE_INT ); - $course_nonce = filter_input( INPUT_POST, 'course' ); - $nonce_check = wp_verify_nonce( $course_nonce, 'dup_course_' . $course_id ); - $ld_builder_settings = filter_input( INPUT_POST, 'ld_builder_settings', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY ); - - if ( $nonce_check === false ) { - echo json_encode( array( 'error' => __( 'Security check failed.', 'ld-content-cloner' ) ) ); - die(); - } - - if ( ( ! isset( $course_id ) ) || ! ( get_post_type( $course_id ) == 'sfwd-courses' ) ) { - echo json_encode( array( 'error' => __( 'The current post is not a Course and hence could not be cloned.', 'ld-content-cloner' ) ) ); - die(); - } - - $course_post = get_post( $course_id, ARRAY_A ); - $course_post = \LDCC_Course\LDCC_Course::stripPostData( $course_post ); - - // Create a new Course - $new_course_id = wp_insert_post( wp_slash( $course_post ), true ); - /** - * This action will run after course clone post is created. - * - * @since 1.2.8 [] - */ - do_action( 'ldcc_course_clone_post_created', $new_course_id, $course_id ); - if ( ! is_wp_error( $new_course_id ) ) { - $ld_course_builder = isset( $ld_builder_settings['course_builder'] ) ? $ld_builder_settings['course_builder'] : ''; - $ld_shared_course_steps = isset( $ld_builder_settings['shared_steps_course'] ) ? $ld_builder_settings['shared_steps_course'] : ''; - self::setMeta( 'course', $course_id, $new_course_id, array(), $ld_course_builder, $ld_shared_course_steps ); - - $send_result = self::ldccCourseSharedSteps( $course_id, $new_course_id ); - echo json_encode( $send_result ); - } else { - echo json_encode( array( 'error' => __( 'Some error occurred. The Course could not be cloned.', 'ld-content-cloner' ) ) ); - } - - die(); - } - - public static function ldccCourseSharedSteps( $course_id, $new_course_id ) { - $course_steps = get_post_meta( $course_id, 'ld_course_steps' ); - $course_steps_h = array(); - if ( ! empty( $course_steps ) ) { - // New check to see if using older or newer LD required after LD 3.4 - if ( array_key_exists( 'steps', $course_steps[0] ) ) { - $course_steps_h = $course_steps[0]['steps']['h']; - } else { - $course_steps_h = $course_steps[0]['h']; - } - $c_data = self::getLDCourseStepsArray( $course_steps_h, $new_course_id ); - } else { - $c_data = self::createLDCourseStepsArray( $course_id, $new_course_id ); - } - $send_result = array( - 'success' => array( - 'old_course_id' => $course_id, - 'new_course_id' => $new_course_id, - 'c_data' => $c_data, - ), - ); - return $send_result; - } - - public static function getLDCourseStepsArray( $course_steps, $new_course_id ) { - $lessons_list = array(); - $quizzes_list = array(); - $h_c_quiz = array(); - $h_lesson = array(); - $lessons = $course_steps['sfwd-lessons']; - foreach ( $lessons as $lesson_id => $l_content ) { - $h_quiz = array(); - $h_topic = array(); - $new_lesson_id = wp_insert_post( - array( - 'post_title' => 'Copy', - 'post_content' => '', - 'post_type' => 'sfwd-lessons', - ) - ); - $lessons_list[] = array( $lesson_id, get_the_title( $lesson_id ), $new_lesson_id, null ); - $topics = $l_content['sfwd-topic']; - foreach ( $topics as $topic_id => $content ) { - $h_t_quiz = array(); - $new_topic_id = wp_insert_post( - array( - 'post_title' => 'Copy', - 'post_content' => '', - 'post_type' => 'sfwd-topic', - ) - ); - $lessons_list[] = array( $topic_id, get_the_title( $topic_id ), $new_topic_id, $new_lesson_id ); - $t_quizzes = $content['sfwd-quiz']; - foreach ( $t_quizzes as $quiz_id => $content ) { - $new_quiz_id = wp_insert_post( - array( - 'post_title' => 'Copy', - 'post_content' => '', - 'post_type' => 'sfwd-quiz', - ) - ); - $quizzes_list[] = array( $quiz_id, get_the_title( $quiz_id ), $new_quiz_id, $new_topic_id ); - $h_t_quiz[ $new_topic_id ][ $new_quiz_id ] = array(); - } - if ( ! isset( $h_t_quiz[ $new_topic_id ] ) ) { - $h_t_quiz[ $new_topic_id ] = array(); - } - $h_topic[ $new_lesson_id ][ $new_topic_id ]['sfwd-quiz'] = $h_t_quiz[ $new_topic_id ]; - } - $l_quizzes = $l_content['sfwd-quiz']; - foreach ( $l_quizzes as $quiz_id => $content ) { - $new_l_quiz_id = wp_insert_post( - array( - 'post_title' => 'Copy', - 'post_content' => '', - 'post_type' => 'sfwd-quiz', - ) - ); - $quizzes_list[] = array( $quiz_id, get_the_title( $quiz_id ), $new_l_quiz_id, $new_lesson_id ); - $h_quiz[ $new_lesson_id ][ $new_l_quiz_id ] = array(); - } - if ( ! isset( $h_topic[ $new_lesson_id ] ) ) { - $h_topic[ $new_lesson_id ] = array(); - } - - if ( ! isset( $h_quiz[ $new_lesson_id ] ) ) { - $h_quiz[ $new_lesson_id ] = array(); - } - $h_lesson[ $new_lesson_id ]['sfwd-topic'] = $h_topic[ $new_lesson_id ]; - $h_lesson[ $new_lesson_id ]['sfwd-quiz'] = $h_quiz[ $new_lesson_id ]; - } - $quizzes = $course_steps['sfwd-quiz']; - foreach ( $quizzes as $quiz_id => $content ) { - $new_c_quiz_id = wp_insert_post( - array( - 'post_title' => 'Copy', - 'post_content' => '', - 'post_type' => 'sfwd-quiz', - ) - ); - $quizzes_list[] = array( $quiz_id, get_the_title( $quiz_id ), $new_c_quiz_id, null ); - $h_c_quiz[ $new_c_quiz_id ] = array(); - } - $h_course['sfwd-lessons'] = $h_lesson; - $h_course['sfwd-quiz'] = $h_c_quiz; - if ( ! isset( $_SESSION ) ) { - session_start(); - } - $_SESSION['course_association'][ $new_course_id ] = $h_course; - self::getLDCourseSteps( $h_course, $new_course_id ); - return array( - 'lesson' => $lessons_list, - 'quiz' => $quizzes_list, - ); - } - - // .get entire ld_course_steps array from h subarray - public static function getLDCourseSteps( $h_course, $new_course_id ) { - $courseStepsClass = new \LDLMS_Course_Steps( $new_course_id ); - if ( ! empty( $h_course ) ) { - $courseStepsClass->set_steps( $h_course ); - } - } - - public static function createLDCourseStepsArray( $course_id, $new_course_id ) { - $lessons_list = array(); - $quizzes_list = array(); - $h_c_quiz = array(); - $h_course = $h_lesson = $h_topic = $h_quiz = $h_c_quiz = $h_t_quiz = array(); - $lessons = learndash_get_course_lessons_list( $course_id, null, array( 'num' => 0 ) ); - foreach ( $lessons as $lesson ) { - $h_quiz = array(); - $h_topic = array(); - $lesson_id = $lesson['post']->ID; - $new_lesson_id = wp_insert_post( wp_slash( array( 'post_type' => 'sfwd-lessons' ) ) ); - $lessons_list[] = array( $lesson_id, $lesson['post']->post_title, $new_lesson_id, null ); - $topics = learndash_get_topic_list( $lesson_id, $course_id ); - foreach ( $topics as $topic ) { - $h_t_quiz = array(); - $topic_id = $topic->ID; - $new_topic_id = wp_insert_post( wp_slash( array( 'post_type' => 'sfwd-topic' ) ) ); - $lessons_list[] = array( $topic_id, $topic->post_title, $new_topic_id, $new_lesson_id ); - $t_quizzes = learndash_get_lesson_quiz_list( $topic_id, '', $course_id ); - foreach ( $t_quizzes as $t_quiz ) { - $quiz_id = $t_quiz['post']->ID; - $new_quiz_id = wp_insert_post( wp_slash( array( 'post_type' => 'sfwd-quiz' ) ) ); - $quizzes_list[] = array( $quiz_id, $t_quiz['post']->post_title, $new_quiz_id, $new_topic_id ); - $h_t_quiz[ $new_topic_id ][ $new_quiz_id ] = array(); - } - if ( ! isset( $h_t_quiz[ $new_topic_id ] ) ) { - $h_t_quiz[ $new_topic_id ] = array(); - } - $h_topic[ $new_lesson_id ][ $new_topic_id ]['sfwd-quiz'] = $h_t_quiz[ $new_topic_id ]; - } - $l_quizzes = learndash_get_lesson_quiz_list( $lesson_id, '', $course_id ); - foreach ( $l_quizzes as $l_quiz ) { - $quiz_id = $l_quiz['post']->ID; - $new_l_quiz_id = wp_insert_post( wp_slash( array( 'post_type' => 'sfwd-quiz' ) ) ); - $quizzes_list[] = array( $quiz_id, $l_quiz['post']->post_title, $new_l_quiz_id, $new_lesson_id ); - $h_quiz[ $new_lesson_id ][ $new_l_quiz_id ] = array(); - } - if ( ! isset( $h_topic[ $new_lesson_id ] ) ) { - $h_topic[ $new_lesson_id ] = array(); - } - - if ( ! isset( $h_quiz[ $new_lesson_id ] ) ) { - $h_quiz[ $new_lesson_id ] = array(); - } - $h_lesson[ $new_lesson_id ]['sfwd-topic'] = $h_topic[ $new_lesson_id ]; - $h_lesson[ $new_lesson_id ]['sfwd-quiz'] = $h_quiz[ $new_lesson_id ]; - } - $quizzes = learndash_get_course_quiz_list( $course_id ); - foreach ( $quizzes as $c_quiz ) { - $quiz_id = $c_quiz['post']->ID; - $new_c_quiz_id = wp_insert_post( wp_slash( array( 'post_type' => 'sfwd-quiz' ) ) ); - $quizzes_list[] = array( $quiz_id, get_the_title( $quiz_id ), $new_c_quiz_id, null ); - $h_c_quiz[ $new_c_quiz_id ] = array(); - } - $h_course['sfwd-lessons'] = $h_lesson; - $h_course['sfwd-quiz'] = $h_c_quiz; - if ( ! isset( $_SESSION ) ) { - session_start(); - } - $_SESSION['course_association'][ $new_course_id ] = $h_course; - self::getLDCourseSteps( $h_course, $new_course_id ); - return array( - 'lesson' => $lessons_list, - 'quiz' => $quizzes_list, - ); - } - - public static function createDuplicateLesson() { - $lesson_id = filter_input( INPUT_POST, 'lesson_id', FILTER_VALIDATE_INT ); - $new_lesson_id = filter_input( INPUT_POST, 'new_lesson_id', FILTER_VALIDATE_INT ); - $topic_lesson_id = filter_input( INPUT_POST, 'topic_lesson_id', FILTER_VALIDATE_INT ); - $ld_builder_settings = filter_input( INPUT_POST, 'ld_builder_settings', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY ); - - if ( ( ! isset( $lesson_id ) ) || ( ! ( get_post_type( $lesson_id ) == 'sfwd-lessons' ) && ! ( get_post_type( $lesson_id ) == 'sfwd-topic' ) ) ) { - echo json_encode( array( 'error' => __( 'The current post is not a Lesson or topic and hence could not be cloned.', 'ld-content-cloner' ) ) ); - die(); - } - $old_course_id = filter_input( INPUT_POST, 'old_course_id', FILTER_VALIDATE_INT ); - $course_id = filter_input( INPUT_POST, 'course_id', FILTER_VALIDATE_INT ); - if ( ( ! isset( $course_id ) ) || ! ( get_post_type( $course_id ) == 'sfwd-courses' ) ) { - echo json_encode( array( 'error' => __( 'The course ID provided with is incorrect for the lesson.', 'ld-content-cloner' ) ) ); - die(); - } - $lesson_post = get_post( $lesson_id, ARRAY_A ); - $old_id = $lesson_post['ID']; - // $lesson_post = self::stripPostData($lesson_post); - $exclude_remove = array( 'post_content', 'post_title', 'post_status', 'post_type', 'comment_status', 'ping_status' ); - foreach ( $lesson_post as $lpkey => $lpvalue ) { - if ( ! in_array( $lpkey, $exclude_remove ) ) { - unset( $lesson_post[ $lpkey ] ); - } - unset( $lpvalue ); - } - $lesson_post['ID'] = $new_lesson_id; - /** - * This filter is used to change the copy word used for cloned modules - * - * @since 1.2.8 - * @var integer $new_lesson_id The new ID before Post update. - * @var integer $old_id The ID of the source module being cloned. - */ - $new_module_slug = apply_filters( 'ldcc_duplicate_slug', 'Copy', $new_lesson_id, $old_id ); - $lesson_post['post_title'] = $lesson_post['post_title'] . ' ' . $new_module_slug; - $new_lesson_id = wp_update_post( wp_slash( $lesson_post ), true ); - if ( ! isset( $_SESSION ) ) { - session_start(); - } - if ( ! isset( $_SESSION['course_association'] ) || ! is_array( $_SESSION['course_association'] ) ) { - wp_send_json_error( new \WP_Error( '001', __( 'Some error occurred. The Lesson was not fully cloned.', 'ld-content-cloner' ) ) ); - die(); - } - $h_course = filter_var( $_SESSION['course_association'][ $course_id ], FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );// Multidimensional array containing course hierarchy. - self::getLDCourseSteps( $h_course, $course_id ); - /** - * This action will run after lesson/topic clone post is created. - * - * @since 1.2.8 [] - */ - do_action( 'ldcc_lesson_or_topic_clone_post_created', $new_lesson_id, $old_id ); - if ( ! is_wp_error( $new_lesson_id ) ) { - $other_data = array( - 'course_id' => $course_id, - 'old_course_id' => $old_course_id, - 'topic_lesson_id' => $topic_lesson_id, - ); - self::setMeta( - 'lesson', - $lesson_id, - $new_lesson_id, - $other_data, - $ld_builder_settings['course_builder'], - $ld_builder_settings['shared_steps_course'] - ); - - $send_result = array( 'success' => array() ); - } else { - $send_result = array( 'error' => __( 'Some error occurred. The Lesson was not fully cloned.', 'ld-content-cloner' ) ); - } - echo json_encode( $send_result ); - die(); - } - - public static function duplicateQuiz( $quiz_id = 0, $lesson_id = 0, $course_id = 0 ) { - // duplicate quiz post - $send_response = false; - if ( $quiz_id == 0 || $quiz_id == '' ) { - $quiz_id = filter_input( INPUT_POST, 'quiz_id', FILTER_VALIDATE_INT ); - $new_quiz_id = filter_input( INPUT_POST, 'new_quiz_id', FILTER_VALIDATE_INT ); - $old_course_id = filter_input( INPUT_POST, 'old_course_id', FILTER_VALIDATE_INT ); - $course_id = filter_input( INPUT_POST, 'course_id', FILTER_VALIDATE_INT ); - $lesson_id = filter_input( INPUT_POST, 'lesson_id', FILTER_VALIDATE_INT ); - $ld_builder_settings = filter_input( INPUT_POST, 'ld_builder_settings', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY ); - $send_response = true; - } - $quiz_post = get_post( $quiz_id, ARRAY_A ); - $old_id = $quiz_post['ID']; - // $lesson_post = self::stripPostData($lesson_post); - $exclude_remove = array( 'post_content', 'post_title', 'post_status', 'post_type', 'comment_status', 'ping_status' ); - foreach ( $quiz_post as $qpkey => $qpvalue ) { - if ( ! in_array( $qpkey, $exclude_remove ) ) { - unset( $quiz_post[ $qpkey ] ); - } - unset( $qpvalue ); - } - $quiz_post['ID'] = $new_quiz_id; - /** - * This filter is used to change the copy word used for cloned modules - * - * @since 1.2.8 - * @var integer $new_quiz_id The new ID before Post update. - * @var integer $old_id The ID of the source module being cloned. - */ - $new_module_slug = apply_filters( 'ldcc_duplicate_slug', 'Copy', $new_quiz_id, $old_id ); - $quiz_post['post_title'] = $quiz_post['post_title'] . ' ' . $new_module_slug; - - $new_quiz_id = wp_update_post( wp_slash( $quiz_post ), true ); - if ( ! isset( $_SESSION ) ) { - session_start(); - } - if ( ! isset( $_SESSION['course_association'] ) || ! is_array( $_SESSION['course_association'] ) ) { - wp_send_json_error( new \WP_Error( '001', __( 'Some error occurred. The Quiz was not fully cloned.', 'ld-content-cloner' ) ) ); - die(); - } - $h_course = filter_var( $_SESSION['course_association'][ $course_id ], FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );// Multidimensional array containing course hierarchy. - - self::getLDCourseSteps( $h_course, $course_id ); - /** - * This action will run after quiz clone post is created. - * - * @since 1.2.8 [] - */ - do_action( 'ldcc_quiz_clone_post_created', $new_quiz_id, $old_id ); - if ( ! is_wp_error( $new_quiz_id ) ) { - $ld_quiz_data_old = get_post_meta( $quiz_id, '_sfwd-quiz', true ); - if ( empty( $pro_quiz_id_old = $ld_quiz_data_old['sfwd-quiz_quiz_pro'] ) ) { - $pro_quiz_id_old = get_post_meta( $quiz_id, 'quiz_pro_id', true ); - } - - $wp_pro_quiz_id = self::ldccQuizBuilder( $new_quiz_id, $pro_quiz_id_old, $old_id ); - self::setMeta( - 'quiz', - $quiz_id, - $new_quiz_id, - array( - 'lesson_id' => $lesson_id, - 'course_id' => $course_id, - 'old_course_id' => $old_course_id, - 'quiz_pro_id' => $wp_pro_quiz_id, - 'quiz_pro_id_old' => $pro_quiz_id_old, - ), - $ld_builder_settings['course_builder'], - $ld_builder_settings['shared_steps_course'] - ); - $questions = self::ldccGetQuizQuestions( $quiz_id, $pro_quiz_id_old ); - $returnQuestions = self::ldccQuestionBuilder( $wp_pro_quiz_id, $questions ); - - if ( $ld_builder_settings['quiz_builder'] == '' ) { - } elseif ( $ld_builder_settings['quiz_builder'] == 'yes' && $ld_builder_settings['shared_steps_quiz'] == 'yes' ) { - self::ldccQuestionBuilderEnabled( $returnQuestions, $new_quiz_id ); - } elseif ( $ld_builder_settings['quiz_builder'] == 'yes' && $ld_builder_settings['shared_steps_quiz'] == '' ) { - self::ldccQuestionBuilderEnabled( $returnQuestions, $new_quiz_id ); - } - - // Get quiz question data from SQL in sorted order - global $wpdb; - $table_prefix = $wpdb->prefix; - $query = 'SELECT id FROM ' . $table_prefix . 'learndash_pro_quiz_question WHERE quiz_id = ' . $wp_pro_quiz_id . ' ORDER BY sort ASC'; - - // Sorted quiz question result data. - $data = $wpdb->get_results( $query, ARRAY_A ); - - // Creating sorted question array data - foreach ( $data as $qusestion_post ) { - $question_post_id = \learndash_get_question_post_by_pro_id( $qusestion_post['id'] ); - $sortdata[ $question_post_id ] = $qusestion_post['id']; - } - - // Updating sort order for questions after post quiz question creation. - update_post_meta( $new_quiz_id, 'ld_quiz_questions', $sortdata ); - - $send_result = array( 'success' => array() ); - } else { - $send_result = array( 'error' => __( 'Some error occurred. The Quiz was not fully cloned.', 'ld-content-cloner' ) ); - } - if ( $send_response ) { - echo json_encode( $send_result ); - die(); - } - } - - public static function ldccQuestionBuilderEnabled( $questions, $new_quiz_id ) { - $question_post_ids = array(); - foreach ( $questions as $question_pro_id ) { - $question_pro_mapper = new \WpProQuiz_Model_QuestionMapper(); - $question_post_ids[] = self::ldccCreateQuestionPost( $question_pro_id, $question_pro_mapper, $new_quiz_id ); - } - $course_id = filter_input( INPUT_POST, 'course_id', FILTER_VALIDATE_INT ); - if ( ! isset( $_SESSION['course_association'] ) ) { - session_start(); - } - if ( ! isset( $_SESSION['course_association'] ) || ! is_array( $_SESSION['course_association'] ) ) { - wp_send_json_error( new \WP_Error( '001', __( 'Some error occurred. The Quiz was not fully cloned.', 'ld-content-cloner' ) ) ); - die(); - } - $h_course = filter_var( $_SESSION['course_association'][ $course_id ], FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );// Multidimensional array containing course hierarchy. - self::getLDCourseSteps( $h_course, $course_id ); - } - - public static function ldccCreateQuestionPost( $question_pro_id, $question_pro_mapper, $new_quiz_id ) { - $question_pro = $question_pro_mapper->fetch( $question_pro_id ); - - $question_post_array = array( - 'post_type' => learndash_get_post_type_slug( 'question' ), - 'post_title' => $question_pro->getTitle(), - 'post_content' => $question_pro->getQuestion(), - 'post_status' => 'publish', - ); - $question_post_id = learndash_get_question_post_by_pro_id( $question_pro_id ); - if ( ! $question_post_id ) { - $question_post_id = wp_insert_post( wp_slash( $question_post_array ) ); - } - if ( ! is_wp_error( $question_post_id ) ) { - do_action( 'ldcc_question_clone_post_created', $question_post_id ); - - learndash_proquiz_sync_question_fields( $question_post_id, $question_pro ); - // if (!$shared) { - learndash_update_setting( $question_post_id, 'quiz', absint( $new_quiz_id ) ); - // } - add_post_meta( $question_post_id, 'ld_quiz_' . absint( $new_quiz_id ), absint( $new_quiz_id ), true ); - // learndash_set_question_quizzes_dirty($question_post_id); - return $question_post_id; - } - } - - public static function ldccGetQuizQuestions( $quiz_id, $pro_quiz_id ) { - $questionMapper = new \WpProQuiz_Model_QuestionMapper(); - $questions = $questionMapper->fetchAll( $pro_quiz_id ); - $questionArray = array(); - foreach ( $questions as $qu ) { - $questionArray[] = $qu->getId(); - } - if ( function_exists( 'learndash_get_quiz_questions' ) ) { - $question_post_ids = learndash_get_quiz_questions( $quiz_id ); - $question_pro_ids = array(); - if ( ! empty( $question_post_ids ) ) { - $question_pro_ids = array_filter( array_values( $question_post_ids ) ); - } - $questionArray = array_unique( - array_merge( - $questionArray, - $question_pro_ids - ) - ); - } - return $questionArray; - } - - public static function ldccQuizBuilder( $new_quiz_id, $pro_quiz_id, $old_id ) { - $ld_quiz_data = get_post_meta( $new_quiz_id, '_sfwd-quiz', true ); - if ( empty( $ld_quiz_data ) ) { - $ld_quiz_data = array(); - } - global $wpdb; - if ( class_exists( '\LDLMS_DB' ) ) { - $_tableMaster = \LDLMS_DB::get_table_name( 'quiz_master', 'wpproquiz' ); - $_tablePrerequisite = \LDLMS_DB::get_table_name( 'quiz_prerequisite', 'wpproquiz' ); - $_tableForm = \LDLMS_DB::get_table_name( 'quiz_form', 'wpproquiz' ); - } else { - $_prefix = $wpdb->prefix . 'wp_pro_quiz_'; - $_tableMaster = $_prefix . 'master'; - $_tablePrerequisite = $_prefix . 'prerequisite'; - $_tableForm = $_prefix . 'form'; - } - - // fetch and create in top quiz master table ( wp_pro_quiz_master ) - $pq_query = "SELECT * FROM $_tableMaster WHERE id = %d;"; - - $pro_quiz = $wpdb->get_row( $wpdb->prepare( $pq_query, $pro_quiz_id ), ARRAY_A ); - - unset( $pro_quiz['id'] ); - - $pro_quiz['name'] .= ' ' . apply_filters( 'ldcc_duplicate_slug', 'Copy', $new_quiz_id, $old_id ); - - $format = array( '%s', '%s', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d' ); - - $ins_result = $wpdb->insert( $_tableMaster, $pro_quiz, $format ); - - $wp_pro_quiz_id = 0; - - if ( $ins_result !== false ) { - $wp_pro_quiz_id = $wpdb->insert_id; - $ld_quiz_data['sfwd-quiz_quiz_pro'] = $wp_pro_quiz_id; - update_post_meta( $new_quiz_id, '_sfwd-quiz', \wdm_recursively_slash_strings( $ld_quiz_data ) ); - // fetch and create in pre-requisites table ( wp_pro_quiz_prerequisite ) - $pqr_query = "SELECT * FROM $_tablePrerequisite WHERE prerequisite_quiz_id = %d;"; - $pror_quizzes = $wpdb->get_results( $wpdb->prepare( $pqr_query, $pro_quiz_id ), ARRAY_A ); - if ( ! empty( $pror_quizzes ) ) { - foreach ( $pror_quizzes as $pror_quiz ) { - $pror_quiz['prerequisite_quiz_id'] = $wp_pro_quiz_id; - $ins_result = $wpdb->insert( $_tablePrerequisite, $pror_quiz, array( '%s', '%s' ) ); - } - } - - // copy custom fields in quiz - $frm_query = "SELECT * FROM $_tableForm WHERE quiz_id = %d;"; - $frm_quizzes = $wpdb->get_results( $wpdb->prepare( $frm_query, $pro_quiz_id ), ARRAY_A ); - if ( ! empty( $frm_quizzes ) ) { - foreach ( $frm_quizzes as $frm_quiz ) { - unset( $frm_quiz['form_id'] ); - $frm_quiz['quiz_id'] = $wp_pro_quiz_id; - $wpdb->insert( $_tableForm, $frm_quiz, array( '%d', '%s', '%d', '%d', '%d', '%s' ) ); - } - } - } - return $wp_pro_quiz_id; - } - - public static function ldccQuestionBuilder( $wp_pro_quiz_id, $questionArr ) { - if ( ! empty( $questionArr ) ) { - $returnQuestions = \LDCC_Course\LDCC_Course::copy_questions( $wp_pro_quiz_id, $questionArr ); - } - return $returnQuestions; - } - - public static function setMeta( $post_type, $old_post_id, $new_post_id, $other_data = array(), $course_builder = '', $shared_steps_course = '' ) { - $exclude_post_meta = array( '_edit_last', '_edit_lock', 'activity_id', 'ir_shared_instructor_ids' ); - - $exclude_post_meta = apply_filters( 'LDCC_exclude_post_meta_keys', $exclude_post_meta, $old_post_id, $new_post_id ); - - if ( empty( $old_post_id ) || empty( $new_post_id ) ) { - return false; - } - if ( $post_type == 'course' ) { - \LDCC_Course\LDCC_Course::updateCourseMeta( $old_post_id, $new_post_id ); - array_push( $exclude_post_meta, '_sfwd-courses', 'ld_course_steps', 'ld_course_steps_dirty' ); - } elseif ( $post_type == 'lesson' ) { - $old_course_id = $other_data['old_course_id']; - \LDCC_Course\LDCC_Course::updateLessonMeta( $old_post_id, $new_post_id, $other_data, $shared_steps_course ); - array_push( $exclude_post_meta, '_sfwd-lessons', 'course_id', 'course_' . $old_course_id . '_lessons_list', 'ld_course_' . $old_course_id, 'lesson_id', '_sfwd-topic' ); - } elseif ( $post_type == 'quiz' ) { - $old_course_id = $other_data['old_course_id']; - $quiz_pro_id_old = $other_data['quiz_pro_id_old']; - \LDCC_Course\LDCC_Course::updateQuizMeta( $old_post_id, $new_post_id, $other_data, $shared_steps_course ); - - array_push( $exclude_post_meta, '_sfwd-quiz', 'course_id', 'lesson_id', 'ld_course_' . $old_course_id, 'ld_quiz_questions', 'quiz_pro_id', 'quiz_pro_id_' . $quiz_pro_id_old, 'quiz_pro_primary_' . $quiz_pro_id_old ); - } - $old_post_meta = get_post_meta( $old_post_id ); - if ( ! empty( $old_post_meta ) ) { - foreach ( $old_post_meta as $key => $value ) { - if ( ! in_array( $key, $exclude_post_meta ) ) { - update_post_meta( $new_post_id, $key, \wdm_recursively_slash_strings( get_post_meta( $old_post_id, $key, true ) ) ); - } - } - } - unset( $value ); - unset( $course_builder ); - return true; - } -} diff --git a/web/app/plugins/ld-content-cloner/includes/class-ldcc-course.php b/web/app/plugins/ld-content-cloner/includes/class-ldcc-course.php deleted file mode 100644 index eec0e1f5a..000000000 --- a/web/app/plugins/ld-content-cloner/includes/class-ldcc-course.php +++ /dev/null @@ -1,346 +0,0 @@ - - */ -class LDCC_Course { - - /** - * This is the default constructor. - * - * @since 1.0.0 - */ - public function __construct() { - } - - /** - * This method is used to copy questions. - * - * @param integer $quiz_id Pro Quiz ID. - * @param array $question_array Question Data Array. - * @return array $return_questions Return Question Array. - */ - public static function copy_questions( $quiz_id, $question_array ) { - $question_mapper = new \WpProQuiz_Model_QuestionMapper(); - - $questions = $question_mapper->fetchById( $question_array ); - usort( $questions, '\LDCC_Course\LDCC_Course::quiz_question_sort' ); - $return_questions = array(); - $category_mapper = new \WpProQuiz_Model_CategoryMapper(); - $category_array = $category_mapper->getCategoryArrayForImport(); - foreach ( $questions as $question ) { - if ( get_class( $question ) !== 'WpProQuiz_Model_Question' ) { - continue; - } - $sortvalue = $question_mapper->getSort( $question->getId() ); - $question->setQuizId( $quiz_id ); - $new_question_slug = apply_filters( 'ldcc_question_duplicate_slug', 'Copy' ); - $question->setTitle( $question->getTitle() . ' ' . $new_question_slug ); - $question->setId( 0 ); - $question->setCategoryId( 0 ); - if ( '' !== trim( $question->getCategoryName() ) ) { - if ( isset( $category_array[ strtolower( $question->getCategoryName() ) ] ) ) { - $question->setCategoryId( $category_array[ strtolower( $question->getCategoryName() ) ] ); - } else { - $category_model = new \WpProQuiz_Model_Category(); - $category_model->setCategoryName( $question->getCategoryName() ); - $category_mapper->save( $category_model ); - - $question->setCategoryId( $category_model->getCategoryId() ); - - $category_array[ strtolower( $question->getCategoryName() ) ] = $category_model->getCategoryId(); - } - } - - $question_mapper->save( $question ); - global $wpdb; - $table_prefix = $wpdb->prefix; - $wpdb->query( - $wpdb->prepare( - "UPDATE {$table_prefix}learndash_pro_quiz_question SET sort = %s WHERE id = %s", - $sortvalue, - $question->getId() - ) - ); - $return_questions[] = $question->getId(); - } - return $return_questions; - } - - /** - * This method is used to set sort quiz question order. - * - * @param object $a Question Model Object. - * @param object $b Question Model Object. - */ - public static function quiz_question_sort( $a, $b ) { - return strcmp( $a->getSort(), $b->getSort() ); - } - - public static function stripPostData( $post_array ) { - $exclude_remove = array( 'post_content', 'post_title', 'post_status', 'post_type', 'comment_status', 'ping_status' ); - foreach ( $post_array as $key => $value ) { - if ( ! in_array( $key, $exclude_remove ) ) { - unset( $post_array[ $key ] ); - } - unset( $value ); - } - - // .publish all contents except course - if ( $post_array['post_type'] == 'sfwd-courses' ) { - $post_array['post_status'] = 'draft'; - } - $new_module_slug = apply_filters( 'ldcc_duplicate_slug_before_insert', 'Copy', $post_array ); - $post_array['post_title'] .= ' ' . $new_module_slug; - unset( $value ); - return $post_array; - } - - public static function updateCourseMeta( $old_post_id, $new_post_id ) { - global $wpdb; - $ld_data = get_post_meta( $old_post_id, '_sfwd-courses', true ); - if ( ! empty( $ld_data ) ) { - $ld_data = self::getDetaultValues( $ld_data ); - if ( ! empty( $ld_data['sfwd-courses_course_price_type'] ) ) { - if ( $ld_data['sfwd-courses_course_price_type'] == 'subscribe' ) { - $billing_cycle_time = get_post_meta( $old_post_id, 'course_price_billing_t3', true ); - update_post_meta( $new_post_id, 'course_price_billing_t3', $billing_cycle_time ); - $billing_cycle_day = get_post_meta( $old_post_id, 'course_price_billing_p3', true ); - update_post_meta( $new_post_id, 'course_price_billing_p3', $billing_cycle_day ); - } - } - } - update_post_meta( $new_post_id, '_sfwd-courses', \wdm_recursively_slash_strings( $ld_data ) ); - $term_taxonomy_ids = $wpdb->get_results( 'SELECT term_taxonomy_id FROM ' . $wpdb->prefix . 'term_relationships where object_id=' . $old_post_id ); - - if ( ! empty( $term_taxonomy_ids ) ) { - foreach ( $term_taxonomy_ids as $term_taxonomy_id ) { - $wpdb->insert( - $wpdb->prefix . 'term_relationships', - array( - 'object_id' => $new_post_id, - 'term_taxonomy_id' => $term_taxonomy_id->term_taxonomy_id, - 'term_order' => 0, - ), - array( - '%d', - '%d', - '%d', - ) - ); - } - } - } - - public static function updateQuizMeta( $old_post_id, $new_post_id, $other_data, $shared_steps_course ) { - global $wpdb; - $unit_course_id = $other_data['course_id']; - - $unit_lesson_id = ! empty( $other_data['lesson_id'] ) ? $other_data['lesson_id'] : 0; - $quiz_pro_id = $other_data['quiz_pro_id']; - - $ld_data = get_post_meta( $old_post_id, '_sfwd-quiz', true ); - - $ld_data['sfwd-quiz_quiz_pro'] = $quiz_pro_id; - - if ( $shared_steps_course == 'yes' ) { - unset( $ld_data['sfwd-quiz_course'] ); - unset( $ld_data['sfwd-quiz_lesson'] ); - update_post_meta( $new_post_id, 'course_id', 0 ); - update_post_meta( $new_post_id, 'lesson_id', 0 ); - update_post_meta( $new_post_id, 'ld_course_' . $unit_course_id, $unit_course_id ); - } else { - $ld_data['sfwd-quiz_course'] = (string) $unit_course_id; - $ld_data['sfwd-quiz_lesson'] = (string) $unit_lesson_id; - update_post_meta( $new_post_id, 'course_id', $unit_course_id ); - update_post_meta( $new_post_id, 'lesson_id', $unit_lesson_id ); - } - - $term_taxonomy_ids = $wpdb->get_results( 'SELECT term_taxonomy_id FROM ' . $wpdb->prefix . 'term_relationships where object_id=' . $old_post_id ); - - if ( ! empty( $term_taxonomy_ids ) && empty( $wpdb->get_var( 'select count(*) from ' . $wpdb->prefix . 'term_relationships where object_id = ' . $new_post_id ) ) ) { - foreach ( $term_taxonomy_ids as $term_taxonomy_id ) { - $wpdb->insert( - $wpdb->prefix . 'term_relationships', - array( - 'object_id' => $new_post_id, - 'term_taxonomy_id' => $term_taxonomy_id->term_taxonomy_id, - 'term_order' => 0, - ), - array( - '%d', - '%d', - '%d', - ) - ); - } - } - $old_quiz = get_post( $old_post_id ); - $menu_order = $old_quiz->menu_order; - $new_quiz_order = array( - 'ID' => $new_post_id, - 'menu_order' => $menu_order, - ); - wp_update_post( $new_quiz_order ); - update_post_meta( $new_post_id, '_sfwd-quiz', $ld_data ); - update_post_meta( $new_post_id, 'quiz_pro_id', $quiz_pro_id ); - update_post_meta( $new_post_id, 'quiz_pro_id_' . $quiz_pro_id, $quiz_pro_id ); - } - - public static function updateLessonMeta( $old_post_id, $new_post_id, $other_data, $shared_steps_course ) { - global $wpdb; - $lesson_course_id = $other_data['course_id']; - $ld_data = get_post_meta( $old_post_id, '_sfwd-lessons', true ); - - if ( $ld_data !== '' ) { - if ( $shared_steps_course == 'yes' ) { - unset( $ld_data['sfwd-lessons_course'] ); - } else { - $ld_data['sfwd-lessons_course'] = $lesson_course_id; - update_post_meta( $new_post_id, 'course_id', $lesson_course_id ); - } - update_post_meta( $new_post_id, '_sfwd-lessons', \wdm_recursively_slash_strings( $ld_data ) ); - } - - update_post_meta( $new_post_id, 'ld_course_' . $lesson_course_id, $lesson_course_id ); - - $topic_meta = get_post_meta( $old_post_id, '_sfwd-topic', true ); - if ( $topic_meta !== '' ) { - if ( $shared_steps_course == 'yes' ) { - unset( $topic_meta['sfwd-topic_course'] ); - unset( $topic_meta['sfwd-topic_lesson'] ); - } else { - $unit_lesson_id = $other_data['topic_lesson_id']; - $topic_meta['sfwd-topic_course'] = $lesson_course_id; - $topic_meta['sfwd-topic_lesson'] = $unit_lesson_id; - } - update_post_meta( $new_post_id, '_sfwd-topic', wp_slash( $topic_meta ) ); - } - - $term_taxonomy_ids = $wpdb->get_results( 'SELECT term_taxonomy_id FROM ' . $wpdb->prefix . 'term_relationships where object_id=' . $old_post_id ); - if ( ! empty( $term_taxonomy_ids ) && empty( $wpdb->get_var( 'select count(*) from ' . $wpdb->prefix . 'term_relationships where object_id = ' . $new_post_id ) ) ) { - foreach ( $term_taxonomy_ids as $term_taxonomy_id ) { - $wpdb->insert( - $wpdb->prefix . 'term_relationships', - array( - 'object_id' => $new_post_id, - 'term_taxonomy_id' => $term_taxonomy_id->term_taxonomy_id, - 'term_order' => 0, - ), - array( - '%d', - '%d', - '%d', - ) - ); - } - } - $old_lesson = get_post( $old_post_id ); - $menu_order = $old_lesson->menu_order; - $new_lesson_order = array( - 'ID' => $new_post_id, - 'menu_order' => $menu_order, - ); - wp_update_post( wp_slash( $new_lesson_order ) ); - update_post_meta( $new_post_id, 'ld_course_' . $lesson_course_id, $lesson_course_id ); - } - - public static function getDetaultValues( $ld_data ) { - if ( empty( $ld_data['sfwd-courses_course_lesson_orderby'] ) ) { - $ld_data['sfwd-courses_course_lesson_orderby'] = ''; - } - if ( empty( $ld_data['sfwd-courses_course_lesson_order'] ) ) { - $ld_data['sfwd-courses_course_lesson_order'] = ''; - } - if ( ! empty( $ld_data['sfwd-courses_course_access_list'] ) ) { - $ld_data['sfwd-courses_course_access_list'] = ''; - } - return $ld_data; - } - - public function addCourseRowActions( $actions, $post_data ) { - if ( get_post_type( $post_data->ID ) === 'sfwd-courses' ) { - $actions = array_merge( - $actions, - array( - 'clone_course' => '' . esc_html( sprintf( __( 'Clone %s', 'ld-content-cloner' ), \LearnDash_Custom_Label::get_label( 'course' ) ) ) . '', - ) - ); - } - return $actions; - } - - public function addLessonRowActions( $actions, $post_data ) { - if ( get_post_type( $post_data->ID ) === 'sfwd-lessons' ) { - $actions = array_merge( - $actions, - array( - 'clone_lesson' => '' . __( 'Clone Lesson' ) . '', - ) - ); - } elseif ( get_post_type( $post_data->ID ) === 'sfwd-quiz' ) { - $actions = array_merge( - $actions, - array( - 'clone_quiz' => '' . __( 'Clone Quiz' ) . '', - ) - ); - } - return $actions; - } - - public function addModalStructure() { - global $current_screen; - - if ( isset( $current_screen ) && $current_screen->base == 'edit' && in_array( $current_screen->id, array( 'edit-sfwd-courses' ) ) ) { - ?> -
@@ -485,7 +537,7 @@ private function render_url_process_step( $process_data ) { /** * Render the course config step. * - * @param array $process_data Processing data. + * @param array $process_data Processing data. */ private function render_course_config_step( $process_data ) { ?> @@ -507,7 +559,7 @@ private function render_course_config_step( $process_data ) {
- + > @@ -515,7 +567,7 @@ private function render_course_config_step( $process_data ) {
- + > @@ -523,7 +575,7 @@ private function render_course_config_step( $process_data ) {
- + > @@ -539,7 +591,7 @@ private function render_course_config_step( $process_data ) {
- + > @@ -568,7 +620,7 @@ private function render_course_config_step( $process_data ) {
- + > @@ -609,7 +661,7 @@ private function render_course_config_step( $process_data ) { /** * Generate the course creation message based on the playlist_data * - * @param array $process_data Processing data. + * @param array $process_data Processing data. * @return string|false The course generation message or false if playlist_data is empty. */ private function generate_course_creation_message( $process_data ) { @@ -627,7 +679,6 @@ private function generate_course_creation_message( $process_data ) { // translators: placeholders: number of lessons. sprintf( _n( '%s lesson', '%s lessons', $course_qty_lessons, 'learndash' ), $course_qty_lessons ) ); - } /** @@ -694,5 +745,4 @@ private function create_course_from_playlist( $playlist_data, $course_price_type return $course_id; } } - } diff --git a/web/app/plugins/sfwd-lms/includes/class-ld-cpt-instance.php b/web/app/plugins/sfwd-lms/includes/class-ld-cpt-instance.php index c7456fa57..41b69aa37 100644 --- a/web/app/plugins/sfwd-lms/includes/class-ld-cpt-instance.php +++ b/web/app/plugins/sfwd-lms/includes/class-ld-cpt-instance.php @@ -11,7 +11,11 @@ exit; } +use LearnDash\Core\Models\Product; +use LearnDash\Core\Models; use LearnDash\Core\Template\Views; +use LearnDash\Core\Themes\Modern\Theme as Modern_Theme; +use LearnDash\Core\Utilities\Cast; if ( ! class_exists( 'SFWD_CPT_Instance' ) ) { @@ -228,8 +232,6 @@ public function get_archive_content( $content ) { } } // end get_archive_content() - - /** * Generate output for courses, lessons, topics, quizzes * Filter callback for 'the_content' (wp core filter) @@ -259,11 +261,43 @@ public function template_content( $content ) { return $content; } + $is_rest_request = defined( 'REST_REQUEST' ) + && Cast::to_bool( constant( 'REST_REQUEST' ) ); + + if ( + ! $is_rest_request + && ! is_singular() + && in_array( + get_post_type( $post ), + LDLMS_Post_Types::get_post_types(), + true + ) + && + /** + * Filters the content on the listing pages to be hidden or shown. + * + * @since 4.20.0.2 + * + * @param bool $is_hidden True to hide content. Default true. + * @param int $post_id Current Post ID. + * + * @return bool True to hide content. False to show content. + */ + apply_filters( 'learndash_template_content_on_listing_is_hidden', true, $post->ID ) + ) { + return wpautop( + esc_html__( 'Open to access this content', 'learndash' ) + ); + } + if ( get_query_var( 'post_type' ) ) { $post_type = get_query_var( 'post_type' ); } - if ( ( ! is_singular() ) || ( $post_type !== $this->post_type ) || ( $post_type !== $post->post_type ) ) { + if ( + $post_type !== $this->post_type + || $post_type !== $post->post_type + ) { return $content; } @@ -424,7 +458,7 @@ public function template_content( $content ) { if ( 'sfwd-courses' === $this->post_type ) { require_once LEARNDASH_LMS_LIBRARY_DIR . '/paypal/enhanced-paypal-shortcodes.php'; - if ( LearnDash_Theme_Register::get_active_theme_instance()->supports_views() ) { + if ( LearnDash_Theme_Register::get_active_theme_instance()->supports_views( LDLMS_Post_Types::get_post_type_key( $this->post_type ) ) ) { if ( empty( $course ) ) { return $content; } @@ -514,20 +548,19 @@ public function template_content( $content ) { $user_wrapper = false; } elseif ( 'sfwd-lessons' === $this->post_type ) { - if ( LearnDash_Theme_Register::get_active_theme_instance()->supports_views() ) { + if ( LearnDash_Theme_Register::get_active_theme_instance()->supports_views( LDLMS_Post_Types::get_post_type_key( $this->post_type ) ) ) { $view = new Views\Lesson( $post ); $content = $view->get_html(); } else { - $show_content = false; + $model = Models\Lesson::create_from_post( $post ); + $show_content = $model->is_content_visible( $user_id ); if ( ! empty( $user_id ) ) { if ( learndash_user_progress_is_step_complete( $user_id, $course_id, $post->ID ) ) { - $show_content = true; $previous_lesson_completed = true; } elseif ( $lesson_progression_enabled ) { if ( learndash_is_sample( $post ) ) { - $show_content = true; $previous_lesson_completed = false; if ( $has_access ) { @@ -559,18 +592,14 @@ public function template_content( $content ) { */ $previous_lesson_completed = apply_filters( 'learndash_previous_step_completed', $previous_lesson_completed, $post->ID, $user_id ); } - $show_content = $previous_lesson_completed; } } else { - $show_content = true; $previous_lesson_completed = true; } } else { if ( ( ! learndash_is_sample( $post ) ) && ( ( learndash_get_setting( $post->ID, 'visible_after' ) ) || ( learndash_get_setting( $post->ID, 'visible_after_specific_date' ) ) ) ) { - $show_content = false; $previous_lesson_completed = false; } else { - $show_content = true; $previous_lesson_completed = true; } } @@ -642,7 +671,7 @@ public function template_content( $content ) { if ( ( defined( 'LEARNDASH_LESSON_VIDEO' ) ) && ( true === LEARNDASH_LESSON_VIDEO ) ) { if ( $show_content ) { $ld_course_videos = Learndash_Course_Video::get_instance(); - $content = $ld_course_videos->add_video_to_content( $content, $post, $lesson_settings ); + $content = $ld_course_videos->add_video_to_content( $content, $post, (array) $lesson_settings ); } } @@ -655,7 +684,7 @@ public function template_content( $content ) { $content = learndash_ob_get_clean( $level ); } } elseif ( 'sfwd-topic' === $this->post_type ) { - if ( LearnDash_Theme_Register::get_active_theme_instance()->supports_views() ) { + if ( LearnDash_Theme_Register::get_active_theme_instance()->supports_views( LDLMS_Post_Types::get_post_type_key( $this->post_type ) ) ) { $view = new Views\Topic( $post ); $content = $view->get_html(); @@ -668,51 +697,44 @@ public function template_content( $content ) { $lesson_post = null; } + $model = Models\Topic::create_from_post( $post ); + $show_content = $model->is_content_visible( $user_id ); + $previous_lesson_completed = false; $previous_topic_completed = false; if ( ! empty( $user_id ) ) { if ( learndash_user_progress_is_step_complete( $user_id, $course_id, $post->ID ) ) { - $show_content = true; $previous_lesson_completed = true; $previous_topic_completed = true; } elseif ( $lesson_progression_enabled ) { - if ( learndash_is_sample( $post ) ) { - $show_content = true; - $previous_topic_completed = false; + if ( $bypass_course_limits_admin_users ) { + $previous_lesson_completed = true; + remove_filter( 'learndash_content', 'lesson_visible_after', 1, 2 ); } else { - if ( $bypass_course_limits_admin_users ) { + $previous_step_post_id = learndash_user_progress_get_previous_incomplete_step( $user_id, $course_id, $post->ID ); + if ( ( $previous_step_post_id ) && ( $previous_step_post_id === $post->ID ) ) { $previous_lesson_completed = true; - remove_filter( 'learndash_content', 'lesson_visible_after', 1, 2 ); } else { - $previous_step_post_id = learndash_user_progress_get_previous_incomplete_step( $user_id, $course_id, $post->ID ); - if ( ( $previous_step_post_id ) && ( $previous_step_post_id === $post->ID ) ) { - $previous_lesson_completed = true; - } else { - $previous_lesson_completed = false; - } - - /** This filter is documented in includes/class-ld-cpt-instance.php */ - $previous_lesson_completed = apply_filters( 'learndash_previous_step_completed', $previous_lesson_completed, $post->ID, $user_id ); - + $previous_lesson_completed = false; } - $previous_topic_completed = $previous_lesson_completed; - $show_content = $previous_lesson_completed; + + /** This filter is documented in includes/class-ld-cpt-instance.php */ + $previous_lesson_completed = apply_filters( 'learndash_previous_step_completed', $previous_lesson_completed, $post->ID, $user_id ); } + + $previous_topic_completed = $previous_lesson_completed; } else { $previous_topic_completed = true; $previous_lesson_completed = true; - $show_content = true; } } else { if ( ( ! learndash_is_sample( $post ) ) && ( ( learndash_get_setting( $lesson_id, 'visible_after' ) ) || ( learndash_get_setting( $lesson_id, 'visible_after_specific_date' ) ) ) ) { $previous_topic_completed = false; $previous_lesson_completed = false; - $show_content = false; } else { $previous_topic_completed = true; $previous_lesson_completed = true; - $show_content = true; } } @@ -776,7 +798,7 @@ public function template_content( $content ) { if ( ( defined( 'LEARNDASH_LESSON_VIDEO' ) ) && ( true === LEARNDASH_LESSON_VIDEO ) ) { if ( $show_content ) { $ld_course_videos = Learndash_Course_Video::get_instance(); - $content = $ld_course_videos->add_video_to_content( $content, $post, $topic_settings ); + $content = $ld_course_videos->add_video_to_content( $content, $post, (array) $topic_settings ); } } @@ -794,7 +816,11 @@ public function template_content( $content ) { } } } elseif ( learndash_get_post_type_slug( 'group' ) === $post->post_type ) { - if ( LearnDash_Theme_Register::get_active_theme_instance()->supports_views() ) { + if ( LearnDash_Theme_Register::get_active_theme_instance()->supports_views( LDLMS_Post_Types::get_post_type_key( $this->post_type ) ) ) { + if ( ! $post instanceof WP_Post ) { + return $content; + } + $view = new Views\Group( $post ); $content = $view->get_html(); @@ -802,11 +828,16 @@ public function template_content( $content ) { $group_id = $post->ID; $group = $post; - if ( learndash_is_user_in_group( $user_id, $group_id ) ) { - $has_access = true; + try { + $product = Product::create_from_post( $group ); + $has_access = $product->user_has_access(); + } catch ( InvalidArgumentException $e ) { + $has_access = false; + } + + if ( $has_access ) { $group_status = learndash_get_user_group_status( $group_id, $user_id ); } else { - $has_access = false; $group_status = ''; } @@ -849,7 +880,7 @@ public function template_content( $content ) { $content = learndash_ob_get_clean( $level ); } } elseif ( learndash_get_post_type_slug( 'exam' ) === $post->post_type ) { - if ( LearnDash_Theme_Register::get_active_theme_instance()->supports_views() ) { + if ( LearnDash_Theme_Register::get_active_theme_instance()->supports_views( LDLMS_Post_Types::get_post_type_key( $this->post_type ) ) ) { $view = new Views\Exam( $post ); $content = $view->get_html(); diff --git a/web/app/plugins/sfwd-lms/includes/class-ld-custom-label.php b/web/app/plugins/sfwd-lms/includes/class-ld-custom-label.php index d080e9a88..fa14284bc 100644 --- a/web/app/plugins/sfwd-lms/includes/class-ld-custom-label.php +++ b/web/app/plugins/sfwd-lms/includes/class-ld-custom-label.php @@ -10,7 +10,7 @@ } /** - * Class LearnDash Custom Label + * Class to test the class-ld-custom-label.php file. */ class LearnDash_Custom_Label { /** @@ -31,6 +31,15 @@ class LearnDash_Custom_Label { */ public static $button_take_group = 'button_take_this_group'; + /** + * Button skip event. + * + * @since 4.12.0 + * + * @var string + */ + public static $button_skip_event = 'button_skip_event'; + /** * Get label based on key name. * @@ -41,6 +50,18 @@ class LearnDash_Custom_Label { public static function get_label( string $key ): string { $key = strtolower( $key ); + // Transactions have been renamed to Orders in version 4.19.0, so we need to support this case. + switch ( $key ) { + case 'order': + $key = 'transaction'; + break; + case 'orders': + $key = 'transactions'; + break; + default: + break; + } + $labels = get_option( 'learndash_settings_custom_labels', array() ); if ( ! is_array( $labels ) ) { $labels = array(); @@ -107,11 +128,11 @@ public static function get_label( string $key ): string { break; case 'transaction': - $label = esc_html__( 'Transaction', 'learndash' ); + $label = esc_html__( 'Order', 'learndash' ); break; case 'transactions': - $label = esc_html__( 'Transactions', 'learndash' ); + $label = esc_html__( 'Orders', 'learndash' ); break; case 'group': @@ -150,6 +171,14 @@ public static function get_label( string $key ): string { $label = esc_html__( 'Certificates', 'learndash' ); break; + case 'virtual_instructor': + $label = esc_html__( 'Virtual Instructor', 'learndash' ); + break; + + case 'virtual_instructors': + $label = esc_html__( 'Virtual Instructors', 'learndash' ); + break; + case self::$button_take_course: $label = esc_html__( 'Take this Course', 'learndash' ); break; @@ -162,8 +191,20 @@ public static function get_label( string $key ): string { $label = esc_html__( 'Mark Complete', 'learndash' ); break; + case self::$button_skip_event: + $label = esc_html__( 'Skip Event', 'learndash' ); + break; + case 'button_click_here_to_continue': - $label = esc_html__( 'Click Here to Continue', 'learndash' ); + $label = esc_html__( 'Continue', 'learndash' ); + break; + + case 'terms_of_service': + $label = esc_html__( 'Terms of Service', 'learndash' ); + break; + + case 'privacy_policy': + $label = esc_html__( 'Privacy Policy', 'learndash' ); break; default: @@ -189,7 +230,7 @@ public static function get_label( string $key ): string { * @return string Lowercase string. */ public static function label_to_lower( string $key ): string { - $label = strtolower( + $label = mb_strtolower( self::get_label( $key ) ); diff --git a/web/app/plugins/sfwd-lms/includes/class-ld-design-wizard.php b/web/app/plugins/sfwd-lms/includes/class-ld-design-wizard.php index e8763dceb..b126cc068 100644 --- a/web/app/plugins/sfwd-lms/includes/class-ld-design-wizard.php +++ b/web/app/plugins/sfwd-lms/includes/class-ld-design-wizard.php @@ -90,180 +90,151 @@ public function register_ajax_handlers() { * * @return array|string>> */ - public function register_templates() : array { + public function register_templates(): array { + // Kadence Pro templates are not supported. We need to make sure the following templates are available in the free Kadence starter templates. $this->templates = array( - 'kadence_seo_skills' => array( - 'id' => 'kadence_seo_skills', - 'label' => 'SEO Skills', + 'kadence_sewing_course' => array( + 'id' => 'kadence_sewing_course', + 'label' => 'Sewing Course', 'theme' => 'kadence', 'theme_label' => 'Kadence', - 'theme_template_id' => 'g21', + 'theme_template_id' => 'g42', 'plugins' => array( 'kadence-starter-templates' => __( 'Starter Templates by Kadence WP', 'learndash' ), ), - 'preview_url' => 'https://startertemplatecloud.com/g21/?cache=bust', + 'preview_url' => 'https://startertemplatecloud.com/g42/?cache=bust', ), - 'kadence_digital_course' => array( - 'id' => 'kadence_digital_course', - 'label' => 'Digital Course', + 'kadence_writing_course' => array( + 'id' => 'kadence_writing_course', + 'label' => 'Writing Course', 'theme' => 'kadence', 'theme_label' => 'Kadence', - 'theme_template_id' => 'g22', + 'theme_template_id' => 'g41', 'plugins' => array( 'kadence-starter-templates' => __( 'Starter Templates by Kadence WP', 'learndash' ), ), - 'preview_url' => 'https://startertemplatecloud.com/g22/?cache=bust', + 'preview_url' => 'https://startertemplatecloud.com/g41/?cache=bust', ), - 'kadence_business_course' => array( - 'id' => 'kadence_business_course', - 'label' => 'Business Course', + 'kadence_nutrition_course' => array( + 'id' => 'kadence_nutrition_course', + 'label' => 'Nutrition Course', 'theme' => 'kadence', 'theme_label' => 'Kadence', - 'theme_template_id' => 'g20', + 'theme_template_id' => 'g37', 'plugins' => array( 'kadence-starter-templates' => __( 'Starter Templates by Kadence WP', 'learndash' ), ), - 'preview_url' => 'https://startertemplatecloud.com/g20/?cache=bust', + 'preview_url' => 'https://startertemplatecloud.com/g37/?cache=bust', ), - 'kadence_course' => array( - 'id' => 'kadence_course', - 'label' => 'Course', + 'kadence_makeup' => array( + 'id' => 'kadence_makeup', + 'label' => 'Makeup', 'theme' => 'kadence', 'theme_label' => 'Kadence', - 'theme_template_id' => 'g03', + 'theme_template_id' => 'g28', 'plugins' => array( 'kadence-starter-templates' => __( 'Starter Templates by Kadence WP', 'learndash' ), ), - 'preview_url' => 'https://startertemplatecloud.com/g03/?cache=bust', + 'preview_url' => 'https://startertemplatecloud.com/g28/?cache=bust', ), - 'kadence_get_income' => array( - 'id' => 'kadence_get_income', - 'label' => 'Get Income', + 'kadence_design_course' => array( + 'id' => 'kadence_design_course', + 'label' => 'Design Course', 'theme' => 'kadence', 'theme_label' => 'Kadence', - 'theme_template_id' => 'member_g01', + 'theme_template_id' => 'g36', 'plugins' => array( 'kadence-starter-templates' => __( 'Starter Templates by Kadence WP', 'learndash' ), ), - 'preview_url' => 'https://startertemplatecloud.com/member-g01/?cache=bust', + 'preview_url' => 'https://startertemplatecloud.com/g36/?cache=bust', ), - 'kadence_online_course' => array( - 'id' => 'kadence_online_course', - 'label' => 'Online Course', + 'kadence_fitness_course' => array( + 'id' => 'kadence_fitness_course', + 'label' => 'Fitness Course', 'theme' => 'kadence', 'theme_label' => 'Kadence', - 'theme_template_id' => 'g04', + 'theme_template_id' => 'g40', 'plugins' => array( 'kadence-starter-templates' => __( 'Starter Templates by Kadence WP', 'learndash' ), ), - 'preview_url' => 'https://startertemplatecloud.com/g04/?cache=bust', + 'preview_url' => 'https://startertemplatecloud.com/g40/?cache=bust', ), - 'kadence_painting_course' => array( - 'id' => 'kadence_painting_course', - 'label' => 'Painting Course', + 'kadence_photo_courses' => array( + 'id' => 'kadence_photo_courses', + 'label' => 'Photo Courses', 'theme' => 'kadence', 'theme_label' => 'Kadence', - 'theme_template_id' => 'g35', + 'theme_template_id' => 'g34', 'plugins' => array( 'kadence-starter-templates' => __( 'Starter Templates by Kadence WP', 'learndash' ), ), - 'preview_url' => 'https://startertemplatecloud.com/g35/?cache=bust', + 'preview_url' => 'https://startertemplatecloud.com/g34/?cache=bust', ), - 'astra_meditation_courses' => array( - 'id' => 'astra_meditation_courses', - 'label' => 'Meditation Courses', - 'theme' => 'astra', - 'theme_label' => 'Astra', - 'theme_template_id' => '56593', - 'color_scheme' => 'light', + 'kadence_seo_skills' => array( + 'id' => 'kadence_seo_skills', + 'label' => 'SEO Skills', + 'theme' => 'kadence', + 'theme_label' => 'Kadence', + 'theme_template_id' => 'g21', 'plugins' => array( - 'astra-sites' => __( 'Starter Templates by Astra', 'learndash' ), + 'kadence-starter-templates' => __( 'Starter Templates by Kadence WP', 'learndash' ), ), - 'preview_url' => 'https://websitedemos.net/learn-meditation-08/', + 'preview_url' => 'https://startertemplatecloud.com/g21/?cache=bust', ), - 'astra_learndash_academy' => array( - 'id' => 'astra_learndash_academy', - 'label' => 'LearnDash Academy', - 'theme' => 'astra', - 'theme_label' => 'Astra', - 'theme_template_id' => '47984', - 'color_scheme' => 'light', + 'kadence_digital_course' => array( + 'id' => 'kadence_digital_course', + 'label' => 'Digital Course', + 'theme' => 'kadence', + 'theme_label' => 'Kadence', + 'theme_template_id' => 'g22', 'plugins' => array( - 'astra-sites' => __( 'Starter Templates by Astra', 'learndash' ), + 'kadence-starter-templates' => __( 'Starter Templates by Kadence WP', 'learndash' ), ), - 'preview_url' => 'https://websitedemos.net/learndash-academy-08/', + 'preview_url' => 'https://startertemplatecloud.com/g22/?cache=bust', ), - 'astra_online_health_coach' => array( - 'id' => 'astra_online_health_coach', - 'label' => 'Online Health Coach', - 'theme' => 'astra', - 'theme_label' => 'Astra', - 'theme_template_id' => '47932', - 'color_scheme' => 'light', + 'kadence_business_course' => array( + 'id' => 'kadence_business_course', + 'label' => 'Business Course', + 'theme' => 'kadence', + 'theme_label' => 'Kadence', + 'theme_template_id' => 'g20', 'plugins' => array( - 'astra-sites' => __( 'Starter Templates by Astra', 'learndash' ), + 'kadence-starter-templates' => __( 'Starter Templates by Kadence WP', 'learndash' ), ), - 'preview_url' => 'https://websitedemos.net/online-health-coach-08/', + 'preview_url' => 'https://startertemplatecloud.com/g20/?cache=bust', ), - 'astra_learn_digital_marketing' => array( - 'id' => 'astra_learn_digital_marketing', - 'label' => 'Learn Digital Marketing', - 'theme' => 'astra', - 'theme_label' => 'Astra', - 'theme_template_id' => '56525', - 'color_scheme' => 'light', + 'kadence_course' => array( + 'id' => 'kadence_course', + 'label' => 'Course', + 'theme' => 'kadence', + 'theme_label' => 'Kadence', + 'theme_template_id' => 'g03', 'plugins' => array( - 'astra-sites' => __( 'Starter Templates by Astra', 'learndash' ), + 'kadence-starter-templates' => __( 'Starter Templates by Kadence WP', 'learndash' ), ), - 'preview_url' => 'https://websitedemos.net/learn-digital-marketing-08/', + 'preview_url' => 'https://startertemplatecloud.com/g03/?cache=bust', ), - 'astra_online_course' => array( - 'id' => 'astra_online_course', + 'kadence_online_course' => array( + 'id' => 'kadence_online_course', 'label' => 'Online Course', - 'theme' => 'astra', - 'theme_label' => 'Astra', - 'theme_template_id' => '48026', - 'color_scheme' => 'light', - 'plugins' => array( - 'astra-sites' => __( 'Starter Templates by Astra', 'learndash' ), - ), - 'preview_url' => 'https://websitedemos.net/online-courses-08/', - ), - 'astra_online_programming_course' => array( - 'id' => 'astra_online_programming_course', - 'label' => 'Online Programming Course', - 'theme' => 'astra', - 'theme_label' => 'Astra', - 'theme_template_id' => '47896', - 'color_scheme' => 'light', - 'plugins' => array( - 'astra-sites' => __( 'Starter Templates by Astra', 'learndash' ), - ), - 'preview_url' => 'https://websitedemos.net/online-coding-course-08/', - ), - 'astra_online_cooking_course' => array( - 'id' => 'astra_online_cooking_course', - 'label' => 'Online Cooking Course', - 'theme' => 'astra', - 'theme_label' => 'Astra', - 'theme_template_id' => '48061', - 'color_scheme' => 'light', + 'theme' => 'kadence', + 'theme_label' => 'Kadence', + 'theme_template_id' => 'g04', 'plugins' => array( - 'astra-sites' => __( 'Starter Templates by Astra', 'learndash' ), + 'kadence-starter-templates' => __( 'Starter Templates by Kadence WP', 'learndash' ), ), - 'preview_url' => 'https://websitedemos.net/online-cooking-course-08/', + 'preview_url' => 'https://startertemplatecloud.com/g04/?cache=bust', ), - 'astra_yoga_instructor' => array( - 'id' => 'astra_yoga_instructor', - 'label' => 'Yoga Instructor', - 'theme' => 'astra', - 'theme_label' => 'Astra', - 'theme_template_id' => '48631', - 'color_scheme' => 'light', + 'kadence_painting_course' => array( + 'id' => 'kadence_painting_course', + 'label' => 'Painting Course', + 'theme' => 'kadence', + 'theme_label' => 'Kadence', + 'theme_template_id' => 'g35', 'plugins' => array( - 'astra-sites' => __( 'Starter Templates by Astra', 'learndash' ), + 'kadence-starter-templates' => __( 'Starter Templates by Kadence WP', 'learndash' ), ), - 'preview_url' => 'https://websitedemos.net/yoga-instructor-08/', + 'preview_url' => 'https://startertemplatecloud.com/g35/?cache=bust', ), ); @@ -410,14 +381,14 @@ public function enqueue_admin_scripts() : void { wp_enqueue_style( 'learndash-design-wizard', LEARNDASH_LMS_PLUGIN_URL . '/assets/css/design-wizard.css', - array(), + array( 'wp-jquery-ui-dialog' ), LEARNDASH_VERSION ); wp_enqueue_script( 'learndash-design-wizard', LEARNDASH_LMS_PLUGIN_URL . '/assets/js/design-wizard.js', - array( 'jquery', 'js-cookie', 'updates' ), + array( 'jquery', 'js-cookie', 'updates', 'jquery-ui-dialog' ), LEARNDASH_VERSION, true ); @@ -444,8 +415,6 @@ public function enqueue_admin_scripts() : void { admin_url( 'admin.php' ) ), 'ajax_init_nonce' => wp_create_nonce( 'ld_dw_build_template' ), - 'ajax_nonce' => wp_create_nonce( 'astra-sites' ), - 'ajax_set_data_nonce' => wp_create_nonce( 'astra-sites-set-ai-site-data' ), 'ajax_kadence_security_nonce' => wp_create_nonce( 'kadence-ajax-verification' ), 'fonts' => $this->get_theme_fonts(), 'palettes' => $this->get_theme_palettes(), @@ -455,6 +424,12 @@ public function enqueue_admin_scripts() : void { 'dw_error_default' => __( 'There\'s unknown error with the design wizard. Please try again later or contact our support if the issue persists.', 'learndash' ), ), 'templates' => $templates, + 'confirm_dialog' => array( + 'proceed' => __( 'I understand, continue.', 'learndash' ), + 'exit' => __( 'Exit Setup', 'learndash' ), + 'start_title' => __( 'Choose a template', 'learndash' ), + 'end_title' => __( 'Ready to Import?', 'learndash' ), + ), ) ); } @@ -687,245 +662,15 @@ public function get_theme_fonts( string $theme = '' ) : array { ), ); - $astra_fonts = array( - 'default' => array( - 'label' => 'Default', - 'families' => array(), - 'details' => array( - 'body-font-family' => '', - 'body-font-variant' => '', - 'body-font-weight' => 400, - 'font-size-body' => array( - 'desktop' => 16, - 'tablet' => '', - 'mobile' => '', - 'desktop-unit' => 'px', - 'tablet-unit' => 'px', - 'mobile-unit' => 'px', - ), - 'body-line-height' => '', - 'headings-font-family' => '', - 'headings-font-weight' => 700, - 'headings-line-height' => '', - 'headings-font-variant' => '', - ), - ), - '1' => array( - 'label' => 'Playfair Display & Source Sans Pro', - 'families' => array( - 'heading' => 'Playfair Display', - 'body' => 'Source Sans Pro', - ), - 'details' => array( - 'body-font-family' => "'Source Sans Pro', sans-serif", - 'body-font-variant' => '', - 'body-font-weight' => 400, - 'font-size-body' => array( - 'desktop' => 16, - 'tablet' => '', - 'mobile' => '', - 'desktop-unit' => 'px', - 'tablet-unit' => 'px', - 'mobile-unit' => 'px', - ), - 'body-line-height' => '', - 'headings-font-family' => "'Playfair Display', serif", - 'headings-font-weight' => 700, - 'headings-line-height' => '', - 'headings-font-variant' => '', - ), - ), - '2' => array( - 'label' => 'Poppins & Lato', - 'families' => array( - 'heading' => 'Poppins', - 'body' => 'Lato', - ), - 'details' => array( - 'body-font-family' => "'Lato', sans-serif", - 'body-font-variant' => '', - 'body-font-weight' => 400, - 'font-size-body' => array( - 'desktop' => 16, - 'tablet' => '', - 'mobile' => '', - 'desktop-unit' => 'px', - 'tablet-unit' => 'px', - 'mobile-unit' => 'px', - ), - 'body-line-height' => '', - 'headings-font-family' => "'Poppins', sans-serif", - 'headings-font-weight' => 700, - 'headings-line-height' => '', - 'headings-font-variant' => '', - ), - ), - '3' => array( - 'label' => 'Monserrat & Lato', - 'families' => array( - 'heading' => 'Monserrat', - 'body' => 'Lato', - ), - 'details' => array( - 'body-font-family' => "'Lato', sans-serif", - 'body-font-variant' => '', - 'body-font-weight' => 400, - 'font-size-body' => array( - 'desktop' => 17, - 'tablet' => '', - 'mobile' => '', - 'desktop-unit' => 'px', - 'tablet-unit' => 'px', - 'mobile-unit' => 'px', - ), - 'body-line-height' => '', - 'headings-font-family' => "'Montserrat', sans-serif", - 'headings-font-weight' => 700, - 'headings-line-height' => '', - 'headings-font-variant' => '', - ), - ), - '4' => array( - 'label' => 'Rubik & Karla', - 'families' => array( - 'heading' => 'Rubik', - 'body' => 'Karla', - ), - 'details' => array( - 'body-font-family' => "'Karla', sans-serif", - 'body-font-variant' => '', - 'body-font-weight' => 400, - 'font-size-body' => array( - 'desktop' => 17, - 'tablet' => '', - 'mobile' => '', - 'desktop-unit' => 'px', - 'tablet-unit' => 'px', - 'mobile-unit' => 'px', - ), - 'body-line-height' => '', - 'headings-font-family' => "'Rubik', sans-serif", - 'headings-font-weight' => 700, - 'headings-line-height' => '', - 'headings-font-variant' => '', - ), - ), - '5' => array( - 'label' => 'Roboto Condensed & Roboto', - 'families' => array( - 'heading' => 'Roboto Condensed', - 'body' => 'Roboto', - ), - 'details' => array( - 'body-font-family' => "'Roboto', sans-serif", - 'body-font-variant' => '', - 'body-font-weight' => 400, - 'font-size-body' => array( - 'desktop' => 16, - 'tablet' => '', - 'mobile' => '', - 'desktop-unit' => 'px', - 'tablet-unit' => 'px', - 'mobile-unit' => 'px', - ), - 'body-line-height' => '', - 'headings-font-family' => "'Roboto Condensed', sans-serif", - 'headings-font-weight' => 700, - 'headings-line-height' => '', - 'headings-font-variant' => '', - ), - ), - '6' => array( - 'label' => 'Merriweather & Inter', - 'families' => array( - 'heading' => 'Merriweather', - 'body' => 'Inter', - ), - 'details' => array( - 'body-font-family' => "'Inter', sans-serif", - 'body-font-variant' => '', - 'body-font-weight' => 400, - 'font-size-body' => array( - 'desktop' => 17, - 'tablet' => '', - 'mobile' => '', - 'desktop-unit' => 'px', - 'tablet-unit' => 'px', - 'mobile-unit' => 'px', - ), - 'body-line-height' => '', - 'headings-font-family' => "'Merriweather', serif", - 'headings-font-weight' => 700, - 'headings-line-height' => '', - 'headings-font-variant' => '', - ), - ), - '7' => array( - 'label' => 'Volkorn & Open Sans', // cspell:disable-line. - 'families' => array( - 'heading' => 'Volkorn', // cspell:disable-line. - 'body' => 'Open Sans', - ), - 'details' => array( - 'body-font-family' => "'Open Sans', sans-serif", - 'body-font-variant' => '', - 'body-font-weight' => 400, - 'font-size-body' => array( - 'desktop' => 16, - 'tablet' => '', - 'mobile' => '', - 'desktop-unit' => 'px', - 'tablet-unit' => 'px', - 'mobile-unit' => 'px', - ), - 'body-line-height' => '', - 'headings-font-family' => "'Vollkorn', serif", - 'headings-font-weight' => 700, - 'headings-line-height' => '', - 'headings-font-variant' => '', - ), - ), - '8' => array( - 'label' => 'Open Sans & Work Sans', - 'families' => array( - 'heading' => 'Open Sans', - 'body' => 'Work Sans', - ), - 'details' => array( - 'body-font-family' => "'Work Sans', sans-serif", - 'body-font-variant' => '', - 'body-font-weight' => 400, - 'font-size-body' => array( - 'desktop' => 16, - 'tablet' => '', - 'mobile' => '', - 'desktop-unit' => 'px', - 'tablet-unit' => 'px', - 'mobile-unit' => 'px', - ), - 'body-line-height' => '', - 'headings-font-family' => "'Open Sans', sans-serif", - 'headings-font-weight' => 700, - 'headings-line-height' => '', - 'headings-font-variant' => '', - ), - ), - ); - if ( ! empty( $theme ) ) { switch ( $theme ) { case 'kadence': $fonts = $kadence_fonts; break; - - case 'astra': - $fonts = $astra_fonts; - break; } } else { $fonts = array( 'kadence' => $kadence_fonts, - 'astra' => $astra_fonts, ); } @@ -952,10 +697,6 @@ public function get_template_fonts( string $template = '', bool $omit_default = case 'kadence': $fonts = $this->get_theme_fonts( 'kadence' ); break; - - case 'astra': - $fonts = $this->get_theme_fonts( 'astra' ); - break; } } @@ -1077,337 +818,15 @@ public function get_theme_palettes( string $theme = '' ) : array { ), ); - $astra_palettes = array( - 'dark' => array( - 'default' => array( - 'slug' => 'default', - 'title' => __( 'Default', 'learndash' ), - 'colors' => array(), - ), - 'style-1' => array( - 'slug' => 'style-1', - 'title' => __( 'Style 1', 'learndash' ), - 'colors' => array( - '#8E43F0', - '#7215EA', - '#FFFFFF', - '#EEEBF4', - '#150E1F', - '#494153', - '#000000', - '#4B4F58', - '#F6F7F8', - ), - ), - 'style-2' => array( - 'slug' => 'style-2', - 'title' => __( 'Style 2', 'learndash' ), - 'colors' => array( - '#EF4D48', - '#D90700', - '#FFFFFF', - '#EEEAEC', - '#2B161B', - '#3C2F32', - '#000000', - '#4B4F58', - '#F6F7F8', - ), - ), - 'style-3' => array( - 'slug' => 'style-3', - 'title' => __( 'Style 3', 'learndash' ), - 'colors' => array( - '#FF42B3', - '#FF0099', - '#FFFFFF', - '#EEEAEC', - '#2B161B', - '#3C2F32', - '#000000', - '#4B4F58', - '#F6F7F8', - ), - ), - 'style-4' => array( - 'slug' => 'style-4', - 'title' => __( 'Style 4', 'learndash' ), - 'colors' => array( - '#FF6A97', - '#FA036B', - '#FFFFFF', - '#EEEAEC', - '#2B161B', - '#3C2F32', - '#000000', - '#4B4F58', - '#F6F7F8', - ), - ), - 'style-5' => array( - 'slug' => 'style-5', - 'title' => __( 'Style 5', 'learndash' ), - 'colors' => array( - '#FF7A3D', - '#FF5100', - '#FFFFFF', - '#F1EDEB', - '#1E1810', - '#443D3A', - '#000000', - '#4B4F58', - '#F6F7F8', - ), - ), - 'style-6' => array( - 'slug' => 'style-6', - 'title' => __( 'Style 6', 'learndash' ), - 'colors' => array( - '#F9C349', - '#FFB100', - '#FFFFFF', - '#F0EFEC', - '#1E1810', - '#4D4A46', - '#000000', - '#4B4F58', - '#F6F7F8', - ), - ), - 'style-7' => array( - 'slug' => 'style-7', - 'title' => __( 'Style 7', 'learndash' ), - 'colors' => array( - '#30C7B5', - '#00AC97', - '#FFFFFF', - '#F0EFEC', - '#1E1810', - '#4D4A46', - '#000000', - '#4B4F58', - '#F6F7F8', - ), - ), - 'style-8' => array( - 'slug' => 'style-8', - 'title' => __( 'Style 8', 'learndash' ), - 'colors' => array( - '#1BAE70', - '#06752E', - '#FFFFFF', - '#EBECEB', - '#14261C', - '#3D4641', - '#000000', - '#4B4F58', - '#F6F7F8', - ), - ), - 'style-9' => array( - 'slug' => 'style-9', - 'title' => __( 'Style 9', 'learndash' ), - 'colors' => array( - '#2FE6FF', - '#00D0EC', - '#FFFFFF', - '#E8EBEC', - '#101218', - '#3B4244', - '#000000', - '#4B4F58', - '#F6F7F8', - ), - ), - 'style-10' => array( - 'slug' => 'style-10', - 'title' => __( 'Style 10', 'learndash' ), - 'colors' => array( - '#4175FC', - '#084AF3', - '#FFFFFF', - '#E8EBEC', - '#101218', - '#3B4244', - '#000000', - '#4B4F58', - '#F6F7F8', - ), - ), - ), - 'light' => array( - 'default' => array( - 'slug' => 'default', - 'title' => __( 'Default', 'learndash' ), - 'colors' => array(), - ), - 'style-1' => array( - 'slug' => 'style-1', - 'title' => __( 'Style 1', 'learndash' ), - 'colors' => array( - '#8E43F0', - '#6300E2', - '#150E1F', - '#584D66', - '#F3F1F6', - '#FFFFFF', - '#000000', - '#4B4F58', - '#F6F7F8', - ), - ), - 'style-2' => array( - 'slug' => 'style-2', - 'title' => __( 'Style 2', 'learndash' ), - 'colors' => array( - '#EF4D48', - '#D90700', - '#2B161B', - '#453E3E', - '#F7F3F5', - '#FFFFFF', - '#000000', - '#4B4F58', - '#F6F7F8', - ), - ), - 'style-3' => array( - 'slug' => 'style-3', - 'title' => __( 'Style 3', 'learndash' ), - 'colors' => array( - '#FF42B3', - '#FF0099', - '#2B161B', - '#554B4E', - '#F6F3F5', - '#FFFFFF', - '#000000', - '#4B4F58', - '#F6F7F8', - ), - ), - 'style-4' => array( - 'slug' => 'style-4', - 'title' => __( 'Style 4', 'learndash' ), - 'colors' => array( - '#FF6A97', - '#FA036B', - '#2B161B', - '#645659', - '#F8F3F5', - '#FFFFFF', - '#000000', - '#4B4F58', - '#F6F7F8', - ), - ), - 'style-5' => array( - 'slug' => 'style-5', - 'title' => __( 'Style 5', 'learndash' ), - 'colors' => array( - '#FF7A3D', - '#FF5100', - '#1E1810', - '#575250', - '#F8F5F4', - '#FFFFFF', - '#000000', - '#4B4F58', - '#F6F7F8', - ), - ), - 'style-6' => array( - 'slug' => 'style-6', - 'title' => __( 'Style 6', 'learndash' ), - 'colors' => array( - '#F9C349', - '#FFB100', - '#1E1810', - '#62615C', - '#F8F7F3', - '#FFFFFF', - '#000000', - '#4B4F58', - '#F6F7F8', - ), - ), - 'style-7' => array( - 'slug' => 'style-7', - 'title' => __( 'Style 7', 'learndash' ), - 'colors' => array( - '#30C7B5', - '#00AC97', - '#14261C', - '#4F5655', - '#F3F6F3', - '#FFFFFF', - '#000000', - '#4B4F58', - '#F6F7F8', - ), - ), - 'style-8' => array( - 'slug' => 'style-8', - 'title' => __( 'Style 8', 'learndash' ), - 'colors' => array( - '#1BAE70', - '#06752E', - '#14261C', - '#4E5652', - '#F4F6F4', - '#FFFFFF', - '#000000', - '#4B4F58', - '#F6F7F8', - ), - ), - 'style-9' => array( - 'slug' => 'style-9', - 'title' => __( 'Style 9', 'learndash' ), - 'colors' => array( - '#2FC1FF', - '#08ACF2', - '#101218', - '#4C5253', - '#F3F6F6', - '#FFFFFF', - '#000000', - '#4B4F58', - '#F6F7F8', - ), - ), - 'style-10' => array( - 'slug' => 'style-10', - 'title' => __( 'Style 10', 'learndash' ), - 'colors' => array( - '#4175FC', - '#084AF3', - '#101218', - '#494B51', - '#F3F5F5', - '#FFFFFF', - '#000000', - '#4B4F58', - '#F6F7F8', - ), - ), - ), - ); - if ( ! empty( $theme ) ) { switch ( $theme ) { case 'kadence': $palettes = $kadence_palettes; break; - - case 'astra': - $palettes = $astra_palettes; - break; } } else { $palettes = array( 'kadence' => $kadence_palettes, - 'astra' => $astra_palettes, ); } @@ -1433,23 +852,6 @@ public function get_template_palettes( string $template, bool $omit_default = fa case 'kadence': $palettes = $this->get_theme_palettes( 'kadence' ); break; - - case 'astra': - $palettes = $this->get_theme_palettes( 'astra' ); - $color_scheme = 'light'; // Default color scheme. - $color_scheme = ! empty( $template['color_scheme'] ) ? $template['color_scheme'] : $color_scheme; - - $palettes = $palettes[ $color_scheme ]; - - $palettes = array_map( - function ( $palette ) { - $palette['colors'] = array_slice( $palette['colors'], 0, 5 ); - - return $palette; - }, - $palettes - ); - break; } } @@ -1983,8 +1385,6 @@ public function ajax_build_template() { $message = ''; if ( isset( $this->ajax_template['theme'] ) && $this->ajax_template['theme'] === 'kadence' ) { $message = __( 'Run Kadence template building process', 'learndash' ); - } elseif ( isset( $this->ajax_template['theme'] ) && $this->ajax_template['theme'] === 'astra' ) { - $message = __( 'Run Astra template building process', 'learndash' ); } return array( 'next_step_message' => $message ); diff --git a/web/app/plugins/sfwd-lms/includes/class-ld-gdpr.php b/web/app/plugins/sfwd-lms/includes/class-ld-gdpr.php index 303bf7eb1..a6fbbdec0 100644 --- a/web/app/plugins/sfwd-lms/includes/class-ld-gdpr.php +++ b/web/app/plugins/sfwd-lms/includes/class-ld-gdpr.php @@ -13,6 +13,8 @@ exit; } +use LearnDash\Core\Utilities\Cast; + if ( ! class_exists( 'LearnDash_GDPR' ) ) { /** * Class to handle GDPR @@ -87,7 +89,11 @@ public function learndash_add_privacy_policy_text() { */ public function add_exporters( array $exporters = array() ): array { $exporters['learndash-transactions'] = array( - 'exporter_friendly_name' => esc_html__( 'LearnDash LMS Transactions', 'learndash' ), + 'exporter_friendly_name' => sprintf( + // Translators: %s: Orders label. + esc_html__( 'LearnDash LMS %s', 'learndash' ), + learndash_get_custom_label( 'orders' ) + ), 'callback' => array( $this, 'export_transactions' ), ); @@ -163,7 +169,14 @@ public function add_exporters( array $exporters = array() ): array { 'callback' => array( $this, 'export_course_progress' ), ); - return $exporters; + /** + * Filters LearnDash GDPR Exporters. + * + * @since 4.7.0.1 + * + * @param array $exporters Array of Exporters. + */ + return apply_filters( 'learndash_privacy_export_exporters', $exporters ); } /** @@ -186,6 +199,8 @@ public function export_transactions( string $email_address, int $page ): array { /** * Filters value of per page privacy export transactions. * + * @since 2.5.8 + * * @param int $per_page_default Per page limit. */ $number = apply_filters( 'learndash_privacy_export_transactions_per_page', $this->per_page_default ); @@ -206,6 +221,10 @@ public function export_transactions( string $email_address, int $page ): array { $transaction_to_export = array(); foreach ( $transactions_query->posts as $transaction ) { + if ( ! $transaction instanceof WP_Post ) { + continue; + } + $transaction_meta_data = array(); $transaction_meta_fields = array(); @@ -213,7 +232,11 @@ public function export_transactions( string $email_address, int $page ): array { if ( 'stripe' === $transaction_type ) { $transaction_meta_data[] = array( - 'name' => __( 'Transaction Type', 'learndash' ), + 'name' => sprintf( + // Translators: %s: Order label. + esc_html__( '%s Type', 'learndash' ), + learndash_get_custom_label( 'order' ) + ), 'value' => __( 'Stripe', 'learndash' ), ); @@ -238,7 +261,11 @@ public function export_transactions( string $email_address, int $page ): array { if ( ! empty( $transaction_type ) ) { $transaction_meta_data[] = array( - 'name' => __( 'Transaction Type', 'learndash' ), + 'name' => sprintf( + // Translators: %s: Order label. + esc_html__( '%s Type', 'learndash' ), + learndash_get_custom_label( 'order' ) + ), 'value' => __( 'PayPal', 'learndash' ), ); @@ -273,7 +300,11 @@ public function export_transactions( string $email_address, int $page ): array { if ( '2co' === $transaction_type ) { $transaction_meta_data[] = array( - 'name' => __( 'Transaction Type', 'learndash' ), + 'name' => sprintf( + // Translators: %s: Order label. + esc_html__( '%s Type', 'learndash' ), + learndash_get_custom_label( 'order' ) + ), 'value' => __( '2Checkout', 'learndash' ), ); @@ -341,7 +372,11 @@ public function export_transactions( string $email_address, int $page ): array { if ( ! empty( $order_ip_address ) ) { $transaction_meta_data[] = array( - 'name' => __( 'Transaction Type', 'learndash' ), + 'name' => sprintf( + // Translators: %s: Order label. + esc_html__( '%s Type', 'learndash' ), + learndash_get_custom_label( 'order' ) + ), 'value' => __( 'Samcart', 'learndash' ), ); @@ -394,7 +429,7 @@ public function export_transactions( string $email_address, int $page ): array { $transaction_meta_data[] = array( 'name' => __( 'Order Date', 'learndash' ), - 'value' => learndash_adjust_date_time_display( strtotime( $transaction->post_date ) ), + 'value' => learndash_adjust_date_time_display( (int) strtotime( $transaction->post_date_gmt ) ), ); foreach ( $transaction_meta_fields as $meta_key => $meta_set ) { @@ -409,7 +444,11 @@ public function export_transactions( string $email_address, int $page ): array { $transaction_to_export[] = array( 'group_id' => 'ld-transactions', - 'group_label' => __( 'LearnDash LMS Purchase Transactions', 'learndash' ), + 'group_label' => sprintf( + // Translators: %s: Orders label. + __( 'LearnDash LMS %s', 'learndash' ), + learndash_get_custom_label( 'orders' ) + ), 'item_id' => "ld-transactions-{$transaction->ID}", 'data' => $transaction_meta_data, ); @@ -442,6 +481,8 @@ public function export_course_assignments( string $email_address, int $page ): a /** * Filters value of per page export for course assignments. * + * @since 4.1.0 + * * @param int $per_page_default Per page limit. */ $posts_per_page = apply_filters( 'learndash_privacy_export_assignments_per_page', $this->per_page_default ); @@ -462,6 +503,10 @@ public function export_course_assignments( string $email_address, int $page ): a $assignments_to_export = array(); foreach ( $assignments_query->posts as $assignment ) { + if ( ! $assignment instanceof WP_Post ) { + continue; + } + $assignment_meta_data = array(); $assignment_url = get_permalink( $assignment->ID ); @@ -472,7 +517,7 @@ public function export_course_assignments( string $email_address, int $page ): a $assignment_meta_data[] = array( 'name' => __( 'Date', 'learndash' ), - 'value' => learndash_adjust_date_time_display( strtotime( $assignment->post_date ) ), + 'value' => learndash_adjust_date_time_display( (int) strtotime( $assignment->post_date_gmt ) ), ); $course_id = get_post_meta( $assignment->ID, 'course_id', true ); @@ -536,6 +581,8 @@ public function export_quiz_essays( string $email_address, int $page ): array { /** * Filters value of per page export for quiz essays. * + * @since 2.5.8 + * * @param int $per_page_default Per page limit. */ $number = apply_filters( 'learndash_privacy_export_quiz_essays_per_page', $this->per_page_default ); @@ -556,6 +603,10 @@ public function export_quiz_essays( string $email_address, int $page ): array { $essays_to_export = array(); foreach ( $essays_query->posts as $essay ) { + if ( ! $essay instanceof WP_Post ) { + continue; + } + $essay_meta_data = array(); $essay_url = get_permalink( $essay->ID ); @@ -569,7 +620,7 @@ public function export_quiz_essays( string $email_address, int $page ): array { $essay_meta_data[] = array( 'name' => __( 'Date', 'learndash' ), - 'value' => learndash_adjust_date_time_display( strtotime( $essay->post_date ) ), + 'value' => learndash_adjust_date_time_display( (int) strtotime( $essay->post_date_gmt ) ), ); $course_id = get_post_meta( $essay->ID, 'course_id', true ); @@ -639,6 +690,8 @@ public function export_enrolled_groups( string $email_address, int $page ): arra /** * Filters value of per page export for enrolled groups. * + * @since 4.1.0 + * * @param int $per_page_default Per page limit. */ $posts_per_page = apply_filters( @@ -715,6 +768,8 @@ public function export_enrolled_courses( string $email_address, int $page ): arr /** * Filters value of per page export for enrolled courses. * + * @since 4.1.0 + * * @param int $per_page_default Per page limit. */ $posts_per_page = apply_filters( @@ -806,6 +861,8 @@ public function export_course_certificates( string $email_address, int $page ): /** * Filters value of per page export for course certificates. * + * @since 4.1.0 + * * @param int $per_page_default Per page limit. */ $posts_per_page = apply_filters( @@ -890,6 +947,8 @@ public function export_quiz_certificates( string $email_address, int $page ): ar /** * Filters value of per page export for quiz certificates. * + * @since 4.1.0 + * * @param int $per_page_default Per page limit. */ $posts_per_page = apply_filters( @@ -972,6 +1031,8 @@ public function export_group_certificates( string $email_address, int $page ): a /** * Filters value of per page export for group certificates. * + * @since 4.1.0 + * * @param int $per_page_default Per page limit. */ $posts_per_page = apply_filters( @@ -1036,7 +1097,15 @@ public function export_group_certificates( string $email_address, int $page ): a * @param string $email_address Email Address of user to export. * @param int $page Page number of export. * - * @return array + * @return array{ + * data: array{}|array{ + * item_id: string, + * group_id: string, + * group_label: string, + * data: array{ name: string, value: string }[], + * }, + * done: bool, + * } */ public function export_course_progress( string $email_address, int $page ): array { $user = $this->get_user_by_email( $email_address ); @@ -1045,146 +1114,197 @@ public function export_course_progress( string $email_address, int $page ): arra return self::DEFAULT_EXPORTER_RESULT; } - /** - * Filters value of per page export for group certificates. - * - * @param int $per_page_default Per page limit. - */ - $posts_per_page = apply_filters( - 'learndash_privacy_export_course_progress_per_page', - $this->per_page_default - ); - - $courses_registered_all = ld_get_mycourses( $user->ID ); + $course_progress = get_user_meta( $user->ID, '_sfwd-course_progress', true ); + $course_progress = empty( $course_progress ) ? [] : (array) $course_progress; - $courses_registered_query_args = array( - 'post_type' => 'sfwd-courses', - 'fields' => 'ids', - 'post__in' => $courses_registered_all, - 'posts_per_page' => $posts_per_page, - 'paged' => $page, + $course_progress_ids = array_diff( + array_merge( + ld_get_mycourses( $user->ID ), + array_keys( $course_progress ) + ), + learndash_get_expired_user_courses_from_meta( $user->ID ) ); - $usermeta = get_user_meta( $user->ID, '_sfwd-course_progress', true ); - $course_progress = empty( $usermeta ) ? array() : $usermeta; - - $course_progress_ids = array_merge( $courses_registered_all, array_keys( $course_progress ) ); - $course_progress_ids = array_diff( $course_progress_ids, learndash_get_expired_user_courses_from_meta( $user->ID ) ); + if ( empty( $course_progress_ids ) ) { + return self::DEFAULT_EXPORTER_RESULT; + } - $course_progress_query_args = array( - 'post_type' => 'sfwd-courses', - 'fields' => 'ids', - 'post__in' => $course_progress_ids, - 'posts_per_page' => $posts_per_page, - 'paged' => $page, + $course_progress_query = new WP_Query( + [ + 'post_type' => LDLMS_Post_Types::get_post_type_slug( LDLMS_Post_Types::COURSE ), + 'fields' => 'ids', + 'post__in' => $course_progress_ids, + /** + * Filters value of per page export for course progress. + * + * @since 4.1.0 + * + * @param int $per_page_default Per page limit. + */ + 'posts_per_page' => apply_filters( + 'learndash_privacy_export_course_progress_per_page', + $this->per_page_default + ), + 'paged' => $page, + ] ); - $course_progress_query = new WP_Query( $course_progress_query_args ); + $found_course_ids = array_map( + function( $course_id ) { + return Cast::to_int( $course_id ); + }, + $course_progress_query->posts + ); - $course_p = $course_progress; - $course_progress = array(); - foreach ( $course_progress_query->posts as $course_id ) { - if ( isset( $course_p[ $course_id ] ) ) { - $course_progress[ $course_id ] = $course_p[ $course_id ]; - } else { - $course_progress[ $course_id ] = array(); + foreach ( $found_course_ids as $course_id ) { + if ( ! isset( $course_progress[ $course_id ] ) ) { + $course_progress[ $course_id ] = []; } } + $course_progress = array_intersect_key( $course_progress, array_flip( $found_course_ids ) ); + if ( empty( $course_progress ) ) { return self::DEFAULT_EXPORTER_RESULT; } - $data = array(); + $courses_data = []; - foreach ( $course_progress as $course_id => $coursep ) { - $progress_summary = learndash_user_get_course_progress( $user->ID, $course_id, 'summary' ); - $status = learndash_course_status_label( $progress_summary['status'] ); - $completed = ( ! empty( $coursep['completed'] ) ? $coursep['completed'] : '0' ); - - $lessons = array(); - - if ( ! empty( $coursep['lessons'] ) ) { - foreach ( $coursep['lessons'] as $lesson_id => $status ) { - $title = sprintf( - // translators: placeholder: Lesson. - esc_html_x( '%s: ', 'placeholder: Lesson', 'learndash' ), - LearnDash_Custom_Label::get_label( 'lesson' ) - ) . get_the_title( $lesson_id ); - $status = ( true === (bool) $status ? 'Completed' : 'Not Completed' ); - - $lessons[] = array( - 'name' => $title, - 'value' => $status, + foreach ( $course_progress as $course_id => $course_progress_data ) { + $topics = []; + $lessons = []; + + if ( ! empty( $course_progress_data['lessons'] ) ) { + foreach ( $course_progress_data['lessons'] as $lesson_id => $lesson_status ) { + $lesson_data = [ + 'name' => sprintf( + // translators: placeholder: Lesson label, Lesson title. + esc_html_x( '%1$s: %2$s', 'placeholder: Lesson label, Lesson title', 'learndash' ), + LearnDash_Custom_Label::get_label( 'lesson' ), + get_the_title( (int) $lesson_id ) + ), + 'value' => true === (bool) $lesson_status + ? esc_html_x( 'Completed', 'Completed lesson', 'learndash' ) + : esc_html_x( 'Not completed', 'Not completed lesson', 'learndash' ), + ]; + + /** + * Filters lesson progress data on GDPR export. + * + * @since 4.7.0.1 + * + * @param array{ name: string, value: string } $lesson_data Lesson data. + * @param int $lesson_id Lesson ID. + * @param int $course_id Course ID. + * @param int $user_id User ID. + */ + $lessons[] = apply_filters( + 'learndash_privacy_export_lesson_progress_data', + $lesson_data, + $lesson_id, + $course_id, + $user->ID ); } } - $topics = array(); - - if ( ! empty( $course_progress[ $course_id ]['topics'] ) ) { - foreach ( $course_progress[ $course_id ]['topics'] as $lesson_id ) { - foreach ( $lesson_id as $topic_id => $status ) { - $title = sprintf( - // translators: placeholder: Topic. - esc_html_x( '%s: ', 'placeholder: Topic', 'learndash' ), - LearnDash_Custom_Label::get_label( 'topic' ) - ) . get_the_title( $topic_id ); - $status = ( true === (bool) $status ? 'Completed' : 'Not Completed' ); - - $topics[] = array( - 'name' => $title, - 'value' => $status, + if ( ! empty( $course_progress_data['topics'] ) ) { + foreach ( $course_progress_data['topics'] as $lesson_id ) { + foreach ( $lesson_id as $topic_id => $topic_status ) { + $topic_data = [ + 'name' => sprintf( + // translators: placeholder: Topic label, Topic title. + esc_html_x( '%1$s: %2$s', 'placeholder: Topic label, Topic title', 'learndash' ), + LearnDash_Custom_Label::get_label( 'topic' ), + get_the_title( (int) $topic_id ) + ), + 'value' => true === (bool) $topic_status + ? esc_html_x( 'Completed', 'Completed topic', 'learndash' ) + : esc_html_x( 'Not completed', 'Not completed topic', 'learndash' ), + ]; + + /** + * Filters topic progress data on GDPR export. + * + * @since 4.7.0.1 + * + * @param array{ name: string, value: string } $topic_data Topic data. + * @param int $topic_id Topic ID. + * @param int $lesson_id Lesson ID. + * @param int $course_id Course ID. + * @param int $user_id User ID. + */ + $topics[] = apply_filters( + 'learndash_privacy_export_topic_progress_data', + $topic_data, + $topic_id, + $lesson_id, + $course_id, + $user->ID ); } } } - $data[] = array( - 'group_id' => 'learndash-course-progress', - 'group_label' => sprintf( - // translators: placeholder: Course. - esc_html_x( 'LearnDash LMS %s Progress', 'placeholder: Course', 'learndash' ), - LearnDash_Custom_Label::get_label( 'course' ) - ), - 'item_id' => "learndash-course-progress-{$course_id}", - 'data' => array( - array( - 'name' => LearnDash_Custom_Label::get_label( 'course' ), - 'value' => get_the_title( $course_id ), - ), - array( - 'name' => sprintf( - // translators: placeholder: Course. - esc_html_x( '%s ID', 'placeholder: Course', 'learndash' ), - LearnDash_Custom_Label::get_label( 'course' ) - ), - 'value' => absint( $course_id ), - ), - array( - 'name' => __( 'URL', 'learndash' ), - 'value' => get_permalink( $course_id ), - ), - array( - 'name' => __( 'Status', 'learndash' ), - 'value' => $status, + $progress_summary = learndash_user_get_course_progress( $user->ID, $course_id, 'summary' ); + + $course_data = [ + [ + 'name' => LearnDash_Custom_Label::get_label( 'course' ), + 'value' => get_the_title( $course_id ), + ], + [ + 'name' => sprintf( + // translators: placeholder: Course. + esc_html_x( '%s ID', 'placeholder: Course', 'learndash' ), + LearnDash_Custom_Label::get_label( 'course' ) ), - array( - 'name' => __( 'Steps Completed', 'learndash' ), - 'value' => $progress_summary['completed'] . ' / ' . $progress_summary['total'], + 'value' => absint( $course_id ), + ], + [ + 'name' => __( 'URL', 'learndash' ), + 'value' => get_permalink( $course_id ), + ], + [ + 'name' => __( 'Status', 'learndash' ), + 'value' => learndash_course_status_label( $progress_summary['status'] ), + ], + [ + 'name' => __( 'Steps Completed', 'learndash' ), + 'value' => $progress_summary['completed'] . ' / ' . $progress_summary['total'], + ], + ]; + + /** + * Filters course progress data on GDPR export. + * + * @since 4.7.0.1 + * + * @param array{ item_id: string, group_id: string, group_label: string, data: array{ name: string, value: mixed }[] } $course_data Course progress data. + * @param int $course_id Course ID. + * @param int $user_id User ID. + */ + $courses_data[] = apply_filters( + 'learndash_privacy_export_course_progress_data', + [ + 'item_id' => "learndash-course-progress-{$course_id}", + 'group_id' => 'learndash-course-progress', + 'group_label' => sprintf( + // translators: placeholder: Course label. + esc_html_x( 'LearnDash LMS %s Progress', 'placeholder: Course', 'learndash' ), + LearnDash_Custom_Label::get_label( 'course' ) ), - ), + 'data' => array_merge( $course_data, $lessons, $topics ), + ], + $course_id, + $user->ID ); - $data_idx = count( $data ) - 1; - $steps_progress = array_merge( $lessons, $topics ); - $data[ $data_idx ]['data'] = array_merge( $data[ $data_idx ]['data'], $steps_progress ); - } - return array( - 'data' => $data, + return [ + 'data' => $courses_data, 'done' => $page >= $course_progress_query->max_num_pages, - ); + ]; } /** @@ -1198,7 +1318,11 @@ public function export_course_progress( string $email_address, int $page ): arra */ public function add_erasers( array $erasers = array() ): array { $erasers[] = array( - 'eraser_friendly_name' => esc_html__( 'LearnDash LMS Transactions', 'learndash' ), + 'eraser_friendly_name' => sprintf( + // Translators: %s: Orders label. + esc_html__( 'LearnDash LMS %s', 'learndash' ), + learndash_get_custom_label( 'orders' ) + ), 'callback' => array( $this, 'erase_transactions' ), ); @@ -1254,6 +1378,8 @@ public function erase_transactions( string $email_address, int $page = 1 ): arra /** * Filters value of per page erase transactions. * + * @since 2.5.8 + * * @param int $per_page_default Per page limit. */ $posts_per_page = apply_filters( 'learndash_privacy_transactions_erase', $this->per_page_default ); diff --git a/web/app/plugins/sfwd-lms/includes/class-ld-lms.php b/web/app/plugins/sfwd-lms/includes/class-ld-lms.php index 7fa0dc75c..28eda1401 100644 --- a/web/app/plugins/sfwd-lms/includes/class-ld-lms.php +++ b/web/app/plugins/sfwd-lms/includes/class-ld-lms.php @@ -15,7 +15,9 @@ use LearnDash\Core\App; use LearnDash\Core\Provider; - +use LearnDash\Core\API; +use LearnDash\Core\Utilities\Cast; +use LearnDash\Core\Utilities\File; if ( ! class_exists( 'SFWD_LMS' ) ) { @@ -134,6 +136,13 @@ public function __construct() { $this->name = 'LMS Options'; $this->prefix = 'sfwd_lms_'; $this->parent_option = 'sfwd_lms_options'; + + /** + * We need to run this immediately to work around issues where some code + * would attempt to use the text domain before it would have otherwise loaded on a hook. + */ + $this->i18nize(); + parent::__construct(); // maybe call the activate function. @@ -142,6 +151,7 @@ public function __construct() { function () { if ( get_option( 'learndash_activation' ) ) { $this->activate(); + delete_option( 'learndash_activation' ); } } @@ -158,7 +168,6 @@ function () { add_action( 'generate_rewrite_rules', array( $this, 'paypal_rewrite_rules' ) ); add_filter( 'sfwd_cpt_loop', array( $this, 'cpt_loop_filter' ) ); add_filter( 'edit_term_count', array( $this, 'tax_term_count' ), 10, 3 ); - add_action( 'plugins_loaded', array( $this, 'i18nize' ) ); // cspell:disable-line. add_action( 'current_screen', array( $this, 'add_telemetry_modal' ) ); require_once LEARNDASH_LMS_PLUGIN_DIR . 'includes/payments/gateways/init.php'; @@ -239,12 +248,14 @@ function() { public function trigger_actions() { global $learndash_course_statuses, $learndash_question_types, $learndash_exam_challenge_statuses; + // Not recommended anymore. Use Post_Type_Status mapper instead. $learndash_course_statuses = array( 'not_started' => esc_html__( 'Not Started', 'learndash' ), 'in_progress' => esc_html__( 'In Progress', 'learndash' ), 'completed' => esc_html__( 'Completed', 'learndash' ), ); + // Not recommended anymore. Use Question_Type enum instead. $learndash_question_types = array( 'single' => esc_html__( 'Single choice', 'learndash' ), 'multiple' => esc_html__( 'Multiple choice', 'learndash' ), @@ -256,6 +267,7 @@ public function trigger_actions() { 'essay' => esc_html__( 'Essay / Open Answer', 'learndash' ), ); + // Not recommended anymore. Use Post_Type_Status mapper instead. $learndash_exam_challenge_statuses = array( 'not_taken' => esc_html__( 'Not Taken', 'learndash' ), 'passed' => esc_html__( 'Passed', 'learndash' ), @@ -450,13 +462,137 @@ public function load_template_functions() { * Loads the plugin's translated strings * * @since 2.1.0 + * @since 4.18.1.1 Added support for WordPress 6.7. + * @since 4.21.2.1 Added support for WordPress 6.8+. + * + * @return void */ public function i18nize() { - if ( ( defined( 'LD_LANG_DIR' ) ) && ( LD_LANG_DIR ) ) { - load_plugin_textdomain( LEARNDASH_LMS_TEXT_DOMAIN, false, LD_LANG_DIR ); + $plugin_basename = trailingslashit( plugin_basename( constant( 'LEARNDASH_LMS_PLUGIN_DIR' ) ) ); + $relative_path = $plugin_basename . 'languages'; + $absolute_path = trailingslashit( constant( 'WP_PLUGIN_DIR' ) ) . $relative_path; + $text_domain = constant( 'LEARNDASH_LMS_TEXT_DOMAIN' ); + + /** + * LD_LANG_DIR should always be an absolute path, but for backwards compatibility, we will also update + * the relative path based on it. + */ + if ( + defined( 'LD_LANG_DIR' ) + && constant( 'LD_LANG_DIR' ) + ) { + $absolute_path = constant( 'LD_LANG_DIR' ); + + /** + * Construct a relative path based on the absolute path to move from our plugin directory + * out to the LD_LANG_DIR directory + * + * This is necessary for pre-6.7 support. + */ + $relative_path = File::get_relative_path( + constant( 'LEARNDASH_LMS_PLUGIN_DIR' ), + $absolute_path + ); + + if ( + strpos( + $absolute_path, + ABSPATH + ) === false + && strpos( + $absolute_path, + '../' + ) === false + ) { + // Accounts for instances where LD_LANG_DIR is pointing to a directory within a plugin. + $relative_path = Cast::to_string( preg_replace( '/^\.?\//', '', $relative_path ) ); + $absolute_path = trailingslashit( constant( 'WP_PLUGIN_DIR' ) ) . $relative_path; + } elseif ( + strpos( + $absolute_path, + '../' + ) !== false + ) { + // Ensures a relative path used as the absolute path can find the .mo file. + $absolute_path = trailingslashit( constant( 'WP_PLUGIN_DIR' ) ) . $absolute_path; + } + } + + /** + * If we're running on a version of WordPress prior to 6.7, + * we can use load_plugin_textdomain() at all times without issue. + * + * This will properly load from the global WordPress languages directory instead if a matching file exists. + */ + if ( + version_compare( + learndash_sanitize_version_string( get_bloginfo( 'version' ) ), + '6.7.0', + '<' + ) + ) { + load_plugin_textdomain( $text_domain, false, $relative_path ); + + return; + } + + $wordpress_languages_directory = trailingslashit( constant( 'WP_LANG_DIR' ) ) . 'plugins/'; + + $mo_file_name = $text_domain . '-' . determine_locale() . '.mo'; + + // Prioritize the WordPress languages directory. + $mo_file_path = $wordpress_languages_directory . $mo_file_name; + + // Fallback to LearnDash plugin location. + if ( ! file_exists( $mo_file_path ) ) { + $mo_file_path = trailingslashit( $absolute_path ) . $mo_file_name; + } + + /** + * Filter the path to the .mo file to use for LearnDash. + * + * @since 4.18.1.1 + * + * @param string $mo_file_path Full path to the .mo file. + * @param string $mo_file_name Name of the .mo file. + * @param string $locale Locale. + * + * @return string + */ + $mo_file_path = apply_filters( + 'learndash_mo_file_path', + $mo_file_path, + $mo_file_name, + determine_locale() + ); + + if ( file_exists( $mo_file_path ) ) { + // If the .mo file does not exist, load_plugin_textdomain() will show a PHP notice on WordPress 6.7+. + load_plugin_textdomain( $text_domain, false, $relative_path ); } else { - load_plugin_textdomain( LEARNDASH_LMS_TEXT_DOMAIN, false, dirname( plugin_basename( dirname( __FILE__ ) ) ) . '/languages' ); + /** + * This fixes an issue with WordPress 6.8+ support. + * + * If the file doesn't exist, we need to fake a loaded translation to prevent + * _load_textdomain_just_in_time() from running. + * + * Using NOOP_Translations will prevent any translations from running, but if a translation file does + * not exist, this would be expected functionality anyway. + */ + global $l10n; + $l10n[ $text_domain ] = new NOOP_Translations(); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Expected, see above. } + + /** + * Workaround for WordPress 6.7+ support. + * + * Pre-WP 6.7, load_plugin_textdomain() would run load_textdomain() for us instead of using + * _load_textdomain_just_in_time(). + * + * As we're loading many things that use translation methods such as `__()` prior to the `init` hook, + * we need to do this to ensure our translations are loaded correctly in WordPress 6.7+. + */ + load_textdomain( $text_domain, $mo_file_path ); } /** @@ -1587,18 +1723,19 @@ public function add_post_types() { 'template_redirect' => true, 'taxonomies' => $course_taxonomies, 'cpt_options' => array( - 'has_archive' => learndash_post_type_has_archive( 'sfwd-courses' ), - 'hierarchical' => false, - 'supports' => array_merge( + 'has_archive' => learndash_post_type_has_archive( 'sfwd-courses' ), + 'hierarchical' => false, + 'supports' => array_merge( array( 'title', 'editor', 'author', 'page-attributes' ), LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Courses_CPT', 'supports' ) ), - 'labels' => $course_labels, - 'capability_type' => 'course', - 'exclude_from_search' => ( LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Courses_CPT', 'include_in_search' ) !== 'yes' ) ? true : false, - 'capabilities' => $course_capabilities, - 'map_meta_cap' => true, - 'show_in_rest' => LearnDash_REST_API::enabled( 'sfwd-courses' ) || LearnDash_REST_API::gutenberg_enabled( 'sfwd-courses' ), + 'labels' => $course_labels, + 'capability_type' => 'course', + 'exclude_from_search' => ( LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Courses_CPT', 'include_in_search' ) !== 'yes' ) ? true : false, + 'capabilities' => $course_capabilities, + 'map_meta_cap' => true, + 'show_in_rest' => LearnDash_REST_API::enabled( 'sfwd-courses' ) || LearnDash_REST_API::gutenberg_enabled( 'sfwd-courses' ), + 'rest_controller_class' => API\Controllers\Courses::class, ), 'options_page_title' => sprintf( // translators: placeholder: Course. @@ -1718,8 +1855,8 @@ public function add_post_types() { 'name' => sprintf( esc_html_x( '%s Per Page', 'placeholder: Lessons', 'learndash' ), LearnDash_Custom_Label::get_label( 'lessons' ) ), 'type' => 'select', 'initial_options' => array( - '' => esc_html__( 'Use Default', 'learndash' ) . ' ( ' . LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Section_Lessons_Display_Order', 'posts_per_page' ) . ' )', - 'CUSTOM' => esc_html__( 'Custom', 'learndash' ), + '' => esc_html__( 'Use Default', 'learndash' ) . ' ( ' . LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Section_Lessons_Display_Order', 'posts_per_page' ) . ' )', + 'on' => esc_html__( 'Custom', 'learndash' ), ), 'default' => '', // translators: placeholders: lessons, course. @@ -1871,17 +2008,18 @@ public function add_post_types() { 'template_redirect' => true, 'taxonomies' => $lesson_taxonomies, 'cpt_options' => array( - 'has_archive' => learndash_post_type_has_archive( 'sfwd-lessons' ), - 'supports' => array_merge( + 'has_archive' => learndash_post_type_has_archive( 'sfwd-lessons' ), + 'supports' => array_merge( array( 'title', 'editor', 'author', 'page-attributes' ), LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Lessons_CPT', 'supports' ) ), - 'labels' => $lesson_labels, - 'capability_type' => 'course', - 'exclude_from_search' => ( LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Lessons_CPT', 'include_in_search' ) !== 'yes' ) ? true : false, - 'capabilities' => $course_capabilities, - 'map_meta_cap' => true, - 'show_in_rest' => LearnDash_REST_API::enabled( 'sfwd-lessons' ) || LearnDash_REST_API::gutenberg_enabled( 'sfwd-lessons' ), + 'labels' => $lesson_labels, + 'capability_type' => 'course', + 'exclude_from_search' => ( LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Lessons_CPT', 'include_in_search' ) !== 'yes' ) ? true : false, + 'capabilities' => $course_capabilities, + 'map_meta_cap' => true, + 'show_in_rest' => LearnDash_REST_API::enabled( 'sfwd-lessons' ) || LearnDash_REST_API::gutenberg_enabled( 'sfwd-lessons' ), + 'rest_controller_class' => API\Controllers\Lessons::class, ), 'options_page_title' => sprintf( // translators: placeholder: Lesson. @@ -2026,17 +2164,18 @@ public function add_post_types() { 'template_redirect' => true, 'taxonomies' => $topic_taxonomies, 'cpt_options' => array( - 'supports' => array_merge( + 'supports' => array_merge( array( 'title', 'editor', 'author', 'page-attributes' ), LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Topics_CPT', 'supports' ) ), - 'has_archive' => learndash_post_type_has_archive( 'sfwd-topic' ), - 'labels' => $lesson_topic_labels, - 'capability_type' => 'course', - 'exclude_from_search' => ( LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Topics_CPT', 'include_in_search' ) !== 'yes' ) ? true : false, - 'capabilities' => $course_capabilities, - 'map_meta_cap' => true, - 'show_in_rest' => LearnDash_REST_API::enabled( 'sfwd-topic' ) || LearnDash_REST_API::gutenberg_enabled( 'sfwd-topic' ), + 'has_archive' => learndash_post_type_has_archive( 'sfwd-topic' ), + 'labels' => $lesson_topic_labels, + 'capability_type' => 'course', + 'exclude_from_search' => ( LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Topics_CPT', 'include_in_search' ) !== 'yes' ) ? true : false, + 'capabilities' => $course_capabilities, + 'map_meta_cap' => true, + 'show_in_rest' => LearnDash_REST_API::enabled( 'sfwd-topic' ) || LearnDash_REST_API::gutenberg_enabled( 'sfwd-topic' ), + 'rest_controller_class' => API\Controllers\Topics::class, ), 'options_page_title' => sprintf( // translators: placeholder: Topic. @@ -2186,18 +2325,19 @@ public function add_post_types() { 'template_redirect' => true, 'taxonomies' => $quiz_taxonomies, 'cpt_options' => array( - 'has_archive' => learndash_post_type_has_archive( 'sfwd-quiz' ), - 'hierarchical' => false, - 'supports' => array_merge( + 'has_archive' => learndash_post_type_has_archive( 'sfwd-quiz' ), + 'hierarchical' => false, + 'supports' => array_merge( array( 'title', 'editor', 'author', 'page-attributes' ), LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Quizzes_CPT', 'supports' ) ), - 'labels' => $quiz_labels, - 'capability_type' => 'course', - 'exclude_from_search' => ( LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Quizzes_CPT', 'include_in_search' ) !== 'yes' ) ? true : false, - 'capabilities' => $course_capabilities, - 'map_meta_cap' => true, - 'show_in_rest' => LearnDash_REST_API::enabled( 'sfwd-quiz' ) || LearnDash_REST_API::gutenberg_enabled( 'sfwd-quiz' ), + 'labels' => $quiz_labels, + 'capability_type' => 'course', + 'exclude_from_search' => ( LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Quizzes_CPT', 'include_in_search' ) !== 'yes' ) ? true : false, + 'capabilities' => $course_capabilities, + 'map_meta_cap' => true, + 'show_in_rest' => LearnDash_REST_API::enabled( 'sfwd-quiz' ) || LearnDash_REST_API::gutenberg_enabled( 'sfwd-quiz' ), + 'rest_controller_class' => API\Controllers\Quizzes::class, ), 'options_page_title' => sprintf( // translators: placeholder: Quiz. @@ -2283,16 +2423,17 @@ public function add_post_types() { 'template_redirect' => false, 'taxonomies' => $question_taxonomies, 'cpt_options' => array( - 'public' => false, - 'hierarchical' => false, - 'supports' => array( 'title', 'thumbnail', 'editor', 'author', 'revisions', 'page-attributes' ), - 'labels' => $question_labels, - 'capability_type' => 'course', - 'exclude_from_search' => true, - 'show_in_nav_menus' => false, - 'capabilities' => $course_capabilities, - 'map_meta_cap' => true, - 'show_in_rest' => true, + 'public' => false, + 'hierarchical' => false, + 'supports' => array( 'title', 'thumbnail', 'editor', 'author', 'revisions', 'page-attributes' ), + 'labels' => $question_labels, + 'capability_type' => 'course', + 'exclude_from_search' => true, + 'show_in_nav_menus' => false, + 'capabilities' => $course_capabilities, + 'map_meta_cap' => true, + 'show_in_rest' => LearnDash_REST_API::enabled( LDLMS_Post_Types::get_post_type_slug( LDLMS_Post_Types::QUESTION ) ) || LearnDash_REST_API::gutenberg_enabled( LDLMS_Post_Types::get_post_type_slug( LDLMS_Post_Types::QUESTION ) ), + 'rest_controller_class' => API\Controllers\Questions::class, ), 'options_page_title' => sprintf( // translators: placeholder: Question. @@ -2322,18 +2463,19 @@ public function add_post_types() { 'template_redirect' => true, 'taxonomies' => array(), 'cpt_options' => array( - 'public' => true, - 'hierarchical' => false, - 'has_archive' => false, - 'supports' => array( 'title', 'editor', 'custom-fields', 'thumbnail', 'revisions' ), - 'labels' => $exam_labels, - 'capability_type' => 'course', - 'exclude_from_search' => true, - 'show_in_nav_menus' => false, - 'capabilities' => $course_capabilities, - 'map_meta_cap' => true, - 'show_in_rest' => LearnDash_REST_API::enabled( $exam_post_type_slug ) || LearnDash_REST_API::gutenberg_enabled( $exam_post_type_slug ), - 'template' => array( + 'public' => true, + 'hierarchical' => false, + 'has_archive' => false, + 'supports' => array( 'title', 'editor', 'custom-fields', 'thumbnail', 'revisions' ), + 'labels' => $exam_labels, + 'capability_type' => 'course', + 'exclude_from_search' => true, + 'show_in_nav_menus' => false, + 'capabilities' => $course_capabilities, + 'map_meta_cap' => true, + 'show_in_rest' => LearnDash_REST_API::enabled( $exam_post_type_slug ) || LearnDash_REST_API::gutenberg_enabled( $exam_post_type_slug ), + 'rest_controller_class' => API\Controllers\Exams::class, + 'template' => array( array( 'learndash/ld-exam' ), ), ), @@ -2358,15 +2500,16 @@ public function add_post_types() { 'post_type' => $coupon_post_type_slug, 'template_redirect' => false, 'cpt_options' => array( - 'public' => false, - 'hierarchical' => false, - 'has_archive' => false, - 'supports' => array( 'title' ), - 'labels' => $coupon_labels, - 'exclude_from_search' => true, - 'show_in_nav_menus' => false, - 'capabilities' => learndash_get_admin_coupons_capabilities(), - 'show_in_rest' => false, + 'public' => false, + 'hierarchical' => false, + 'has_archive' => false, + 'supports' => array( 'title' ), + 'labels' => $coupon_labels, + 'exclude_from_search' => true, + 'show_in_nav_menus' => false, + 'capabilities' => learndash_get_admin_coupons_capabilities(), + 'show_in_rest' => false, + 'rest_controller_class' => API\Controllers\Coupons::class, ), 'options_page_title' => sprintf( // translators: placeholder: Coupon. @@ -2418,16 +2561,17 @@ public function add_post_types() { 'options_page_title' => esc_html__( 'LearnDash Certificates Options', 'learndash' ), 'default_options' => $cert_defaults, 'cpt_options' => array( - 'labels' => $certificates_labels, - 'exclude_from_search' => true, - 'has_archive' => false, - 'hierarchical' => false, - 'supports' => array( 'title', 'editor', 'thumbnail', 'author', 'revisions' ), - 'show_in_nav_menus' => false, - 'capability_type' => 'course', - 'capabilities' => $course_capabilities, - 'map_meta_cap' => true, - 'show_in_rest' => false, + 'labels' => $certificates_labels, + 'exclude_from_search' => true, + 'has_archive' => false, + 'hierarchical' => false, + 'supports' => array( 'title', 'editor', 'thumbnail', 'author', 'revisions' ), + 'show_in_nav_menus' => false, + 'capability_type' => 'course', + 'capabilities' => $course_capabilities, + 'map_meta_cap' => true, + 'show_in_rest' => false, + 'rest_controller_class' => API\Controllers\Certificates::class, ), ); @@ -2604,19 +2748,20 @@ public function add_post_types() { 'template_redirect' => true, 'taxonomies' => $group_taxonomies, 'cpt_options' => array( - 'supports' => array_merge( + 'supports' => array_merge( array( 'title', 'editor', 'author' ), LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Groups_CPT', 'supports' ) ), - 'has_archive' => learndash_post_type_has_archive( 'groups' ), - 'labels' => $group_labels, - 'capability_type' => 'groups', - 'hierarchical' => learndash_is_groups_hierarchical_enabled(), - 'public' => ( LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Groups_CPT', 'public' ) === 'yes' ) ? true : false, - 'exclude_from_search' => ( LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Groups_CPT', 'include_in_search' ) !== 'yes' ) ? true : false, - 'capabilities' => $group_capabilities, - 'map_meta_cap' => true, - 'show_in_rest' => LearnDash_REST_API::enabled( 'groups' ) || LearnDash_REST_API::gutenberg_enabled( 'groups' ), + 'has_archive' => learndash_post_type_has_archive( 'groups' ), + 'labels' => $group_labels, + 'capability_type' => 'group', + 'hierarchical' => learndash_is_groups_hierarchical_enabled(), + 'public' => ( LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Groups_CPT', 'public' ) === 'yes' ) ? true : false, + 'exclude_from_search' => ( LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Groups_CPT', 'include_in_search' ) !== 'yes' ) ? true : false, + 'capabilities' => $group_capabilities, + 'map_meta_cap' => true, + 'show_in_rest' => LearnDash_REST_API::enabled( 'groups' ) || LearnDash_REST_API::gutenberg_enabled( 'groups' ), + 'rest_controller_class' => API\Controllers\Groups::class, ), 'default_options' => array(), 'fields' => array(), @@ -2649,25 +2794,41 @@ public function add_post_types() { if ( learndash_is_admin_user() ) { $this->post_args['sfwd-transactions'] = array( - 'plugin_name' => esc_html__( 'Transactions', 'learndash' ), + 'plugin_name' => LearnDash_Custom_Label::get_label( 'orders' ), 'slug_name' => 'transactions', 'post_type' => 'sfwd-transactions', 'template_redirect' => false, - 'options_page_title' => esc_html__( 'LearnDash Transactions Options', 'learndash' ), + 'options_page_title' => sprintf( + // translators: placeholder: Orders custom label. + esc_html_x( 'LearnDash %s Settings', 'placeholder: Orders', 'learndash' ), + LearnDash_Custom_Label::get_label( 'orders' ) + ), 'cpt_options' => array( - 'supports' => array( 'title', 'custom-fields', 'page-attributes' ), - 'exclude_from_search' => true, - 'publicly_queryable' => false, - 'show_in_nav_menus' => false, - 'show_in_admin_bar' => false, - 'hierarchical' => true, + 'supports' => [ '' ], // Intentionally an empty string to prevent default post type supports from being used. + 'exclude_from_search' => true, + 'publicly_queryable' => false, + 'show_in_nav_menus' => false, + 'show_in_admin_bar' => false, + 'hierarchical' => true, + 'show_in_rest' => false, + 'rest_controller_class' => API\Controllers\Transactions::class, + 'map_meta_cap' => true, // Ensure all other capabilities are generated. + 'capabilities' => [ + 'create_posts' => 'do_not_allow', // Remove the "Add New" button from the admin bar. + ], ), 'fields' => array(), 'default_options' => array( null => array( 'type' => 'html', 'save' => false, - 'default' => esc_html__( 'Click the Export button below to export the transaction list.', 'learndash' ), + 'default' => sprintf( + // Translators: %s: order label. + esc_html__( 'Click the Export button below to export the %s list.', 'learndash' ), + esc_html( + learndash_get_custom_label_lower( 'order' ) + ) + ), ), ), ); @@ -2762,12 +2923,14 @@ public static function get_course_info( $user_id, $atts = array() ) { // Quizzes. 'quiz_num' => false, + 'quiz_paged' => 1, 'quiz_filter_quiz' => null, 'quiz_filter_course' => null, 'quiz_filter_lesson' => null, 'quiz_filter_topic' => null, 'quiz_orderby' => 'taken', 'quiz_order' => 'DESC', + 'quiz_offset' => 0, ) ); @@ -2780,6 +2943,15 @@ public static function get_course_info( $user_id, $atts = array() ) { $atts['type'] = array_map( 'trim', $atts['type'] ); } + // Protect group ID. + if ( + ! learndash_shortcode_can_current_user_access_post( + Cast::to_int( $atts['group_id'] ) + ) + ) { + return ''; + } + if ( ! empty( $atts['group_id'] ) ) { $atts['course_ids'] = learndash_group_enrolled_courses( $atts['group_id'] ); $atts['quiz_ids'] = learndash_get_group_course_quiz_ids( $atts['group_id'] ); @@ -3111,7 +3283,7 @@ public static function get_course_info( $user_id, $atts = array() ) { $quiz_key = $quiz_attempt['time'] . '-' . $quiz_attempt['quiz']; } elseif ( 'title' == $atts['quiz_orderby'] ) { $quiz_key = $post_idx . '-' . $quiz_attempt['time']; - } elseif ( 'ID' == $atts['quiz_orderby'] ) { + } elseif ( 'id' === strtolower( $atts['quiz_orderby'] ) ) { $quiz_key = str_pad( (string) $quiz_attempt['quiz'], 10, '0', STR_PAD_LEFT ) . '-' . $quiz_attempt['time']; } elseif ( 'date' == $atts['quiz_orderby'] ) { // Quiz Post date. $quiz_post = get_post( $quiz_attempt['quiz'] ); @@ -3138,7 +3310,7 @@ public static function get_course_info( $user_id, $atts = array() ) { $quizzes = $quizzes_tmp; - if ( 'DESC' == $atts['quiz_order'] ) { + if ( 'desc' === strtolower( $atts['quiz_order'] ) ) { krsort( $quizzes ); } else { ksort( $quizzes ); @@ -3157,13 +3329,19 @@ public static function get_course_info( $user_id, $atts = array() ) { /** * Filters paged query argument for quiz info. * + * @since 2.5.4 + * * @param int $paged Number of Pages. + * + * @return int */ - $quizzes_pager['paged'] = apply_filters( 'learndash_quiz_info_paged', 1 ); + $quizzes_pager['paged'] = apply_filters( 'learndash_quiz_info_paged', $atts['quiz_paged'] ); $quizzes_pager['total_items'] = count( $quizzes ); $quizzes_pager['total_pages'] = ceil( count( $quizzes ) / $quizzes_per_page ); - $quizzes = array_slice( $quizzes, ( $quizzes_pager['paged'] * $quizzes_per_page ) - $quizzes_per_page, $quizzes_per_page, false ); + $quizzes_pager['offset'] = $atts['quiz_offset']; + + $quizzes = array_slice( $quizzes, ( ( $quizzes_pager['paged'] - 1 ) * $quizzes_per_page ) + $quizzes_pager['offset'], $quizzes_per_page, false ); } } } @@ -3455,8 +3633,12 @@ public static function course_progress_data( $course_id = null ) { 'total' => '', ); - $course_completed_meta = get_user_meta( $user_id, 'course_completed_' . $course->ID, true ); - ( empty( $course_completed_meta ) ) ? $course_completed_date = '' : $course_completed_date = date_i18n( 'F j, Y H:i:s', $course_completed_meta ); + $course_completed_meta = Cast::to_int( + get_user_meta( $user_id, 'course_completed_' . $course->ID, true ) + ); + $course_completed_date = ! empty( $course_completed_meta ) + ? learndash_adjust_date_time_display( $course_completed_meta, 'F j, Y H:i:s' ) + : ''; $row = array( 'user_id' => $user_id, @@ -3836,7 +4018,7 @@ public function quiz_export_init() { 'rank' => $v['rank'], 'score' => $v['score'], 'total' => $v['question_show_count'], - 'date' => date_i18n( DATE_RSS, $v['time'] ), + 'date' => learndash_adjust_date_time_display( Cast::to_int( $v['time'] ), DATE_RSS ), ); } } else { @@ -4841,18 +5023,16 @@ public static function get_template( $name, $args, $echo = false, $return_file_p $template_filename .= '.php'; } - /** - * Filters template file name. - * - * @since 3.0.0 - * - * @param string $template_filename Template file name. - * @param string $name Template name. - * @param array|null $args Template data. - * @param bool|null $echo Whether to echo the template output or not. - * @param bool $return_file_path Whether to return file or path or not. - */ - $template_filename = apply_filters( 'learndash_template_filename', $template_filename, $name, $args, $echo, $return_file_path ); + /** This filter is documented in src/Core/Template/Template.php */ + $template_filename = apply_filters( + 'learndash_template_filename', + $template_filename, + $name, + $args, + $echo, + $return_file_path, + null + ); if ( empty( $template_filename ) ) { return; @@ -5264,10 +5444,6 @@ public function hub_after_upgrade_admin_notice() { return; } - if ( ! learndash_is_learndash_hub_active() ) { - return; - } - ?>

@@ -5299,10 +5475,9 @@ public function hub_after_upgrade_admin_notice() { * @return void */ public function add_telemetry_modal( WP_Screen $current_screen ): void { - if ( - ( - ! empty( $current_screen->post_type ) - && in_array( $current_screen->post_type, learndash_get_post_types(), true ) + $should_show = ( + ! empty( $current_screen->post_type ) + && in_array( $current_screen->post_type, learndash_get_post_types(), true ) ) || ( ! empty( $current_screen->parent_file ) @@ -5314,37 +5489,50 @@ public function add_telemetry_modal( WP_Screen $current_screen ): void { && false !== strpos( sanitize_text_field( wp_unslash( $_GET['page'] ) ), 'learndash' ) && $_GET['page'] !== 'learndash-setup-wizard' && $_GET['page'] !== 'learndash-design-wizard' - ) - ) { - add_filter( - 'stellarwp/telemetry/learndash/optin_args', // cspell:disable-line. - function( $args ) { - $args['plugin_logo'] = LEARNDASH_LMS_PLUGIN_URL . 'assets/images/logo_black.svg'; - $args['plugin_logo_width'] = 205; - $args['plugin_logo_height'] = 33; - $args['plugin_logo_alt'] = 'LearnDash Logo'; - - $args['heading'] = esc_html__( 'We hope you love LearnDash.', 'learndash' ); - - $args['intro'] = sprintf( - // translators: placeholder: username. - esc_html__( - 'Hi, %1$s! This is an invitation to help us improve LearnDash products by sharing product usage data with StellarWP. LearnDash is part of the StellarWP family of brands. If you opt-in we\'ll share some helpful WordPress and StellarWP product info with you from time to time. And if you skip this, that\'s okay! Our products will continue to work.', - 'learndash' - ), - $args['user_name'] - ); - - $args['permissions_url'] = 'https://www.learndash.com/telemetry-tracking/'; - $args['tos_url'] = 'https://www.learndash.com/terms-and-conditions/'; - - return $args; - } ); - // cspell:disable-next-line. - do_action( 'stellarwp/telemetry/learndash/optin' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound,WordPress.NamingConventions.ValidHookName.UseUnderscores + /** + * Whether to show the telemetry modal. + * + * @since 4.25.3 + * + * @param bool $should_show Whether to show the telemetry modal. + * @param WP_Screen $current_screen Current screen. + * + * @return bool Whether to show the telemetry modal. + */ + if ( ! apply_filters( 'learndash_show_telemetry_modal', $should_show, $current_screen ) ) { + return; } + + add_filter( + 'stellarwp/telemetry/learndash/optin_args', // cspell:disable-line. + function ( $args ) { + $args['plugin_logo'] = LEARNDASH_LMS_PLUGIN_URL . 'assets/images/logo_black.svg'; + $args['plugin_logo_width'] = 205; + $args['plugin_logo_height'] = 33; + $args['plugin_logo_alt'] = 'LearnDash Logo'; + + $args['heading'] = esc_html__( 'We hope you love LearnDash.', 'learndash' ); + + $args['intro'] = sprintf( + // translators: placeholder: username. + esc_html__( + 'Hi, %1$s! This is an invitation to help us improve LearnDash products by sharing product usage data with StellarWP. LearnDash is part of the StellarWP family of brands. If you opt-in we\'ll share some helpful WordPress and StellarWP product info with you from time to time. And if you skip this, that\'s okay! Our products will continue to work.', + 'learndash' + ), + $args['user_name'] + ); + + $args['permissions_url'] = 'https://www.learndash.com/telemetry-tracking/'; + $args['tos_url'] = 'https://www.learndash.com/terms-and-conditions/'; + + return $args; + } + ); + + // cspell:disable-next-line. + do_action( 'stellarwp/telemetry/learndash/optin' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound,WordPress.NamingConventions.ValidHookName.UseUnderscores } } } diff --git a/web/app/plugins/sfwd-lms/includes/class-ld-setup-wizard.php b/web/app/plugins/sfwd-lms/includes/class-ld-setup-wizard.php index eca8cd6da..9c167f8d2 100644 --- a/web/app/plugins/sfwd-lms/includes/class-ld-setup-wizard.php +++ b/web/app/plugins/sfwd-lms/includes/class-ld-setup-wizard.php @@ -2,10 +2,15 @@ /** * LearnDash class for displaying the setup wizard. * - * @package LearnDash - * @since 4.0.0 + * @package LearnDash + * @since 4.0.0 */ +use LearnDash\Core\Modules\Payments\Gateways\Stripe\Connection_Handler; +use LearnDash\Core\Modules\Payments\Gateways\Paypal\Payment_Gateway as Paypal_Payment_Gateway; +use LearnDash\Core\Utilities\Cast; +use LearnDash\Core\Utilities\Location; + if ( ! defined( 'ABSPATH' ) ) { exit; } @@ -27,7 +32,6 @@ class LearnDash_Setup_Wizard { const DATA_KEY = 'learndash_setup_wizard'; const CERTIFICATE_BUILDER_SLUG = 'learndash-certificate-builder/learndash-certificate-builder.php'; - const COURSE_GRID_SLUG = 'learndash-course-grid/learndash_course_grid.php'; const WOOCOMMERCE_SLUG = 'woocommerce/woocommerce.php'; const LEARNDASH_WOOCOMMERCE_SLUG = 'learndash-woocommerce/learndash_woocommerce.php'; @@ -39,6 +43,15 @@ class LearnDash_Setup_Wizard { const ADMIN_REDIRECT_PAGE = 'admin.php?page=learndash-setup'; const FINAL_ADMIN_REDIRECT_PAGE = 'admin.php?page=learndash-setup'; + /** + * The option key for the StellarSites integration. + * + * @since 4.21.5 + * + * @var string + */ + private const LEARNDASH_SETUP_WIZARD_STELLARSITES = 'learndash_setup_wizard_stellarsites_triggered'; + /** * The single instance of the class. */ @@ -56,21 +69,92 @@ public function __construct() { add_action( 'wp_ajax_learndash_setup_wizard_save_data', array( $this, 'save_data' ) ); add_action( 'wp_ajax_learndash_finalize', array( $this, 'finalize_setup' ) ); add_action( 'admin_post_stripe_connect_wizard_process', array( $this, 'enable_stripe_connect_and_redirect' ) ); + add_action( 'current_screen', [ $this, 'redirect_after_stellar_sites_plugin_activation' ] ); + } + + /** + * Check if this is a LearnDash submenu item click and handle wizard redirect if StellarSites MU plugin is active. + * + * @since 4.21.5 + * + * @return void + */ + public function redirect_after_stellar_sites_plugin_activation( WP_Screen $screen ): void { + if ( ! Location::is_learndash_admin_page() ) { + return; + } + + // Check if the StellarSites MU plugin is active. + if ( ! class_exists( '\StellarWP\StellarSites\Plugin' ) ) { + return; + } + + // Check if the wizard has already been triggered. + $wizard_triggered = get_option( self::LEARNDASH_SETUP_WIZARD_STELLARSITES, false ); + + if ( $wizard_triggered ) { + return; + } + + // Get wizard status. + $wizard_status = get_option( self::STATUS_KEY ); + + // Only redirect if the wizard hasn't been completed or dismissed. + if ( + $wizard_status !== self::STATUS_COMPLETED + && $wizard_status !== self::STATUS_CLOSED + ) { + // Mark the wizard as triggered to prevent future redirects. + update_option( self::LEARNDASH_SETUP_WIZARD_STELLARSITES, true ); + + // Redirect to wizard. + learndash_safe_redirect( admin_url( 'admin.php?page=' . self::HANDLE ) ); + } } /** - * Enable stripe connect and then redirect to the wizard again. + * Retrieves the wizard status. + * + * @since 4.21.5 + * + * @return string The value of the wizard status from the options. */ - public function enable_stripe_connect_and_redirect() { - // enable stripe connect. + public static function get_status(): string { + /** + * Filters the status of the setup wizard. + * + * @since 4.21.5 + * + * @param string $status The value of the wizard status from the options. + */ + return apply_filters( + 'learndash_setup_wizard_status', + Cast::to_string( + get_option( self::STATUS_KEY ) + ) + ); + } + + /** + * Enables the Stripe connect and then redirect to the wizard again. + * + * @since 4.0.0 + * + * @return void + */ + public function enable_stripe_connect_and_redirect(): void { + // Enable stripe connect. if ( LearnDash_Settings_Section_Stripe_Connect::is_stripe_connected() ) { LearnDash_Settings_Section::set_section_setting( 'LearnDash_Settings_Section_Stripe_Connect', 'enabled', 'yes' ); } - // force update wizard data. + // Force update wizard data. $this->update_data( 'charge', 'yes' ); $this->update_data( 'charge_method', 'stripe' ); + // Create a transient to flag that we need to create webhooks. + set_transient( 'learndash_stripe_connect_create_webhooks', true, HOUR_IN_SECONDS ); + learndash_safe_redirect( admin_url( 'admin.php?page=' . self::HANDLE ) ); } @@ -181,17 +265,16 @@ public function finalize_setup() { $this->create_profile_page(); break; case 'process_course_listing': - // download and setup course grid, create course listing page. + // Import demo course. + // phpcs:ignore Generic.CodeAnalysis.EmptyStatement -- TODO: Remove this comment later. + if ( 'yes' === $data['course_demo'] ) { + Learndash_Admin_Import_Export::import_demo_content(); + } + + // Create course listing page. if ( 'multiple' === $data['courses_amount'] ) { $this->create_courses_listing_page(); } - // install course grid plugin. - if ( 'true' === $data['course_grid'] ) { - $ret = $this->maybe_install_a_plugin( self::COURSE_GRID_SLUG ); - if ( true === $ret ) { - activate_plugin( self::COURSE_GRID_SLUG ); - } - } break; case 'process_certificate_builder': // install certificate builder plugin. @@ -460,29 +543,9 @@ public function verify_license() { update_option( self::LICENSE_KEY, $license_key ); update_option( self::LICENSE_EMAIL_KEY, $email ); - $license_status = false; - if ( learndash_is_learndash_hub_active() ) { - $license_status = learndash_validate_hub_license( $email, $license_key ); - } else { - $updater_sfwd_lms = learndash_get_updater_instance( true ); - if ( ( $updater_sfwd_lms ) && ( is_a( $updater_sfwd_lms, 'nss_plugin_updater_sfwd_lms' ) ) ) { - /** - * Remove the time to check timestamp. Within the getRemote_license() method - * is calls time_to_recheck_license() which uses this option to determine if - * the license needs to be checked again. - */ - delete_option( 'nss_plugin_check_sfwd_lms' ); - $license_status = $updater_sfwd_lms->getRemote_license(); - } - - // The return from getRemote_license() is literally "1" (string) for valid. Anything else is invalid. - if ( '1' !== $license_status ) { - wp_send_json_error(); - } + // Licensing validation. - // license is valid. - $license_status = true; - } + $license_status = learndash_validate_hub_license( $email, $license_key, true ); if ( ! $license_status ) { wp_send_json_error(); @@ -551,7 +614,7 @@ private function get_scenes(): array { 'next' => isset( $keys[ $pos + 1 ] ) ? $keys[ $pos + 1 ] : '', 'prev' => isset( $keys[ $pos - 1 ] ) ? $keys[ $pos - 1 ] : '', ); - $pos++; + ++$pos; } return $scenes; @@ -578,7 +641,12 @@ public function enqueue_scripts() { constant( 'SCRIPT_DEBUG' ) === true ? time() : LEARNDASH_VERSION, true ); - $data = get_option( self::DATA_KEY ); + + $data = get_option( self::DATA_KEY ); + if ( ! is_array( $data ) ) { + $data = []; + } + $currency_code = learndash_get_currency_code(); $currency_country = LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Section_Payments_Defaults', 'country' ) ?? ''; @@ -586,6 +654,10 @@ public function enqueue_scripts() { $scenes = $this->get_scenes(); $current_scene = isset( $data['scene'] ) && isset( $scenes[ $data['scene'] ] ) ? $data['scene'] : array_keys( $scenes )[0]; + // Define if we need to create webhooks. + $stripe_create_webhooks = get_transient( 'learndash_stripe_connect_create_webhooks' ); + delete_transient( 'learndash_stripe_connect_create_webhooks' ); + wp_localize_script( self::HANDLE, 'ldSetupWizard', @@ -603,13 +675,24 @@ public function enqueue_scripts() { 'stripe_connect' => LearnDash_Settings_Section_Stripe_Connect::generate_connect_url( admin_url( 'admin-post.php?action=stripe_connect_wizard_process' ) ), 'iso_4217' => 'https://en.wikipedia.org/wiki/ISO_4217#Active_codes', 'no_step_url' => $this->get_completed_redirect_url(), + 'paypal_connect' => esc_url_raw( + add_query_arg( + [ + 'page' => 'learndash_lms_payments', + 'section-payment' => 'settings_paypal_checkout', + 'setup-wizard' => '1', + ], + admin_url( 'admin.php' ) + ) + ), ), 'nonces' => array( - 'verify' => wp_create_nonce( 'ld_setup_wizard_verify_license' ), - 'save' => wp_create_nonce( 'ld_setup_wizard_save_data' ), - 'finalize' => wp_create_nonce( 'ld_setup_wizard_finalize' ), + 'verify' => wp_create_nonce( 'ld_setup_wizard_verify_license' ), + 'save' => wp_create_nonce( 'ld_setup_wizard_save_data' ), + 'finalize' => wp_create_nonce( 'ld_setup_wizard_finalize' ), + 'stripe_ajax_post_connect' => wp_create_nonce( Connection_Handler::$ajax_action_post_connect ), ), - 'data' => array( + 'data' => [ 'scenes' => $scenes, 'scene' => $current_scene, 'email' => $data['email'] ?? get_option( self::LICENSE_EMAIL_KEY, '' ), @@ -617,6 +700,7 @@ public function enqueue_scripts() { 'use_registered_email' => $data['use_registered_email'] ?? 'yes', 'notification_email' => $data['notification_email'] ?? '', 'license_validated' => $data['license_validated'] ?? 'no', + 'course_demo' => $data['course_demo'] ?? 'no', 'courses_amount' => $data['courses_amount'] ?? 'single', 'course_type' => $data['course_type'] ?? array(), 'group_access' => $data['group_access'] ?? 'no', @@ -628,10 +712,11 @@ public function enqueue_scripts() { 'currency_select2_default' => ! empty( $currency_country ) ? ucwords( mb_strtolower( $currency_country ) ) . ' (' . learndash_get_currency_symbol( $currency_code ) . ') ' : '', 'stripe_connected' => LearnDash_Settings_Section_Stripe_Connect::is_stripe_connected(), 'stripe_webhook_notice' => wp_kses_post( LearnDash_Settings_Section_Stripe_Connect::get_stripe_webhook_notice() ), - ), + 'stripe_create_webhooks' => $stripe_create_webhooks ? 'yes' : 'no', + 'paypal_connected' => Paypal_Payment_Gateway::account_is_connected(), + ], 'plugins' => array( 'certificate_builder' => is_plugin_active( self::CERTIFICATE_BUILDER_SLUG ), - 'course_grid' => is_plugin_active( self::COURSE_GRID_SLUG ), 'woocommerce' => is_plugin_active( self::WOOCOMMERCE_SLUG ), ), 'currency_codes' => array( @@ -667,6 +752,16 @@ public function register_menu() { // Hide the admin menu item, the page stays available. remove_menu_page( self::HANDLE ); + + if ( + isset( $_GET['page'] ) + && self::HANDLE === sanitize_text_field( wp_unslash( $_GET['page'] ) ) + ) { + // remove_menu_page() call affects the global title and makes it null in the end, + // which causes a deprecation error in WP core cause it requires it to be a string. + global $title; + $title = ''; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- It's intentional. + } } /** @@ -677,15 +772,26 @@ public function register_menu() { protected function should_display(): bool { $should_display = false; - $wizard_status = get_option( self::STATUS_KEY ); + $wizard_status = self::get_status(); // The wizard is in progress, but closed by an accident or something like that. if ( self::STATUS_ONGOING === $wizard_status ) { $should_display = true; } + // No license key/email. + if ( + empty( get_option( self::LICENSE_KEY ) ) + || empty( get_option( self::LICENSE_EMAIL_KEY ) ) + ) { + $should_display = true; + } + + // Add StellarSites MU plugin integration check. if ( - empty( get_option( self::LICENSE_KEY ) ) || - empty( get_option( self::LICENSE_EMAIL_KEY ) ) + class_exists( '\StellarWP\StellarSites\Plugin' ) + && ! get_option( self::LEARNDASH_SETUP_WIZARD_STELLARSITES, false ) + && $wizard_status !== self::STATUS_COMPLETED + && $wizard_status !== self::STATUS_CLOSED ) { $should_display = true; } diff --git a/web/app/plugins/sfwd-lms/includes/class-ld-translations.php b/web/app/plugins/sfwd-lms/includes/class-ld-translations.php index 64bdb3dab..108dda947 100644 --- a/web/app/plugins/sfwd-lms/includes/class-ld-translations.php +++ b/web/app/plugins/sfwd-lms/includes/class-ld-translations.php @@ -15,7 +15,6 @@ * Class for LearnDash Translations. */ class LearnDash_Translations { - /** * Project slug for this instance. * @@ -83,7 +82,10 @@ public function __construct( $project_slug = '' ) { * @param string $project_language_dir Project Language Directory. */ public static function register_translation_slug( $project_slug = '', $project_language_dir = '' ) { - if ( ( ! empty( $project_slug ) ) && ( ! isset( self::$project_slugs[ $project_slug ] ) ) ) { + if ( + ! empty( $project_slug ) + && ! isset( self::$project_slugs[ $project_slug ] ) + ) { self::$project_slugs[ $project_slug ] = trailingslashit( $project_language_dir ); } } @@ -106,8 +108,10 @@ public static function get_last_update() { * @return string directory path. */ public static function get_language_directory( $project_slug = '', $relative_to_home = true ) { - if ( ( ! empty( $project_slug ) ) && ( isset( self::$project_slugs [ $project_slug ] ) ) ) { - + if ( + ! empty( $project_slug ) + && isset( self::$project_slugs [ $project_slug ] ) + ) { if ( true !== $relative_to_home ) { return trailingslashit( self::$project_slugs[ $project_slug ] ); } else { @@ -128,7 +132,10 @@ public static function get_language_directory( $project_slug = '', $relative_to_ public static function is_language_directory_writable( $project_slug = '' ) { if ( ! empty( $project_slug ) ) { $translations_dir = self::get_language_directory( $project_slug, false ); - if ( ( ! empty( $translations_dir ) ) && ( is_writable( $translations_dir ) ) ) { + if ( + ! empty( $translations_dir ) + && is_writable( $translations_dir ) + ) { return true; } } @@ -216,14 +223,18 @@ public static function get_action_url( $action = '', $project = '', $locale = '' public static function install_translation( $project = '', $locale = '' ) { $reply_data = array(); - if ( ( ! empty( $project ) ) && ( ! empty( $locale ) ) ) { - + if ( + ! empty( $project ) + && ! empty( $locale ) + ) { if ( self::is_language_directory_writable( $project ) ) { $translation_set = self::project_get_available_translations( $project, $locale ); - if ( ( isset( $translation_set['links'] ) ) && ( ! empty( $translation_set['links'] ) ) ) { + if ( + isset( $translation_set['links'] ) + && ! empty( $translation_set['links'] ) + ) { foreach ( $translation_set['links'] as $link_key => $link_url ) { - /** * Filters translation URL arguments. * @@ -237,7 +248,10 @@ public static function install_translation( $project = '', $locale = '' ) { } $response = wp_remote_get( $link_url, $url_args ); - if ( ( is_array( $response ) ) && ( wp_remote_retrieve_response_code( $response ) == '200' ) ) { + if ( + is_array( $response ) + && wp_remote_retrieve_response_code( $response ) == '200' + ) { $response_body = wp_remote_retrieve_body( $response ); if ( ! empty( $response_body ) ) { $fp = fopen( $dest_filename, 'w+' ); //phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen @@ -300,7 +314,10 @@ public static function download_pot_file( $project_slug = '' ) { public static function download_po_file( $project_slug = '', $locale_slug = '' ) { $reply_data = array(); - if ( ( ! empty( $project_slug ) ) && ( ! empty( $locale_slug ) ) ) { + if ( + ! empty( $project_slug ) + && ! empty( $locale_slug ) + ) { $installed_translations = self::get_installed_translations( $project_slug ); if ( isset( $installed_translations[ $locale_slug ] ) ) { $installed_set = $installed_translations[ $locale_slug ]; @@ -333,14 +350,18 @@ public static function download_po_file( $project_slug = '', $locale_slug = '' ) public static function update_translation( $project = '', $locale = '' ) { $reply_data = array(); - if ( ( ! empty( $project ) ) && ( ! empty( $locale ) ) ) { - + if ( + ! empty( $project ) + && ! empty( $locale ) + ) { if ( self::is_language_directory_writable( $project ) ) { $translation_set = self::project_get_available_translations( $project, $locale ); - if ( ( isset( $translation_set['links'] ) ) && ( ! empty( $translation_set['links'] ) ) ) { + if ( + isset( $translation_set['links'] ) + && ! empty( $translation_set['links'] ) + ) { foreach ( $translation_set['links'] as $link_key => $link_url ) { - /** This filter is documented in includes/class-ld-translations.php */ $url_args = apply_filters( 'learndash_translations_url_args', array( 'timeout' => LEARNDASH_HTTP_REMOTE_GET_TIMEOUT ) ); @@ -350,7 +371,10 @@ public static function update_translation( $project = '', $locale = '' ) { } $response = wp_remote_get( $link_url, $url_args ); - if ( ( is_array( $response ) ) && ( wp_remote_retrieve_response_code( $response ) == '200' ) ) { + if ( + is_array( $response ) + && wp_remote_retrieve_response_code( $response ) == '200' + ) { $response_body = wp_remote_retrieve_body( $response ); if ( ! empty( $response_body ) ) { $fp = fopen( $dest_filename, 'w+' ); //phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen @@ -384,12 +408,17 @@ public static function update_translation( $project = '', $locale = '' ) { public static function remove_translation( $project = '', $locale = '' ) { $reply_data = array(); - if ( ( ! empty( $project ) ) && ( ! empty( $locale ) ) ) { - + if ( + ! empty( $project ) + && ! empty( $locale ) + ) { if ( self::is_language_directory_writable( $project ) ) { $translation_set = self::project_get_available_translations( $project, $locale ); - if ( ( isset( $translation_set['links'] ) ) && ( ! empty( $translation_set['links'] ) ) ) { + if ( + isset( $translation_set['links'] ) + && ! empty( $translation_set['links'] ) + ) { foreach ( $translation_set['links'] as $link_key => $link_url ) { /** This filter is documented in includes/class-ld-translations.php */ $url_args = apply_filters( 'learndash_translations_url_args', array() ); @@ -406,6 +435,25 @@ public static function remove_translation( $project = '', $locale = '' ) { ) . '

'; } } + } else { + // Fallback for locally installed translations without remote data. + $languages_dir = self::get_language_directory( $project, false ); + + foreach ( array( 'mo', 'po' ) as $ext ) { + $dest_filename = $languages_dir . $project . '-' . $locale . '.' . $ext; + if ( file_exists( $dest_filename ) ) { + unlink( $dest_filename ); + $reply_data['status'] = true; + } + } + + if ( ! empty( $reply_data['status'] ) ) { + $reply_data['message'] = '

' . sprintf( + // translators: placeholders: Language code. + esc_html_x( 'Translation removed: %s', 'placeholder: Language code', 'learndash' ), + $locale + ) . '

'; + } } } } @@ -433,7 +481,10 @@ public function show_meta_box() { ?>
available_translations ) ) || ( ! empty( $this->installed_translations ) ) ) { + if ( + ! empty( $this->available_translations ) + || ! empty( $this->installed_translations ) + ) { $this->show_installed_translations(); $this->show_available_translations(); } else { @@ -458,16 +509,25 @@ public static function get_available_translations( $project = '', $force = false $ld_translations = get_option( self::$options_key, null ); if ( ! isset( $ld_translations['last_check'] ) ) { $ld_translations['last_check'] = time() - ( LEARNDASH_TRANSLATIONS_URL_CACHE + 1 ); - } elseif ( ( isset( $_GET['action'] ) ) && ( 'refresh' === $_GET['action'] ) ) { - if ( ( isset( $_GET['ld-translation-nonce'] ) ) && ( ! empty( $_GET['ld-translation-nonce'] ) ) && ( wp_verify_nonce( $_GET['ld-translation-nonce'], 'ld-translation-refresh' ) ) ) { + } elseif ( + isset( $_GET['action'] ) + && 'refresh' === $_GET['action'] + ) { + if ( + isset( $_GET['ld-translation-nonce'] ) + && ! empty( $_GET['ld-translation-nonce'] ) + && wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['ld-translation-nonce'] ) ), 'ld-translation-refresh' ) + ) { $ld_translations['last_check'] = time() - ( LEARNDASH_TRANSLATIONS_URL_CACHE + 1 ); } } $time_diff = abs( time() - intval( $ld_translations['last_check'] ) ); - if ( ( true === $force ) || ( $time_diff > LEARNDASH_TRANSLATIONS_URL_CACHE ) ) { - + if ( + true === $force + || $time_diff > LEARNDASH_TRANSLATIONS_URL_CACHE + ) { $project_slugs = implode( ',', array_keys( self::$project_slugs ) ); $url = add_query_arg( @@ -483,7 +543,10 @@ public static function get_available_translations( $project = '', $force = false $url_args = apply_filters( 'learndash_translations_url_args', $url_args ); $response = wp_remote_get( $url, $url_args ); - if ( ( is_array( $response ) ) && ( wp_remote_retrieve_response_code( $response ) == '200' ) ) { + if ( + is_array( $response ) + && wp_remote_retrieve_response_code( $response ) == '200' + ) { $response_body = wp_remote_retrieve_body( $response ); if ( ! empty( $response_body ) ) { @@ -499,7 +562,10 @@ public static function get_available_translations( $project = '', $force = false } if ( ! empty( $project ) ) { - if ( ( isset( $ld_translations['translation_sets'][ $project ] ) ) && ( ! empty( $ld_translations['translation_sets'][ $project ] ) ) ) { + if ( + isset( $ld_translations['translation_sets'][ $project ] ) + && ! empty( $ld_translations['translation_sets'][ $project ] ) + ) { return $ld_translations['translation_sets'][ $project ]; } } @@ -510,7 +576,6 @@ public static function get_available_translations( $project = '', $force = false * Show installed translations */ public function show_installed_translations() { - $pot_file = self::get_language_directory( $this->project_slug, false ) . '' . $this->project_slug . '.pot'; if ( file_exists( $pot_file ) ) { ?> @@ -535,26 +600,38 @@ public function show_installed_translations() { available_translations ) ) && ( ! empty( $this->available_translations ) ) && ( is_array( $this->installed_translations ) ) && ( ! empty( $this->installed_translations ) ) ) { - foreach ( $this->available_translations as $idx => $translation_set ) { - $translation_locale = $translation_set['wp_locale']; - if ( isset( $this->installed_translations[ $translation_locale ] ) ) { - $installed_set = $this->installed_translations[ $translation_locale ]; - $this->show_installed_translation_row( $translation_locale, $translation_set, $installed_set ); - } - } - - foreach ( $this->installed_translations as $installed_locale => $installed_set ) { - $install_matched = false; + if ( + is_array( $this->installed_translations ) + && ! empty( $this->installed_translations ) + ) { + if ( + is_array( $this->available_translations ) + && ! empty( $this->available_translations ) + ) { foreach ( $this->available_translations as $idx => $translation_set ) { $translation_locale = $translation_set['wp_locale']; - if ( $translation_locale == $installed_locale ) { - $install_matched = true; - break; + if ( isset( $this->installed_translations[ $translation_locale ] ) ) { + $installed_set = $this->installed_translations[ $translation_locale ]; + $this->show_installed_translation_row( $translation_locale, $translation_set, $installed_set ); } } - if ( ! $install_matched ) { + foreach ( $this->installed_translations as $installed_locale => $installed_set ) { + $install_matched = false; + foreach ( $this->available_translations as $idx => $translation_set ) { + $translation_locale = $translation_set['wp_locale']; + if ( $translation_locale == $installed_locale ) { + $install_matched = true; + break; + } + } + + if ( ! $install_matched ) { + $this->show_installed_translation_row( $installed_locale, null, $installed_set ); + } + } + } else { + foreach ( $this->installed_translations as $installed_locale => $installed_set ) { $this->show_installed_translation_row( $installed_locale, null, $installed_set ); } } @@ -570,7 +647,7 @@ public function show_installed_translations() {

' . esc_attr( '' ) . esc_attr( self::get_language_directory( $this->project_slug, true ) ) . '' @@ -648,17 +725,28 @@ public function show_available_translations() { } // Taken from options-general.php. - if ( ! is_multisite() && defined( 'WPLANG' ) && '' !== WPLANG && 'en_US' !== WPLANG && ! in_array( WPLANG, $wp_languages, true ) ) { + if ( + ! is_multisite() + && defined( 'WPLANG' ) + && '' !== WPLANG + && 'en_US' !== WPLANG + && ! in_array( WPLANG, $wp_languages, true ) + ) { $wp_languages[] = WPLANG; } $wp_locale = get_locale(); - if ( ( ! empty( $wp_locale ) ) && ( ! in_array( $wp_locale, $wp_languages, true ) ) ) { + if ( + ! empty( $wp_locale ) + && ! in_array( $wp_locale, $wp_languages, true ) + ) { $wp_languages[] = $wp_locale; } - if ( ( is_array( $this->available_translations ) ) && ( ! empty( $this->available_translations ) ) ) { - + if ( + is_array( $this->available_translations ) + && ! empty( $this->available_translations ) + ) { $available_translations = array(); $available_translations['recommended'] = array(); $available_translations['available'] = array(); @@ -674,7 +762,10 @@ public function show_available_translations() { } } - if ( ( ! empty( $available_translations['recommended'] ) ) || ( ! empty( $available_translations['available'] ) ) ) { + if ( + ! empty( $available_translations['recommended'] ) + || ! empty( $available_translations['available'] ) + ) { ?>

@@ -682,7 +773,10 @@ public function show_available_translations() { 'sfwd-courses', - self::LESSON => 'sfwd-lessons', - self::TOPIC => 'sfwd-topic', - self::QUIZ => 'sfwd-quiz', - self::QUESTION => 'sfwd-question', - self::TRANSACTION => 'sfwd-transactions', - self::GROUP => 'groups', - self::ASSIGNMENT => 'sfwd-assignment', - self::ESSAY => 'sfwd-essays', - self::CERTIFICATE => 'sfwd-certificates', - self::EXAM => 'ld-exam', - self::COUPON => 'ld-coupon', + self::COURSE => 'sfwd-courses', + self::LESSON => 'sfwd-lessons', + self::TOPIC => 'sfwd-topic', + self::QUIZ => 'sfwd-quiz', + self::QUESTION => 'sfwd-question', + self::TRANSACTION => 'sfwd-transactions', + self::GROUP => 'groups', + self::ASSIGNMENT => 'sfwd-assignment', + self::ESSAY => 'sfwd-essays', + self::CERTIFICATE => 'sfwd-certificates', + self::EXAM => 'ld-exam', + self::COUPON => 'ld-coupon', + self::VIRTUAL_INSTRUCTOR => 'ld-virt-instructor', ); /** @@ -67,6 +73,7 @@ class LDLMS_Post_Types { self::CERTIFICATE, self::EXAM, self::COUPON, + self::VIRTUAL_INSTRUCTOR, ), self::COURSE => array( self::COURSE, @@ -122,6 +129,46 @@ public static function init() { } } + /** + * Get available statuses for a specific post type. + * + * Note: + * Some of these come from the global variables $learndash_course_statuses, $learndash_exam_challenge_statuses. + * We want to move away from globals and have a single source of truth for statuses. + * + * @since 5.0.0 + * + * @param string $post_type The post type to get statuses for. + * + * @return array|null Array of statuses with keys and labels. Null if no statuses are found. + */ + public static function get_post_type_statuses( string $post_type ): ?array { + global $learndash_course_statuses, $learndash_exam_challenge_statuses; + + switch ( $post_type ) { + case self::get_post_type_slug( self::COURSE ): + return $learndash_course_statuses; + case self::get_post_type_slug( self::TOPIC ): + case self::get_post_type_slug( self::LESSON ): + return [ + 'not-started' => esc_html__( 'Not Started', 'learndash' ), + 'in-progress' => esc_html__( 'In Progress', 'learndash' ), + 'completed' => esc_html__( 'Completed', 'learndash' ), + ]; + case self::get_post_type_slug( self::QUIZ ): + return [ + 'not-started' => esc_html__( 'Not Started', 'learndash' ), + 'in-progress' => esc_html__( 'In Progress', 'learndash' ), + 'passed' => esc_html__( 'Passed', 'learndash' ), + 'failed' => esc_html__( 'Failed', 'learndash' ), + ]; + case self::get_post_type_slug( self::EXAM ): + return $learndash_exam_challenge_statuses; + default: + return null; + } + } + /** * Get an array of all custom tables. * @@ -132,7 +179,7 @@ public static function init() { * @param string $return_type Used to designate the returned value. String or array. * @param string $quote_char Wrap the return values in quote character. Only for return_type 'string'. * - * @return array|string Post type slugs array or string. See `$return_type` parameter. + * @return ($return_type is "string" ? string : array) Post type slugs array or string. See `$return_type` parameter. */ public static function get_post_types( $post_type_section = 'all', $return_type = 'array', $quote_char = '' ) { $post_types_return = array(); diff --git a/web/app/plugins/sfwd-lms/includes/classes/class-ldlms-factory-post.php b/web/app/plugins/sfwd-lms/includes/classes/class-ldlms-factory-post.php index 419dd9b07..b83610a90 100644 --- a/web/app/plugins/sfwd-lms/includes/classes/class-ldlms-factory-post.php +++ b/web/app/plugins/sfwd-lms/includes/classes/class-ldlms-factory-post.php @@ -148,20 +148,21 @@ public static function quiz_questions( $quiz = null, $reload = false ) { } /** - * Get a Course Steps. + * Returns course steps. * - * @param int|object $course Either course_id integer or WP_Post instance. - * @param bool $reload To force reload of instance. + * @param int|WP_Post $course Course post ID or WP_Post instance. + * @param bool $reload To force reloading of instance. * - * @return object|null Instance of `LDLMS_Course_Steps` or null + * @return LDLMS_Course_Steps|null */ public static function course_steps( $course = null, $reload = false ) { if ( ! empty( $course ) ) { $model = 'LDLMS_Course_Steps'; - $course_id = 0; - - if ( ( is_a( $course, 'WP_Post' ) ) && ( learndash_get_post_type_slug( 'course' ) === $course->post_type ) ) { + if ( + $course instanceof WP_Post + && learndash_get_post_type_slug( 'course' ) === $course->post_type + ) { $course_id = absint( $course->ID ); } else { $course_id = absint( $course ); diff --git a/web/app/plugins/sfwd-lms/includes/classes/class-ldlms-model-course-steps.php b/web/app/plugins/sfwd-lms/includes/classes/class-ldlms-model-course-steps.php index 899ee4ed7..4a0efd632 100644 --- a/web/app/plugins/sfwd-lms/includes/classes/class-ldlms-model-course-steps.php +++ b/web/app/plugins/sfwd-lms/includes/classes/class-ldlms-model-course-steps.php @@ -119,6 +119,14 @@ public function load_steps() { if ( true === $this->meta['empty'] ) { // Note here since we are loading the steps via legacy methods we don't need to validate. $this->steps['h'] = $this->load_steps_legacy(); + + // I don't want to affect the default flow, so this is a safe way to do this step after it was imported only. + if ( get_post_meta( $this->course_id, 'course_steps_update_after_import_is_needed', true ) ) { + // This is necessary to rebuild the steps after the import. + $steps_h = $this->steps['h']; + + delete_post_meta( $this->course_id, 'course_steps_update_after_import_is_needed' ); + } } $this->build_steps(); @@ -257,7 +265,6 @@ protected function save_steps_meta() { $this->set_steps_count_meta(); } - /** * Sets the Course steps dirty flag and will force the steps to be * reloaded from queries. @@ -1001,20 +1008,38 @@ private function flatten_item_parent_steps( $steps = array() ) { * This is generally called when editing the course and the course steps has been changed. * * @since 2.5.0 + * @since 4.10.0 Add $keep_sections parameter to keep sections when updating steps. + * + * @param array $course_steps Array of Course steps. + * @param bool $keep_sections Whether to keep the existing sections when setting steps or not. Default false. * - * @param array $course_steps Array of Course steps. + * @return void */ - public function set_steps( $course_steps = array() ) { + public function set_steps( $course_steps = array(), bool $keep_sections = false ): void { if ( ! empty( $this->course_id ) ) { $this->saving_steps = true; $this->load_steps_meta(); - if ( isset( $course_steps['section-heading'] ) ) { - $this->set_section_headings( $course_steps['section-heading'] ); - unset( $course_steps['section-heading'] ); + if ( $keep_sections ) { + // Get the value directly from meta data to keep the structure of the sections unchanged to maintain its function in the course builder. + + $course_sections = get_post_meta( $this->course_id, 'course_sections', true ); + + if ( is_string( $course_sections ) ) { + $course_sections = json_decode( $course_sections, true ); + } + + $course_sections = is_array( $course_sections ) ? $course_sections : []; + + $this->set_section_headings( $course_sections ); } else { - $this->set_section_headings( array() ); + if ( isset( $course_steps['section-heading'] ) ) { + $this->set_section_headings( $course_steps['section-heading'] ); + unset( $course_steps['section-heading'] ); + } else { + $this->set_section_headings( array() ); + } } $this->steps['h'] = $course_steps; @@ -1040,6 +1065,19 @@ public function set_steps( $course_steps = array() ) { } } + /** + * Set course steps while keeping the sections. + * + * @since 4.10.0 + * + * @param array> $course_steps Course steps. + * + * @return void + */ + public function set_steps_keeping_sections( array $course_steps = [] ): void { + $this->set_steps( $course_steps, true ); + } + /** * Set Course Section Headings. * @@ -1589,11 +1627,11 @@ private function load_steps_legacy() { } /** - * Get Course Step parents. + * Returns the parent steps for a given step. Empty array if no parent steps. * * @since 2.5.0 * - * @param int $post_id Current step post ID. + * @param int $post_id Current step post ID. * @param string $post_type Parent step post_type to. */ public function get_item_parent_steps( $post_id = 0, $post_type = '' ) { @@ -1617,7 +1655,7 @@ public function get_item_parent_steps( $post_id = 0, $post_type = '' ) { } /** - * Get Single Course Step parent. + * Returns the parent step ID for a given step. 0 if no parent step. * * @since 2.5.0 * diff --git a/web/app/plugins/sfwd-lms/includes/classes/class-ldlms-model-exam.php b/web/app/plugins/sfwd-lms/includes/classes/class-ldlms-model-exam.php index a33610a17..c0c11add0 100644 --- a/web/app/plugins/sfwd-lms/includes/classes/class-ldlms-model-exam.php +++ b/web/app/plugins/sfwd-lms/includes/classes/class-ldlms-model-exam.php @@ -18,7 +18,6 @@ * @uses LDLMS_Model */ class LDLMS_Model_Exam extends LDLMS_Model_Post { - /** * User ID. * @@ -242,10 +241,13 @@ public function get_grade() { * @return int Returns the count of valid questions. */ public function get_questions_count() { + $this->load_question_models_from_post_content(); + $questions_total = 0; + foreach ( $this->question_models as $question_model ) { if ( true === $question_model->is_valid ) { - $questions_total++; + ++$questions_total; } } @@ -296,7 +298,6 @@ public function process_exam_submit() { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized if ( ( isset( $_POST['exam-nonce'] ) ) && ( ! empty( $_POST['exam-nonce'] ) ) && ( wp_verify_nonce( $_POST['exam-nonce'], $this->get_nonce_key() ) ) ) { - $this->student_submit_data = array(); if ( ! isset( $_POST['exam_id'] ) ) { @@ -361,7 +362,6 @@ protected function exam_questions_grading() { $question_model->question_grade( $this->student_submit_data ); } } - } /** @@ -383,10 +383,10 @@ public function exam_grading_from_questions() { continue; } - $questions_total++; + ++$questions_total; if ( ( true === $question_model->is_graded ) && ( true === $question_model->get_grade ) ) { - $questions_correct++; + ++$questions_correct; } } @@ -470,7 +470,6 @@ public function get_result_button_params() { $this->post->ID, $exam_status_slug ); - } else { // If the exam is not graded then there are not values to set here. $exam_result_button['button_label'] = ''; @@ -577,7 +576,7 @@ public function load_question_models_from_post_content() { $this->question_models[ $question_block_idx ] = $ld_exam_question_object; } - $question_block_idx++; + ++$question_block_idx; } } } @@ -649,7 +648,7 @@ protected function prepare_exam_activity_meta() { continue; } - $exam_meta['questions_count']++; + ++$exam_meta['questions_count']; $question_block_meta = array( 'question_type' => $question_model->question_type, @@ -660,7 +659,7 @@ protected function prepare_exam_activity_meta() { ); if ( true === $question_block_meta['question_grade'] ) { - $exam_meta['questions_correct']++; + ++$exam_meta['questions_correct']; } $question_block = $question_model->get_block; @@ -683,7 +682,6 @@ protected function prepare_exam_activity_meta() { } $exam_meta['questions'] = $exam_questions_meta; - } return $exam_meta; diff --git a/web/app/plugins/sfwd-lms/includes/classes/class-ldlms-model-user-course-progress.php b/web/app/plugins/sfwd-lms/includes/classes/class-ldlms-model-user-course-progress.php index 7415767ca..63042ae58 100644 --- a/web/app/plugins/sfwd-lms/includes/classes/class-ldlms-model-user-course-progress.php +++ b/web/app/plugins/sfwd-lms/includes/classes/class-ldlms-model-user-course-progress.php @@ -10,8 +10,12 @@ exit; } -if ( ( ! class_exists( 'LDLMS_Model_User_Course_Progress' ) ) && ( class_exists( 'LDLMS_Model_User' ) ) ) { +use LearnDash\Core\Utilities\Cast; +if ( + ! class_exists( 'LDLMS_Model_User_Course_Progress' ) + && class_exists( 'LDLMS_Model_User' ) +) { /** * Class for LearnDash LearnDash User Progress Course Class. * @@ -19,7 +23,6 @@ * @uses LDLMS_Model_User */ class LDLMS_Model_User_Course_Progress extends LDLMS_Model_User { - /** * User Progress Loaded flag. * @@ -106,7 +109,11 @@ private function initialize( $user_id = 0 ) { } $user = get_user_by( 'ID', $user_id ); - if ( ( $user ) && ( is_a( $user, 'WP_User' ) ) && ( $user->ID === $user_id ) ) { + if ( + $user + && is_a( $user, 'WP_User' ) + && $user->ID === $user_id + ) { $this->user_id = $user_id; $this->user = $user; $return = true; @@ -131,7 +138,10 @@ private function initialize( $user_id = 0 ) { * @param mixed $_meta_value Meta value. */ public function changed_user_meta_progress_legacy( $meta_id, $object_id, $meta_key, $_meta_value ) { - if ( ( $object_id === $this->user_id ) && ( $meta_key === $this->progress_meta_key ) ) { + if ( + $object_id === $this->user_id + && $meta_key === $this->progress_meta_key + ) { if ( ! $this->user_meta_updating ) { $this->set_progress_unloaded(); } @@ -146,7 +156,10 @@ public function changed_user_meta_progress_legacy( $meta_id, $object_id, $meta_k * @param bool $force_reload True to force reload of usermeta item. */ public function load_user_meta_progress_legacy( $force_reload = false ) { - if ( ( ! $this->progress_legacy_loaded ) || ( true === $force_reload ) ) { + if ( + ! $this->progress_legacy_loaded + || true === $force_reload + ) { $this->progress_legacy_loaded = true; $this->progress_legacy = get_user_meta( $this->user_id, $this->progress_meta_key, true ); @@ -192,7 +205,6 @@ protected function load_course_progress( $course_id = 0 ) { // Update the legacy data structure as other processes will reference it. $this->progress_legacy[ $course_id ] = $this->progress[ $course_id ]['legacy']; - } if ( ! isset( $this->progress[ $course_id ]['co'] ) ) { @@ -239,11 +251,17 @@ public function get_course_progress_legacy( $course_id = 0 ) { $progress_legacy = array(); } - if ( ( ! isset( $progress_legacy['lessons'] ) ) || ( ! is_array( $progress_legacy['lessons'] ) ) ) { + if ( + ! isset( $progress_legacy['lessons'] ) + || ! is_array( $progress_legacy['lessons'] ) + ) { $progress_legacy['lessons'] = array(); } - if ( ( ! isset( $progress_legacy['topics'] ) ) || ( ! is_array( $progress_legacy['topics'] ) ) ) { + if ( + ! isset( $progress_legacy['topics'] ) + || ! is_array( $progress_legacy['topics'] ) + ) { $progress_legacy['topics'] = array(); } @@ -283,7 +301,6 @@ protected function build_course_progress_legacy( $course_id = 0 ) { $course_id = absint( $course_id ); if ( ! empty( $course_id ) ) { - $steps_legacy = learndash_course_get_steps_by_type( $course_id, 'legacy' ); $progress_legacy = $this->get_course_progress_legacy( $course_id ); @@ -291,21 +308,35 @@ protected function build_course_progress_legacy( $course_id = 0 ) { * Merge the Lesson and Topic steps from the known steps_legacy array into * the current progress_legacy array. */ - if ( ( isset( $steps_legacy['lessons'] ) ) && ( ! empty( $steps_legacy['lessons'] ) ) ) { - + if ( + isset( $steps_legacy['lessons'] ) + && ! empty( $steps_legacy['lessons'] ) + ) { foreach ( $steps_legacy['lessons'] as $lesson_id => $lesson_id_status ) { - if ( ( isset( $progress_legacy['lessons'][ $lesson_id ] ) ) && ( $progress_legacy['lessons'][ $lesson_id ] ) ) { + if ( + isset( $progress_legacy['lessons'][ $lesson_id ] ) + && $progress_legacy['lessons'][ $lesson_id ] + ) { $steps_legacy['lessons'][ $lesson_id ] = $progress_legacy['lessons'][ $lesson_id ]; } } $progress_legacy['lessons'] = $steps_legacy['lessons']; } - if ( ( isset( $steps_legacy['topics'] ) ) && ( ! empty( $steps_legacy['topics'] ) ) ) { + if ( + isset( $steps_legacy['topics'] ) + && ! empty( $steps_legacy['topics'] ) + ) { foreach ( $steps_legacy['topics'] as $lesson_id => $lesson_set ) { - if ( ( is_array( $lesson_set ) ) && ( ! empty( $lesson_set ) ) ) { + if ( + is_array( $lesson_set ) + && ! empty( $lesson_set ) + ) { foreach ( $lesson_set as $topic_id => $topic_id_status ) { - if ( ( isset( $progress_legacy['topics'][ $lesson_id ][ $topic_id ] ) ) && ( $progress_legacy['topics'][ $lesson_id ][ $topic_id ] ) ) { + if ( + isset( $progress_legacy['topics'][ $lesson_id ][ $topic_id ] ) + && $progress_legacy['topics'][ $lesson_id ][ $topic_id ] + ) { $steps_legacy['topics'][ $lesson_id ][ $topic_id ] = $progress_legacy['topics'][ $lesson_id ][ $topic_id ]; } } @@ -352,7 +383,10 @@ protected function build_course_progress_completion_order( $course_id = 0 ) { } } - if ( ( isset( $progress_legacy['lessons'] ) ) && ( ! empty( $progress_legacy['lessons'] ) ) ) { + if ( + isset( $progress_legacy['lessons'] ) + && ! empty( $progress_legacy['lessons'] ) + ) { foreach ( $progress_legacy['lessons'] as $lesson_id => $status ) { if ( isset( $progress_co[ $lesson_slug . ':' . $lesson_id ] ) ) { $progress_co[ $lesson_slug . ':' . $lesson_id ] = $status; @@ -360,9 +394,15 @@ protected function build_course_progress_completion_order( $course_id = 0 ) { } } - if ( ( isset( $progress_legacy['topics'] ) ) && ( ! empty( $progress_legacy['topics'] ) ) ) { + if ( + isset( $progress_legacy['topics'] ) + && ! empty( $progress_legacy['topics'] ) + ) { foreach ( $progress_legacy['topics'] as $lesson_id => $topics ) { - if ( ( is_array( $topics ) ) && ( ! empty( $topics ) ) ) { + if ( + is_array( $topics ) + && ! empty( $topics ) + ) { foreach ( $topics as $topic_id => $status ) { if ( isset( $progress_co[ $topic_slug . ':' . $topic_id ] ) ) { $progress_co[ $topic_slug . ':' . $topic_id ] = $status; @@ -410,7 +450,10 @@ protected function build_course_progress_linear_order( $course_id = 0 ) { } } - if ( ( isset( $progress_legacy['lessons'] ) ) && ( ! empty( $progress_legacy['lessons'] ) ) ) { + if ( + isset( $progress_legacy['lessons'] ) + && ! empty( $progress_legacy['lessons'] ) + ) { foreach ( $progress_legacy['lessons'] as $lesson_id => $status ) { if ( isset( $progress_co[ $lesson_slug . ':' . $lesson_id ] ) ) { $progress_co[ $lesson_slug . ':' . $lesson_id ] = $status; @@ -418,9 +461,15 @@ protected function build_course_progress_linear_order( $course_id = 0 ) { } } - if ( ( isset( $progress_legacy['topics'] ) ) && ( ! empty( $progress_legacy['topics'] ) ) ) { + if ( + isset( $progress_legacy['topics'] ) + && ! empty( $progress_legacy['topics'] ) + ) { foreach ( $progress_legacy['topics'] as $lesson_id => $topics ) { - if ( ( is_array( $topics ) ) && ( ! empty( $topics ) ) ) { + if ( + is_array( $topics ) + && ! empty( $topics ) + ) { foreach ( $topics as $topic_id => $status ) { if ( isset( $progress_co[ $topic_slug . ':' . $topic_id ] ) ) { $progress_co[ $topic_slug . ':' . $topic_id ] = $status; @@ -449,7 +498,10 @@ protected function build_course_progress_completed_count( $course_id = 0 ) { $course_id = absint( $course_id ); if ( ! empty( $course_id ) ) { - if ( ( isset( $this->progress[ $course_id ]['co'] ) ) && ( ! empty( $this->progress[ $course_id ]['co'] ) ) ) { + if ( + isset( $this->progress[ $course_id ]['co'] ) + && ! empty( $this->progress[ $course_id ]['co'] ) + ) { foreach ( $this->progress[ $course_id ]['co'] as $progress_step_key => $status ) { list( $progress_step_post_type, $progress_step_post_id ) = explode( ':', $progress_step_key ); if ( in_array( $progress_step_post_type, learndash_get_post_type_slug( array( 'lesson', 'topic' ) ), true ) ) { @@ -458,7 +510,10 @@ protected function build_course_progress_completed_count( $course_id = 0 ) { } } - if ( ( learndash_has_global_quizzes( $course_id ) ) && ( learndash_is_all_global_quizzes_complete( $this->user_id, $course_id ) ) ) { + if ( + learndash_has_global_quizzes( $course_id ) + && learndash_is_all_global_quizzes_complete( $this->user_id, $course_id ) + ) { ++$course_completed_count; } } @@ -523,7 +578,6 @@ protected function build_course_progress_by_activity( $course_id = 0 ) { $progress_activity = array(); if ( ! empty( $course_id ) ) { - $course_steps_co = learndash_course_get_steps_by_type( $course_id, 'co' ); $course_activity_remove_items = array(); @@ -546,10 +600,16 @@ protected function build_course_progress_by_activity( $course_id = 0 ) { $activity_item['activity_completed'] = ( isset( $activity_item['activity_completed'] ) ) ? absint( $activity_item['activity_completed'] ) : 0; $activity_item['activity_updated'] = ( isset( $activity_item['activity_updated'] ) ) ? absint( $activity_item['activity_updated'] ) : 0; - if ( ( ! empty( $activity_item['post_id'] ) ) && ( ! empty( $activity_item['activity_type'] ) ) ) { + if ( + ! empty( $activity_item['post_id'] ) + && ! empty( $activity_item['activity_type'] ) + ) { $activity_item_post_type = learndash_get_post_type_slug( $activity_item['activity_type'] ); if ( in_array( $activity_item_post_type, learndash_get_post_types( 'course' ), true ) ) { - if ( ( 'course' === $activity_item['activity_type'] ) || ( in_array( $activity_item_post_type . ':' . $activity_item['post_id'], $course_steps_co, true ) ) ) { + if ( + 'course' === $activity_item['activity_type'] + || in_array( $activity_item_post_type . ':' . $activity_item['post_id'], $course_steps_co, true ) + ) { $progress_activity[ $activity_item_post_type . ':' . $activity_item['post_id'] ] = $activity_item; } } @@ -596,12 +656,13 @@ public function get_progress( $course_id = 0, $progress_type = 'legacy' ) { if ( isset( $this->progress[ $course_id ] ) ) { if ( 'activity' === $progress_type ) { return $this->build_course_progress_by_activity( $course_id ); - } else { - if ( ( ! empty( $progress_type ) ) && ( isset( $this->progress[ $course_id ][ $progress_type ] ) ) ) { + } elseif ( + ! empty( $progress_type ) + && isset( $this->progress[ $course_id ][ $progress_type ] ) + ) { return $this->progress[ $course_id ][ $progress_type ]; - } else { - return $this->progress[ $course_id ]; - } + } else { + return $this->progress[ $course_id ]; } } } @@ -619,7 +680,10 @@ public function get_progress( $course_id = 0, $progress_type = 'legacy' ) { */ public function set_progress( $course_id = 0, $progress = array() ) { $course_id = absint( $course_id ); - if ( ( ! empty( $this->user_id ) ) && ( ! empty( $course_id ) ) ) { + if ( + ! empty( $this->user_id ) + && ! empty( $course_id ) + ) { // For reload of the user meta in case there were other changes outside of our processes. $this->load_user_meta_progress_legacy( true ); @@ -744,7 +808,10 @@ function learndash_user_progress_get_previous_incomplete_step( $user_id = 0, $co */ $parent_steps = learndash_course_get_all_parent_step_ids( $course_id, $progress_step_post_id ); $parent_steps = array_map( 'absint', $parent_steps ); - if ( ( empty( $parent_steps ) ) || ( ! in_array( $step_id, $parent_steps, true ) ) ) { + if ( + empty( $parent_steps ) + || ! in_array( $step_id, $parent_steps, true ) + ) { return absint( $progress_step_post_id ); } } elseif ( ! empty( $progress_step_post_id ) ) { @@ -856,6 +923,7 @@ function learndash_user_progress_get_all_incomplete_steps( $user_id = 0, $course * Utility function to get first incomplete course step for user. * * @since 3.4.0 + * @since 5.0.3 First incomplete step now respects the logic of `learndash_course_get_step_completion_data` to determine the correct next step. * * @param int $user_id User ID. * @param int $course_id Course ID. @@ -863,24 +931,58 @@ function learndash_user_progress_get_all_incomplete_steps( $user_id = 0, $course * @return int Incomplete course step ID. */ function learndash_user_progress_get_first_incomplete_step( $user_id = 0, $course_id = 0 ) { - $step_id = 0; + $user_id = Cast::to_int( $user_id ); + $course_id = Cast::to_int( $course_id ); + $course_progress_object = LDLMS_Factory_User::course_progress( $user_id ); - $user_id = absint( $user_id ); - if ( empty( $user_id ) ) { - return $step_id; + if ( + empty( $user_id ) + || empty( $course_id ) + || ! $course_progress_object instanceof LDLMS_Model_User_Course_Progress + ) { + return 0; // Invalid user or course. } - $course_id = absint( $course_id ); - if ( empty( $course_id ) ) { - return $step_id; + // Grab all the steps in linear order from the course progress object. + $course_progress_steps = $course_progress_object->get_progress( $course_id, 'l' ); + + if ( empty( $course_progress_steps ) ) { + return 0; // No steps found. } - $incomplete_steps = learndash_user_progress_get_all_incomplete_steps( $user_id, $course_id ); - if ( ! empty( $incomplete_steps ) ) { - $step_id = absint( $incomplete_steps[0] ); + // Get the last completed step key. + $last_completed_step_key = Cast::to_string( + array_key_last( + array_filter( + $course_progress_steps, + fn( $progress_status ) => (bool) $progress_status + ) + ) + ); + + // Get the first step key. + + $first_step_key = Cast::to_string( array_key_first( $course_progress_steps ) ); + $first_step_id = Cast::to_int( explode( ':', $first_step_key )[1] ); + + if ( empty( $last_completed_step_key ) ) { + // If no last completed step key, return the first step ID. + return $first_step_id; } - return $step_id; + // Extract the step ID from the step key. + $last_completed_step_id = Cast::to_int( explode( ':', $last_completed_step_key )[1] ); + + // Use learndash_course_get_step_completion_data to determine the correct next step, + // accounting for video, assignment, timer, and external requirements on parent steps. + + $step_completion_data = learndash_course_get_step_completion_data( $last_completed_step_id, $course_id, $user_id, true ); + + if ( ! empty( $step_completion_data['next_step_id'] ) ) { + return Cast::to_int( $step_completion_data['next_step_id'] ); + } + + return $first_step_id; } /** @@ -895,7 +997,6 @@ function learndash_user_progress_get_first_incomplete_step( $user_id = 0, $cours * @return array Array of incomplete step IDs. */ function learndash_user_progression_get_incomplete_child_steps( $user_id = 0, $course_id = 0, $step_id = 0 ) { - $incomplete_child_steps = array(); $user_id = absint( $user_id ); @@ -912,7 +1013,6 @@ function learndash_user_progression_get_incomplete_child_steps( $user_id = 0, $c } return $incomplete_child_steps; - } /** @@ -927,7 +1027,6 @@ function learndash_user_progression_get_incomplete_child_steps( $user_id = 0, $c * @return array Array of completed step IDs. */ function learndash_user_progression_get_complete_child_steps( $user_id = 0, $course_id = 0, $step_id = 0 ) { - $complete_child_steps = array(); $user_id = absint( $user_id ); @@ -980,14 +1079,20 @@ function learndash_user_progress_is_step_complete( $user_id = 0, $course_id = 0, // If the course is 'completed' for the user. Then ALL steps are completed. $course_progress_summary = $course_progress_object->get_progress( $course_id, 'summary' ); - if ( ( isset( $course_progress_summary['status'] ) ) && ( 'completed' === $course_progress_summary['status'] ) ) { + if ( + isset( $course_progress_summary['status'] ) + && 'completed' === $course_progress_summary['status'] + ) { return true; } $course_progress_steps = $course_progress_object->get_progress( $course_id, 'co' ); if ( ! empty( $course_progress_steps ) ) { $step_key = get_post_type( $step_id ) . ':' . $step_id; - if ( ( isset( $course_progress_steps[ $step_key ] ) ) && ( $course_progress_steps[ $step_key ] ) ) { + if ( + isset( $course_progress_steps[ $step_key ] ) + && $course_progress_steps[ $step_key ] + ) { return true; } } @@ -1032,7 +1137,10 @@ function learndash_user_progress_get_parent_incomplete_step( $user_id = 0, $cour * Returns an array of parent steps in top-down order: Lesson, Topic, etc. */ $step_parent_ids = learndash_course_get_all_parent_step_ids( $course_id, $step_id ); - if ( ( is_array( $step_parent_ids ) ) && ( ! empty( $step_parent_ids ) ) ) { + if ( + is_array( $step_parent_ids ) + && ! empty( $step_parent_ids ) + ) { foreach ( $step_parent_ids as $step_parent_id ) { if ( in_array( get_post_type( $step_parent_id ), learndash_get_post_type_slug( array( 'lesson', 'topic' ) ), true ) ) { if ( ! learndash_user_progress_is_step_complete( $user_id, $course_id, $step_parent_id ) ) { diff --git a/web/app/plugins/sfwd-lms/includes/classes/class-ldlms-model-user-quiz-resume.php b/web/app/plugins/sfwd-lms/includes/classes/class-ldlms-model-user-quiz-resume.php index b4128e3fd..fcc0d743f 100644 --- a/web/app/plugins/sfwd-lms/includes/classes/class-ldlms-model-user-quiz-resume.php +++ b/web/app/plugins/sfwd-lms/includes/classes/class-ldlms-model-user-quiz-resume.php @@ -15,7 +15,6 @@ * Class to create the instance. */ class LDLMS_User_Quiz_Resume { - /** * Activity meta key. * @@ -60,12 +59,24 @@ public static function get_user_quiz_resume_activity( $user_id = 0, $quiz_id = 0 if ( ( is_object( $activity ) ) && ( property_exists( $activity, 'activity_id' ) ) && ( ! empty( $activity->activity_id ) ) ) { $activity = new LDLMS_Model_Activity( $activity ); - // If we have an existing activity record we include the meta. - $activity->activity_meta = (array) learndash_get_user_activity_meta( $activity->activity_id, self::$meta_key, true, true ); + // If we have an existing activity record and it's valid, we include the meta. + + $activity_meta_raw = (array) learndash_get_user_activity_meta( $activity->activity_id, self::$meta_key, true, true ); + + // Validate the activity meta before using it. + + if ( self::validate_quiz_resume_data( $activity_meta_raw ) ) { + $activity->activity_meta = $activity_meta_raw; + } else { + // Delete the activity meta record if it's invalid. + learndash_delete_user_activity_meta( $activity->activity_id, self::$meta_key ); + + $activity->activity_meta = []; + } } elseif ( true === $create ) { $activity = learndash_activity_start_quiz( $user_id, $course_id, $quiz_id, $quiz_started ); if ( ! is_null( $activity ) ) { - $activity->activity_meta = array(); + $activity->activity_meta = []; } } } @@ -103,15 +114,43 @@ public static function update_user_quiz_resume_metadata( $user_id = 0, $quiz_id property_exists( $activity, 'activity_id' ) && ! empty( $activity->activity_id ) ) { - $changes_made = true; - foreach ( $results as $result_key => $result_data ) { $activity->activity_meta[ $result_key ] = $result_data; } + // If the meta data is invalid, skip the update. It prevents malformed data from being saved. + if ( ! self::validate_quiz_resume_data( $activity->activity_meta ) ) { + return false; + } + + $changes_made = true; + learndash_update_user_activity_meta( $activity->activity_id, self::$meta_key, $activity->activity_meta ); } + /** + * Fires when the quiz resume metadata is updated. + * + * @since 4.7.0.1 + * + * @param bool $changes_made A flag indicating if changes were made. + * @param array{ quiz_started: int, results: mixed[] } $activity_data Activity data, including quiz started timestamp and results. + * @param int $quiz_id Quiz ID. + * @param int $course_id Course ID. + * @param int $user_id User ID. + */ + do_action( + 'learndash_quiz_resume_metadata_updated', + $changes_made, + [ + 'quiz_started' => $quiz_started, + 'results' => $results, + ], + $quiz_id, + $course_id, + $user_id + ); + return $changes_made; } @@ -141,5 +180,75 @@ public static function delete_user_quiz_resume_metadata( $user_id = 0, $quiz_id } } + /** + * Validates the quiz resume data meta to ensure integrity. + * + * Checks if reviewBox entries marked as solved have corresponding question data. + * + * @since 4.25.8 + * + * @param array $activity_meta The quiz resume activity meta data array to validate. + * + * @return bool True if data is valid, false otherwise. + */ + private static function validate_quiz_resume_data( array $activity_meta ): bool { + // If empty, it's considered valid (fresh start). + if ( empty( $activity_meta ) ) { + return true; + } + + // If reviewBox doesn't exist, it's valid (no action taken yet). + if ( + ! isset( $activity_meta['reviewBox'] ) + || ! is_array( $activity_meta['reviewBox'] ) + ) { + return true; + } + + // Validate each reviewBox entry that has a "solved" key. + + $review_box = $activity_meta['reviewBox']; + + foreach ( $review_box as $review_index => $review_data ) { + // Invalid reviewBox entry. + if ( ! is_array( $review_data ) ) { + return false; + } + + // Skip not solved entries. + if ( ! isset( $review_data['solved'] ) ) { + continue; + } + + $question_id_found = false; + + // Find the numeric key that has an index matching this reviewBox position. + foreach ( $activity_meta as $key => $value ) { + // Skip non-numeric keys as they are not relevant to this validation. + if ( ! is_numeric( $key ) ) { + continue; + } + + // Check if this question has the matching index. + + if ( + isset( $value['index'] ) + && absint( $value['index'] ) === absint( $review_index ) + ) { + $question_id_found = true; + + break; + } + } + + // If no question ID was found for this solved review, data is invalid. + + if ( ! $question_id_found ) { + return false; + } + } + + return true; + } } } diff --git a/web/app/plugins/sfwd-lms/includes/coupon/ld-coupon-functions.php b/web/app/plugins/sfwd-lms/includes/coupon/ld-coupon-functions.php index 76f487bf9..460da6d3e 100644 --- a/web/app/plugins/sfwd-lms/includes/coupon/ld-coupon-functions.php +++ b/web/app/plugins/sfwd-lms/includes/coupon/ld-coupon-functions.php @@ -49,6 +49,21 @@ function learndash_check_coupon_is_valid( string $coupon_code, int $post_id ): a $course_post_type = LDLMS_Post_Types::get_post_type_slug( LDLMS_Post_Types::COURSE ); $group_post_type = LDLMS_Post_Types::get_post_type_slug( LDLMS_Post_Types::GROUP ); + /** + * Override the coupon check and return with the expected response array. + * + * @since 4.20.2 + * + * @return null|array{ + * is_valid: bool, + * error: string + * } + */ + $response = apply_filters( 'learndash_coupon_check_is_valid', null, $coupon_code, $post_id, $errors ); + if ( $response !== null ) { + return $response; + } + // Check if params are empty. if ( empty( $coupon_code ) || empty( $post_id ) ) { @@ -155,6 +170,22 @@ function learndash_check_coupon_is_valid( string $coupon_code, int $post_id ): a function learndash_calculate_coupon_discounted_price( int $coupon_id, float $price ): float { $coupon = get_post( $coupon_id ); + /** + * Filters the calculated price for when a coupon would be applied. + * + * @since 4.20.2 + * + * @param null|float $new_price The new price if we are overriding. + * @param null|WP_Post $coupon The coupon WP_Post object if one is found. + * @param float $price The price to be discounted by the coupon. + * + * @return float|null + */ + $new_price = apply_filters( 'learndash_coupon_discounted_price', null, $coupon, $price ); + if ( $new_price !== null ) { + return $new_price; + } + if ( is_null( $coupon ) ) { return $price; } @@ -215,7 +246,19 @@ function learndash_get_coupon_by_code( string $coupon_code ): ?WP_Post { $query = new WP_Query( $query_args ); - return empty( $query->posts ) ? null : $query->posts[0]; + $post = empty( $query->posts ) ? null : $query->posts[0]; + + /** + * Filter or override a WP_Post for a particular coupon code. + * + * @since 4.20.2 + * + * @param null|WP_Post $post The parameter to override the coupon fetching by coupon code. + * @param string $coupon_code The coupon string. + * + * @return WP_Post|null + */ + return apply_filters( 'learndash_coupon_get_by_code', $post, $coupon_code ); // @phpstan-ignore-line } /** @@ -226,6 +269,18 @@ function learndash_get_coupon_by_code( string $coupon_code ): ?WP_Post { * @return bool */ function learndash_active_coupons_exist(): bool { + /** + * Override whether there is a valid coupon that exists. + * + * @since 4.20.2 + * + * @param null|bool $coupons_exist Flag whether a valid coupon exists. + */ + $coupons_exist = apply_filters( 'learndash_coupon_exists_and_is_active', null ); + if ( $coupons_exist !== null ) { + return $coupons_exist; + } + $coupon_post_type = LDLMS_Post_Types::get_post_type_slug( LDLMS_Post_Types::COUPON ); if ( 0 === wp_count_posts( strval( $coupon_post_type ) )->publish ) { @@ -309,11 +364,33 @@ function learndash_increment_coupon_redemptions( int $coupon_id, int $post_id, i LEARNDASH_COUPON_META_KEY_REDEMPTIONS ); + /** + * Fires before coupon redemptions are incremented. + * + * @since 4.20.2 + * + * @param int $coupon_id The coupon post ID. + * @param int $post_id The course post ID. + * @param int $user_id The user ID. + */ + do_action( 'learndash_coupon_before_redemption', $coupon_id, $post_id, $user_id ); + learndash_update_setting( $coupon_id, LEARNDASH_COUPON_META_KEY_REDEMPTIONS, $redemptions + 1 ); + + /** + * Fires after coupon redemptions are incremented. + * + * @since 4.20.2 + * + * @param int $coupon_id The coupon post ID. + * @param int $post_id The course post ID. + * @param int $user_id The user ID. + */ + do_action( 'learndash_coupon_after_redemption', $coupon_id, $post_id, $user_id ); } /** @@ -352,11 +429,38 @@ function learndash_attach_coupon( int $post_id, int $coupon_id, float $price, fl return; } + /** + * Filters the Learndash_Coupon_DTO when a coupon is being applied. + * + * @since 4.20.2 + * + * @param Learndash_Coupon_DTO $coupon_dto The computed price with discounts applied. + * @param int $post_id Product post ID. + * @param int|null $coupon_id The coupon post ID. + * + * @return Learndash_Coupon_DTO + */ + $coupon_dto = apply_filters( 'learndash_coupon_to_attach', $coupon_dto, $post_id, $coupon_id ); + set_transient( learndash_map_coupon_transient_key( $post_id, get_current_user_id() ), $coupon_dto->to_array(), DAY_IN_SECONDS ); + + /** + * Fires after a coupon is attached to a product. + * + * @since 4.20.1 + * + * @param int $product_id Product ID. + * @param int $coupon_id Coupon ID. + * @param int $user_id User ID. + * @param Learndash_Coupon_DTO $coupon_dto Coupon DTO. + * + * @return void + */ + do_action( 'learndash_coupon_attached', $post_id, $coupon_id, get_current_user_id(), $coupon_dto ); } /** @@ -373,6 +477,18 @@ function learndash_detach_coupon( int $post_id, int $user_id ): void { delete_transient( learndash_map_coupon_transient_key( $post_id, $user_id ) ); + + /** + * Fires after a coupon is detached from a product. + * + * @since 4.20.1 + * + * @param int $product_id Product ID. + * @param int $user_id User ID. + * + * @return void + */ + do_action( 'learndash_coupon_detached', $post_id, $user_id ); } /** @@ -395,7 +511,18 @@ function learndash_get_attached_coupon_data( int $post_id, int $user_id ): ?Lear } try { - return Learndash_Coupon_DTO::create( (array) $attached_coupon_data ); + /** + * Filters the Learndash_Coupon_DTO for the coupon attached by the user. + * + * @since 4.20.2 + * + * @param Learndash_Coupon_DTO $coupon_dto The DTO of the coupon being fetched. + * @param int $post_id Product post ID. + * @param int $user_id The user ID associated with the coupon. + * + * @return Learndash_Coupon_DTO + */ + return apply_filters( 'learndash_coupon_attached_data', Learndash_Coupon_DTO::create( (array) $attached_coupon_data ), $post_id, $user_id ); } catch ( Learndash_DTO_Validation_Exception $e ) { return null; } @@ -416,7 +543,18 @@ function learndash_post_has_attached_coupon( int $post_id, int $user_id ): bool learndash_map_coupon_transient_key( $post_id, $user_id ) ); - return false !== $attached_coupon_data; + /** + * Filters whether the post has an attached coupon for the user. + * + * @since 4.20.2 + * + * @param bool $has_coupon Whether the post has an attached coupon. + * @param int $post_id Product post ID. + * @param int $user_id The user ID we are checking for a coupon. + * + * @return bool + */ + return apply_filters( 'learndash_coupon_is_attached_to_product', false !== $attached_coupon_data, $post_id, $user_id ); } /** @@ -828,6 +966,18 @@ function learndash_enroll_with_zero_price(): void { $product->enroll( $user ); + /** + * Fires when a user was enrolled to a product when the price was calculated to zero. + * + * @since 4.20.2 + * + * @param Product $product Product model. + * @param WP_User $user The WP_User being enrolled. + * + * @return void + */ + do_action( 'learndash_coupon_user_enrolled_with_zero_price', $product, $user ); + // Redirect. wp_send_json_success( diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/meta-box-rtl.css b/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/meta-box-rtl.css new file mode 100644 index 000000000..ec6bfdff2 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/meta-box-rtl.css @@ -0,0 +1,1672 @@ +/*!******************************************************************************************************************************************************************************************************************************************************!*\ + !*** css ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[4].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[4].use[2]!./node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[4].use[3]!./src/assets/scss/meta-box.scss ***! + \******************************************************************************************************************************************************************************************************************************************************/ +@charset "UTF-8"; +/** + * Course Grid Meta Box SCSS. + * + * cSpell:ignore descripton csvg fwww fsvg cpath + */ +/* stylelint-disable no-descending-specificity */ +/* stylelint-disable selector-class-pattern */ +/* stylelint-disable selector-id-pattern */ +.form-table.sfwd { + clear: none; +} + +.form-table.sfwd td { + vertical-align: top; + padding: 16px 0 10px 0; + line-height: 20px; + font-size: 12px; +} + +.form-table.sfwd th { + width: 200px; + padding: 10px 9px 12px 0; +} + +.sfwd_help_text_link { + text-align: right; + float: right; + width: 100%; + max-width: 300px; + /* 10up-added */ + align-items: center; + display: flex; + flex-direction: row-reverse; + justify-content: space-between; +} + +.sfwd_help_text_link img { + /*width: 40px;*/ + width: 30px; + height: 30px; + float: right; +} + +.sfwd_label { + color: #5f5f5f; + font-weight: 700; + line-height: 19px; + width: 60%; + float: left; + margin: 0; + flex: 1; +} + +.sfwd_help_text_div { + text-align: right; + width: 100%; + margin: 10px 0 10px 0; +} + +.sfwd_help_text { + font-size: 12px; + float: right; + clear: right; + color: #797979; + line-height: 15px; + font-style: italic; + font-weight: lighter; + margin-left: 30px; +} + +.sfwd_head_tagline { + color: #5f5f5f; + font-size: 13px; +} + +.sfwd_head_nav { + float: right; + font-size: 18px; + margin: 0 0 16px 0; + font-family: HelveticaNeue-Light, "Helvetica Neue Light", "Helvetica Neue", sans-serif; + border-bottom: 1px solid #ccc; + width: 100%; +} + +.sfwd_head_nav_tab { + padding: 10px 15px 10px 15px; + margin: 0 15px 0 0; + border-width: 1px 1px 0; + border-radius: 4px 4px 0 0; + border-style: solid; + border-color: #ccc #ccc #fff; + float: right; + opacity: 0.5; + color: #000; + text-shadow: #fff 0 1px 0; + text-decoration: none; +} + +.sfwd_head_nav_tab.sfwd_head_nav_active { + opacity: 1; + margin-bottom: -1px; + border-width: 1px; +} + +.sfwd_head_nav_tab:first-child { + margin-right: 0; +} + +.sfwd_head_nav_tab:hover { + opacity: 1; +} + +.sfwd_header { + float: right; + clear: right; +} + +.sfwd_advert { + padding: 10px; + margin-bottom: 20px; + border: 1px solid #ddd; + height: 200px; + width: 423px; +} + +.sfwd_adverts { + float: left; +} + +.sfwd_content { + min-width: 760px; + clear: right; +} + +.sfwd_options_wrapper .hndle { + font-size: 15px; + font-family: Georgia, "Times New Roman", "Bitstream Charter", Times, serif; + font-weight: 400; + padding: 7px 10px; + margin: 0; + line-height: 1; +} + +#sfp_feature_manager_metabox.postbox { + float: right; +} + +.sfwd_advert p { + margin: 25px 0 25px 0; +} + +.widget, +#widget-list .widget-top, +.postbox, +#titlediv, +.sfwd_options_wrapper .postarea, +.stuffbox { + border-color: #dfdfdf; + box-shadow: inset 0 1px 0 #fff; + border-radius: 3px; +} + +.sfwd_advert h3 { + padding: 0; + margin-top: 6px; +} + +.sfwd_metabox_text p { + margin: 0 0 0 0; + width: 101%; +} + +.sfwd_sidebar { + width: 457px; + margin-right: 10px; +} + +.sfwd_metabox_text { + margin-bottom: 0; +} + +.sfwd_metabox_wrapper { + padding: 0; +} + +.sfwd_metabox_text *:last-child { + margin: 0; +} + +.sfwd_metabox_feature { + margin-top: 20px; +} + +.sfwd_option_label { + float: right; + /* margin: 0px 0 10px 5px; */ + margin: 5px; + width: 38%; + min-width: 210px; + max-width: 300px; + text-align: left; + vertical-align: top; + color: #5f5f5f !important; +} + +.sfwd_metabox_text h2 { + font-size: 14px; + padding: 0; + font-weight: 700; + line-height: 29px; +} + +#sfwd-about .sfwd_metabox_text #mc-embedded-subscribe-form h2 { + font-size: 13px; +} + +.sfwd input[readonly] { + background-color: #eee; + margin: 5px 0 5px 0 !important; +} + +.sfwd_settings_left { + float: right; + padding: 0; + margin: 0 0 0 0; + width: 100%; +} + +.sfwd_right_sidebar { + float: left; +} + +.sfwd_options { + width: 100%; + margin: 18px 0 10px 0; +} + +.sfwd_input { + clear: right; + width: 100%; + padding: 5px; +} + +.sfwd_option_input { + float: right; + width: 58%; + margin: 5px; + /* padding-left: 10px; */ + min-width: 320px; + max-width: 900px; +} + +#side-sortables .sfwd_option_input { + min-width: 220px; + max-width: 220px; +} + +.sfwd_top_label .sfwd_option_input, +.sfwd_no_label .sfwd_option_input { + width: 100%; +} + +.sfwd_settings_left .postbox { + float: right; + width: 100%; +} + +.sfwd_option_setting_label { + float: right; + min-width: 125px; + min-height: 35px; + width: 25%; + max-width: 175px; +} + +.sfwd_settings_left .postbox .inside { + padding: 0; + margin: 0; +} + +#sfwd_opengraph_settings { + width: 100%; +} + +.sfwd_no_label { + float: right; + width: 92%; + margin: 0 13px 20px 23px; +} + +.sfwd_top_label { + width: 96%; + margin: 0 10px; +} + +.sfwd_hidden_type { + margin: 0; + padding: 0; + height: 0; +} + +.sfwd_module.error.below-h2 { + padding: 5px 0; + margin: 0 0 15px 477px !important; +} + +.sfwd_input input[type=checkbox], +.sfwd_input input[type=radio] { + vertical-align: text-bottom; +} + +#sfp { + width: 100%; +} + +.sfwd_input.sfwd_top_label .sfwd_option_input { + margin: 0 0 10px 0; +} + +.sfwd_error_notice { + font-size: 15px; + font-style: italic; + color: #5f5f5f; +} + +#sfwd-courses_course_price_billing_cycle select { + margin-top: -4px; + height: 35px; +} + +#sfwd-courses_course_price_billing_cycle input { + width: 40px; +} + +.sfwd_help_text ul { + margin: 15px 20px 0 0; +} + +.sfwd_help_text ul li { + line-height: 20px; + margin: 0; +} + +.sfwd_sidebar #side-sortables { + width: 98%; +} + +.sfwd_header_tabs li { + display: inline; + padding: 0; + margin: 0; +} + +.sfwd_header_tabs { + margin: 0; +} + +.sfwd_header_nav { + margin: 0; +} + +.sfwd_header_tabs li a.sfwd_header_tab.active { + background-color: rgb(255, 255, 255); + background-color: rgba(255, 255, 255, 0.75); +} + +.sfwd_header_tabs li a.sfwd_header_tab { + color: #464646; + font-size: 15px; + text-decoration: none; + border: solid 1px #ccc; + border-right: none; + margin: 0; + padding: 6px 6px 1px 6px; +} + +.sfwd_header_tabs li:first-child a.sfwd_header_tab { + border-right: solid 1px #ccc; +} + +.sfwd_tab { + border: solid 1px #ccc; + background-color: rgb(255, 255, 255); + background-color: rgba(255, 255, 255, 0.5); +} + +.wrap > h2 { + padding-bottom: 14px; +} + +#learndash_group_users_search { + display: none; +} + +table.learndash-group-users-select { + width: 100%; +} + +table.learndash-group-users-select td.td_learndash_group_users_search { + width: 45%; +} + +table.learndash-group-users-select td.td_learndash_group_users_search select { + min-width: 100%; + height: 150px; +} + +/** + * Hide the 'Add New' button on the Assignment + * and Submitted Essays list tables + */ +body.post-type-sfwd-assignment .ld-global-header .global-new-entity-button, +body.post-type-sfwd-essays .ld-global-header .global-new-entity-button, +body.post-type-sfwd-transactions .ld-global-header .global-new-entity-button { + display: none; +} + +/* Styles for the Support tab table output */ +table#learndash-data-reports, +table#learndash-data-upgrades { + border: 0; +} + +.learndash-data-reports-status, +.learndash-data-upgrades-status { + width: 100%; +} + +.learndash-data-reports-status .progress-meter, +.learndash-data-upgrades-status .progress-meter { + width: 100%; + height: 20px; + border: 1px solid #000; +} + +.learndash-data-reports-status .progress-meter .progress-meter-image, +.learndash-data-upgrades-status .progress-meter .progress-meter-image { + background-color: #0f0; + float: right; + height: 16px; + width: 0; + margin: 2px 0; +} + +.sfwd_input .sfwd_option_div select[multiple] { + width: 100%; + min-height: 100px; +} + +table.learndash-support-settings tbody th { + text-align: right; + vertical-align: top; + padding: 5px 15px 5px 0; +} + +.learndash-settings-page-wrap div.sfwd_options { + padding-bottom: 30px; +} + +.learndash_shortcodes_section .learndash_required_field { + color: #f00; +} + +.sfwd_input.learndash-settings-field-error { + background-color: #ffdfe0; + border-bottom: 1px solid #c89797; + border-top: 1px solid #c89797; +} + +.sfwd_input p.ld-clear { + height: 0; + clear: right; + padding: 0; +} + +.edit-post-header__settings .components-popover__content a:hover { + color: #007cba; +} + +/* learndash-admin-settings-page.css */ +.learndash-settings-page-wrap .error, +.learndash-settings-page-wrap .error a { + color: #f00; +} + +a.learndash-description-link { + color: #000; + text-decoration: none; +} + +span.learndash-description { + display: none; +} + +.sfwd_options .sfwd_input p.ld-clear { + margin: 0; + line-height: 0; +} + +.sfwd_options .ld-setting-field-sub { + padding-top: 5px; +} + +.sfwd_options .ld-setting-field-sub input[type=button] { + margin-left: 5px; +} + +.ld-metabox-description p { + margin: 5px 0 0 0; + color: #666; + font-weight: 400; + font-style: italic; +} + +.sfwd_options .sfwd_option_label .descripton { + clear: both; + display: block; + float: right; + font-weight: 400; + text-align: right; +} + +.sfwd_options .ld-settings-sub-level-1 .sfwd_input { + margin-right: 10px; + padding-right: 10px; + position: relative; + border-right: 1px solid #ccc; +} + +.sfwd_options .ld-settings-sub-level-1 .ld-settings-sub-level-2 { + margin-right: 10px; + padding-right: 5px; + border-right: 1px solid #ccc; +} + +.sfwd_options .ld-settings-sub-level-1 .ld-settings-sub-level-2 .sfwd_input .sfwd_option_label { + /* max-width: 279px; */ + width: calc(38% - 1px); + max-width: 290px; +} + +.sfwd_options .ld-settings-inner .sfwd_input { + margin-right: 25px; + padding-right: 20px; + border-right: 1px solid #ccc; +} + +/* +.sfwd_options .ld-settings-inner .sfwd_input:first-child:nth-last-child(1) { + border-left: 0px; +} +*/ +.sfwd_options .ld-settings-inner .sfwd_input .sfwd_option_label { + margin-left: 0; + margin-right: 0; + padding-left: 0; + width: 30%; + min-width: none; + max-width: none; +} + +.sfwd_options .ld-settings-inner .sfwd_input .sfwd_option_label.sfwd_option_label_full, +.sfwd_options .sfwd_input .sfwd_option_label.sfwd_option_label_full { + width: 100%; +} + +.sfwd_options .ld-settings-inner .sfwd_input .sfwd_option_input { + width: 65%; + min-width: 120px; + max-width: none; +} + +.sfwd_options .ld-settings-inner .sfwd_input .sfwd_option_input.sfwd_option_input_full, +.sfwd_options .sfwd_option_input.sfwd_option_input_full { + width: 100%; +} + +.sfwd_options .sfwd_input_type_quiz-custom-fields .sfwd_option_input.sfwd_option_input_full { + float: none; +} + +/* Settings Fields CSS */ +/* Switch toggle CSS */ +.sfwd_options .ld-switch-wrapper { + display: flex; + margin-top: 5px; +} + +.sfwd_options .ld-switch { + margin-left: 16px; + position: relative; +} + +.sfwd_options .ld-switch__input { + border: none; + height: 100%; + right: 0; + margin: 0; + opacity: 0; + padding: 0; + position: absolute; + top: 0; + width: 100%; + z-index: 1; +} + +.sfwd_options .ld-switch__track { + background-color: #fff; + border-radius: 9px; + border: 2px solid #6c7781; + box-sizing: border-box; + content: ""; + display: inline-block; + height: 18px; + transition: 0.2s background ease, 0.2s border ease; + vertical-align: top; + width: 36px; +} + +.sfwd_options .ld-switch__thumb { + background-color: #6c7781; + border-radius: 50%; + border: 5px solid #6c7781; + box-sizing: border-box; + display: block; + height: 10px; + right: 4px; + position: absolute; + top: 4px; + transition: 0.1s transform ease; + width: 10px; +} + +.sfwd_options .ld-switch__on-off { + border-radius: 100%; + border: 2px solid #6c7781; + box-sizing: border-box; + display: block; + height: 6px; + position: absolute; + left: 6px; + top: 6px; + width: 6px; +} + +.sfwd_options .ld-switch__input:checked ~ .ld-switch__track { + background-color: #11a0d2; + border-color: #11a0d2; +} + +.sfwd_options .ld-switch__input:checked ~ .ld-switch__thumb { + background-color: #fff; + border-width: 0; + transform: translateX(-18px); +} + +.sfwd_options .ld-switch__input:checked ~ .ld-switch__on-off { + background-color: #fff; + border-radius: 0; + border: 0; + height: 6px; + right: 8px; + left: auto; + width: 2px; +} + +.sfwd_options .ld-switch__input:focus ~ .ld-switch__track { + box-shadow: 0 0 0 2px #fff, 0 0 0 3px #6c7781; + outline-offset: 2px; + outline: 2px solid transparent; +} + +.sfwd_options .ld-switch__input:hover ~ .ld-switch__track { + border-color: #11a0d2; +} + +.sfwd_options .ld-switch__input:checked:hover ~ .ld-switch__track { + background-color: #6c7781; + border-color: #6c7781; +} + +.sfwd_options .ld-switch.-disabled ~ label, +.sfwd_options .ld-switch__input[disabled=disabled] { + pointer-events: none; +} + +.sfwd_options .ld-switch__input[disabled=disabled] { + opacity: 0 !important; +} + +.sfwd_options .ld-switch__input[disabled=disabled] ~ .ld-switch__track { + opacity: 0.5; +} + +/* Radio CSS*/ +.sfwd_options .ld-radio-input { + border: 0; + clip-path: inset(50%); + clip: rect(1px, 1px, 1px, 1px); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; + word-wrap: normal !important; +} + +.sfwd_options .ld-radio-input__label { + margin-left: 16px; +} + +.sfwd_options .ld-radio-input__label::before { + border-radius: 100%; + border: 2px solid #6c7781; + box-sizing: border-box; + content: ""; + display: inline-block; + height: 16px; + margin-left: 10px; + vertical-align: middle; + width: 16px; +} + +.sfwd_options .ld-radio-input__label > span { + vertical-align: middle; + font-weight: 700; + color: #5f5f5f; +} + +.sfwd_options .ld-radio-input:checked + .ld-radio-input__label::before { + background-color: #11a0d2; + box-shadow: inset 0 0 0 2px #fff; +} + +.sfwd_options .ld-radio-input:checked:focus + .ld-radio-input__label::before { + box-shadow: inset 0 0 0 2px #fff, 0 0 0 2px #fff, 0 0 0 3px #6c7781; +} + +.sfwd_options .ld-radio-input:focus + .ld-radio-input__label::before { + box-shadow: 0 0 0 2px #fff, 0 0 0 3px #6c7781; + outline-offset: 2px; + outline: 2px solid transparent; +} + +.sfwd_options .ld-radio-input:hover + .ld-radio-input__label::before { + border-color: #11a0d2; +} + +.sfwd_options .ld-radio-input[disabled=disabled], +.sfwd_options .ld-radio-input[disabled=disabled] + .ld-radio-input__label { + pointer-events: none; +} + +.sfwd_options .ld-radio-input[disabled=disabled] + .ld-radio-input__label::before { + opacity: 0.5; +} + +.sfwd_options .ld-radio-description { + color: #666; + padding-right: 25px; +} + +/* Checkbox CSS*/ +.sfwd_options .ld-checkbox-input { + border: 0; + clip-path: inset(50%); + clip: rect(1px, 1px, 1px, 1px); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; + word-wrap: normal !important; +} + +.sfwd_options .ld-checkbox-input__label { + margin-left: 16px; +} + +.sfwd_options .ld-checkbox-input__label::before { + border: 2px solid #6c7781; + box-sizing: border-box; + content: ""; + display: inline-block; + height: 16px; + margin-left: 10px; + vertical-align: middle; + width: 16px; +} + +.sfwd_options .ld-checkbox-input__label > span { + vertical-align: middle; +} + +.sfwd_options .ld-checkbox-input:checked + .ld-checkbox-input__label::before { + align-items: center; + color: #11a0d2; + content: "✓"; + display: inline-flex; + justify-content: center; + font-weight: 900; +} + +.sfwd_options .ld-checkbox-input:focus + .ld-checkbox-input__label::before { + box-shadow: 0 0 0 2px #fff, 0 0 0 3px #6c7781; + outline-offset: 2px; + outline: 2px solid transparent; +} + +.sfwd_options .ld-checkbox-input:hover + .ld-checkbox-input__label::before { + border-color: #11a0d2; +} + +.sfwd_options .ld-checkbox-input[disabled=disabled], +.sfwd_options .ld-checkbox-input[disabled=disabled] + .ld-checkbox-input__label { + pointer-events: none; +} + +.sfwd_options .ld-checkbox-input[disabled=disabled] + .ld-checkbox-input__label::before { + opacity: 0.5; +} + +.sfwd_options .sfwd_option_input p.learndash-section-field-checkbox-p { + margin: 3px 0 0 0; + padding: 0; +} + +/* Text Input CSS */ +.sfwd_options .learndash-section-field-text { + border-radius: 2px; + border: 1px solid #ddd; + box-shadow: none; + box-sizing: border-box; + font-size: 14px; + padding: 5px 7px; + width: 100%; +} + +.sfwd_options .learndash-section-field-number.-medium, +.sfwd_options .learndash-section-field-text.-medium, +.sfwd_options .learndash-section-field-url.-medium { + width: 50%; +} + +.sfwd_options .learndash-section-field-number.-small, +.sfwd_options .learndash-section-field-text.-small, +.sfwd_options .learndash-section-field-url.-small { + width: 100px; +} + +.sfwd_options .learndash-section-field-number:focus, +.sfwd_options .learndash-section-field-text:focus { + border-color: #11a0d2; + outline: 0; +} + +.sfwd_options .learndash-section-field-number:hover, +.sfwd_options .learndash-section-field-text:hover, +.sfwd_options .learndash-section-field-url:hover { + border-color: #999; +} + +.sfwd_options .learndash-section-field-number.full-text, +.sfwd_options .learndash-section-field-text.full-text, +.sfwd_options .learndash-section-field-url.full-text { + width: 100%; +} + +.sfwd_options span.learndash_settings_field_text_prefix.-medium { + width: 75%; + display: inline-block; + padding-top: 0; + padding-bottom: 0; + color: rgba(51, 51, 51, 0.5); +} + +.sfwd_options span.learndash_settings_field_text_prefix input[type=text] { + width: max-content; + border: 0; + padding-right: 0; + padding-bottom: 8px; +} + +/* Select CSS */ +.sfwd_options .ld-select { + background-color: #fff; + border-radius: 3px; + border: 1px solid #ccc; + display: inline-block; + overflow: hidden; + position: relative; + vertical-align: middle; + width: 100%; + max-width: 450px; +} + +.sfwd_options .ld-select::after { + border: 5px solid transparent; + border-bottom: 0; + border-top-color: #000; + content: ""; + height: 0; + pointer-events: none; + position: absolute; + left: 5px; + speak: none; + top: 50%; + transform: translate(0, -50%); + width: 0; +} + +.sfwd_options .ld-select-multiple::after, +.sfwd_options .ld-select2::after { + border: none; +} + +.select2-container--learndash .select2-selection--single .select2-selection__rendered { + color: #72777c !important; +} + +.select2-container--learndash .select2-results__option--highlighted[aria-selected] { + background-color: #11a0d2 !important; +} + +.sfwd_options .ld-select-multiple.ld-select2 .select2-container .select2-selection__rendered > *:first-child.select2-search--inline { + width: 100% !important; +} + +.sfwd_options .ld-select-multiple.ld-select2 .select2-container .select2-selection__rendered > *:first-child.select2-search--inline .select2-search__field { + width: 100% !important; +} + +.sfwd_options .ld-select-multiple.ld-select2 .select2-container li { + margin-bottom: 0; +} + +.sfwd_options .select2-container .select2-search--inline .select2-search__field { + margin-top: 3px; + margin-bottom: 2px; +} + +.sfwd_options .ld-select select { + appearance: none; + background: none; + border: 0; + font-size: 14px; + height: 100%; + margin: 0; + padding: 5px 10px; + width: 100%; + max-width: 100%; + /* width: 110% \9; */ + z-index: 2; +} + +.sfwd_options .ld-select select:focus { + box-shadow: inset 0 0 0 1px #6c7781; +} + +.sfwd_options .ld-select select::-ms-expand { + display: none; +} + +.sfwd_options .ld-select select:-moz-focusring { + text-shadow: var(--select--focus-ring--text-shadow); +} + +.sfwd_options .ld-select select option { + border: 0; + width: 100%; +} + +.sfwd_options .ld-select2 .select2-container--learndash { + width: 100% !important; + max-width: 450px; + height: 100%; +} + +.sfwd_options .ld-select2 .select2-container--learndash .select2-selection--single { + padding-top: 3px; + padding-bottom: 3px; + height: 100%; + border: 0; +} + +.sfwd_options .ld-select2 .select2-container--learndash .select2-selection--single .select2-selection__arrow { + height: 100%; +} + +.sfwd_options .ld-select2 .select2-container--learndash .select2-selection--single .select2-selection__arrow b { + border-top-color: inherit; +} + +.sfwd_options .select2-container--learndash .select2-selection--multiple { + border: 0 solid #aaa !important; +} + +/* stylelint-disable-next-line no-duplicate-selectors */ +.sfwd_options .select2-container .select2-search--inline .select2-search__field { + padding-top: 5px !important; + color: #444 !important; +} + +/* Select2 Post Type listing selectors */ +body.edit-php .tablenav.top .select2-container--learndash, +body.users-php .tablenav.top .select2-container--learndash { + margin-left: 6px; + margin-right: 1px; + font-size: 14px; + line-height: 2; + border-color: #7e8993; + box-shadow: none; + border-radius: 3px; + min-height: 30px; + max-width: 25rem; + -webkit-appearance: none; + color: #32373c !important; + cursor: pointer; + vertical-align: middle; + float: right; +} + +body.edit-php .tablenav.top .select2-container--learndash .select2-selection--single, +body.users-php .tablenav.top .select2-container--learndash .select2-selection--single { + height: 30px; + box-shadow: 0 0 0 transparent; + border-radius: 4px; + border: 1px solid #7e8993; + background-color: #fff; + color: #32373c !important; + /* stylelint-disable-next-line max-line-length */ + /* stylelint-disable-next-line declaration-block-no-shorthand-property-overrides, function-url-quotes */ + background: #fff url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M5%206l5%205%205-5%202%201-7%207-7-7%202-1z%22%20fill%3D%22%23555%22%2F%3E%3C%2Fsvg%3E") no-repeat left 5px top 55%; + background-size: 16px 16px; +} + +body.edit-php .tablenav.top .select2-container--learndash .select2-selection--single .select2-selection__placeholder, +body.users-php .tablenav.top .select2-container--learndash .select2-selection--single .select2-selection__placeholder { + color: #32373c !important; +} + +/* Hide the default */ +body.edit-php .tablenav.top .select2-container--learndash .select2-selection--single .select2-selection__arrow, +body.users-php .tablenav.top .select2-container--learndash .select2-selection--single .select2-selection__arrow { + display: none; +} + +/* Settings Row CSS */ +.sfwd_options .sfwd_option_div p.ld-radio-input-wrapper { + margin-bottom: 1px; +} + +.sfwd_options .sfwd_input textarea { + color: #515151; + margin: 0; + font-size: 14px; + line-height: 25px; + width: 100%; +} + +.sfwd_options .sfwd_input > .sfwd_input:first-child { + margin-top: 20px; +} + +.sfwd_options .sfwd_option_input p { + margin-top: 0; +} + +.sfwd_options .sfwd_option_label { + box-sizing: border-box; + flex: 1 0 100%; + font-weight: 700; + margin-bottom: 10px; + padding-left: 0; /* 20px;*/ + /* position: relative; */ +} + +.sfwd_options .sfwd_option_input { + flex: 1 0 100%; + margin-bottom: 10px; +} + +.sfwd_options .sfwd_option_div select[multiple] { + width: 100%; + min-height: 100px; +} + +.sfwd_options .ld-settings-sub.ld-settings-sub-state-closed, +.sfwd_options .ld-settings-inner-state-closed, +.sfwd_options .ld-theme-settings-section-state-closed { + display: none; +} + +.sfwd_options .ld-settings-sub.ld-settings-sub-state-open, +.sfwd_options .ld-settings-inner-state-open .sfwd_options .ld-theme-settings-section-state-open { + display: block; +} + +.sfwd_options .ld-settings-sub-advanced .sfwd_input { + margin-right: 1px; + border-right: 1px solid #ccc; +} + +.sfwd_options .ld-settings-sub-advanced .ld-settings-sub-advanced-inner-state-closed { + display: none; +} + +.sfwd_options .ld-settings-sub-advanced .ld-settings-sub-advanced-inner-state-open { + display: block; +} + +.sfwd_options .ld-settings-sub-advanced .ld-settings-sub-advanced-inner .sfwd_option_label { + width: auto; +} + +.sfwd_options .ld-settings-sub-advanced .ld-settings-sub-advanced-inner .sfwd_option_input { + width: auto; +} + +.sfwd_options .tooltip { + position: relative; + display: inline-block; + opacity: 1; +} + +/* Tooltip text */ +.sfwd_options .tooltip .tooltiptext { + visibility: hidden; + width: 180px; + background-color: #11a0d2; + color: #fff; + text-align: center; + padding: 5px 0; + border-radius: 6px; + margin-right: -90px; /* Use half of the width (120/2 = 60), to center the tooltip */ + bottom: 100%; + right: 50%; + margin-bottom: 5px; + /* Position the tooltip text - see examples below! */ + position: absolute; + z-index: 1; +} + +/* Show the tooltip text when you mouse over the tooltip container */ +.sfwd_options .-disabled.tooltip:hover .tooltiptext { + visibility: visible; +} + +/* Tooltip top of element */ +/* Arrow */ +.sfwd_options .tooltip .tooltiptext::after { + content: " "; + position: absolute; + top: 100%; /* At the bottom of the tooltip */ + right: 50%; + margin-right: -5px; + border-width: 5px; + border-style: solid; + border-color: #11a0d2 transparent transparent transparent; +} + +/* Tooltip to right of element */ +/** + * Quiz Custom Fields style + */ +.sfwd_options .form_table_wrapper { + margin-top: 0; + padding: 0; + border: 0 solid #c2c2c2; +} + +.sfwd_options .form_table_wrapper table { + border-collapse: collapse; +} + +/* Line item CSS */ +.sfwd_options .form_table_wrapper #form_add { + background-color: transparent; + /* stylelint-disable-next-line function-url-quotes */ + background-image: url("data:image/svg+xml,%3Csvg width=%27256%27 height=%27256%27 viewBox=%270 0 256 256%27 xmlns=%27http://www.w3.org/2000/svg%27%3E%3Cpath fill=%27%23007cba%27 d=%27M185.066 128c0 3.534-2.866 6-6.4 6H134v44.666c0 3.534-2.467 6.399-6 6.399-3.534 0-6-2.865-6-6.399V134H77.332c-3.535 0-6.4-2.466-6.4-6s2.866-6 6.4-6H122V77.331c0-3.534 2.466-6.4 6-6.4 3.533 0 6 2.866 6 6.4V122h44.666c3.534 0 6.4 2.466 6.4 6zM256 128C256 57.42 198.58 0 128 0S0 57.42 0 128s57.42 128 128 128 128-57.42 128-128zm-12.8 0c0 63.521-51.679 115.2-115.2 115.2-63.522 0-115.2-51.679-115.2-115.2C12.8 64.478 64.478 12.8 128 12.8c63.521 0 115.2 51.678 115.2 115.2z%27 fill-rule=%27nonzero%27%3E%3C/path%3E%3C/svg%3E"); + background-position: center right 3px; + background-repeat: no-repeat; + background-size: 16px 16px; + border: 0; + color: #007cba; + cursor: pointer; + font-size: 14px; + font-weight: 700; + padding: 5px 30px 5px 10px; + box-shadow: none; +} + +.sfwd_options .form_table_wrapper #form_add:hover { + /* stylelint-disable-next-line function-url-quotes */ + background-image: url("data:image/svg+xml,%3Csvg width=%27256%27 height=%27256%27 viewBox=%270 0 256 256%27 xmlns=%27http://www.w3.org/2000/svg%27%3E%3Cpath fill=%27%2311a0d2%27 d=%27M185.066 128c0 3.534-2.866 6-6.4 6H134v44.666c0 3.534-2.467 6.399-6 6.399-3.534 0-6-2.865-6-6.399V134H77.332c-3.535 0-6.4-2.466-6.4-6s2.866-6 6.4-6H122V77.331c0-3.534 2.466-6.4 6-6.4 3.533 0 6 2.866 6 6.4V122h44.666c3.534 0 6.4 2.466 6.4 6zM256 128C256 57.42 198.58 0 128 0S0 57.42 0 128s57.42 128 128 128 128-57.42 128-128zm-12.8 0c0 63.521-51.679 115.2-115.2 115.2-63.522 0-115.2-51.679-115.2-115.2C12.8 64.478 64.478 12.8 128 12.8c63.521 0 115.2 51.678 115.2 115.2z%27 fill-rule=%27nonzero%27%3E%3C/path%3E%3C/svg%3E"); + color: #11a0d2; +} + +.sfwd_options .form_table_wrapper .form_move { + text-decoration: none; +} + +.sfwd_options .form_table_wrapper .form_delete { + background-color: transparent; + /* stylelint-disable-next-line function-url-quotes */ + background-image: url("data:image/svg+xml,%3Csvg aria-hidden=%27true%27 role=%27img%27 focusable=%27false%27 class=%27dashicon dashicons-dismiss%27 xmlns=%27http://www.w3.org/2000/svg%27 width=%2720%27 height=%2720%27 viewBox=%270 0 20 20%27%3E%3Cpath fill=%27%23a00%27 d=%27M10 2c4.42 0 8 3.58 8 8s-3.58 8-8 8-8-3.58-8-8 3.58-8 8-8zm5 11l-3-3 3-3-2-2-3 3-3-3-2 2 3 3-3 3 2 2 3-3 3 3z%27%3E%3C/path%3E%3C/svg%3E"); + background-position: center right 3px; + background-repeat: no-repeat; + border: 0; + color: #a00; + cursor: pointer; + font-weight: 700; + margin: 0; + opacity: 0; + padding: 5px 30px 5px 10px; + transition: opacity 0.1s; + visibility: hidden; +} + +.sfwd_options .form_table_wrapper .form_delete:hover { + color: #f00; +} + +.sfwd_options .form_table_wrapper tbody.ui-sortable tr:hover .form_delete { + opacity: 1; + visibility: visible; +} + +.sfwd_options .form_table_wrapper thead tr th, +.sfwd_options .form_table_wrapper tbody.ui-sortable tr td { + padding: 10px 5px; + transition: box-shadow 0.1s; +} + +.sfwd_options .form_table_wrapper tbody.ui-sortable tr:hover td { + box-shadow: 0 1px 0 0 #11a0d2, 0 -1px 0 0 #11a0d2; +} + +.sfwd_options .form_table_wrapper tbody.ui-sortable tr:hover td:first-of-type { + box-shadow: 0 1px 0 0 #11a0d2, 0 -1px 0 0 #11a0d2, 1px 0 0 0 #11a0d2; +} + +.sfwd_options .form_table_wrapper tbody.ui-sortable tr:hover td:last-of-type { + box-shadow: 0 1px 0 0 #11a0d2, 0 -1px 0 0 #11a0d2, -1px 0 0 0 #11a0d2; +} + +.sfwd_options .form_table_wrapper tbody.ui-sortable tr td:first-of-type { + text-align: center; +} + +.sfwd_options .form_table_wrapper .ld-select.-field select { + padding: 0 10px; +} + +.sfwd_options .form_table_wrapper #form_table thead th { + text-transform: uppercase; +} + +.sfwd_options .form_table_wrapper #form_add_wrapper { + margin-top: 10px; + margin-right: 10px; +} + +/** +Quiz Edit Result Text lists +*/ +#learndash-quiz-resultList ul#resultList { + width: 100%; +} + +#learndash-quiz-resultList ul#resultList li { + padding: 5px; + border: 1; + border: 1px dotted; +} + +#learndash-quiz-resultList ul#resultList li .resultHeader { + margin-bottom: 5px; + padding: 10px; + background-color: #ebebeb; /* rgb(207, 207, 207); */ +} + +#learndash-quiz-resultList input.addResult { + background-color: transparent; + /* stylelint-disable-next-line function-url-quotes */ + background-image: url("data:image/svg+xml,%3Csvg width=%27256%27 height=%27256%27 viewBox=%270 0 256 256%27 xmlns=%27http://www.w3.org/2000/svg%27%3E%3Cpath fill=%27%23007cba%27 d=%27M185.066 128c0 3.534-2.866 6-6.4 6H134v44.666c0 3.534-2.467 6.399-6 6.399-3.534 0-6-2.865-6-6.399V134H77.332c-3.535 0-6.4-2.466-6.4-6s2.866-6 6.4-6H122V77.331c0-3.534 2.466-6.4 6-6.4 3.533 0 6 2.866 6 6.4V122h44.666c3.534 0 6.4 2.466 6.4 6zM256 128C256 57.42 198.58 0 128 0S0 57.42 0 128s57.42 128 128 128 128-57.42 128-128zm-12.8 0c0 63.521-51.679 115.2-115.2 115.2-63.522 0-115.2-51.679-115.2-115.2C12.8 64.478 64.478 12.8 128 12.8c63.521 0 115.2 51.678 115.2 115.2z%27 fill-rule=%27nonzero%27%3E%3C/path%3E%3C/svg%3E"); + background-position: center right 3px; + background-repeat: no-repeat; + background-size: 16px 16px; + border: 0; + color: #007cba; + cursor: pointer; + font-size: 14px; + font-weight: 700; + padding: 5px 30px 5px 10px; +} + +#learndash-quiz-resultList ul#resultList li input.deleteResult { + float: left; + background-color: transparent; + /* stylelint-disable-next-line function-url-quotes */ + background-image: url("data:image/svg+xml,%3Csvg aria-hidden=%27true%27 role=%27img%27 focusable=%27false%27 class=%27dashicon dashicons-dismiss%27 xmlns=%27http://www.w3.org/2000/svg%27 width=%2720%27 height=%2720%27 viewBox=%270 0 20 20%27%3E%3Cpath fill=%27%23a00%27 d=%27M10 2c4.42 0 8 3.58 8 8s-3.58 8-8 8-8-3.58-8-8 3.58-8 8-8zm5 11l-3-3 3-3-2-2-3 3-3-3-2 2 3 3-3 3 2 2 3-3 3 3z%27%3E%3C/path%3E%3C/svg%3E"); + background-position: center right 3px; + background-repeat: no-repeat; + border: 0; + color: #a00; + cursor: pointer; + font-weight: 700; + margin: 0; + opacity: 0; + padding: 5px 30px 5px 10px; + transition: opacity 0.1s; + visibility: hidden; +} + +#learndash-quiz-resultList ul#resultList li:hover input.deleteResult { + opacity: 1; + visibility: visible; +} + +#learndash-quiz-resultList #resultList li .expand-arrow { + cursor: pointer; + margin-top: 3px; + float: left; +} + +#learndash-quiz-resultList #resultList li .expand-arrow-up svg { + transform: rotate(-180deg); +} + +.sfwd_options .sfwd_option_label .descripton p { + margin-bottom: 0; +} + +.sfwd_options .sfwd_option_input_full { + margin-right: 0; + margin-left: 0; +} + +.learndash_navigation_questions_list ul.learndash-quiz-questions li a { + font-weight: 400; + text-decoration: none !important; +} + +.learndash_navigation_questions_list ul.learndash-quiz-questions li.ld-question-overview-widget-item-current a { + font-weight: 700; +} + +.learndash_navigation_questions_list .ld-question-overview-widget-add { + font-weight: 700; + text-decoration: none !important; +} + +.sfwd_options #learndash-quiz-admin-data-handling-settings_toplistDataAddBlock_field, +.sfwd_options #learndash-quiz-admin-data-handling-settings_associated_settings_field, +.sfwd_options #learndash-quiz-admin-data-handling-settings_emailNotification_field, +.sfwd_options #learndash-quiz-admin-data-handling-settings_timeLimitCookie_field, +.sfwd_options #learndash-quiz-admin-data-handling-settings_toplistDataShowIn_field, +.sfwd_options #learndash-quiz-admin-data-handling-settings_statisticsIpLock_field, +.sfwd_options #learndash-quiz-display-content-settings_showMaxQuestion_field, +.sfwd_options #learndash-quiz-display-content-settings_showMaxQuestionValue_field, +.sfwd_options #learndash-quiz-display-content-settings_quizModus_multiple_questionsPerPage_field, +.sfwd_options #learndash-quiz-results-options_resultText_field, +.sfwd_options #learndash-quiz-display-content-settings_quizModus_single_feedback_field { + border-right: none; + margin-right: 0; + padding-right: 0; +} + +.sfwd_options #learndash-course-access-settings_course_access_list_field, +.sfwd_options #learndash-course-display-content-settings_course_materials_field, +.sfwd_options #learndash-lesson-display-content-settings_lesson_materials_field, +.sfwd_options #learndash-topic-display-content-settings_topic_materials_field, +.sfwd_options #learndash-lesson-display-content-settings_lesson_assignment_points_amount_field, +.sfwd_options #learndash-topic-display-content-settings_lesson_assignment_points_amount_field, +.sfwd_options #learndash-quiz-display-content-settings_quiz_materials_field, +.sfwd_options #learndash-quiz-display-content-settings_showMaxQuestionValue_field, +.sfwd_options #learndash-quiz-display-content-settings_quizModus_single_back_button_field { + border-right: none; +} + +.sfwd_options #learndash-lesson-access-settings_visible_after_field, +.sfwd_options #learndash-lesson-access-settings_visible_after_specific_date_field, +.sfwd_options #learndash-quiz-display-content-settings_quizModus_single_back_button_field { + border-right: none; + /* padding-left: 5px; */ + padding-right: 0; +} + +.sfwd_options #learndash-quiz-results-options_resultText_field { + padding-right: 10px; +} + +.sfwd_options input[name=templateLoad], +.sfwd_options input[name=templateName] { + margin-top: 5px; +} + +.ld-settings-inner .ld-radio-input__label > span { + font-weight: 400; +} + +.ld-divider { + border-bottom: 1px solid #eee; + margin: 20px 0 20px 0; +} + +.sfwd_options .ld-settings-inner-lesson_video_display_timing_after .sfwd_option_input, +.sfwd_options .ld-settings-inner .sfwd_option_input { + width: 40% !important; +} + +.sfwd_options #learndash-lesson-access-settings_visible_after_specific_date_field .sfwd_option_input { + width: 80% !important; +} + +.sfwd_options .ld-settings-sub .sfwd_option_label { + width: calc(38% - 15px); + max-width: 285px; +} + +.sfwd_options #learndash-lesson-display-content-settings_assignment_upload_limit_count_field .sfwd_option_label, +.sfwd_options #learndash-lesson-display-content-settings_lesson_assignment_deletion_enabled_field .sfwd_option_label { + width: 35% !important; +} + +.sfwd_options #learndash-lesson-access-settings_visible_after_specific_date_field input[type=number] { + padding: 0 !important; +} + +.sfwd_options .ld-settings-inner-lesson_video_display_timing_after .sfwd_option_label { + width: 35% !important; +} + +.sfwd_options .ld-settings-inner-quizModus_single .sfwd_option_input { + width: 65% !important; +} + +.sfwd_options .ld-settings-email-header-wrapper { + margin-bottom: 30px; +} + +.sfwd_options .ld-settings-email-header { + font-weight: 700; +} + +.sfwd_options .ld-settings-email-description { + font-weight: 300; +} + +/* Add support for error display */ +.sfwd_options .learndash_settings_field_invalid label.sfwd_label { + color: #f00; +} + +.sfwd_options .learndash_settings_field_invalid input:invalid { + border: 1px solid #f00; + box-shadow: none; +} + +.sfwd_options .learndash_settings_field_invalid .learndash-section-field-error { + color: #f00; +} + +#learndash-settings-fields-notice-errors p.errors-header { + font-weight: 900; +} + +#learndash-settings-fields-notice-errors ul.errors-list { + list-style: disc; +} + +#learndash-settings-fields-notice-errors ul.errors-list li { + margin-right: 15px; +} + +/** + * Added to bring back the visible indicator on + * checkbox in Builder sidebar elements. + * + * See LEARNDASH-4114 + */ +.ld__builder-sidebar-widget .components-checkbox-control__input[type=checkbox]:checked::before { + /* stylelint-disable-next-line function-url-quotes */ + content: url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2020%2020%27%3E%3Cpath%20d%3D%27M14.83%204.89l1.34.94-5.81%208.38H9.02L5.78%209.67l1.34-1.25%202.57%202.4z%27%20fill%3D%27%231e8cbe%27%2F%3E%3C%2Fsvg%3E"); +} + +.plugin-update p.ld-plugin-update-notice::before { + content: ""; + margin-left: 0; +} + +.plugin-update .ld-plugin-update-notice, +.notice.ld-plugin-update-notice { + padding: 10px; + margin-top: 10px; +} + +.ld-plugin-update-notice .version { + font-weight: 700; +} + +.ld-plugin-update-notice .header { + font-size: 130%; + font-weight: 700; +} + +/** +Sections/Settings Info banners. +*/ +.ld_settings_postbox .ld-settings-info-banner { + display: block; + padding: 5px 10px 5px 10px; + margin: 5px 0; +} + +.ld_settings_postbox .ld-settings-info-banner p::before { + /* stylelint-disable-next-line font-family-no-missing-generic-family-keyword */ + font: 400 20px/1 dashicons; + float: right; +} + +.ld_settings_postbox .ld-settings-info-banner p { + margin: 0.5em 0; + padding: 0; + font-size: 13px; + /* stylelint-disable-next-line declaration-property-unit-allowed-list */ + line-height: 1.5em; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + vertical-align: top; +} + +.ld_settings_postbox .ld-settings-info-banner.ld-settings-info-banner-alert { + background-color: #fbeaea; + border-right-color: #dc3232; + border-right-width: 2px; + border-right-style: solid; +} + +.ld_settings_postbox .ld-settings-info-banner.ld-settings-info-banner-alert p::before { + color: #dc3232; + content: "\f534"; + margin-left: 6px; +} + +.ld_settings_postbox .ld-settings-info-banner.ld-settings-info-banner-success { + border-color: #46b450; + border-width: 0 2px 1px 0; + border-style: solid; +} + +/* LearnDash Settings Sub menu */ +ul.learndash-settings-sub { + float: none; +} + +ul.learndash-settings-sub li.learndash-settings-sub-current a { + font-weight: 700; +} + +/* LearnDash Settings Table general styles */ +table.learndash-settings-table th { + font-weight: 700; +} + +table.learndash-settings-table td.col-valign-middle { + vertical-align: middle; +} + +table.learndash-settings-table-sortable .ui-sortable-helper { + display: table; +} + +table.learndash-settings-table-sortable td.col-name-move { + cursor: grab; +} + +/** Settings for Group Attributes metabox */ +.edit-post-sidebar #learndash_group_attributes_metabox select#group_parent_id { + max-width: 85%; + width: 100%; +} + +#learndash_group_attributes_metabox input#group_menu_order { + display: block; +} + +.edit-post-sidebar #learndash_group_attributes_metabox .group-menu-order-label-wrapper { + margin-top: 10px; +} + +/** Styles for WordPress 5.5 changes */ +.ld_settings_postbox .postbox-header { + display: block; +} + +.edit-post-meta-boxes-area #poststuff .ld_settings_postbox .postbox-header .hndle, +.edit-post-meta-boxes-area #poststuff #learndash_course_builder .postbox-header .hndle, +.edit-post-meta-boxes-area #poststuff #learndash_quiz_builder .postbox-header .hndle { + border-bottom: none; + padding: 5px 12px; + width: auto; +} + +.ld_settings_postbox .postbox-header .hndle { + display: inline-block; +} + +.ld_settings_postbox .postbox-header .handle-actions { + display: inline-block; + float: left; +} + +.ld_settings_postbox .postbox-header .handle-actions .handle-order-lower, +.ld_settings_postbox .postbox-header .handle-actions .handle-order-higher, +body[data-active-tab=learndash_course_builder] .postbox-header .handle-actions .handle-order-lower, +body[data-active-tab=learndash_course_builder] .postbox-header .handle-actions .handle-order-higher, +body[data-active-tab=learndash_quiz_builder] .postbox-header .handle-actions .handle-order-lower, +body[data-active-tab=learndash_quiz_builder] .postbox-header .handle-actions .handle-order-higher { + display: none; +} + +.ld_settings_postbox .postbox-header .ld-metabox-description { + display: block; + padding: 0 12px 5px; +} + +#course-shortcodes.wrap .inside .dashicons, +#course-shortcodes.wrap .inside .dashicons-before::before, +#certificate-shortcodes.wrap .inside .dashicons, +#certificate-shortcodes.wrap .inside .dashicons-before::before { + text-decoration: none; +} + +/* Stripe Payments Settings */ +.sfwd_options .learndash-stripe-connect, +.notice.connect-stripe .learndash-stripe-connect { + align-items: center; + background: #6772e5; + border-radius: 5px; + color: #fff; + display: flex; + font-size: 16px; + justify-content: center; + letter-spacing: 0.6px; + padding: 6px 24px; + text-decoration: none; + transition: all 0.3s ease; + width: 200px; +} + +.sfwd_options .learndash-stripe-connect:active, +.learndash-stripe-connect:focus, +.learndash-stripe-connect:hover, +.notice.connect-stripe .learndash-stripe-connect:active, +.notice.connect-stripe .learndash-stripe-connect:focus, +.notice.connect-stripe .learndash-stripe-connect:hover { + background: #3f4ddf; + color: #fff; +} + +.sfwd_options .learndash-stripe-connect .stripe-logo, +.notice.connect-stripe .learndash-stripe-connect .stripe-logo { + padding: 2px 0 0 10px; +} diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/meta-box.css b/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/meta-box.css new file mode 100644 index 000000000..99c92c4d3 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/meta-box.css @@ -0,0 +1,1674 @@ +/*!******************************************************************************************************************************************************************************************************************************************************!*\ + !*** css ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[4].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[4].use[2]!./node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[4].use[3]!./src/assets/scss/meta-box.scss ***! + \******************************************************************************************************************************************************************************************************************************************************/ +@charset "UTF-8"; +/** + * Course Grid Meta Box SCSS. + * + * cSpell:ignore descripton csvg fwww fsvg cpath + */ +/* stylelint-disable no-descending-specificity */ +/* stylelint-disable selector-class-pattern */ +/* stylelint-disable selector-id-pattern */ +.form-table.sfwd { + clear: none; +} + +.form-table.sfwd td { + vertical-align: top; + padding: 16px 0 10px 0; + line-height: 20px; + font-size: 12px; +} + +.form-table.sfwd th { + width: 200px; + padding: 10px 0 12px 9px; +} + +.sfwd_help_text_link { + text-align: left; + float: left; + width: 100%; + max-width: 300px; + /* 10up-added */ + align-items: center; + display: flex; + flex-direction: row-reverse; + justify-content: space-between; +} + +.sfwd_help_text_link img { + /*width: 40px;*/ + width: 30px; + height: 30px; + float: left; +} + +.sfwd_label { + color: #5f5f5f; + font-weight: 700; + line-height: 19px; + width: 60%; + float: right; + margin: 0; + flex: 1; +} + +.sfwd_help_text_div { + text-align: left; + width: 100%; + margin: 10px 0 10px 0; +} + +.sfwd_help_text { + font-size: 12px; + float: left; + clear: left; + color: #797979; + line-height: 15px; + font-style: italic; + font-weight: lighter; + margin-right: 30px; +} + +.sfwd_head_tagline { + color: #5f5f5f; + font-size: 13px; +} + +.sfwd_head_nav { + float: left; + font-size: 18px; + margin: 0 0 16px 0; + font-family: HelveticaNeue-Light, "Helvetica Neue Light", "Helvetica Neue", sans-serif; + border-bottom: 1px solid #ccc; + width: 100%; +} + +.sfwd_head_nav_tab { + padding: 10px 15px 10px 15px; + margin: 0 0 0 15px; + border-width: 1px 1px 0; + border-radius: 4px 4px 0 0; + border-style: solid; + border-color: #ccc #ccc #fff; + float: left; + opacity: 0.5; + color: #000; + text-shadow: #fff 0 1px 0; + text-decoration: none; +} + +.sfwd_head_nav_tab.sfwd_head_nav_active { + opacity: 1; + margin-bottom: -1px; + border-width: 1px; +} + +.sfwd_head_nav_tab:first-child { + margin-left: 0; +} + +.sfwd_head_nav_tab:hover { + opacity: 1; +} + +.sfwd_header { + float: left; + clear: left; +} + +.sfwd_advert { + padding: 10px; + margin-bottom: 20px; + border: 1px solid #ddd; + height: 200px; + width: 423px; +} + +.sfwd_adverts { + float: right; +} + +.sfwd_content { + min-width: 760px; + clear: left; +} + +.sfwd_options_wrapper .hndle { + font-size: 15px; + font-family: Georgia, "Times New Roman", "Bitstream Charter", Times, serif; + font-weight: 400; + padding: 7px 10px; + margin: 0; + line-height: 1; +} + +#sfp_feature_manager_metabox.postbox { + float: left; +} + +.sfwd_advert p { + margin: 25px 0 25px 0; +} + +.widget, +#widget-list .widget-top, +.postbox, +#titlediv, +.sfwd_options_wrapper .postarea, +.stuffbox { + border-color: #dfdfdf; + box-shadow: inset 0 1px 0 #fff; + border-radius: 3px; +} + +.sfwd_advert h3 { + padding: 0; + margin-top: 6px; +} + +.sfwd_metabox_text p { + margin: 0 0 0 0; + width: 101%; +} + +.sfwd_sidebar { + width: 457px; + margin-left: 10px; +} + +.sfwd_metabox_text { + margin-bottom: 0; +} + +.sfwd_metabox_wrapper { + padding: 0; +} + +.sfwd_metabox_text *:last-child { + margin: 0; +} + +.sfwd_metabox_feature { + margin-top: 20px; +} + +.sfwd_option_label { + float: left; + /* margin: 0px 0 10px 5px; */ + margin: 5px; + width: 38%; + min-width: 210px; + max-width: 300px; + text-align: right; + vertical-align: top; + color: #5f5f5f !important; +} + +.sfwd_metabox_text h2 { + font-size: 14px; + padding: 0; + font-weight: 700; + line-height: 29px; +} + +#sfwd-about .sfwd_metabox_text #mc-embedded-subscribe-form h2 { + font-size: 13px; +} + +.sfwd input[readonly] { + background-color: #eee; + margin: 5px 0 5px 0 !important; +} + +.sfwd_settings_left { + float: left; + padding: 0; + margin: 0 0 0 0; + width: 100%; +} + +.sfwd_right_sidebar { + float: right; +} + +.sfwd_options { + width: 100%; + margin: 18px 0 10px 0; +} + +.sfwd_input { + clear: left; + width: 100%; + padding: 5px; +} + +.sfwd_option_input { + float: left; + width: 58%; + margin: 5px; + /* padding-left: 10px; */ + min-width: 320px; + max-width: 900px; +} + +#side-sortables .sfwd_option_input { + min-width: 220px; + max-width: 220px; +} + +.sfwd_top_label .sfwd_option_input, +.sfwd_no_label .sfwd_option_input { + width: 100%; +} + +.sfwd_settings_left .postbox { + float: left; + width: 100%; +} + +.sfwd_option_setting_label { + float: left; + min-width: 125px; + min-height: 35px; + width: 25%; + max-width: 175px; +} + +.sfwd_settings_left .postbox .inside { + padding: 0; + margin: 0; +} + +#sfwd_opengraph_settings { + width: 100%; +} + +.sfwd_no_label { + float: left; + width: 92%; + margin: 0 23px 20px 13px; +} + +.sfwd_top_label { + width: 96%; + margin: 0 10px; +} + +.sfwd_hidden_type { + margin: 0; + padding: 0; + height: 0; +} + +.sfwd_module.error.below-h2 { + padding: 5px 0; + margin: 0 477px 15px 0 !important; +} + +.sfwd_input input[type=checkbox], +.sfwd_input input[type=radio] { + vertical-align: text-bottom; +} + +#sfp { + width: 100%; +} + +.sfwd_input.sfwd_top_label .sfwd_option_input { + margin: 0 0 10px 0; +} + +.sfwd_error_notice { + font-size: 15px; + font-style: italic; + color: #5f5f5f; +} + +#sfwd-courses_course_price_billing_cycle select { + margin-top: -4px; + height: 35px; +} + +#sfwd-courses_course_price_billing_cycle input { + width: 40px; +} + +.sfwd_help_text ul { + margin: 15px 0 0 20px; +} + +.sfwd_help_text ul li { + line-height: 20px; + margin: 0; +} + +.sfwd_sidebar #side-sortables { + width: 98%; +} + +.sfwd_header_tabs li { + display: inline; + padding: 0; + margin: 0; +} + +.sfwd_header_tabs { + margin: 0; +} + +.sfwd_header_nav { + margin: 0; +} + +.sfwd_header_tabs li a.sfwd_header_tab.active { + background-color: rgb(255, 255, 255); + background-color: rgba(255, 255, 255, 0.75); +} + +.sfwd_header_tabs li a.sfwd_header_tab { + color: #464646; + font-size: 15px; + text-decoration: none; + border: solid 1px #ccc; + border-left: none; + margin: 0; + padding: 6px 6px 1px 6px; +} + +.sfwd_header_tabs li:first-child a.sfwd_header_tab { + border-left: solid 1px #ccc; +} + +.sfwd_tab { + border: solid 1px #ccc; + background-color: rgb(255, 255, 255); + background-color: rgba(255, 255, 255, 0.5); +} + +.wrap > h2 { + padding-bottom: 14px; +} + +#learndash_group_users_search { + display: none; +} + +table.learndash-group-users-select { + width: 100%; +} + +table.learndash-group-users-select td.td_learndash_group_users_search { + width: 45%; +} + +table.learndash-group-users-select td.td_learndash_group_users_search select { + min-width: 100%; + height: 150px; +} + +/** + * Hide the 'Add New' button on the Assignment + * and Submitted Essays list tables + */ +body.post-type-sfwd-assignment .ld-global-header .global-new-entity-button, +body.post-type-sfwd-essays .ld-global-header .global-new-entity-button, +body.post-type-sfwd-transactions .ld-global-header .global-new-entity-button { + display: none; +} + +/* Styles for the Support tab table output */ +table#learndash-data-reports, +table#learndash-data-upgrades { + border: 0; +} + +.learndash-data-reports-status, +.learndash-data-upgrades-status { + width: 100%; +} + +.learndash-data-reports-status .progress-meter, +.learndash-data-upgrades-status .progress-meter { + width: 100%; + height: 20px; + border: 1px solid #000; +} + +.learndash-data-reports-status .progress-meter .progress-meter-image, +.learndash-data-upgrades-status .progress-meter .progress-meter-image { + background-color: #0f0; + float: left; + height: 16px; + width: 0; + margin: 2px 0; +} + +.sfwd_input .sfwd_option_div select[multiple] { + width: 100%; + min-height: 100px; +} + +table.learndash-support-settings tbody th { + text-align: left; + vertical-align: top; + padding: 5px 0 5px 15px; +} + +.learndash-settings-page-wrap div.sfwd_options { + padding-bottom: 30px; +} + +.learndash_shortcodes_section .learndash_required_field { + color: #f00; +} + +.sfwd_input.learndash-settings-field-error { + background-color: #ffdfe0; + border-bottom: 1px solid #c89797; + border-top: 1px solid #c89797; +} + +.sfwd_input p.ld-clear { + height: 0; + clear: left; + padding: 0; +} + +.edit-post-header__settings .components-popover__content a:hover { + color: #007cba; +} + +/* learndash-admin-settings-page.css */ +.learndash-settings-page-wrap .error, +.learndash-settings-page-wrap .error a { + color: #f00; +} + +a.learndash-description-link { + color: #000; + text-decoration: none; +} + +span.learndash-description { + display: none; +} + +.sfwd_options .sfwd_input p.ld-clear { + margin: 0; + line-height: 0; +} + +.sfwd_options .ld-setting-field-sub { + padding-top: 5px; +} + +.sfwd_options .ld-setting-field-sub input[type=button] { + margin-right: 5px; +} + +.ld-metabox-description p { + margin: 5px 0 0 0; + color: #666; + font-weight: 400; + font-style: italic; +} + +.sfwd_options .sfwd_option_label .descripton { + clear: both; + display: block; + float: left; + font-weight: 400; + text-align: left; +} + +.sfwd_options .ld-settings-sub-level-1 .sfwd_input { + margin-left: 10px; + padding-left: 10px; + position: relative; + border-left: 1px solid #ccc; +} + +.sfwd_options .ld-settings-sub-level-1 .ld-settings-sub-level-2 { + margin-left: 10px; + padding-left: 5px; + border-left: 1px solid #ccc; +} + +.sfwd_options .ld-settings-sub-level-1 .ld-settings-sub-level-2 .sfwd_input .sfwd_option_label { + /* max-width: 279px; */ + width: calc(38% - 1px); + max-width: 290px; +} + +.sfwd_options .ld-settings-inner .sfwd_input { + margin-left: 25px; + padding-left: 20px; + border-left: 1px solid #ccc; +} + +/* +.sfwd_options .ld-settings-inner .sfwd_input:first-child:nth-last-child(1) { + border-left: 0px; +} +*/ +.sfwd_options .ld-settings-inner .sfwd_input .sfwd_option_label { + margin-right: 0; + margin-left: 0; + padding-right: 0; + width: 30%; + min-width: none; + max-width: none; +} + +.sfwd_options .ld-settings-inner .sfwd_input .sfwd_option_label.sfwd_option_label_full, +.sfwd_options .sfwd_input .sfwd_option_label.sfwd_option_label_full { + width: 100%; +} + +.sfwd_options .ld-settings-inner .sfwd_input .sfwd_option_input { + width: 65%; + min-width: 120px; + max-width: none; +} + +.sfwd_options .ld-settings-inner .sfwd_input .sfwd_option_input.sfwd_option_input_full, +.sfwd_options .sfwd_option_input.sfwd_option_input_full { + width: 100%; +} + +.sfwd_options .sfwd_input_type_quiz-custom-fields .sfwd_option_input.sfwd_option_input_full { + float: none; +} + +/* Settings Fields CSS */ +/* Switch toggle CSS */ +.sfwd_options .ld-switch-wrapper { + display: flex; + margin-top: 5px; +} + +.sfwd_options .ld-switch { + margin-right: 16px; + position: relative; +} + +.sfwd_options .ld-switch__input { + border: none; + height: 100%; + left: 0; + margin: 0; + opacity: 0; + padding: 0; + position: absolute; + top: 0; + width: 100%; + z-index: 1; +} + +.sfwd_options .ld-switch__track { + background-color: #fff; + border-radius: 9px; + border: 2px solid #6c7781; + box-sizing: border-box; + content: ""; + display: inline-block; + height: 18px; + transition: 0.2s background ease, 0.2s border ease; + vertical-align: top; + width: 36px; +} + +.sfwd_options .ld-switch__thumb { + background-color: #6c7781; + border-radius: 50%; + border: 5px solid #6c7781; + box-sizing: border-box; + display: block; + height: 10px; + left: 4px; + position: absolute; + top: 4px; + transition: 0.1s transform ease; + width: 10px; +} + +.sfwd_options .ld-switch__on-off { + border-radius: 100%; + border: 2px solid #6c7781; + box-sizing: border-box; + display: block; + height: 6px; + position: absolute; + right: 6px; + top: 6px; + width: 6px; +} + +.sfwd_options .ld-switch__input:checked ~ .ld-switch__track { + background-color: #11a0d2; + border-color: #11a0d2; +} + +.sfwd_options .ld-switch__input:checked ~ .ld-switch__thumb { + background-color: #fff; + border-width: 0; + transform: translateX(18px); +} + +.sfwd_options .ld-switch__input:checked ~ .ld-switch__on-off { + background-color: #fff; + border-radius: 0; + border: 0; + height: 6px; + left: 8px; + right: auto; + width: 2px; +} + +.sfwd_options .ld-switch__input:focus ~ .ld-switch__track { + box-shadow: 0 0 0 2px #fff, 0 0 0 3px #6c7781; + outline-offset: 2px; + outline: 2px solid transparent; +} + +.sfwd_options .ld-switch__input:hover ~ .ld-switch__track { + border-color: #11a0d2; +} + +.sfwd_options .ld-switch__input:checked:hover ~ .ld-switch__track { + background-color: #6c7781; + border-color: #6c7781; +} + +.sfwd_options .ld-switch.-disabled ~ label, +.sfwd_options .ld-switch__input[disabled=disabled] { + pointer-events: none; +} + +.sfwd_options .ld-switch__input[disabled=disabled] { + opacity: 0 !important; +} + +.sfwd_options .ld-switch__input[disabled=disabled] ~ .ld-switch__track { + opacity: 0.5; +} + +/* Radio CSS*/ +.sfwd_options .ld-radio-input { + border: 0; + clip-path: inset(50%); + clip: rect(1px, 1px, 1px, 1px); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; + word-wrap: normal !important; +} + +.sfwd_options .ld-radio-input__label { + margin-right: 16px; +} + +.sfwd_options .ld-radio-input__label::before { + border-radius: 100%; + border: 2px solid #6c7781; + box-sizing: border-box; + content: ""; + display: inline-block; + height: 16px; + margin-right: 10px; + vertical-align: middle; + width: 16px; +} + +.sfwd_options .ld-radio-input__label > span { + vertical-align: middle; + font-weight: 700; + color: #5f5f5f; +} + +.sfwd_options .ld-radio-input:checked + .ld-radio-input__label::before { + background-color: #11a0d2; + box-shadow: inset 0 0 0 2px #fff; +} + +.sfwd_options .ld-radio-input:checked:focus + .ld-radio-input__label::before { + box-shadow: inset 0 0 0 2px #fff, 0 0 0 2px #fff, 0 0 0 3px #6c7781; +} + +.sfwd_options .ld-radio-input:focus + .ld-radio-input__label::before { + box-shadow: 0 0 0 2px #fff, 0 0 0 3px #6c7781; + outline-offset: 2px; + outline: 2px solid transparent; +} + +.sfwd_options .ld-radio-input:hover + .ld-radio-input__label::before { + border-color: #11a0d2; +} + +.sfwd_options .ld-radio-input[disabled=disabled], +.sfwd_options .ld-radio-input[disabled=disabled] + .ld-radio-input__label { + pointer-events: none; +} + +.sfwd_options .ld-radio-input[disabled=disabled] + .ld-radio-input__label::before { + opacity: 0.5; +} + +.sfwd_options .ld-radio-description { + color: #666; + padding-left: 25px; +} + +/* Checkbox CSS*/ +.sfwd_options .ld-checkbox-input { + border: 0; + clip-path: inset(50%); + clip: rect(1px, 1px, 1px, 1px); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; + word-wrap: normal !important; +} + +.sfwd_options .ld-checkbox-input__label { + margin-right: 16px; +} + +.sfwd_options .ld-checkbox-input__label::before { + border: 2px solid #6c7781; + box-sizing: border-box; + content: ""; + display: inline-block; + height: 16px; + margin-right: 10px; + vertical-align: middle; + width: 16px; +} + +.sfwd_options .ld-checkbox-input__label > span { + vertical-align: middle; +} + +.sfwd_options .ld-checkbox-input:checked + .ld-checkbox-input__label::before { + align-items: center; + color: #11a0d2; + content: "✓"; + display: inline-flex; + justify-content: center; + font-weight: 900; +} + +.sfwd_options .ld-checkbox-input:focus + .ld-checkbox-input__label::before { + box-shadow: 0 0 0 2px #fff, 0 0 0 3px #6c7781; + outline-offset: 2px; + outline: 2px solid transparent; +} + +.sfwd_options .ld-checkbox-input:hover + .ld-checkbox-input__label::before { + border-color: #11a0d2; +} + +.sfwd_options .ld-checkbox-input[disabled=disabled], +.sfwd_options .ld-checkbox-input[disabled=disabled] + .ld-checkbox-input__label { + pointer-events: none; +} + +.sfwd_options .ld-checkbox-input[disabled=disabled] + .ld-checkbox-input__label::before { + opacity: 0.5; +} + +.sfwd_options .sfwd_option_input p.learndash-section-field-checkbox-p { + margin: 3px 0 0 0; + padding: 0; +} + +/* Text Input CSS */ +.sfwd_options .learndash-section-field-text { + border-radius: 2px; + border: 1px solid #ddd; + box-shadow: none; + box-sizing: border-box; + font-size: 14px; + padding: 5px 7px; + width: 100%; +} + +.sfwd_options .learndash-section-field-number.-medium, +.sfwd_options .learndash-section-field-text.-medium, +.sfwd_options .learndash-section-field-url.-medium { + width: 50%; +} + +.sfwd_options .learndash-section-field-number.-small, +.sfwd_options .learndash-section-field-text.-small, +.sfwd_options .learndash-section-field-url.-small { + width: 100px; +} + +.sfwd_options .learndash-section-field-number:focus, +.sfwd_options .learndash-section-field-text:focus { + border-color: #11a0d2; + outline: 0; +} + +.sfwd_options .learndash-section-field-number:hover, +.sfwd_options .learndash-section-field-text:hover, +.sfwd_options .learndash-section-field-url:hover { + border-color: #999; +} + +.sfwd_options .learndash-section-field-number.full-text, +.sfwd_options .learndash-section-field-text.full-text, +.sfwd_options .learndash-section-field-url.full-text { + width: 100%; +} + +.sfwd_options span.learndash_settings_field_text_prefix.-medium { + width: 75%; + display: inline-block; + padding-top: 0; + padding-bottom: 0; + color: rgba(51, 51, 51, 0.5); +} + +.sfwd_options span.learndash_settings_field_text_prefix input[type=text] { + width: max-content; + border: 0; + padding-left: 0; + padding-bottom: 8px; +} + +/* Select CSS */ +.sfwd_options .ld-select { + background-color: #fff; + border-radius: 3px; + border: 1px solid #ccc; + display: inline-block; + overflow: hidden; + position: relative; + vertical-align: middle; + width: 100%; + max-width: 450px; +} + +.sfwd_options .ld-select::after { + border: 5px solid transparent; + border-bottom: 0; + border-top-color: #000; + content: ""; + height: 0; + pointer-events: none; + position: absolute; + right: 5px; + speak: none; + top: 50%; + transform: translate(0, -50%); + width: 0; +} + +.sfwd_options .ld-select-multiple::after, +.sfwd_options .ld-select2::after { + border: none; +} + +.select2-container--learndash .select2-selection--single .select2-selection__rendered { + color: #72777c !important; +} + +.select2-container--learndash .select2-results__option--highlighted[aria-selected] { + background-color: #11a0d2 !important; +} + +.sfwd_options .ld-select-multiple.ld-select2 .select2-container .select2-selection__rendered > *:first-child.select2-search--inline { + width: 100% !important; +} + +.sfwd_options .ld-select-multiple.ld-select2 .select2-container .select2-selection__rendered > *:first-child.select2-search--inline .select2-search__field { + width: 100% !important; +} + +.sfwd_options .ld-select-multiple.ld-select2 .select2-container li { + margin-bottom: 0; +} + +.sfwd_options .select2-container .select2-search--inline .select2-search__field { + margin-top: 3px; + margin-bottom: 2px; +} + +.sfwd_options .ld-select select { + appearance: none; + background: none; + border: 0; + font-size: 14px; + height: 100%; + margin: 0; + padding: 5px 10px; + width: 100%; + max-width: 100%; + /* width: 110% \9; */ + z-index: 2; +} + +.sfwd_options .ld-select select:focus { + box-shadow: inset 0 0 0 1px #6c7781; +} + +.sfwd_options .ld-select select::-ms-expand { + display: none; +} + +.sfwd_options .ld-select select:-moz-focusring { + text-shadow: var(--select--focus-ring--text-shadow); +} + +.sfwd_options .ld-select select option { + border: 0; + width: 100%; +} + +.sfwd_options .ld-select2 .select2-container--learndash { + width: 100% !important; + max-width: 450px; + height: 100%; +} + +.sfwd_options .ld-select2 .select2-container--learndash .select2-selection--single { + padding-top: 3px; + padding-bottom: 3px; + height: 100%; + border: 0; +} + +.sfwd_options .ld-select2 .select2-container--learndash .select2-selection--single .select2-selection__arrow { + height: 100%; +} + +.sfwd_options .ld-select2 .select2-container--learndash .select2-selection--single .select2-selection__arrow b { + border-top-color: inherit; +} + +.sfwd_options .select2-container--learndash .select2-selection--multiple { + border: 0 solid #aaa !important; +} + +/* stylelint-disable-next-line no-duplicate-selectors */ +.sfwd_options .select2-container .select2-search--inline .select2-search__field { + padding-top: 5px !important; + color: #444 !important; +} + +/* Select2 Post Type listing selectors */ +body.edit-php .tablenav.top .select2-container--learndash, +body.users-php .tablenav.top .select2-container--learndash { + margin-right: 6px; + margin-left: 1px; + font-size: 14px; + line-height: 2; + border-color: #7e8993; + box-shadow: none; + border-radius: 3px; + min-height: 30px; + max-width: 25rem; + -webkit-appearance: none; + color: #32373c !important; + cursor: pointer; + vertical-align: middle; + float: left; +} + +body.edit-php .tablenav.top .select2-container--learndash .select2-selection--single, +body.users-php .tablenav.top .select2-container--learndash .select2-selection--single { + height: 30px; + box-shadow: 0 0 0 transparent; + border-radius: 4px; + border: 1px solid #7e8993; + background-color: #fff; + color: #32373c !important; + /* stylelint-disable-next-line max-line-length */ + /* stylelint-disable-next-line declaration-block-no-shorthand-property-overrides, function-url-quotes */ + background: #fff url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M5%206l5%205%205-5%202%201-7%207-7-7%202-1z%22%20fill%3D%22%23555%22%2F%3E%3C%2Fsvg%3E") no-repeat right 5px top 55%; + background-size: 16px 16px; +} + +body.edit-php .tablenav.top .select2-container--learndash .select2-selection--single .select2-selection__placeholder, +body.users-php .tablenav.top .select2-container--learndash .select2-selection--single .select2-selection__placeholder { + color: #32373c !important; +} + +/* Hide the default */ +body.edit-php .tablenav.top .select2-container--learndash .select2-selection--single .select2-selection__arrow, +body.users-php .tablenav.top .select2-container--learndash .select2-selection--single .select2-selection__arrow { + display: none; +} + +/* Settings Row CSS */ +.sfwd_options .sfwd_option_div p.ld-radio-input-wrapper { + margin-bottom: 1px; +} + +.sfwd_options .sfwd_input textarea { + color: #515151; + margin: 0; + font-size: 14px; + line-height: 25px; + width: 100%; +} + +.sfwd_options .sfwd_input > .sfwd_input:first-child { + margin-top: 20px; +} + +.sfwd_options .sfwd_option_input p { + margin-top: 0; +} + +.sfwd_options .sfwd_option_label { + box-sizing: border-box; + flex: 1 0 100%; + font-weight: 700; + margin-bottom: 10px; + padding-right: 0; /* 20px;*/ + /* position: relative; */ +} + +.sfwd_options .sfwd_option_input { + flex: 1 0 100%; + margin-bottom: 10px; +} + +.sfwd_options .sfwd_option_div select[multiple] { + width: 100%; + min-height: 100px; +} + +.sfwd_options .ld-settings-sub.ld-settings-sub-state-closed, +.sfwd_options .ld-settings-inner-state-closed, +.sfwd_options .ld-theme-settings-section-state-closed { + display: none; +} + +.sfwd_options .ld-settings-sub.ld-settings-sub-state-open, +.sfwd_options .ld-settings-inner-state-open .sfwd_options .ld-theme-settings-section-state-open { + display: block; +} + +.sfwd_options .ld-settings-sub-advanced .sfwd_input { + margin-left: 1px; + border-left: 1px solid #ccc; +} + +.sfwd_options .ld-settings-sub-advanced .ld-settings-sub-advanced-inner-state-closed { + display: none; +} + +.sfwd_options .ld-settings-sub-advanced .ld-settings-sub-advanced-inner-state-open { + display: block; +} + +.sfwd_options .ld-settings-sub-advanced .ld-settings-sub-advanced-inner .sfwd_option_label { + width: auto; +} + +.sfwd_options .ld-settings-sub-advanced .ld-settings-sub-advanced-inner .sfwd_option_input { + width: auto; +} + +.sfwd_options .tooltip { + position: relative; + display: inline-block; + opacity: 1; +} + +/* Tooltip text */ +.sfwd_options .tooltip .tooltiptext { + visibility: hidden; + width: 180px; + background-color: #11a0d2; + color: #fff; + text-align: center; + padding: 5px 0; + border-radius: 6px; + margin-left: -90px; /* Use half of the width (120/2 = 60), to center the tooltip */ + bottom: 100%; + left: 50%; + margin-bottom: 5px; + /* Position the tooltip text - see examples below! */ + position: absolute; + z-index: 1; +} + +/* Show the tooltip text when you mouse over the tooltip container */ +.sfwd_options .-disabled.tooltip:hover .tooltiptext { + visibility: visible; +} + +/* Tooltip top of element */ +/* Arrow */ +.sfwd_options .tooltip .tooltiptext::after { + content: " "; + position: absolute; + top: 100%; /* At the bottom of the tooltip */ + left: 50%; + margin-left: -5px; + border-width: 5px; + border-style: solid; + border-color: #11a0d2 transparent transparent transparent; +} + +/* Tooltip to right of element */ +/** + * Quiz Custom Fields style + */ +.sfwd_options .form_table_wrapper { + margin-top: 0; + padding: 0; + border: 0 solid #c2c2c2; +} + +.sfwd_options .form_table_wrapper table { + border-collapse: collapse; +} + +/* Line item CSS */ +.sfwd_options .form_table_wrapper #form_add { + background-color: transparent; + /* stylelint-disable-next-line function-url-quotes */ + background-image: url("data:image/svg+xml,%3Csvg width=%27256%27 height=%27256%27 viewBox=%270 0 256 256%27 xmlns=%27http://www.w3.org/2000/svg%27%3E%3Cpath fill=%27%23007cba%27 d=%27M185.066 128c0 3.534-2.866 6-6.4 6H134v44.666c0 3.534-2.467 6.399-6 6.399-3.534 0-6-2.865-6-6.399V134H77.332c-3.535 0-6.4-2.466-6.4-6s2.866-6 6.4-6H122V77.331c0-3.534 2.466-6.4 6-6.4 3.533 0 6 2.866 6 6.4V122h44.666c3.534 0 6.4 2.466 6.4 6zM256 128C256 57.42 198.58 0 128 0S0 57.42 0 128s57.42 128 128 128 128-57.42 128-128zm-12.8 0c0 63.521-51.679 115.2-115.2 115.2-63.522 0-115.2-51.679-115.2-115.2C12.8 64.478 64.478 12.8 128 12.8c63.521 0 115.2 51.678 115.2 115.2z%27 fill-rule=%27nonzero%27%3E%3C/path%3E%3C/svg%3E"); + background-position: center left 3px; + background-repeat: no-repeat; + background-size: 16px 16px; + border: 0; + color: #007cba; + cursor: pointer; + font-size: 14px; + font-weight: 700; + padding: 5px 10px 5px 30px; + box-shadow: none; +} + +.sfwd_options .form_table_wrapper #form_add:hover { + /* stylelint-disable-next-line function-url-quotes */ + background-image: url("data:image/svg+xml,%3Csvg width=%27256%27 height=%27256%27 viewBox=%270 0 256 256%27 xmlns=%27http://www.w3.org/2000/svg%27%3E%3Cpath fill=%27%2311a0d2%27 d=%27M185.066 128c0 3.534-2.866 6-6.4 6H134v44.666c0 3.534-2.467 6.399-6 6.399-3.534 0-6-2.865-6-6.399V134H77.332c-3.535 0-6.4-2.466-6.4-6s2.866-6 6.4-6H122V77.331c0-3.534 2.466-6.4 6-6.4 3.533 0 6 2.866 6 6.4V122h44.666c3.534 0 6.4 2.466 6.4 6zM256 128C256 57.42 198.58 0 128 0S0 57.42 0 128s57.42 128 128 128 128-57.42 128-128zm-12.8 0c0 63.521-51.679 115.2-115.2 115.2-63.522 0-115.2-51.679-115.2-115.2C12.8 64.478 64.478 12.8 128 12.8c63.521 0 115.2 51.678 115.2 115.2z%27 fill-rule=%27nonzero%27%3E%3C/path%3E%3C/svg%3E"); + color: #11a0d2; +} + +.sfwd_options .form_table_wrapper .form_move { + text-decoration: none; +} + +.sfwd_options .form_table_wrapper .form_delete { + background-color: transparent; + /* stylelint-disable-next-line function-url-quotes */ + background-image: url("data:image/svg+xml,%3Csvg aria-hidden=%27true%27 role=%27img%27 focusable=%27false%27 class=%27dashicon dashicons-dismiss%27 xmlns=%27http://www.w3.org/2000/svg%27 width=%2720%27 height=%2720%27 viewBox=%270 0 20 20%27%3E%3Cpath fill=%27%23a00%27 d=%27M10 2c4.42 0 8 3.58 8 8s-3.58 8-8 8-8-3.58-8-8 3.58-8 8-8zm5 11l-3-3 3-3-2-2-3 3-3-3-2 2 3 3-3 3 2 2 3-3 3 3z%27%3E%3C/path%3E%3C/svg%3E"); + background-position: center left 3px; + background-repeat: no-repeat; + border: 0; + color: #a00; + cursor: pointer; + font-weight: 700; + margin: 0; + opacity: 0; + padding: 5px 10px 5px 30px; + transition: opacity 0.1s; + visibility: hidden; +} + +.sfwd_options .form_table_wrapper .form_delete:hover { + color: #f00; +} + +.sfwd_options .form_table_wrapper tbody.ui-sortable tr:hover .form_delete { + opacity: 1; + visibility: visible; +} + +.sfwd_options .form_table_wrapper thead tr th, +.sfwd_options .form_table_wrapper tbody.ui-sortable tr td { + padding: 10px 5px; + transition: box-shadow 0.1s; +} + +.sfwd_options .form_table_wrapper tbody.ui-sortable tr:hover td { + box-shadow: 0 1px 0 0 #11a0d2, 0 -1px 0 0 #11a0d2; +} + +.sfwd_options .form_table_wrapper tbody.ui-sortable tr:hover td:first-of-type { + box-shadow: 0 1px 0 0 #11a0d2, 0 -1px 0 0 #11a0d2, -1px 0 0 0 #11a0d2; +} + +.sfwd_options .form_table_wrapper tbody.ui-sortable tr:hover td:last-of-type { + box-shadow: 0 1px 0 0 #11a0d2, 0 -1px 0 0 #11a0d2, 1px 0 0 0 #11a0d2; +} + +.sfwd_options .form_table_wrapper tbody.ui-sortable tr td:first-of-type { + text-align: center; +} + +.sfwd_options .form_table_wrapper .ld-select.-field select { + padding: 0 10px; +} + +.sfwd_options .form_table_wrapper #form_table thead th { + text-transform: uppercase; +} + +.sfwd_options .form_table_wrapper #form_add_wrapper { + margin-top: 10px; + margin-left: 10px; +} + +/** +Quiz Edit Result Text lists +*/ +#learndash-quiz-resultList ul#resultList { + width: 100%; +} + +#learndash-quiz-resultList ul#resultList li { + padding: 5px; + border: 1; + border: 1px dotted; +} + +#learndash-quiz-resultList ul#resultList li .resultHeader { + margin-bottom: 5px; + padding: 10px; + background-color: #ebebeb; /* rgb(207, 207, 207); */ +} + +#learndash-quiz-resultList input.addResult { + background-color: transparent; + /* stylelint-disable-next-line function-url-quotes */ + background-image: url("data:image/svg+xml,%3Csvg width=%27256%27 height=%27256%27 viewBox=%270 0 256 256%27 xmlns=%27http://www.w3.org/2000/svg%27%3E%3Cpath fill=%27%23007cba%27 d=%27M185.066 128c0 3.534-2.866 6-6.4 6H134v44.666c0 3.534-2.467 6.399-6 6.399-3.534 0-6-2.865-6-6.399V134H77.332c-3.535 0-6.4-2.466-6.4-6s2.866-6 6.4-6H122V77.331c0-3.534 2.466-6.4 6-6.4 3.533 0 6 2.866 6 6.4V122h44.666c3.534 0 6.4 2.466 6.4 6zM256 128C256 57.42 198.58 0 128 0S0 57.42 0 128s57.42 128 128 128 128-57.42 128-128zm-12.8 0c0 63.521-51.679 115.2-115.2 115.2-63.522 0-115.2-51.679-115.2-115.2C12.8 64.478 64.478 12.8 128 12.8c63.521 0 115.2 51.678 115.2 115.2z%27 fill-rule=%27nonzero%27%3E%3C/path%3E%3C/svg%3E"); + background-position: center left 3px; + background-repeat: no-repeat; + background-size: 16px 16px; + border: 0; + color: #007cba; + cursor: pointer; + font-size: 14px; + font-weight: 700; + padding: 5px 10px 5px 30px; +} + +#learndash-quiz-resultList ul#resultList li input.deleteResult { + float: right; + background-color: transparent; + /* stylelint-disable-next-line function-url-quotes */ + background-image: url("data:image/svg+xml,%3Csvg aria-hidden=%27true%27 role=%27img%27 focusable=%27false%27 class=%27dashicon dashicons-dismiss%27 xmlns=%27http://www.w3.org/2000/svg%27 width=%2720%27 height=%2720%27 viewBox=%270 0 20 20%27%3E%3Cpath fill=%27%23a00%27 d=%27M10 2c4.42 0 8 3.58 8 8s-3.58 8-8 8-8-3.58-8-8 3.58-8 8-8zm5 11l-3-3 3-3-2-2-3 3-3-3-2 2 3 3-3 3 2 2 3-3 3 3z%27%3E%3C/path%3E%3C/svg%3E"); + background-position: center left 3px; + background-repeat: no-repeat; + border: 0; + color: #a00; + cursor: pointer; + font-weight: 700; + margin: 0; + opacity: 0; + padding: 5px 10px 5px 30px; + transition: opacity 0.1s; + visibility: hidden; +} + +#learndash-quiz-resultList ul#resultList li:hover input.deleteResult { + opacity: 1; + visibility: visible; +} + +#learndash-quiz-resultList #resultList li .expand-arrow { + cursor: pointer; + margin-top: 3px; + float: right; +} + +#learndash-quiz-resultList #resultList li .expand-arrow-up svg { + transform: rotate(180deg); +} + +.sfwd_options .sfwd_option_label .descripton p { + margin-bottom: 0; +} + +.sfwd_options .sfwd_option_input_full { + margin-left: 0; + margin-right: 0; +} + +.learndash_navigation_questions_list ul.learndash-quiz-questions li a { + font-weight: 400; + text-decoration: none !important; +} + +.learndash_navigation_questions_list ul.learndash-quiz-questions li.ld-question-overview-widget-item-current a { + font-weight: 700; +} + +.learndash_navigation_questions_list .ld-question-overview-widget-add { + font-weight: 700; + text-decoration: none !important; +} + +.sfwd_options #learndash-quiz-admin-data-handling-settings_toplistDataAddBlock_field, +.sfwd_options #learndash-quiz-admin-data-handling-settings_associated_settings_field, +.sfwd_options #learndash-quiz-admin-data-handling-settings_emailNotification_field, +.sfwd_options #learndash-quiz-admin-data-handling-settings_timeLimitCookie_field, +.sfwd_options #learndash-quiz-admin-data-handling-settings_toplistDataShowIn_field, +.sfwd_options #learndash-quiz-admin-data-handling-settings_statisticsIpLock_field, +.sfwd_options #learndash-quiz-display-content-settings_showMaxQuestion_field, +.sfwd_options #learndash-quiz-display-content-settings_showMaxQuestionValue_field, +.sfwd_options #learndash-quiz-display-content-settings_quizModus_multiple_questionsPerPage_field, +.sfwd_options #learndash-quiz-results-options_resultText_field, +.sfwd_options #learndash-quiz-display-content-settings_quizModus_single_feedback_field { + border-left: none; + margin-left: 0; + padding-left: 0; +} + +.sfwd_options #learndash-course-access-settings_course_access_list_field, +.sfwd_options #learndash-course-display-content-settings_course_materials_field, +.sfwd_options #learndash-lesson-display-content-settings_lesson_materials_field, +.sfwd_options #learndash-topic-display-content-settings_topic_materials_field, +.sfwd_options #learndash-lesson-display-content-settings_lesson_assignment_points_amount_field, +.sfwd_options #learndash-topic-display-content-settings_lesson_assignment_points_amount_field, +.sfwd_options #learndash-quiz-display-content-settings_quiz_materials_field, +.sfwd_options #learndash-quiz-display-content-settings_showMaxQuestionValue_field, +.sfwd_options #learndash-quiz-display-content-settings_quizModus_single_back_button_field { + border-left: none; +} + +.sfwd_options #learndash-lesson-access-settings_visible_after_field, +.sfwd_options #learndash-lesson-access-settings_visible_after_specific_date_field, +.sfwd_options #learndash-quiz-display-content-settings_quizModus_single_back_button_field { + border-left: none; + /* padding-left: 5px; */ + padding-left: 0; +} + +.sfwd_options #learndash-quiz-results-options_resultText_field { + padding-left: 10px; +} + +.sfwd_options input[name=templateLoad], +.sfwd_options input[name=templateName] { + margin-top: 5px; +} + +.ld-settings-inner .ld-radio-input__label > span { + font-weight: 400; +} + +.ld-divider { + border-bottom: 1px solid #eee; + margin: 20px 0 20px 0; +} + +.sfwd_options .ld-settings-inner-lesson_video_display_timing_after .sfwd_option_input, +.sfwd_options .ld-settings-inner .sfwd_option_input { + width: 40% !important; +} + +.sfwd_options #learndash-lesson-access-settings_visible_after_specific_date_field .sfwd_option_input { + width: 80% !important; +} + +.sfwd_options .ld-settings-sub .sfwd_option_label { + width: calc(38% - 15px); + max-width: 285px; +} + +.sfwd_options #learndash-lesson-display-content-settings_assignment_upload_limit_count_field .sfwd_option_label, +.sfwd_options #learndash-lesson-display-content-settings_lesson_assignment_deletion_enabled_field .sfwd_option_label { + width: 35% !important; +} + +.sfwd_options #learndash-lesson-access-settings_visible_after_specific_date_field input[type=number] { + padding: 0 !important; +} + +.sfwd_options .ld-settings-inner-lesson_video_display_timing_after .sfwd_option_label { + width: 35% !important; +} + +.sfwd_options .ld-settings-inner-quizModus_single .sfwd_option_input { + width: 65% !important; +} + +.sfwd_options .ld-settings-email-header-wrapper { + margin-bottom: 30px; +} + +.sfwd_options .ld-settings-email-header { + font-weight: 700; +} + +.sfwd_options .ld-settings-email-description { + font-weight: 300; +} + +/* Add support for error display */ +.sfwd_options .learndash_settings_field_invalid label.sfwd_label { + color: #f00; +} + +.sfwd_options .learndash_settings_field_invalid input:invalid { + border: 1px solid #f00; + box-shadow: none; +} + +.sfwd_options .learndash_settings_field_invalid .learndash-section-field-error { + color: #f00; +} + +#learndash-settings-fields-notice-errors p.errors-header { + font-weight: 900; +} + +#learndash-settings-fields-notice-errors ul.errors-list { + list-style: disc; +} + +#learndash-settings-fields-notice-errors ul.errors-list li { + margin-left: 15px; +} + +/** + * Added to bring back the visible indicator on + * checkbox in Builder sidebar elements. + * + * See LEARNDASH-4114 + */ +.ld__builder-sidebar-widget .components-checkbox-control__input[type=checkbox]:checked::before { + /* stylelint-disable-next-line function-url-quotes */ + content: url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2020%2020%27%3E%3Cpath%20d%3D%27M14.83%204.89l1.34.94-5.81%208.38H9.02L5.78%209.67l1.34-1.25%202.57%202.4z%27%20fill%3D%27%231e8cbe%27%2F%3E%3C%2Fsvg%3E"); +} + +.plugin-update p.ld-plugin-update-notice::before { + content: ""; + margin-right: 0; +} + +.plugin-update .ld-plugin-update-notice, +.notice.ld-plugin-update-notice { + padding: 10px; + margin-top: 10px; +} + +.ld-plugin-update-notice .version { + font-weight: 700; +} + +.ld-plugin-update-notice .header { + font-size: 130%; + font-weight: 700; +} + +/** +Sections/Settings Info banners. +*/ +.ld_settings_postbox .ld-settings-info-banner { + display: block; + padding: 5px 10px 5px 10px; + margin: 5px 0; +} + +.ld_settings_postbox .ld-settings-info-banner p::before { + /* stylelint-disable-next-line font-family-no-missing-generic-family-keyword */ + font: 400 20px/1 dashicons; + float: left; +} + +.ld_settings_postbox .ld-settings-info-banner p { + margin: 0.5em 0; + padding: 0; + font-size: 13px; + /* stylelint-disable-next-line declaration-property-unit-allowed-list */ + line-height: 1.5em; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + vertical-align: top; +} + +.ld_settings_postbox .ld-settings-info-banner.ld-settings-info-banner-alert { + background-color: #fbeaea; + border-left-color: #dc3232; + border-left-width: 2px; + border-left-style: solid; +} + +.ld_settings_postbox .ld-settings-info-banner.ld-settings-info-banner-alert p::before { + color: #dc3232; + content: "\f534"; + margin-right: 6px; +} + +.ld_settings_postbox .ld-settings-info-banner.ld-settings-info-banner-success { + border-color: #46b450; + border-width: 0 0 1px 2px; + border-style: solid; +} + +/* LearnDash Settings Sub menu */ +ul.learndash-settings-sub { + float: none; +} + +ul.learndash-settings-sub li.learndash-settings-sub-current a { + font-weight: 700; +} + +/* LearnDash Settings Table general styles */ +table.learndash-settings-table th { + font-weight: 700; +} + +table.learndash-settings-table td.col-valign-middle { + vertical-align: middle; +} + +table.learndash-settings-table-sortable .ui-sortable-helper { + display: table; +} + +table.learndash-settings-table-sortable td.col-name-move { + cursor: grab; +} + +/** Settings for Group Attributes metabox */ +.edit-post-sidebar #learndash_group_attributes_metabox select#group_parent_id { + max-width: 85%; + width: 100%; +} + +#learndash_group_attributes_metabox input#group_menu_order { + display: block; +} + +.edit-post-sidebar #learndash_group_attributes_metabox .group-menu-order-label-wrapper { + margin-top: 10px; +} + +/** Styles for WordPress 5.5 changes */ +.ld_settings_postbox .postbox-header { + display: block; +} + +.edit-post-meta-boxes-area #poststuff .ld_settings_postbox .postbox-header .hndle, +.edit-post-meta-boxes-area #poststuff #learndash_course_builder .postbox-header .hndle, +.edit-post-meta-boxes-area #poststuff #learndash_quiz_builder .postbox-header .hndle { + border-bottom: none; + padding: 5px 12px; + width: auto; +} + +.ld_settings_postbox .postbox-header .hndle { + display: inline-block; +} + +.ld_settings_postbox .postbox-header .handle-actions { + display: inline-block; + float: right; +} + +.ld_settings_postbox .postbox-header .handle-actions .handle-order-lower, +.ld_settings_postbox .postbox-header .handle-actions .handle-order-higher, +body[data-active-tab=learndash_course_builder] .postbox-header .handle-actions .handle-order-lower, +body[data-active-tab=learndash_course_builder] .postbox-header .handle-actions .handle-order-higher, +body[data-active-tab=learndash_quiz_builder] .postbox-header .handle-actions .handle-order-lower, +body[data-active-tab=learndash_quiz_builder] .postbox-header .handle-actions .handle-order-higher { + display: none; +} + +.ld_settings_postbox .postbox-header .ld-metabox-description { + display: block; + padding: 0 12px 5px; +} + +#course-shortcodes.wrap .inside .dashicons, +#course-shortcodes.wrap .inside .dashicons-before::before, +#certificate-shortcodes.wrap .inside .dashicons, +#certificate-shortcodes.wrap .inside .dashicons-before::before { + text-decoration: none; +} + +/* Stripe Payments Settings */ +.sfwd_options .learndash-stripe-connect, +.notice.connect-stripe .learndash-stripe-connect { + align-items: center; + background: #6772e5; + border-radius: 5px; + color: #fff; + display: flex; + font-size: 16px; + justify-content: center; + letter-spacing: 0.6px; + padding: 6px 24px; + text-decoration: none; + transition: all 0.3s ease; + width: 200px; +} + +.sfwd_options .learndash-stripe-connect:active, +.learndash-stripe-connect:focus, +.learndash-stripe-connect:hover, +.notice.connect-stripe .learndash-stripe-connect:active, +.notice.connect-stripe .learndash-stripe-connect:focus, +.notice.connect-stripe .learndash-stripe-connect:hover { + background: #3f4ddf; + color: #fff; +} + +.sfwd_options .learndash-stripe-connect .stripe-logo, +.notice.connect-stripe .learndash-stripe-connect .stripe-logo { + padding: 2px 10px 0 0; +} + +/*# sourceMappingURL=meta-box.css.map*/ \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/meta-box.css.map b/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/meta-box.css.map new file mode 100644 index 000000000..422867812 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/meta-box.css.map @@ -0,0 +1 @@ +{"version":3,"file":"../css/meta-box.css","mappings":";;;AAAA,gBAAgB;AAAhB;;;;EAAA;AAMA;AACA;AACA;AAEA;EACC;AAAD;;AAGA;EACC;EACA;EACA;EACA;AAAD;;AAGA;EACC;EACA;AAAD;;AAGA;EACC;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;AADD;;AAIA;EAEC;EACA;EACA;EACA;AAFD;;AAKA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;AAFD;;AAKA;EACC;EACA;EACA;AAFD;;AAKA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAFD;;AAKA;EACC;EACA;AAFD;;AAKA;EACC;EACA;EACA;EACA;EACA;EACA;AAFD;;AAKA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAFD;;AAKA;EACC;EACA;EACA;AAFD;;AAKA;EACC;AAFD;;AAKA;EACC;AAFD;;AAKA;EACC;EACA;AAFD;;AAKA;EACC;EACA;EACA;EACA;EACA;AAFD;;AAKA;EACC;AAFD;;AAKA;EACC;EACA;AAFD;;AAKA;EACC;EACA;EACA;EACA;EACA;EACA;AAFD;;AAKA;EACC;AAFD;;AAKA;EACC;AAFD;;AAKA;;;;;;EAMC;EAGA;EAIA;AAFD;;AAKA;EACC;EACA;AAFD;;AAKA;EACC;EACA;AAFD;;AAKA;EACC;EACA;AAFD;;AAKA;EACC;AAFD;;AAKA;EACC;AAFD;;AAKA;EACC;AAFD;;AAKA;EACC;AAFD;;AAKA;EACC;EAEA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;AAJD;;AAOA;EACC;EACA;EACA;EACA;AAJD;;AAOA;EACC;AAJD;;AAOA;EACC;EACA;AAJD;;AAOA;EACC;EACA;EACA;EACA;AAJD;;AAOA;EACC;AAJD;;AAOA;EACC;EACA;AAJD;;AAOA;EACC;EACA;EACA;AAJD;;AAOA;EACC;EACA;EACA;EAEA;EACA;EACA;AALD;;AAQA;EACC;EACA;AALD;;AAQA;;EAEC;AALD;;AAQA;EACC;EACA;AALD;;AAQA;EACC;EACA;EACA;EACA;EACA;AALD;;AAQA;EACC;EACA;AALD;;AAQA;EACC;AALD;;AAQA;EACC;EACA;EACA;AALD;;AAQA;EACC;EACA;AALD;;AAQA;EACC;EACA;EACA;AALD;;AAQA;EACC;EACA;AALD;;AAQA;;EAEC;AALD;;AAQA;EACC;AALD;;AAQA;EACC;AALD;;AAQA;EACC;EACA;EACA;AALD;;AAQA;EACC;EACA;AALD;;AAQA;EACC;AALD;;AAQA;EACC;AALD;;AAQA;EACC;EACA;AALD;;AAQA;EACC;AALD;;AAQA;EACC;EACA;EACA;AALD;;AAQA;EACC;AALD;;AAQA;EACC;AALD;;AAQA;EACC;EACA;AALD;;AAQA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;AALD;;AAQA;EACC;AALD;;AAQA;EACC;EACA;EACA;AALD;;AAQA;EACC;AALD;;AAQA;EACC;AALD;;AASA;EACC;AAND;;AASA;EACC;AAND;;AASA;EACC;EACA;AAND;;AASA;;;EAAA;AAIA;;;EAGC;AAND;;AAUA;AAEA;;EAEC;AARD;;AAWA;;EAEC;AARD;;AAWA;;EAEC;EACA;EACA;AARD;;AAWA;;EAEC;EACA;EACA;EACA;EACA;AARD;;AAWA;EACC;EACA;AARD;;AAWA;EACC;EACA;EACA;AARD;;AAWA;EACC;AARD;;AAWA;EACC;AARD;;AAWA;EACC;EACA;EACA;AARD;;AAWA;EACC;EACA;EACA;AARD;;AAWA;EACC;AARD;;AAWA;AAEA;;EAEC;AATD;;AAYA;EACC;EACA;AATD;;AAYA;EACC;AATD;;AAYA;EACC;EACA;AATD;;AAYA;EACC;AATD;;AAYA;EACC;AATD;;AAYA;EACC;EACA;EACA;EACA;AATD;;AAYA;EACC;EACA;EACA;EACA;EACA;AATD;;AAYA;EACC;EACA;EACA;EACA;AATD;;AAYA;EACC;EACA;EACA;AATD;;AAYA;EAEC;EACA;EACA;AAVD;;AAaA;EACC;EACA;EACA;AAVD;;AAaA;;;;CAAA;AAKA;EACC;EACA;EACA;EACA;EACA;EACA;AAVD;;AAaA;;EAEC;AAVD;;AAaA;EACC;EACA;EACA;AAVD;;AAaA;;EAEC;AAVD;;AAaA;EACC;AAVD;;AAaA;AAEA;AAEA;EACC;EACA;AAZD;;AAeA;EACC;EACA;AAZD;;AAeA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAZD;;AAeA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAZD;;AAeA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAZD;;AAeA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAZD;;AAeA;EACC;EACA;AAZD;;AAeA;EACC;EACA;EACA;AAZD;;AAeA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;AAZD;;AAeA;EACC;EACA;EACA;AAZD;;AAeA;EACC;AAZD;;AAeA;EACC;EACA;AAZD;;AAeA;;EAEC;AAZD;;AAeA;EACC;AAZD;;AAeA;EACC;AAZD;;AAeA;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAbD;;AAgBA;EACC;AAbD;;AAgBA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAbD;;AAgBA;EACC;EACA;EACA;AAbD;;AAgBA;EACC;EACA;AAbD;;AAgBA;EACC;AAbD;;AAgBA;EACC;EACA;EACA;AAbD;;AAgBA;EACC;AAbD;;AAgBA;;EAEC;AAbD;;AAgBA;EACC;AAbD;;AAgBA;EACC;EACA;AAbD;;AAgBA;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAdD;;AAiBA;EACC;AAdD;;AAiBA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAdD;;AAiBA;EACC;AAdD;;AAiBA;EACC;EACA;EACA;EACA;EACA;EACA;AAdD;;AAiBA;EACC;EACA;EACA;AAdD;;AAiBA;EACC;AAdD;;AAiBA;;EAEC;AAdD;;AAiBA;EACC;AAdD;;AAiBA;EACC;EACA;AAdD;;AAiBA;AACA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;AAdD;;AAiBA;;;EAGC;AAdD;;AAiBA;;;EAGC;AAdD;;AAiBA;;EAEC;EACA;AAdD;;AAiBA;;;EAGC;AAdD;;AAiBA;;;EAGC;AAdD;;AAiBA;EACC;EACA;EACA;EACA;EACA;AAdD;;AAiBA;EACC;EACA;EACA;EACA;AAdD;;AAiBA;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAfD;;AAkBA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAfD;;AAkBA;;EAEC;AAfD;;AAkBA;EACC;AAfD;;AAkBA;EACC;AAfD;;AAkBA;EACC;AAfD;;AAkBA;EACC;AAfD;;AAkBA;EACC;AAfD;;AAkBA;EACC;EACA;AAfD;;AAkBA;EAGC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;AAhBD;;AAmBA;EACC;AAhBD;;AAmBA;EACC;AAhBD;;AAmBA;EACC;AAhBD;;AAmBA;EACC;EACA;AAhBD;;AAmBA;EACC;EACA;EACA;AAhBD;;AAmBA;EACC;EACA;EACA;EACA;AAhBD;;AAmBA;EACC;AAhBD;;AAmBA;EACC;AAhBD;;AAmBA;EACC;AAhBD;;AAmBA;AACA;EACC;EACA;AAhBD;;AAoBA;AACA;;EAEC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAjBD;;AAoBA;;EAEC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAjBD;;AAoBA;;EAEC;AAjBD;;AAoBA;AACA;;EAEC;AAjBD;;AAoBA;AAEA;EACC;AAlBD;;AAqBA;EACC;EAEA;EACA;EACA;EACA;AAnBD;;AAsBA;EACC;AAnBD;;AAsBA;EACC;AAnBD;;AAsBA;EACC;EACA;EACA;EACA;EACA;EAEA;AApBD;;AAuBA;EACC;EACA;AApBD;;AAuBA;EACC;EACA;AApBD;;AAuBA;;;EAGC;AApBD;;AAuBA;;EAGC;AArBD;;AAwBA;EACC;EACA;AArBD;;AAwBA;EACC;AArBD;;AAwBA;EACC;AArBD;;AAwBA;EACC;AArBD;;AAwBA;EACC;AArBD;;AAyBA;EACC;EACA;EACA;AAtBD;;AAyBA;AACA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;AAvBD;;AA0BA;AACA;EACC;AAvBD;;AA0BA;AAEA;AACA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAxBD;;AA4BA;AAEA;;EAAA;AAIA;EACC;EACA;EACA;AA3BD;;AA8BA;EACC;AA3BD;;AA8BA;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AA5BD;;AA+BA;EACC;EACA;EACA;AA5BD;;AA+BA;EACC;AA5BD;;AA+BA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AA5BD;;AA+BA;EACC;AA5BD;;AA+BA;EACC;EACA;AA5BD;;AA+BA;;EAEC;EACA;AA5BD;;AA+BA;EACC;AA5BD;;AA+BA;EACC;AA5BD;;AA+BA;EACC;AA5BD;;AA+BA;EACC;AA5BD;;AA+BA;EACC;AA5BD;;AA+BA;EACC;AA5BD;;AA+BA;EACC;EACA;AA5BD;;AAgCA;;CAAA;AAIA;EACC;AA9BD;;AAiCA;EAEC;EACA;EACA;AA/BD;;AAkCA;EAEC;EACA;EACA;AAhCD;;AAmCA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAhCD;;AAmCA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAhCD;;AAmCA;EACC;EACA;AAhCD;;AAmCA;EACC;EACA;EACA;AAhCD;;AAmCA;EACC;AAhCD;;AAmCA;EACC;AAhCD;;AAmCA;EACC;EACA;AAhCD;;AAoCA;EACC;EACA;AAjCD;;AAoCA;EACC;AAjCD;;AAoCA;EACC;EACA;AAjCD;;AAoCA;;;;;;;;;;;EAWC;EACA;EACA;AAjCD;;AAoCA;;;;;;;;;EASC;AAjCD;;AAoCA;;;EAGC;EAEA;EACA;AAlCD;;AAqCA;EACC;AAlCD;;AAqCA;;EAEC;AAlCD;;AAqCA;EACC;AAlCD;;AAqCA;EACC;EACA;AAlCD;;AAqCA;;EAEC;AAlCD;;AAqCA;EACC;AAlCD;;AAqCA;EACC;EACA;AAlCD;;AAqCA;;EAEC;AAlCD;;AAqCA;EACC;AAlCD;;AAqCA;EACC;AAlCD;;AAqCA;EACC;AAlCD;;AAqCA;EACC;AAlCD;;AAqCA;EACC;AAlCD;;AAqCA;EACC;AAlCD;;AAqCA;AACA;EACC;AAlCD;;AAqCA;EACC;EACA;AAlCD;;AAqCA;EACC;AAlCD;;AAqCA;EACC;AAlCD;;AAqCA;EACC;AAlCD;;AAqCA;EACC;AAlCD;;AAqCA;;;;;EAAA;AAMA;EACC;EACA;AAlCD;;AAqCA;EACC;EACA;AAlCD;;AAqCA;;EAEC;EACA;AAlCD;;AAqCA;EACC;AAlCD;;AAqCA;EACC;EACA;AAlCD;;AAqCA;;CAAA;AAGA;EACC;EACA;EACA;AAlCD;;AAqCA;EACC;EACA;EACA;AAlCD;;AAqCA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAlCD;;AAqCA;EACC;EACA;EACA;EACA;AAlCD;;AAqCA;EACC;EACA;EACA;AAlCD;;AAqCA;EACC;EACA;EACA;AAlCD;;AAqCA;AACA;EACC;AAlCD;;AAqCA;EACC;AAlCD;;AAqCA;AACA;EACC;AAlCD;;AAqCA;EACC;AAlCD;;AAqCA;EACC;AAlCD;;AAqCA;EACC;AAlCD;;AAqCA;AAEA;EACC;EACA;AAnCD;;AAsCA;EACC;AAnCD;;AAsCA;EACC;AAnCD;;AAsCA;AACA;EACC;AAnCD;;AAsCA;;;EAGC;EACA;EACA;AAnCD;;AAsCA;EACC;AAnCD;;AAsCA;EACC;EACA;AAnCD;;AAsCA;;;;;;EAMC;AAnCD;;AAsCA;EACC;EACA;AAnCD;;AAsCA;;;;EAIC;AAnCD;;AAsCA;AAEA;;EAEC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AApCD;;AAuCA;;;;;;EAMC;EACA;AApCD;;AAuCA;;EAEC;AApCD,C","sources":["webpack://learndash-course-grid/./src/assets/scss/meta-box.scss"],"sourcesContent":["/**\n * Course Grid Meta Box SCSS.\n *\n * cSpell:ignore descripton csvg fwww fsvg cpath\n */\n\n/* stylelint-disable no-descending-specificity */\n/* stylelint-disable selector-class-pattern */\n/* stylelint-disable selector-id-pattern */\n\n.form-table.sfwd {\n\tclear: none;\n}\n\n.form-table.sfwd td {\n\tvertical-align: top;\n\tpadding: 16px 0 10px 0;\n\tline-height: 20px;\n\tfont-size: 12px;\n}\n\n.form-table.sfwd th {\n\twidth: 200px;\n\tpadding: 10px 0 12px 9px;\n}\n\n.sfwd_help_text_link {\n\ttext-align: left;\n\tfloat: left;\n\twidth: 100%;\n\tmax-width: 300px;\n\n\t/* 10up-added */\n\talign-items: center;\n\tdisplay: flex;\n\tflex-direction: row-reverse;\n\tjustify-content: space-between;\n}\n\n.sfwd_help_text_link img {\n\n\t/*width: 40px;*/\n\twidth: 30px;\n\theight: 30px;\n\tfloat: left;\n}\n\n.sfwd_label {\n\tcolor: #5f5f5f;\n\tfont-weight: 700;\n\tline-height: 19px;\n\twidth: 60%;\n\tfloat: right;\n\tmargin: 0;\n\tflex: 1;\n}\n\n.sfwd_help_text_div {\n\ttext-align: left;\n\twidth: 100%;\n\tmargin: 10px 0 10px 0;\n}\n\n.sfwd_help_text {\n\tfont-size: 12px;\n\tfloat: left;\n\tclear: left;\n\tcolor: #797979;\n\tline-height: 15px;\n\tfont-style: italic;\n\tfont-weight: lighter;\n\tmargin-right: 30px;\n}\n\n.sfwd_head_tagline {\n\tcolor: #5f5f5f;\n\tfont-size: 13px;\n}\n\n.sfwd_head_nav {\n\tfloat: left;\n\tfont-size: 18px;\n\tmargin: 0 0 16px 0;\n\tfont-family: HelveticaNeue-Light, \"Helvetica Neue Light\", \"Helvetica Neue\", sans-serif;\n\tborder-bottom: 1px solid #ccc;\n\twidth: 100%;\n}\n\n.sfwd_head_nav_tab {\n\tpadding: 10px 15px 10px 15px;\n\tmargin: 0 0 0 15px;\n\tborder-width: 1px 1px 0;\n\tborder-radius: 4px 4px 0 0;\n\tborder-style: solid;\n\tborder-color: #ccc #ccc #fff;\n\tfloat: left;\n\topacity: 0.5;\n\tcolor: #000;\n\ttext-shadow: #fff 0 1px 0;\n\ttext-decoration: none;\n}\n\n.sfwd_head_nav_tab.sfwd_head_nav_active {\n\topacity: 1;\n\tmargin-bottom: -1px;\n\tborder-width: 1px;\n}\n\n.sfwd_head_nav_tab:first-child {\n\tmargin-left: 0;\n}\n\n.sfwd_head_nav_tab:hover {\n\topacity: 1;\n}\n\n.sfwd_header {\n\tfloat: left;\n\tclear: left;\n}\n\n.sfwd_advert {\n\tpadding: 10px;\n\tmargin-bottom: 20px;\n\tborder: 1px solid #ddd;\n\theight: 200px;\n\twidth: 423px;\n}\n\n.sfwd_adverts {\n\tfloat: right;\n}\n\n.sfwd_content {\n\tmin-width: 760px;\n\tclear: left;\n}\n\n.sfwd_options_wrapper .hndle {\n\tfont-size: 15px;\n\tfont-family: Georgia, \"Times New Roman\", \"Bitstream Charter\", Times, serif;\n\tfont-weight: 400;\n\tpadding: 7px 10px;\n\tmargin: 0;\n\tline-height: 1;\n}\n\n#sfp_feature_manager_metabox.postbox {\n\tfloat: left;\n}\n\n.sfwd_advert p {\n\tmargin: 25px 0 25px 0;\n}\n\n.widget,\n#widget-list .widget-top,\n.postbox,\n#titlediv,\n.sfwd_options_wrapper .postarea,\n.stuffbox {\n\tborder-color: #dfdfdf;\n\t-moz-box-shadow: inset 0 1px 0 #fff;\n\t-webkit-box-shadow: inset 0 1px 0 #fff;\n\tbox-shadow: inset 0 1px 0 #fff;\n\t-moz-border-radius: 3px;\n\t-khtml-border-radius: 3px;\n\t-webkit-border-radius: 3px;\n\tborder-radius: 3px;\n}\n\n.sfwd_advert h3 {\n\tpadding: 0;\n\tmargin-top: 6px;\n}\n\n.sfwd_metabox_text p {\n\tmargin: 0 0 0 0;\n\twidth: 101%;\n}\n\n.sfwd_sidebar {\n\twidth: 457px;\n\tmargin-left: 10px;\n}\n\n.sfwd_metabox_text {\n\tmargin-bottom: 0;\n}\n\n.sfwd_metabox_wrapper {\n\tpadding: 0;\n}\n\n.sfwd_metabox_text *:last-child {\n\tmargin: 0;\n}\n\n.sfwd_metabox_feature {\n\tmargin-top: 20px;\n}\n\n.sfwd_option_label {\n\tfloat: left;\n\n\t/* margin: 0px 0 10px 5px; */\n\tmargin: 5px;\n\twidth: 38%;\n\tmin-width: 210px;\n\tmax-width: 300px;\n\n\ttext-align: right;\n\tvertical-align: top;\n\tcolor: #5f5f5f !important;\n}\n\n.sfwd_metabox_text h2 {\n\tfont-size: 14px;\n\tpadding: 0;\n\tfont-weight: 700;\n\tline-height: 29px;\n}\n\n#sfwd-about .sfwd_metabox_text #mc-embedded-subscribe-form h2 {\n\tfont-size: 13px;\n}\n\n.sfwd input[readonly] {\n\tbackground-color: #eee;\n\tmargin: 5px 0 5px 0 !important;\n}\n\n.sfwd_settings_left {\n\tfloat: left;\n\tpadding: 0;\n\tmargin: 0 0 0 0;\n\twidth: 100%;\n}\n\n.sfwd_right_sidebar {\n\tfloat: right;\n}\n\n.sfwd_options {\n\twidth: 100%;\n\tmargin: 18px 0 10px 0;\n}\n\n.sfwd_input {\n\tclear: left;\n\twidth: 100%;\n\tpadding: 5px;\n}\n\n.sfwd_option_input {\n\tfloat: left;\n\twidth: 58%;\n\tmargin: 5px;\n\n\t/* padding-left: 10px; */\n\tmin-width: 320px;\n\tmax-width: 900px;\n}\n\n#side-sortables .sfwd_option_input {\n\tmin-width: 220px;\n\tmax-width: 220px;\n}\n\n.sfwd_top_label .sfwd_option_input,\n.sfwd_no_label .sfwd_option_input {\n\twidth: 100%;\n}\n\n.sfwd_settings_left .postbox {\n\tfloat: left;\n\twidth: 100%;\n}\n\n.sfwd_option_setting_label {\n\tfloat: left;\n\tmin-width: 125px;\n\tmin-height: 35px;\n\twidth: 25%;\n\tmax-width: 175px;\n}\n\n.sfwd_settings_left .postbox .inside {\n\tpadding: 0;\n\tmargin: 0;\n}\n\n#sfwd_opengraph_settings {\n\twidth: 100%;\n}\n\n.sfwd_no_label {\n\tfloat: left;\n\twidth: 92%;\n\tmargin: 0 23px 20px 13px;\n}\n\n.sfwd_top_label {\n\twidth: 96%;\n\tmargin: 0 10px;\n}\n\n.sfwd_hidden_type {\n\tmargin: 0;\n\tpadding: 0;\n\theight: 0;\n}\n\n.sfwd_module.error.below-h2 {\n\tpadding: 5px 0;\n\tmargin: 0 477px 15px 0 !important;\n}\n\n.sfwd_input input[type=\"checkbox\"],\n.sfwd_input input[type=\"radio\"] {\n\tvertical-align: text-bottom;\n}\n\n#sfp {\n\twidth: 100%;\n}\n\n.sfwd_input.sfwd_top_label .sfwd_option_input {\n\tmargin: 0 0 10px 0;\n}\n\n.sfwd_error_notice {\n\tfont-size: 15px;\n\tfont-style: italic;\n\tcolor: #5f5f5f;\n}\n\n#sfwd-courses_course_price_billing_cycle select {\n\tmargin-top: -4px;\n\theight: 35px;\n}\n\n#sfwd-courses_course_price_billing_cycle input {\n\twidth: 40px;\n}\n\n.sfwd_help_text ul {\n\tmargin: 15px 0 0 20px;\n}\n\n.sfwd_help_text ul li {\n\tline-height: 20px;\n\tmargin: 0;\n}\n\n.sfwd_sidebar #side-sortables {\n\twidth: 98%;\n}\n\n.sfwd_header_tabs li {\n\tdisplay: inline;\n\tpadding: 0;\n\tmargin: 0;\n}\n\n.sfwd_header_tabs {\n\tmargin: 0;\n}\n\n.sfwd_header_nav {\n\tmargin: 0;\n}\n\n.sfwd_header_tabs li a.sfwd_header_tab.active {\n\tbackground-color: rgb(255, 255, 255);\n\tbackground-color: rgba(255, 255, 255, 0.75);\n}\n\n.sfwd_header_tabs li a.sfwd_header_tab {\n\tcolor: #464646;\n\tfont-size: 15px;\n\ttext-decoration: none;\n\tborder: solid 1px #ccc;\n\tborder-left: none;\n\tmargin: 0;\n\tpadding: 6px 6px 1px 6px;\n}\n\n.sfwd_header_tabs li:first-child a.sfwd_header_tab {\n\tborder-left: solid 1px #ccc;\n}\n\n.sfwd_tab {\n\tborder: solid 1px #ccc;\n\tbackground-color: rgb(255, 255, 255);\n\tbackground-color: rgba(255, 255, 255, 0.5);\n}\n\n.wrap > h2 {\n\tpadding-bottom: 14px;\n}\n\n#learndash_group_users_search {\n\tdisplay: none;\n}\n\n\ntable.learndash-group-users-select {\n\twidth: 100%;\n}\n\ntable.learndash-group-users-select td.td_learndash_group_users_search {\n\twidth: 45%;\n}\n\ntable.learndash-group-users-select td.td_learndash_group_users_search select {\n\tmin-width: 100%;\n\theight: 150px;\n}\n\n/**\n * Hide the 'Add New' button on the Assignment\n * and Submitted Essays list tables\n */\nbody.post-type-sfwd-assignment .ld-global-header .global-new-entity-button,\nbody.post-type-sfwd-essays .ld-global-header .global-new-entity-button,\nbody.post-type-sfwd-transactions .ld-global-header .global-new-entity-button {\n\tdisplay: none;\n}\n\n\n/* Styles for the Support tab table output */\n\ntable#learndash-data-reports,\ntable#learndash-data-upgrades {\n\tborder: 0;\n}\n\n.learndash-data-reports-status,\n.learndash-data-upgrades-status {\n\twidth: 100%;\n}\n\n.learndash-data-reports-status .progress-meter,\n.learndash-data-upgrades-status .progress-meter {\n\twidth: 100%;\n\theight: 20px;\n\tborder: 1px solid #000;\n}\n\n.learndash-data-reports-status .progress-meter .progress-meter-image,\n.learndash-data-upgrades-status .progress-meter .progress-meter-image {\n\tbackground-color: #0f0;\n\tfloat: left;\n\theight: 16px;\n\twidth: 0;\n\tmargin: 2px 0;\n}\n\n.sfwd_input .sfwd_option_div select[multiple] {\n\twidth: 100%;\n\tmin-height: 100px;\n}\n\ntable.learndash-support-settings tbody th {\n\ttext-align: left;\n\tvertical-align: top;\n\tpadding: 5px 0 5px 15px;\n}\n\n.learndash-settings-page-wrap div.sfwd_options {\n\tpadding-bottom: 30px;\n}\n\n.learndash_shortcodes_section .learndash_required_field {\n\tcolor: #f00;\n}\n\n.sfwd_input.learndash-settings-field-error {\n\tbackground-color: #ffdfe0;\n\tborder-bottom: 1px solid #c89797;\n\tborder-top: 1px solid #c89797;\n}\n\n.sfwd_input p.ld-clear {\n\theight: 0;\n\tclear: left;\n\tpadding: 0;\n}\n\n.edit-post-header__settings .components-popover__content a:hover {\n\tcolor: #007cba;\n}\n\n/* learndash-admin-settings-page.css */\n\n.learndash-settings-page-wrap .error,\n.learndash-settings-page-wrap .error a {\n\tcolor: #f00;\n}\n\na.learndash-description-link {\n\tcolor: #000;\n\ttext-decoration: none;\n}\n\nspan.learndash-description {\n\tdisplay: none;\n}\n\n.sfwd_options .sfwd_input p.ld-clear {\n\tmargin: 0;\n\tline-height: 0;\n}\n\n.sfwd_options .ld-setting-field-sub {\n\tpadding-top: 5px;\n}\n\n.sfwd_options .ld-setting-field-sub input[type=\"button\"] {\n\tmargin-right: 5px;\n}\n\n.ld-metabox-description p {\n\tmargin: 5px 0 0 0;\n\tcolor: #666;\n\tfont-weight: 400;\n\tfont-style: italic;\n}\n\n.sfwd_options .sfwd_option_label .descripton {\n\tclear: both;\n\tdisplay: block;\n\tfloat: left;\n\tfont-weight: 400;\n\ttext-align: left;\n}\n\n.sfwd_options .ld-settings-sub-level-1 .sfwd_input {\n\tmargin-left: 10px;\n\tpadding-left: 10px;\n\tposition: relative;\n\tborder-left: 1px solid #ccc;\n}\n\n.sfwd_options .ld-settings-sub-level-1 .ld-settings-sub-level-2 {\n\tmargin-left: 10px;\n\tpadding-left: 5px;\n\tborder-left: 1px solid #ccc;\n}\n\n.sfwd_options .ld-settings-sub-level-1 .ld-settings-sub-level-2 .sfwd_input .sfwd_option_label {\n\n\t/* max-width: 279px; */\n\twidth: calc(38% - 1px);\n\tmax-width: calc(300px - 10px);\n}\n\n.sfwd_options .ld-settings-inner .sfwd_input {\n\tmargin-left: 25px;\n\tpadding-left: 20px;\n\tborder-left: 1px solid #ccc;\n}\n\n/*\n.sfwd_options .ld-settings-inner .sfwd_input:first-child:nth-last-child(1) {\n border-left: 0px;\n}\n*/\n.sfwd_options .ld-settings-inner .sfwd_input .sfwd_option_label {\n\tmargin-right: 0;\n\tmargin-left: 0;\n\tpadding-right: 0;\n\twidth: 30%;\n\tmin-width: none;\n\tmax-width: none;\n}\n\n.sfwd_options .ld-settings-inner .sfwd_input .sfwd_option_label.sfwd_option_label_full,\n.sfwd_options .sfwd_input .sfwd_option_label.sfwd_option_label_full {\n\twidth: 100%;\n}\n\n.sfwd_options .ld-settings-inner .sfwd_input .sfwd_option_input {\n\twidth: 65%;\n\tmin-width: 120px;\n\tmax-width: none;\n}\n\n.sfwd_options .ld-settings-inner .sfwd_input .sfwd_option_input.sfwd_option_input_full,\n.sfwd_options .sfwd_option_input.sfwd_option_input_full {\n\twidth: 100%;\n}\n\n.sfwd_options .sfwd_input_type_quiz-custom-fields .sfwd_option_input.sfwd_option_input_full {\n\tfloat: none;\n}\n\n/* Settings Fields CSS */\n\n/* Switch toggle CSS */\n\n.sfwd_options .ld-switch-wrapper {\n\tdisplay: flex;\n\tmargin-top: 5px;\n}\n\n.sfwd_options .ld-switch {\n\tmargin-right: 16px;\n\tposition: relative;\n}\n\n.sfwd_options .ld-switch__input {\n\tborder: none;\n\theight: 100%;\n\tleft: 0;\n\tmargin: 0;\n\topacity: 0;\n\tpadding: 0;\n\tposition: absolute;\n\ttop: 0;\n\twidth: 100%;\n\tz-index: 1;\n}\n\n.sfwd_options .ld-switch__track {\n\tbackground-color: #fff;\n\tborder-radius: 9px;\n\tborder: 2px solid #6c7781;\n\tbox-sizing: border-box;\n\tcontent: \"\";\n\tdisplay: inline-block;\n\theight: 18px;\n\ttransition: 0.2s background ease, 0.2s border ease;\n\tvertical-align: top;\n\twidth: 36px;\n}\n\n.sfwd_options .ld-switch__thumb {\n\tbackground-color: #6c7781;\n\tborder-radius: 50%;\n\tborder: 5px solid #6c7781;\n\tbox-sizing: border-box;\n\tdisplay: block;\n\theight: 10px;\n\tleft: 4px;\n\tposition: absolute;\n\ttop: 4px;\n\ttransition: 0.1s transform ease;\n\twidth: 10px;\n}\n\n.sfwd_options .ld-switch__on-off {\n\tborder-radius: 100%;\n\tborder: 2px solid #6c7781;\n\tbox-sizing: border-box;\n\tdisplay: block;\n\theight: 6px;\n\tposition: absolute;\n\tright: 6px;\n\ttop: 6px;\n\twidth: 6px;\n}\n\n.sfwd_options .ld-switch__input:checked ~ .ld-switch__track {\n\tbackground-color: #11a0d2;\n\tborder-color: #11a0d2;\n}\n\n.sfwd_options .ld-switch__input:checked ~ .ld-switch__thumb {\n\tbackground-color: #fff;\n\tborder-width: 0;\n\ttransform: translateX(18px);\n}\n\n.sfwd_options .ld-switch__input:checked ~ .ld-switch__on-off {\n\tbackground-color: #fff;\n\tborder-radius: 0;\n\tborder: 0;\n\theight: 6px;\n\tleft: 8px;\n\tright: auto;\n\twidth: 2px;\n}\n\n.sfwd_options .ld-switch__input:focus ~ .ld-switch__track {\n\tbox-shadow: 0 0 0 2px #fff, 0 0 0 3px #6c7781;\n\toutline-offset: 2px;\n\toutline: 2px solid transparent;\n}\n\n.sfwd_options .ld-switch__input:hover ~ .ld-switch__track {\n\tborder-color: #11a0d2;\n}\n\n.sfwd_options .ld-switch__input:checked:hover ~ .ld-switch__track {\n\tbackground-color: #6c7781;\n\tborder-color: #6c7781;\n}\n\n.sfwd_options .ld-switch.-disabled ~ label,\n.sfwd_options .ld-switch__input[disabled=\"disabled\"] {\n\tpointer-events: none;\n}\n\n.sfwd_options .ld-switch__input[disabled=\"disabled\"] {\n\topacity: 0 !important;\n}\n\n.sfwd_options .ld-switch__input[disabled=\"disabled\"] ~ .ld-switch__track {\n\topacity: 0.5;\n}\n\n/* Radio CSS*/\n\n.sfwd_options .ld-radio-input {\n\tborder: 0;\n\tclip-path: inset(50%);\n\tclip: rect(1px, 1px, 1px, 1px);\n\theight: 1px;\n\tmargin: -1px;\n\toverflow: hidden;\n\tpadding: 0;\n\tposition: absolute;\n\twidth: 1px;\n\tword-wrap: normal !important;\n}\n\n.sfwd_options .ld-radio-input__label {\n\tmargin-right: 16px;\n}\n\n.sfwd_options .ld-radio-input__label::before {\n\tborder-radius: 100%;\n\tborder: 2px solid #6c7781;\n\tbox-sizing: border-box;\n\tcontent: \"\";\n\tdisplay: inline-block;\n\theight: 16px;\n\tmargin-right: 10px;\n\tvertical-align: middle;\n\twidth: 16px;\n}\n\n.sfwd_options .ld-radio-input__label > span {\n\tvertical-align: middle;\n\tfont-weight: 700;\n\tcolor: #5f5f5f;\n}\n\n.sfwd_options .ld-radio-input:checked + .ld-radio-input__label::before {\n\tbackground-color: #11a0d2;\n\tbox-shadow: inset 0 0 0 2px #fff;\n}\n\n.sfwd_options .ld-radio-input:checked:focus + .ld-radio-input__label::before {\n\tbox-shadow: inset 0 0 0 2px #fff, 0 0 0 2px #fff, 0 0 0 3px #6c7781;\n}\n\n.sfwd_options .ld-radio-input:focus + .ld-radio-input__label::before {\n\tbox-shadow: 0 0 0 2px #fff, 0 0 0 3px #6c7781;\n\toutline-offset: 2px;\n\toutline: 2px solid transparent;\n}\n\n.sfwd_options .ld-radio-input:hover + .ld-radio-input__label::before {\n\tborder-color: #11a0d2;\n}\n\n.sfwd_options .ld-radio-input[disabled=\"disabled\"],\n.sfwd_options .ld-radio-input[disabled=\"disabled\"] + .ld-radio-input__label {\n\tpointer-events: none;\n}\n\n.sfwd_options .ld-radio-input[disabled=\"disabled\"] + .ld-radio-input__label::before {\n\topacity: 0.5;\n}\n\n.sfwd_options .ld-radio-description {\n\tcolor: #666;\n\tpadding-left: 25px;\n}\n\n/* Checkbox CSS*/\n\n.sfwd_options .ld-checkbox-input {\n\tborder: 0;\n\tclip-path: inset(50%);\n\tclip: rect(1px, 1px, 1px, 1px);\n\theight: 1px;\n\tmargin: -1px;\n\toverflow: hidden;\n\tpadding: 0;\n\tposition: absolute;\n\twidth: 1px;\n\tword-wrap: normal !important;\n}\n\n.sfwd_options .ld-checkbox-input__label {\n\tmargin-right: 16px;\n}\n\n.sfwd_options .ld-checkbox-input__label::before {\n\tborder: 2px solid #6c7781;\n\tbox-sizing: border-box;\n\tcontent: \"\";\n\tdisplay: inline-block;\n\theight: 16px;\n\tmargin-right: 10px;\n\tvertical-align: middle;\n\twidth: 16px;\n}\n\n.sfwd_options .ld-checkbox-input__label > span {\n\tvertical-align: middle;\n}\n\n.sfwd_options .ld-checkbox-input:checked + .ld-checkbox-input__label::before {\n\talign-items: center;\n\tcolor: #11a0d2;\n\tcontent: \"\\2713\";\n\tdisplay: inline-flex;\n\tjustify-content: center;\n\tfont-weight: 900;\n}\n\n.sfwd_options .ld-checkbox-input:focus + .ld-checkbox-input__label::before {\n\tbox-shadow: 0 0 0 2px #fff, 0 0 0 3px #6c7781;\n\toutline-offset: 2px;\n\toutline: 2px solid transparent;\n}\n\n.sfwd_options .ld-checkbox-input:hover + .ld-checkbox-input__label::before {\n\tborder-color: #11a0d2;\n}\n\n.sfwd_options .ld-checkbox-input[disabled=\"disabled\"],\n.sfwd_options .ld-checkbox-input[disabled=\"disabled\"] + .ld-checkbox-input__label {\n\tpointer-events: none;\n}\n\n.sfwd_options .ld-checkbox-input[disabled=\"disabled\"] + .ld-checkbox-input__label::before {\n\topacity: 0.5;\n}\n\n.sfwd_options .sfwd_option_input p.learndash-section-field-checkbox-p {\n\tmargin: 3px 0 0 0;\n\tpadding: 0;\n}\n\n/* Text Input CSS */\n.sfwd_options .learndash-section-field-text {\n\tborder-radius: 2px;\n\tborder: 1px solid #ddd;\n\tbox-shadow: none;\n\tbox-sizing: border-box;\n\tfont-size: 14px;\n\tpadding: 5px 7px;\n\twidth: 100%;\n}\n\n.sfwd_options .learndash-section-field-number.-medium,\n.sfwd_options .learndash-section-field-text.-medium,\n.sfwd_options .learndash-section-field-url.-medium {\n\twidth: 50%;\n}\n\n.sfwd_options .learndash-section-field-number.-small,\n.sfwd_options .learndash-section-field-text.-small,\n.sfwd_options .learndash-section-field-url.-small {\n\twidth: 100px;\n}\n\n.sfwd_options .learndash-section-field-number:focus,\n.sfwd_options .learndash-section-field-text:focus {\n\tborder-color: #11a0d2;\n\toutline: 0;\n}\n\n.sfwd_options .learndash-section-field-number:hover,\n.sfwd_options .learndash-section-field-text:hover,\n.sfwd_options .learndash-section-field-url:hover {\n\tborder-color: #999;\n}\n\n.sfwd_options .learndash-section-field-number.full-text,\n.sfwd_options .learndash-section-field-text.full-text,\n.sfwd_options .learndash-section-field-url.full-text {\n\twidth: 100%;\n}\n\n.sfwd_options span.learndash_settings_field_text_prefix.-medium {\n\twidth: 75%;\n\tdisplay: inline-block;\n\tpadding-top: 0;\n\tpadding-bottom: 0;\n\tcolor: rgba(51, 51, 51, 0.5);\n}\n\n.sfwd_options span.learndash_settings_field_text_prefix input[type=\"text\"] {\n\twidth: max-content;\n\tborder: 0;\n\tpadding-left: 0;\n\tpadding-bottom: 8px;\n}\n\n/* Select CSS */\n\n.sfwd_options .ld-select {\n\tbackground-color: #fff;\n\tborder-radius: 3px;\n\tborder: 1px solid #ccc;\n\tdisplay: inline-block;\n\toverflow: hidden;\n\tposition: relative;\n\tvertical-align: middle;\n\twidth: 100%;\n\tmax-width: 450px;\n}\n\n.sfwd_options .ld-select::after {\n\tborder: 5px solid transparent;\n\tborder-bottom: 0;\n\tborder-top-color: #000;\n\tcontent: \"\";\n\theight: 0;\n\tpointer-events: none;\n\tposition: absolute;\n\tright: 5px;\n\tspeak: none;\n\ttop: 50%;\n\ttransform: translate(0, -50%);\n\twidth: 0;\n}\n\n.sfwd_options .ld-select-multiple::after,\n.sfwd_options .ld-select2::after {\n\tborder: none;\n}\n\n.select2-container--learndash .select2-selection--single .select2-selection__rendered {\n\tcolor: #72777c !important;\n}\n\n.select2-container--learndash .select2-results__option--highlighted[aria-selected] {\n\tbackground-color: #11a0d2 !important;\n}\n\n.sfwd_options .ld-select-multiple.ld-select2 .select2-container .select2-selection__rendered > *:first-child.select2-search--inline {\n\twidth: 100% !important;\n}\n\n.sfwd_options .ld-select-multiple.ld-select2 .select2-container .select2-selection__rendered > *:first-child.select2-search--inline .select2-search__field {\n\twidth: 100% !important;\n}\n\n.sfwd_options .ld-select-multiple.ld-select2 .select2-container li {\n\tmargin-bottom: 0;\n}\n\n.sfwd_options .select2-container .select2-search--inline .select2-search__field {\n\tmargin-top: 3px;\n\tmargin-bottom: 2px;\n}\n\n.sfwd_options .ld-select select {\n\t-moz-appearance: none;\n\t-webkit-appearance: inherit;\n\tappearance: none;\n\tbackground: none;\n\tborder: 0;\n\tfont-size: 14px;\n\theight: 100%;\n\tmargin: 0;\n\tpadding: 5px 10px;\n\twidth: 100%;\n\tmax-width: 100%;\n\n\t/* width: 110% \\9; */\n\tz-index: 2;\n}\n\n.sfwd_options .ld-select select:focus {\n\tbox-shadow: inset 0 0 0 1px #6c7781;\n}\n\n.sfwd_options .ld-select select::-ms-expand {\n\tdisplay: none;\n}\n\n.sfwd_options .ld-select select:-moz-focusring {\n\ttext-shadow: var(--select--focus-ring--text-shadow);\n}\n\n.sfwd_options .ld-select select option {\n\tborder: 0;\n\twidth: 100%;\n}\n\n.sfwd_options .ld-select2 .select2-container--learndash {\n\twidth: 100% !important;\n\tmax-width: 450px;\n\theight: 100%;\n}\n\n.sfwd_options .ld-select2 .select2-container--learndash .select2-selection--single {\n\tpadding-top: 3px;\n\tpadding-bottom: 3px;\n\theight: 100%;\n\tborder: 0;\n}\n\n.sfwd_options .ld-select2 .select2-container--learndash .select2-selection--single .select2-selection__arrow {\n\theight: 100%;\n}\n\n.sfwd_options .ld-select2 .select2-container--learndash .select2-selection--single .select2-selection__arrow b {\n\tborder-top-color: inherit;\n}\n\n.sfwd_options .select2-container--learndash .select2-selection--multiple {\n\tborder: 0 solid #aaa !important;\n}\n\n/* stylelint-disable-next-line no-duplicate-selectors */\n.sfwd_options .select2-container .select2-search--inline .select2-search__field {\n\tpadding-top: 5px !important;\n\tcolor: #444 !important;\n}\n\n\n/* Select2 Post Type listing selectors */\nbody.edit-php .tablenav.top .select2-container--learndash,\nbody.users-php .tablenav.top .select2-container--learndash {\n\tmargin-right: 6px;\n\tmargin-left: 1px;\n\tfont-size: 14px;\n\tline-height: 2;\n\tborder-color: #7e8993;\n\tbox-shadow: none;\n\tborder-radius: 3px;\n\tmin-height: 30px;\n\tmax-width: 25rem;\n\t-webkit-appearance: none;\n\tcolor: #32373c !important;\n\tcursor: pointer;\n\tvertical-align: middle;\n\tfloat: left;\n}\n\nbody.edit-php .tablenav.top .select2-container--learndash .select2-selection--single,\nbody.users-php .tablenav.top .select2-container--learndash .select2-selection--single {\n\theight: 30px;\n\tbox-shadow: 0 0 0 transparent;\n\tborder-radius: 4px;\n\tborder: 1px solid #7e8993;\n\tbackground-color: #fff;\n\tcolor: #32373c !important;\n\t/* stylelint-disable-next-line max-line-length */\n\t/* stylelint-disable-next-line declaration-block-no-shorthand-property-overrides, function-url-quotes */\n\tbackground: #fff url(\"data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M5%206l5%205%205-5%202%201-7%207-7-7%202-1z%22%20fill%3D%22%23555%22%2F%3E%3C%2Fsvg%3E\") no-repeat right 5px top 55%;\n\tbackground-size: 16px 16px;\n}\n\nbody.edit-php .tablenav.top .select2-container--learndash .select2-selection--single .select2-selection__placeholder,\nbody.users-php .tablenav.top .select2-container--learndash .select2-selection--single .select2-selection__placeholder {\n\tcolor: #32373c !important;\n}\n\n/* Hide the default */\nbody.edit-php .tablenav.top .select2-container--learndash .select2-selection--single .select2-selection__arrow,\nbody.users-php .tablenav.top .select2-container--learndash .select2-selection--single .select2-selection__arrow {\n\tdisplay: none;\n}\n\n/* Settings Row CSS */\n\n.sfwd_options .sfwd_option_div p.ld-radio-input-wrapper {\n\tmargin-bottom: 1px;\n}\n\n.sfwd_options .sfwd_input textarea {\n\tcolor: #515151;\n\n\tmargin: 0;\n\tfont-size: 14px;\n\tline-height: 25px;\n\twidth: 100%;\n}\n\n.sfwd_options .sfwd_input > .sfwd_input:first-child {\n\tmargin-top: 20px;\n}\n\n.sfwd_options .sfwd_option_input p {\n\tmargin-top: 0;\n}\n\n.sfwd_options .sfwd_option_label {\n\tbox-sizing: border-box;\n\tflex: 1 0 100%;\n\tfont-weight: 700;\n\tmargin-bottom: 10px;\n\tpadding-right: 0; /* 20px;*/\n\n\t/* position: relative; */\n}\n\n.sfwd_options .sfwd_option_input {\n\tflex: 1 0 100%;\n\tmargin-bottom: 10px;\n}\n\n.sfwd_options .sfwd_option_div select[multiple] {\n\twidth: 100%;\n\tmin-height: 100px;\n}\n\n.sfwd_options .ld-settings-sub.ld-settings-sub-state-closed,\n.sfwd_options .ld-settings-inner-state-closed,\n.sfwd_options .ld-theme-settings-section-state-closed {\n\tdisplay: none;\n}\n\n.sfwd_options .ld-settings-sub.ld-settings-sub-state-open,\n.sfwd_options .ld-settings-inner-state-open\n.sfwd_options .ld-theme-settings-section-state-open {\n\tdisplay: block;\n}\n\n.sfwd_options .ld-settings-sub-advanced .sfwd_input {\n\tmargin-left: 1px;\n\tborder-left: 1px solid #ccc;\n}\n\n.sfwd_options .ld-settings-sub-advanced .ld-settings-sub-advanced-inner-state-closed {\n\tdisplay: none;\n}\n\n.sfwd_options .ld-settings-sub-advanced .ld-settings-sub-advanced-inner-state-open {\n\tdisplay: block;\n}\n\n.sfwd_options .ld-settings-sub-advanced .ld-settings-sub-advanced-inner .sfwd_option_label {\n\twidth: auto;\n}\n\n.sfwd_options .ld-settings-sub-advanced .ld-settings-sub-advanced-inner .sfwd_option_input {\n\twidth: auto;\n}\n\n\n.sfwd_options .tooltip {\n\tposition: relative;\n\tdisplay: inline-block;\n\topacity: 1;\n}\n\n/* Tooltip text */\n.sfwd_options .tooltip .tooltiptext {\n\tvisibility: hidden;\n\twidth: 180px;\n\tbackground-color: #11a0d2 /* #1e8cbe */;\n\tcolor: #fff;\n\ttext-align: center;\n\tpadding: 5px 0;\n\tborder-radius: 6px;\n\tmargin-left: -90px; /* Use half of the width (120/2 = 60), to center the tooltip */\n\tbottom: 100%;\n\tleft: 50%;\n\tmargin-bottom: 5px;\n\n\t/* Position the tooltip text - see examples below! */\n\tposition: absolute;\n\tz-index: 1;\n}\n\n/* Show the tooltip text when you mouse over the tooltip container */\n.sfwd_options .-disabled.tooltip:hover .tooltiptext {\n\tvisibility: visible;\n}\n\n/* Tooltip top of element */\n\n/* Arrow */\n.sfwd_options .tooltip .tooltiptext::after {\n\tcontent: \" \";\n\tposition: absolute;\n\ttop: 100%; /* At the bottom of the tooltip */\n\tleft: 50%;\n\tmargin-left: -5px;\n\tborder-width: 5px;\n\tborder-style: solid;\n\tborder-color: #11a0d2 /* #1e8cbe */ transparent transparent transparent;\n}\n\n\n/* Tooltip to right of element */\n\n/**\n * Quiz Custom Fields style\n */\n\n.sfwd_options .form_table_wrapper {\n\tmargin-top: 0;\n\tpadding: 0;\n\tborder: 0 solid #c2c2c2;\n}\n\n.sfwd_options .form_table_wrapper table {\n\tborder-collapse: collapse;\n}\n\n/* Line item CSS */\n\n.sfwd_options .form_table_wrapper #form_add {\n\tbackground-color: transparent;\n\t/* stylelint-disable-next-line function-url-quotes */\n\tbackground-image: url(\"data:image/svg+xml,%3Csvg width='256' height='256' viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%23007cba' d='M185.066 128c0 3.534-2.866 6-6.4 6H134v44.666c0 3.534-2.467 6.399-6 6.399-3.534 0-6-2.865-6-6.399V134H77.332c-3.535 0-6.4-2.466-6.4-6s2.866-6 6.4-6H122V77.331c0-3.534 2.466-6.4 6-6.4 3.533 0 6 2.866 6 6.4V122h44.666c3.534 0 6.4 2.466 6.4 6zM256 128C256 57.42 198.58 0 128 0S0 57.42 0 128s57.42 128 128 128 128-57.42 128-128zm-12.8 0c0 63.521-51.679 115.2-115.2 115.2-63.522 0-115.2-51.679-115.2-115.2C12.8 64.478 64.478 12.8 128 12.8c63.521 0 115.2 51.678 115.2 115.2z' fill-rule='nonzero'%3E%3C/path%3E%3C/svg%3E\");\n\tbackground-position: center left 3px;\n\tbackground-repeat: no-repeat;\n\tbackground-size: 16px 16px;\n\tborder: 0;\n\tcolor: #007cba;\n\tcursor: pointer;\n\tfont-size: 14px;\n\tfont-weight: 700;\n\tpadding: 5px 10px 5px 30px;\n\tbox-shadow: none;\n}\n\n.sfwd_options .form_table_wrapper #form_add:hover {\n\t/* stylelint-disable-next-line function-url-quotes */\n\tbackground-image: url(\"data:image/svg+xml,%3Csvg width='256' height='256' viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%2311a0d2' d='M185.066 128c0 3.534-2.866 6-6.4 6H134v44.666c0 3.534-2.467 6.399-6 6.399-3.534 0-6-2.865-6-6.399V134H77.332c-3.535 0-6.4-2.466-6.4-6s2.866-6 6.4-6H122V77.331c0-3.534 2.466-6.4 6-6.4 3.533 0 6 2.866 6 6.4V122h44.666c3.534 0 6.4 2.466 6.4 6zM256 128C256 57.42 198.58 0 128 0S0 57.42 0 128s57.42 128 128 128 128-57.42 128-128zm-12.8 0c0 63.521-51.679 115.2-115.2 115.2-63.522 0-115.2-51.679-115.2-115.2C12.8 64.478 64.478 12.8 128 12.8c63.521 0 115.2 51.678 115.2 115.2z' fill-rule='nonzero'%3E%3C/path%3E%3C/svg%3E\");\n\tcolor: #11a0d2;\n}\n\n.sfwd_options .form_table_wrapper .form_move {\n\ttext-decoration: none;\n}\n\n.sfwd_options .form_table_wrapper .form_delete {\n\tbackground-color: transparent;\n\t/* stylelint-disable-next-line function-url-quotes */\n\tbackground-image: url(\"data:image/svg+xml,%3Csvg aria-hidden='true' role='img' focusable='false' class='dashicon dashicons-dismiss' xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Cpath fill='%23a00' d='M10 2c4.42 0 8 3.58 8 8s-3.58 8-8 8-8-3.58-8-8 3.58-8 8-8zm5 11l-3-3 3-3-2-2-3 3-3-3-2 2 3 3-3 3 2 2 3-3 3 3z'%3E%3C/path%3E%3C/svg%3E\");\n\tbackground-position: center left 3px;\n\tbackground-repeat: no-repeat;\n\tborder: 0;\n\tcolor: #a00;\n\tcursor: pointer;\n\tfont-weight: 700;\n\tmargin: 0;\n\topacity: 0;\n\tpadding: 5px 10px 5px 30px;\n\ttransition: opacity 0.1s;\n\tvisibility: hidden;\n}\n\n.sfwd_options .form_table_wrapper .form_delete:hover {\n\tcolor: #f00;\n}\n\n.sfwd_options .form_table_wrapper tbody.ui-sortable tr:hover .form_delete {\n\topacity: 1;\n\tvisibility: visible;\n}\n\n.sfwd_options .form_table_wrapper thead tr th,\n.sfwd_options .form_table_wrapper tbody.ui-sortable tr td {\n\tpadding: 10px 5px;\n\ttransition: box-shadow 0.1s;\n}\n\n.sfwd_options .form_table_wrapper tbody.ui-sortable tr:hover td {\n\tbox-shadow: 0 1px 0 0 #11a0d2, 0 -1px 0 0 #11a0d2;\n}\n\n.sfwd_options .form_table_wrapper tbody.ui-sortable tr:hover td:first-of-type {\n\tbox-shadow: 0 1px 0 0 #11a0d2, 0 -1px 0 0 #11a0d2, -1px 0 0 0 #11a0d2;\n}\n\n.sfwd_options .form_table_wrapper tbody.ui-sortable tr:hover td:last-of-type {\n\tbox-shadow: 0 1px 0 0 #11a0d2, 0 -1px 0 0 #11a0d2, 1px 0 0 0 #11a0d2;\n}\n\n.sfwd_options .form_table_wrapper tbody.ui-sortable tr td:first-of-type {\n\ttext-align: center;\n}\n\n.sfwd_options .form_table_wrapper .ld-select.-field select {\n\tpadding: 0 10px;\n}\n\n.sfwd_options .form_table_wrapper #form_table thead th {\n\ttext-transform: uppercase;\n}\n\n.sfwd_options .form_table_wrapper #form_add_wrapper {\n\tmargin-top: 10px;\n\tmargin-left: 10px;\n}\n\n\n/**\nQuiz Edit Result Text lists\n*/\n\n#learndash-quiz-resultList ul#resultList {\n\twidth: 100%;\n}\n\n#learndash-quiz-resultList ul#resultList li {\n\n\tpadding: 5px;\n\tborder: 1;\n\tborder: 1px dotted;\n}\n\n#learndash-quiz-resultList ul#resultList li .resultHeader {\n\n\tmargin-bottom: 5px;\n\tpadding: 10px;\n\tbackground-color: #ebebeb; /* rgb(207, 207, 207); */\n}\n\n#learndash-quiz-resultList input.addResult {\n\tbackground-color: transparent;\n\t/* stylelint-disable-next-line function-url-quotes */\n\tbackground-image: url(\"data:image/svg+xml,%3Csvg width='256' height='256' viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%23007cba' d='M185.066 128c0 3.534-2.866 6-6.4 6H134v44.666c0 3.534-2.467 6.399-6 6.399-3.534 0-6-2.865-6-6.399V134H77.332c-3.535 0-6.4-2.466-6.4-6s2.866-6 6.4-6H122V77.331c0-3.534 2.466-6.4 6-6.4 3.533 0 6 2.866 6 6.4V122h44.666c3.534 0 6.4 2.466 6.4 6zM256 128C256 57.42 198.58 0 128 0S0 57.42 0 128s57.42 128 128 128 128-57.42 128-128zm-12.8 0c0 63.521-51.679 115.2-115.2 115.2-63.522 0-115.2-51.679-115.2-115.2C12.8 64.478 64.478 12.8 128 12.8c63.521 0 115.2 51.678 115.2 115.2z' fill-rule='nonzero'%3E%3C/path%3E%3C/svg%3E\");\n\tbackground-position: center left 3px;\n\tbackground-repeat: no-repeat;\n\tbackground-size: 16px 16px;\n\tborder: 0;\n\tcolor: #007cba;\n\tcursor: pointer;\n\tfont-size: 14px;\n\tfont-weight: 700;\n\tpadding: 5px 10px 5px 30px;\n}\n\n#learndash-quiz-resultList ul#resultList li input.deleteResult {\n\tfloat: right;\n\tbackground-color: transparent;\n\t/* stylelint-disable-next-line function-url-quotes */\n\tbackground-image: url(\"data:image/svg+xml,%3Csvg aria-hidden='true' role='img' focusable='false' class='dashicon dashicons-dismiss' xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Cpath fill='%23a00' d='M10 2c4.42 0 8 3.58 8 8s-3.58 8-8 8-8-3.58-8-8 3.58-8 8-8zm5 11l-3-3 3-3-2-2-3 3-3-3-2 2 3 3-3 3 2 2 3-3 3 3z'%3E%3C/path%3E%3C/svg%3E\");\n\tbackground-position: center left 3px;\n\tbackground-repeat: no-repeat;\n\tborder: 0;\n\tcolor: #a00;\n\tcursor: pointer;\n\tfont-weight: 700;\n\tmargin: 0;\n\topacity: 0;\n\tpadding: 5px 10px 5px 30px;\n\ttransition: opacity 0.1s;\n\tvisibility: hidden;\n}\n\n#learndash-quiz-resultList ul#resultList li:hover input.deleteResult {\n\topacity: 1;\n\tvisibility: visible;\n}\n\n#learndash-quiz-resultList #resultList li .expand-arrow {\n\tcursor: pointer;\n\tmargin-top: 3px;\n\tfloat: right;\n}\n\n#learndash-quiz-resultList #resultList li .expand-arrow-up svg {\n\ttransform: rotate(180deg);\n}\n\n.sfwd_options .sfwd_option_label .descripton p {\n\tmargin-bottom: 0;\n}\n\n.sfwd_options .sfwd_option_input_full {\n\tmargin-left: 0;\n\tmargin-right: 0;\n}\n\n\n.learndash_navigation_questions_list ul.learndash-quiz-questions li a {\n\tfont-weight: 400;\n\ttext-decoration: none !important;\n}\n\n.learndash_navigation_questions_list ul.learndash-quiz-questions li.ld-question-overview-widget-item-current a {\n\tfont-weight: 700;\n}\n\n.learndash_navigation_questions_list .ld-question-overview-widget-add {\n\tfont-weight: 700;\n\ttext-decoration: none !important;\n}\n\n.sfwd_options #learndash-quiz-admin-data-handling-settings_toplistDataAddBlock_field,\n.sfwd_options #learndash-quiz-admin-data-handling-settings_associated_settings_field,\n.sfwd_options #learndash-quiz-admin-data-handling-settings_emailNotification_field,\n.sfwd_options #learndash-quiz-admin-data-handling-settings_timeLimitCookie_field,\n.sfwd_options #learndash-quiz-admin-data-handling-settings_toplistDataShowIn_field,\n.sfwd_options #learndash-quiz-admin-data-handling-settings_statisticsIpLock_field,\n.sfwd_options #learndash-quiz-display-content-settings_showMaxQuestion_field,\n.sfwd_options #learndash-quiz-display-content-settings_showMaxQuestionValue_field,\n.sfwd_options #learndash-quiz-display-content-settings_quizModus_multiple_questionsPerPage_field,\n.sfwd_options #learndash-quiz-results-options_resultText_field,\n.sfwd_options #learndash-quiz-display-content-settings_quizModus_single_feedback_field {\n\tborder-left: none;\n\tmargin-left: 0;\n\tpadding-left: 0;\n}\n\n.sfwd_options #learndash-course-access-settings_course_access_list_field,\n.sfwd_options #learndash-course-display-content-settings_course_materials_field,\n.sfwd_options #learndash-lesson-display-content-settings_lesson_materials_field,\n.sfwd_options #learndash-topic-display-content-settings_topic_materials_field,\n.sfwd_options #learndash-lesson-display-content-settings_lesson_assignment_points_amount_field,\n.sfwd_options #learndash-topic-display-content-settings_lesson_assignment_points_amount_field,\n.sfwd_options #learndash-quiz-display-content-settings_quiz_materials_field,\n.sfwd_options #learndash-quiz-display-content-settings_showMaxQuestionValue_field,\n.sfwd_options #learndash-quiz-display-content-settings_quizModus_single_back_button_field {\n\tborder-left: none;\n}\n\n.sfwd_options #learndash-lesson-access-settings_visible_after_field,\n.sfwd_options #learndash-lesson-access-settings_visible_after_specific_date_field,\n.sfwd_options #learndash-quiz-display-content-settings_quizModus_single_back_button_field {\n\tborder-left: none;\n\n\t/* padding-left: 5px; */\n\tpadding-left: 0;\n}\n\n.sfwd_options #learndash-quiz-results-options_resultText_field {\n\tpadding-left: 10px;\n}\n\n.sfwd_options input[name=\"templateLoad\"],\n.sfwd_options input[name=\"templateName\"] {\n\tmargin-top: 5px;\n}\n\n.ld-settings-inner .ld-radio-input__label > span {\n\tfont-weight: 400;\n}\n\n.ld-divider {\n\tborder-bottom: 1px solid #eee;\n\tmargin: 20px 0 20px 0;\n}\n\n.sfwd_options .ld-settings-inner-lesson_video_display_timing_after .sfwd_option_input,\n.sfwd_options .ld-settings-inner .sfwd_option_input {\n\twidth: 40% !important;\n}\n\n.sfwd_options #learndash-lesson-access-settings_visible_after_specific_date_field .sfwd_option_input {\n\twidth: 80% !important;\n}\n\n.sfwd_options .ld-settings-sub .sfwd_option_label {\n\twidth: calc(38% - 15px);\n\tmax-width: calc(300px - 15px);\n}\n\n.sfwd_options #learndash-lesson-display-content-settings_assignment_upload_limit_count_field .sfwd_option_label,\n.sfwd_options #learndash-lesson-display-content-settings_lesson_assignment_deletion_enabled_field .sfwd_option_label {\n\twidth: 35% !important;\n}\n\n.sfwd_options #learndash-lesson-access-settings_visible_after_specific_date_field input[type=\"number\"] {\n\tpadding: 0 !important;\n}\n\n.sfwd_options .ld-settings-inner-lesson_video_display_timing_after .sfwd_option_label {\n\twidth: 35% !important;\n}\n\n.sfwd_options .ld-settings-inner-quizModus_single .sfwd_option_input {\n\twidth: 65% !important;\n}\n\n.sfwd_options .ld-settings-email-header-wrapper {\n\tmargin-bottom: 30px;\n}\n\n.sfwd_options .ld-settings-email-header {\n\tfont-weight: 700;\n}\n\n.sfwd_options .ld-settings-email-description {\n\tfont-weight: 300;\n}\n\n/* Add support for error display */\n.sfwd_options .learndash_settings_field_invalid label.sfwd_label {\n\tcolor: #f00;\n}\n\n.sfwd_options .learndash_settings_field_invalid input:invalid {\n\tborder: 1px solid #f00;\n\tbox-shadow: none;\n}\n\n.sfwd_options .learndash_settings_field_invalid .learndash-section-field-error {\n\tcolor: #f00;\n}\n\n#learndash-settings-fields-notice-errors p.errors-header {\n\tfont-weight: 900;\n}\n\n#learndash-settings-fields-notice-errors ul.errors-list {\n\tlist-style: disc;\n}\n\n#learndash-settings-fields-notice-errors ul.errors-list li {\n\tmargin-left: 15px;\n}\n\n/**\n * Added to bring back the visible indicator on\n * checkbox in Builder sidebar elements.\n *\n * See LEARNDASH-4114\n */\n.ld__builder-sidebar-widget .components-checkbox-control__input[type=\"checkbox\"]:checked::before {\n\t/* stylelint-disable-next-line function-url-quotes */\n\tcontent: url(\"data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2020%2020%27%3E%3Cpath%20d%3D%27M14.83%204.89l1.34.94-5.81%208.38H9.02L5.78%209.67l1.34-1.25%202.57%202.4z%27%20fill%3D%27%231e8cbe%27%2F%3E%3C%2Fsvg%3E\");\n}\n\n.plugin-update p.ld-plugin-update-notice::before {\n\tcontent: \"\";\n\tmargin-right: 0;\n}\n\n.plugin-update .ld-plugin-update-notice,\n.notice.ld-plugin-update-notice {\n\tpadding: 10px;\n\tmargin-top: 10px;\n}\n\n.ld-plugin-update-notice .version {\n\tfont-weight: 700;\n}\n\n.ld-plugin-update-notice .header {\n\tfont-size: 130%;\n\tfont-weight: 700;\n}\n\n/**\nSections/Settings Info banners.\n*/\n.ld_settings_postbox .ld-settings-info-banner {\n\tdisplay: block;\n\tpadding: 5px 10px 5px 10px;\n\tmargin: 5px 0;\n}\n\n.ld_settings_postbox .ld-settings-info-banner p::before {\n\t/* stylelint-disable-next-line font-family-no-missing-generic-family-keyword */\n\tfont: 400 20px/1 dashicons;\n\tfloat: left;\n}\n\n.ld_settings_postbox .ld-settings-info-banner p {\n\tmargin: 0.5em 0;\n\tpadding: 0;\n\tfont-size: 13px;\n\t/* stylelint-disable-next-line declaration-property-unit-allowed-list */\n\tline-height: 1.5em;\n\t-webkit-font-smoothing: antialiased;\n\t-moz-osx-font-smoothing: grayscale;\n\tvertical-align: top;\n}\n\n.ld_settings_postbox .ld-settings-info-banner.ld-settings-info-banner-alert {\n\tbackground-color: #fbeaea;\n\tborder-left-color: #dc3232;\n\tborder-left-width: 2px;\n\tborder-left-style: solid;\n}\n\n.ld_settings_postbox .ld-settings-info-banner.ld-settings-info-banner-alert p::before {\n\tcolor: #dc3232;\n\tcontent: \"\\f534\";\n\tmargin-right: 6px;\n}\n\n.ld_settings_postbox .ld-settings-info-banner.ld-settings-info-banner-success {\n\tborder-color: #46b450;\n\tborder-width: 0 0 1px 2px;\n\tborder-style: solid;\n}\n\n/* LearnDash Settings Sub menu */\nul.learndash-settings-sub {\n\tfloat: none;\n}\n\nul.learndash-settings-sub li.learndash-settings-sub-current a {\n\tfont-weight: 700;\n}\n\n/* LearnDash Settings Table general styles */\ntable.learndash-settings-table th {\n\tfont-weight: 700;\n}\n\ntable.learndash-settings-table td.col-valign-middle {\n\tvertical-align: middle;\n}\n\ntable.learndash-settings-table-sortable .ui-sortable-helper {\n\tdisplay: table;\n}\n\ntable.learndash-settings-table-sortable td.col-name-move {\n\tcursor: grab;\n}\n\n/** Settings for Group Attributes metabox */\n\n.edit-post-sidebar #learndash_group_attributes_metabox select#group_parent_id {\n\tmax-width: 85%;\n\twidth: 100%;\n}\n\n#learndash_group_attributes_metabox input#group_menu_order {\n\tdisplay: block;\n}\n\n.edit-post-sidebar #learndash_group_attributes_metabox .group-menu-order-label-wrapper {\n\tmargin-top: 10px;\n}\n\n/** Styles for WordPress 5.5 changes */\n.ld_settings_postbox .postbox-header {\n\tdisplay: block;\n}\n\n.edit-post-meta-boxes-area #poststuff .ld_settings_postbox .postbox-header .hndle,\n.edit-post-meta-boxes-area #poststuff #learndash_course_builder .postbox-header .hndle,\n.edit-post-meta-boxes-area #poststuff #learndash_quiz_builder .postbox-header .hndle {\n\tborder-bottom: none;\n\tpadding: 5px 12px;\n\twidth: auto;\n}\n\n.ld_settings_postbox .postbox-header .hndle {\n\tdisplay: inline-block;\n}\n\n.ld_settings_postbox .postbox-header .handle-actions {\n\tdisplay: inline-block;\n\tfloat: right;\n}\n\n.ld_settings_postbox .postbox-header .handle-actions .handle-order-lower,\n.ld_settings_postbox .postbox-header .handle-actions .handle-order-higher,\nbody[data-active-tab=\"learndash_course_builder\"] .postbox-header .handle-actions .handle-order-lower,\nbody[data-active-tab=\"learndash_course_builder\"] .postbox-header .handle-actions .handle-order-higher,\nbody[data-active-tab=\"learndash_quiz_builder\"] .postbox-header .handle-actions .handle-order-lower,\nbody[data-active-tab=\"learndash_quiz_builder\"] .postbox-header .handle-actions .handle-order-higher {\n\tdisplay: none;\n}\n\n.ld_settings_postbox .postbox-header .ld-metabox-description {\n\tdisplay: block;\n\tpadding: 0 12px 5px;\n}\n\n#course-shortcodes.wrap .inside .dashicons,\n#course-shortcodes.wrap .inside .dashicons-before::before,\n#certificate-shortcodes.wrap .inside .dashicons,\n#certificate-shortcodes.wrap .inside .dashicons-before::before {\n\ttext-decoration: none;\n}\n\n/* Stripe Payments Settings */\n\n.sfwd_options .learndash-stripe-connect,\n.notice.connect-stripe .learndash-stripe-connect {\n\talign-items: center;\n\tbackground: #6772e5;\n\tborder-radius: 5px;\n\tcolor: #fff;\n\tdisplay: flex;\n\tfont-size: 16px;\n\tjustify-content: center;\n\tletter-spacing: 0.6px;\n\tpadding: 6px 24px;\n\ttext-decoration: none;\n\ttransition: all 0.3s ease;\n\twidth: 200px;\n}\n\n.sfwd_options .learndash-stripe-connect:active,\n.learndash-stripe-connect:focus,\n.learndash-stripe-connect:hover,\n.notice.connect-stripe .learndash-stripe-connect:active,\n.notice.connect-stripe .learndash-stripe-connect:focus,\n.notice.connect-stripe .learndash-stripe-connect:hover {\n\tbackground: #3f4ddf;\n\tcolor: #fff;\n}\n\n.sfwd_options .learndash-stripe-connect .stripe-logo,\n.notice.connect-stripe .learndash-stripe-connect .stripe-logo {\n\tpadding: 2px 10px 0 0;\n}\n"],"names":[],"sourceRoot":""} \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/meta-box.min-rtl.css b/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/meta-box.min-rtl.css new file mode 100644 index 000000000..7721705c5 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/meta-box.min-rtl.css @@ -0,0 +1 @@ +.form-table.sfwd{clear:none}.form-table.sfwd td{font-size:12px;line-height:20px;padding:16px 0 10px;vertical-align:top}.form-table.sfwd th{padding:10px 9px 12px 0;width:200px}.sfwd_help_text_link{align-items:center;display:flex;flex-direction:row-reverse;float:right;justify-content:space-between;max-width:300px;text-align:right;width:100%}.sfwd_help_text_link img{float:right;height:30px;width:30px}.sfwd_label{color:#5f5f5f;flex:1;float:left;font-weight:700;line-height:19px;margin:0;width:60%}.sfwd_help_text_div{margin:10px 0;text-align:right;width:100%}.sfwd_help_text{clear:right;color:#797979;float:right;font-size:12px;font-style:italic;font-weight:lighter;line-height:15px;margin-left:30px}.sfwd_head_tagline{color:#5f5f5f;font-size:13px}.sfwd_head_nav{border-bottom:1px solid #ccc;float:right;font-family:HelveticaNeue-Light,Helvetica Neue Light,Helvetica Neue,sans-serif;font-size:18px;margin:0 0 16px;width:100%}.sfwd_head_nav_tab{border:1px solid #ccc;border-bottom:0 solid #fff;border-radius:4px 4px 0 0;color:#000;float:right;margin:0 15px 0 0;opacity:.5;padding:10px 15px;text-decoration:none;text-shadow:#fff 0 1px 0}.sfwd_head_nav_tab.sfwd_head_nav_active{border-width:1px;margin-bottom:-1px;opacity:1}.sfwd_head_nav_tab:first-child{margin-right:0}.sfwd_head_nav_tab:hover{opacity:1}.sfwd_header{clear:right;float:right}.sfwd_advert{border:1px solid #ddd;height:200px;margin-bottom:20px;padding:10px;width:423px}.sfwd_adverts{float:left}.sfwd_content{clear:right;min-width:760px}.sfwd_options_wrapper .hndle{font-family:Georgia,Times New Roman,Bitstream Charter,Times,serif;font-size:15px;font-weight:400;line-height:1;margin:0;padding:7px 10px}#sfp_feature_manager_metabox.postbox{float:right}.sfwd_advert p{margin:25px 0}#titlediv,#widget-list .widget-top,.postbox,.sfwd_options_wrapper .postarea,.stuffbox,.widget{border-color:#dfdfdf;border-radius:3px;box-shadow:inset 0 1px 0 #fff}.sfwd_advert h3{margin-top:6px;padding:0}.sfwd_metabox_text p{margin:0;width:101%}.sfwd_sidebar{margin-right:10px;width:457px}.sfwd_metabox_text{margin-bottom:0}.sfwd_metabox_wrapper{padding:0}.sfwd_metabox_text :last-child{margin:0}.sfwd_metabox_feature{margin-top:20px}.sfwd_option_label{color:#5f5f5f!important;float:right;margin:5px;max-width:300px;min-width:210px;text-align:left;vertical-align:top;width:38%}.sfwd_metabox_text h2{font-size:14px;font-weight:700;line-height:29px;padding:0}#sfwd-about .sfwd_metabox_text #mc-embedded-subscribe-form h2{font-size:13px}.sfwd input[readonly]{background-color:#eee;margin:5px 0!important}.sfwd_settings_left{float:right;margin:0;padding:0;width:100%}.sfwd_right_sidebar{float:left}.sfwd_options{margin:18px 0 10px;width:100%}.sfwd_input{clear:right;padding:5px;width:100%}.sfwd_option_input{float:right;margin:5px;max-width:900px;min-width:320px;width:58%}#side-sortables .sfwd_option_input{max-width:220px;min-width:220px}.sfwd_no_label .sfwd_option_input,.sfwd_top_label .sfwd_option_input{width:100%}.sfwd_settings_left .postbox{float:right;width:100%}.sfwd_option_setting_label{float:right;max-width:175px;min-height:35px;min-width:125px;width:25%}.sfwd_settings_left .postbox .inside{margin:0;padding:0}#sfwd_opengraph_settings{width:100%}.sfwd_no_label{float:right;margin:0 13px 20px 23px;width:92%}.sfwd_top_label{margin:0 10px;width:96%}.sfwd_hidden_type{height:0;margin:0;padding:0}.sfwd_module.error.below-h2{margin:0 0 15px 477px!important;padding:5px 0}.sfwd_input input[type=checkbox],.sfwd_input input[type=radio]{vertical-align:text-bottom}#sfp{width:100%}.sfwd_input.sfwd_top_label .sfwd_option_input{margin:0 0 10px}.sfwd_error_notice{color:#5f5f5f;font-size:15px;font-style:italic}#sfwd-courses_course_price_billing_cycle select{height:35px;margin-top:-4px}#sfwd-courses_course_price_billing_cycle input{width:40px}.sfwd_help_text ul{margin:15px 20px 0 0}.sfwd_help_text ul li{line-height:20px;margin:0}.sfwd_sidebar #side-sortables{width:98%}.sfwd_header_tabs li{display:inline;margin:0;padding:0}.sfwd_header_nav,.sfwd_header_tabs{margin:0}.sfwd_header_tabs li a.sfwd_header_tab.active{background-color:#fff;background-color:#ffffffbf}.sfwd_header_tabs li a.sfwd_header_tab{border:1px solid #ccc;border-right:none;color:#464646;font-size:15px;margin:0;padding:6px 6px 1px;text-decoration:none}.sfwd_header_tabs li:first-child a.sfwd_header_tab{border-right:1px solid #ccc}.sfwd_tab{background-color:#fff;background-color:#ffffff80;border:1px solid #ccc}.wrap>h2{padding-bottom:14px}#learndash_group_users_search{display:none}table.learndash-group-users-select{width:100%}table.learndash-group-users-select td.td_learndash_group_users_search{width:45%}table.learndash-group-users-select td.td_learndash_group_users_search select{height:150px;min-width:100%}body.post-type-sfwd-assignment .ld-global-header .global-new-entity-button,body.post-type-sfwd-essays .ld-global-header .global-new-entity-button,body.post-type-sfwd-transactions .ld-global-header .global-new-entity-button{display:none}table#learndash-data-reports,table#learndash-data-upgrades{border:0}.learndash-data-reports-status,.learndash-data-upgrades-status{width:100%}.learndash-data-reports-status .progress-meter,.learndash-data-upgrades-status .progress-meter{border:1px solid #000;height:20px;width:100%}.learndash-data-reports-status .progress-meter .progress-meter-image,.learndash-data-upgrades-status .progress-meter .progress-meter-image{background-color:lime;float:right;height:16px;margin:2px 0;width:0}.sfwd_input .sfwd_option_div select[multiple]{min-height:100px;width:100%}table.learndash-support-settings tbody th{padding:5px 15px 5px 0;text-align:right;vertical-align:top}.learndash-settings-page-wrap div.sfwd_options{padding-bottom:30px}.learndash_shortcodes_section .learndash_required_field{color:red}.sfwd_input.learndash-settings-field-error{background-color:#ffdfe0;border-bottom:1px solid #c89797;border-top:1px solid #c89797}.sfwd_input p.ld-clear{clear:right;height:0;padding:0}.edit-post-header__settings .components-popover__content a:hover{color:#007cba}.learndash-settings-page-wrap .error,.learndash-settings-page-wrap .error a{color:red}a.learndash-description-link{color:#000;text-decoration:none}span.learndash-description{display:none}.sfwd_options .sfwd_input p.ld-clear{line-height:0;margin:0}.sfwd_options .ld-setting-field-sub{padding-top:5px}.sfwd_options .ld-setting-field-sub input[type=button]{margin-left:5px}.ld-metabox-description p{color:#666;font-style:italic;font-weight:400;margin:5px 0 0}.sfwd_options .sfwd_option_label .descripton{clear:both;display:block;float:right;font-weight:400;text-align:right}.sfwd_options .ld-settings-sub-level-1 .sfwd_input{border-right:1px solid #ccc;margin-right:10px;padding-right:10px;position:relative}.sfwd_options .ld-settings-sub-level-1 .ld-settings-sub-level-2{border-right:1px solid #ccc;margin-right:10px;padding-right:5px}.sfwd_options .ld-settings-sub-level-1 .ld-settings-sub-level-2 .sfwd_input .sfwd_option_label{max-width:290px;width:calc(38% - 1px)}.sfwd_options .ld-settings-inner .sfwd_input{border-right:1px solid #ccc;margin-right:25px;padding-right:20px}.sfwd_options .ld-settings-inner .sfwd_input .sfwd_option_label{margin-right:0;margin-left:0;max-width:none;min-width:none;padding-left:0;width:30%}.sfwd_options .ld-settings-inner .sfwd_input .sfwd_option_label.sfwd_option_label_full,.sfwd_options .sfwd_input .sfwd_option_label.sfwd_option_label_full{width:100%}.sfwd_options .ld-settings-inner .sfwd_input .sfwd_option_input{max-width:none;min-width:120px;width:65%}.sfwd_options .ld-settings-inner .sfwd_input .sfwd_option_input.sfwd_option_input_full,.sfwd_options .sfwd_option_input.sfwd_option_input_full{width:100%}.sfwd_options .sfwd_input_type_quiz-custom-fields .sfwd_option_input.sfwd_option_input_full{float:none}.sfwd_options .ld-switch-wrapper{display:flex;margin-top:5px}.sfwd_options .ld-switch{margin-left:16px;position:relative}.sfwd_options .ld-switch__input{border:none;height:100%;right:0;margin:0;opacity:0;padding:0;position:absolute;top:0;width:100%;z-index:1}.sfwd_options .ld-switch__track{background-color:#fff;border:2px solid #6c7781;border-radius:9px;box-sizing:border-box;content:"";display:inline-block;height:18px;transition:background .2s ease,border .2s ease;vertical-align:top;width:36px}.sfwd_options .ld-switch__thumb{background-color:#6c7781;border:5px solid #6c7781;border-radius:50%;box-sizing:border-box;display:block;height:10px;right:4px;position:absolute;top:4px;transition:transform .1s ease;width:10px}.sfwd_options .ld-switch__on-off{border:2px solid #6c7781;border-radius:100%;box-sizing:border-box;display:block;height:6px;position:absolute;left:6px;top:6px;width:6px}.sfwd_options .ld-switch__input:checked~.ld-switch__track{background-color:#11a0d2;border-color:#11a0d2}.sfwd_options .ld-switch__input:checked~.ld-switch__thumb{background-color:#fff;border-width:0;transform:translateX(-18px)}.sfwd_options .ld-switch__input:checked~.ld-switch__on-off{background-color:#fff;border:0;border-radius:0;height:6px;right:8px;left:auto;width:2px}.sfwd_options .ld-switch__input:focus~.ld-switch__track{box-shadow:0 0 0 2px #fff,0 0 0 3px #6c7781;outline:2px solid #0000;outline-offset:2px}.sfwd_options .ld-switch__input:hover~.ld-switch__track{border-color:#11a0d2}.sfwd_options .ld-switch__input:checked:hover~.ld-switch__track{background-color:#6c7781;border-color:#6c7781}.sfwd_options .ld-switch.-disabled~label,.sfwd_options .ld-switch__input[disabled=disabled]{pointer-events:none}.sfwd_options .ld-switch__input[disabled=disabled]{opacity:0!important}.sfwd_options .ld-switch__input[disabled=disabled]~.ld-switch__track{opacity:.5}.sfwd_options .ld-radio-input{border:0;clip-path:inset(50%);clip:rect(1px,1px,1px,1px);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;word-wrap:normal!important}.sfwd_options .ld-radio-input__label{margin-left:16px}.sfwd_options .ld-radio-input__label:before{border:2px solid #6c7781;border-radius:100%;box-sizing:border-box;content:"";display:inline-block;height:16px;margin-left:10px;vertical-align:middle;width:16px}.sfwd_options .ld-radio-input__label>span{color:#5f5f5f;font-weight:700;vertical-align:middle}.sfwd_options .ld-radio-input:checked+.ld-radio-input__label:before{background-color:#11a0d2;box-shadow:inset 0 0 0 2px #fff}.sfwd_options .ld-radio-input:checked:focus+.ld-radio-input__label:before{box-shadow:inset 0 0 0 2px #fff,0 0 0 2px #fff,0 0 0 3px #6c7781}.sfwd_options .ld-radio-input:focus+.ld-radio-input__label:before{box-shadow:0 0 0 2px #fff,0 0 0 3px #6c7781;outline:2px solid #0000;outline-offset:2px}.sfwd_options .ld-radio-input:hover+.ld-radio-input__label:before{border-color:#11a0d2}.sfwd_options .ld-radio-input[disabled=disabled],.sfwd_options .ld-radio-input[disabled=disabled]+.ld-radio-input__label{pointer-events:none}.sfwd_options .ld-radio-input[disabled=disabled]+.ld-radio-input__label:before{opacity:.5}.sfwd_options .ld-radio-description{color:#666;padding-right:25px}.sfwd_options .ld-checkbox-input{border:0;clip-path:inset(50%);clip:rect(1px,1px,1px,1px);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;word-wrap:normal!important}.sfwd_options .ld-checkbox-input__label{margin-left:16px}.sfwd_options .ld-checkbox-input__label:before{border:2px solid #6c7781;box-sizing:border-box;content:"";display:inline-block;height:16px;margin-left:10px;vertical-align:middle;width:16px}.sfwd_options .ld-checkbox-input__label>span{vertical-align:middle}.sfwd_options .ld-checkbox-input:checked+.ld-checkbox-input__label:before{align-items:center;color:#11a0d2;content:"✓";display:inline-flex;font-weight:900;justify-content:center}.sfwd_options .ld-checkbox-input:focus+.ld-checkbox-input__label:before{box-shadow:0 0 0 2px #fff,0 0 0 3px #6c7781;outline:2px solid #0000;outline-offset:2px}.sfwd_options .ld-checkbox-input:hover+.ld-checkbox-input__label:before{border-color:#11a0d2}.sfwd_options .ld-checkbox-input[disabled=disabled],.sfwd_options .ld-checkbox-input[disabled=disabled]+.ld-checkbox-input__label{pointer-events:none}.sfwd_options .ld-checkbox-input[disabled=disabled]+.ld-checkbox-input__label:before{opacity:.5}.sfwd_options .sfwd_option_input p.learndash-section-field-checkbox-p{margin:3px 0 0;padding:0}.sfwd_options .learndash-section-field-text{border:1px solid #ddd;border-radius:2px;box-shadow:none;box-sizing:border-box;font-size:14px;padding:5px 7px;width:100%}.sfwd_options .learndash-section-field-number.-medium,.sfwd_options .learndash-section-field-text.-medium,.sfwd_options .learndash-section-field-url.-medium{width:50%}.sfwd_options .learndash-section-field-number.-small,.sfwd_options .learndash-section-field-text.-small,.sfwd_options .learndash-section-field-url.-small{width:100px}.sfwd_options .learndash-section-field-number:focus,.sfwd_options .learndash-section-field-text:focus{border-color:#11a0d2;outline:0}.sfwd_options .learndash-section-field-number:hover,.sfwd_options .learndash-section-field-text:hover,.sfwd_options .learndash-section-field-url:hover{border-color:#999}.sfwd_options .learndash-section-field-number.full-text,.sfwd_options .learndash-section-field-text.full-text,.sfwd_options .learndash-section-field-url.full-text{width:100%}.sfwd_options span.learndash_settings_field_text_prefix.-medium{color:#33333380;display:inline-block;padding-bottom:0;padding-top:0;width:75%}.sfwd_options span.learndash_settings_field_text_prefix input[type=text]{border:0;padding-bottom:8px;padding-right:0;width:max-content}.sfwd_options .ld-select{background-color:#fff;border:1px solid #ccc;border-radius:3px;display:inline-block;max-width:450px;overflow:hidden;position:relative;vertical-align:middle;width:100%}.sfwd_options .ld-select:after{border-bottom:0;border-right:5px solid #0000;border-left:5px solid #0000;border-top:5px solid #000;content:"";height:0;pointer-events:none;position:absolute;left:5px;speak:none;top:50%;transform:translateY(-50%);width:0}.sfwd_options .ld-select-multiple:after,.sfwd_options .ld-select2:after{border:none}.select2-container--learndash .select2-selection--single .select2-selection__rendered{color:#72777c!important}.select2-container--learndash .select2-results__option--highlighted[aria-selected]{background-color:#11a0d2!important}.sfwd_options .ld-select-multiple.ld-select2 .select2-container .select2-selection__rendered>:first-child.select2-search--inline,.sfwd_options .ld-select-multiple.ld-select2 .select2-container .select2-selection__rendered>:first-child.select2-search--inline .select2-search__field{width:100%!important}.sfwd_options .ld-select-multiple.ld-select2 .select2-container li{margin-bottom:0}.sfwd_options .select2-container .select2-search--inline .select2-search__field{margin-bottom:2px;margin-top:3px}.sfwd_options .ld-select select{appearance:none;background:none;border:0;font-size:14px;height:100%;margin:0;max-width:100%;padding:5px 10px;width:100%;z-index:2}.sfwd_options .ld-select select:focus{box-shadow:inset 0 0 0 1px #6c7781}.sfwd_options .ld-select select::-ms-expand{display:none}.sfwd_options .ld-select select:-moz-focusring{text-shadow:var(--select--focus-ring--text-shadow)}.sfwd_options .ld-select select option{border:0;width:100%}.sfwd_options .ld-select2 .select2-container--learndash{height:100%;max-width:450px;width:100%!important}.sfwd_options .ld-select2 .select2-container--learndash .select2-selection--single{border:0;height:100%;padding-bottom:3px;padding-top:3px}.sfwd_options .ld-select2 .select2-container--learndash .select2-selection--single .select2-selection__arrow{height:100%}.sfwd_options .ld-select2 .select2-container--learndash .select2-selection--single .select2-selection__arrow b{border-top-color:inherit}.sfwd_options .select2-container--learndash .select2-selection--multiple{border:0 solid #aaa!important}.sfwd_options .select2-container .select2-search--inline .select2-search__field{color:#444!important;padding-top:5px!important}body.edit-php .tablenav.top .select2-container--learndash,body.users-php .tablenav.top .select2-container--learndash{-webkit-appearance:none;border-color:#7e8993;border-radius:3px;box-shadow:none;color:#32373c!important;cursor:pointer;float:right;font-size:14px;line-height:2;margin-right:1px;margin-left:6px;max-width:25rem;min-height:30px;vertical-align:middle}body.edit-php .tablenav.top .select2-container--learndash .select2-selection--single,body.users-php .tablenav.top .select2-container--learndash .select2-selection--single{background-color:#fff;background:#fff url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M5%206l5%205%205-5%202%201-7%207-7-7%202-1z%22%20fill%3D%22%23555%22%2F%3E%3C%2Fsvg%3E") no-repeat left 5px top 55%;background-size:16px 16px;border:1px solid #7e8993;border-radius:4px;box-shadow:0 0 0 #0000;color:#32373c!important;height:30px}body.edit-php .tablenav.top .select2-container--learndash .select2-selection--single .select2-selection__placeholder,body.users-php .tablenav.top .select2-container--learndash .select2-selection--single .select2-selection__placeholder{color:#32373c!important}body.edit-php .tablenav.top .select2-container--learndash .select2-selection--single .select2-selection__arrow,body.users-php .tablenav.top .select2-container--learndash .select2-selection--single .select2-selection__arrow{display:none}.sfwd_options .sfwd_option_div p.ld-radio-input-wrapper{margin-bottom:1px}.sfwd_options .sfwd_input textarea{color:#515151;font-size:14px;line-height:25px;margin:0;width:100%}.sfwd_options .sfwd_input>.sfwd_input:first-child{margin-top:20px}.sfwd_options .sfwd_option_input p{margin-top:0}.sfwd_options .sfwd_option_label{box-sizing:border-box;flex:1 0 100%;font-weight:700;margin-bottom:10px;padding-left:0}.sfwd_options .sfwd_option_input{flex:1 0 100%;margin-bottom:10px}.sfwd_options .sfwd_option_div select[multiple]{min-height:100px;width:100%}.sfwd_options .ld-settings-inner-state-closed,.sfwd_options .ld-settings-sub.ld-settings-sub-state-closed,.sfwd_options .ld-theme-settings-section-state-closed{display:none}.sfwd_options .ld-settings-inner-state-open .sfwd_options .ld-theme-settings-section-state-open,.sfwd_options .ld-settings-sub.ld-settings-sub-state-open{display:block}.sfwd_options .ld-settings-sub-advanced .sfwd_input{border-right:1px solid #ccc;margin-right:1px}.sfwd_options .ld-settings-sub-advanced .ld-settings-sub-advanced-inner-state-closed{display:none}.sfwd_options .ld-settings-sub-advanced .ld-settings-sub-advanced-inner-state-open{display:block}.sfwd_options .ld-settings-sub-advanced .ld-settings-sub-advanced-inner .sfwd_option_input,.sfwd_options .ld-settings-sub-advanced .ld-settings-sub-advanced-inner .sfwd_option_label{width:auto}.sfwd_options .tooltip{display:inline-block;opacity:1;position:relative}.sfwd_options .tooltip .tooltiptext{background-color:#11a0d2;border-radius:6px;bottom:100%;color:#fff;right:50%;margin-bottom:5px;margin-right:-90px;padding:5px 0;position:absolute;text-align:center;visibility:hidden;width:180px;z-index:1}.sfwd_options .-disabled.tooltip:hover .tooltiptext{visibility:visible}.sfwd_options .tooltip .tooltiptext:after{border:5px solid #0000;border-top-color:#11a0d2;content:" ";right:50%;margin-right:-5px;position:absolute;top:100%}.sfwd_options .form_table_wrapper{border:0 solid #c2c2c2;margin-top:0;padding:0}.sfwd_options .form_table_wrapper table{border-collapse:collapse}.sfwd_options .form_table_wrapper #form_add{background-color:#0000;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%27256%27 height=%27256%27%3E%3Cpath fill=%27%23007cba%27 d=%27M185.066 128c0 3.534-2.866 6-6.4 6H134v44.666c0 3.534-2.467 6.399-6 6.399s-6-2.865-6-6.399V134H77.332c-3.535 0-6.4-2.466-6.4-6s2.866-6 6.4-6H122V77.331c0-3.534 2.466-6.4 6-6.4s6 2.866 6 6.4V122h44.666c3.534 0 6.4 2.466 6.4 6M256 128C256 57.42 198.58 0 128 0S0 57.42 0 128s57.42 128 128 128 128-57.42 128-128m-12.8 0c0 63.521-51.679 115.2-115.2 115.2S12.8 191.521 12.8 128 64.478 12.8 128 12.8c63.521 0 115.2 51.678 115.2 115.2%27/%3E%3C/svg%3E");background-position:center right 3px;background-repeat:no-repeat;background-size:16px 16px;border:0;box-shadow:none;color:#007cba;cursor:pointer;font-size:14px;font-weight:700;padding:5px 30px 5px 10px}.sfwd_options .form_table_wrapper #form_add:hover{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%27256%27 height=%27256%27%3E%3Cpath fill=%27%2311a0d2%27 d=%27M185.066 128c0 3.534-2.866 6-6.4 6H134v44.666c0 3.534-2.467 6.399-6 6.399s-6-2.865-6-6.399V134H77.332c-3.535 0-6.4-2.466-6.4-6s2.866-6 6.4-6H122V77.331c0-3.534 2.466-6.4 6-6.4s6 2.866 6 6.4V122h44.666c3.534 0 6.4 2.466 6.4 6M256 128C256 57.42 198.58 0 128 0S0 57.42 0 128s57.42 128 128 128 128-57.42 128-128m-12.8 0c0 63.521-51.679 115.2-115.2 115.2S12.8 191.521 12.8 128 64.478 12.8 128 12.8c63.521 0 115.2 51.678 115.2 115.2%27/%3E%3C/svg%3E");color:#11a0d2}.sfwd_options .form_table_wrapper .form_move{text-decoration:none}.sfwd_options .form_table_wrapper .form_delete{background-color:#0000;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%2720%27 height=%2720%27 aria-hidden=%27true%27 class=%27dashicon dashicons-dismiss%27%3E%3Cpath fill=%27%23a00%27 d=%27M10 2c4.42 0 8 3.58 8 8s-3.58 8-8 8-8-3.58-8-8 3.58-8 8-8m5 11-3-3 3-3-2-2-3 3-3-3-2 2 3 3-3 3 2 2 3-3 3 3z%27/%3E%3C/svg%3E");background-position:center right 3px;background-repeat:no-repeat;border:0;color:#a00;cursor:pointer;font-weight:700;margin:0;opacity:0;padding:5px 30px 5px 10px;transition:opacity .1s;visibility:hidden}.sfwd_options .form_table_wrapper .form_delete:hover{color:red}.sfwd_options .form_table_wrapper tbody.ui-sortable tr:hover .form_delete{opacity:1;visibility:visible}.sfwd_options .form_table_wrapper tbody.ui-sortable tr td,.sfwd_options .form_table_wrapper thead tr th{padding:10px 5px;transition:box-shadow .1s}.sfwd_options .form_table_wrapper tbody.ui-sortable tr:hover td{box-shadow:0 1px 0 0 #11a0d2,0 -1px 0 0 #11a0d2}.sfwd_options .form_table_wrapper tbody.ui-sortable tr:hover td:first-of-type{box-shadow:0 1px 0 0 #11a0d2,0 -1px 0 0 #11a0d2,1px 0 0 0 #11a0d2}.sfwd_options .form_table_wrapper tbody.ui-sortable tr:hover td:last-of-type{box-shadow:0 1px 0 0 #11a0d2,0 -1px 0 0 #11a0d2,-1px 0 0 0 #11a0d2}.sfwd_options .form_table_wrapper tbody.ui-sortable tr td:first-of-type{text-align:center}.sfwd_options .form_table_wrapper .ld-select.-field select{padding:0 10px}.sfwd_options .form_table_wrapper #form_table thead th{text-transform:uppercase}.sfwd_options .form_table_wrapper #form_add_wrapper{margin-right:10px;margin-top:10px}#learndash-quiz-resultList ul#resultList{width:100%}#learndash-quiz-resultList ul#resultList li{border:1px dotted;padding:5px}#learndash-quiz-resultList ul#resultList li .resultHeader{background-color:#ebebeb;margin-bottom:5px;padding:10px}#learndash-quiz-resultList input.addResult{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%27256%27 height=%27256%27%3E%3Cpath fill=%27%23007cba%27 d=%27M185.066 128c0 3.534-2.866 6-6.4 6H134v44.666c0 3.534-2.467 6.399-6 6.399s-6-2.865-6-6.399V134H77.332c-3.535 0-6.4-2.466-6.4-6s2.866-6 6.4-6H122V77.331c0-3.534 2.466-6.4 6-6.4s6 2.866 6 6.4V122h44.666c3.534 0 6.4 2.466 6.4 6M256 128C256 57.42 198.58 0 128 0S0 57.42 0 128s57.42 128 128 128 128-57.42 128-128m-12.8 0c0 63.521-51.679 115.2-115.2 115.2S12.8 191.521 12.8 128 64.478 12.8 128 12.8c63.521 0 115.2 51.678 115.2 115.2%27/%3E%3C/svg%3E");background-size:16px 16px;color:#007cba;font-size:14px}#learndash-quiz-resultList input.addResult,#learndash-quiz-resultList ul#resultList li input.deleteResult{background-color:#0000;background-position:center right 3px;background-repeat:no-repeat;border:0;cursor:pointer;font-weight:700;padding:5px 30px 5px 10px}#learndash-quiz-resultList ul#resultList li input.deleteResult{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%2720%27 height=%2720%27 aria-hidden=%27true%27 class=%27dashicon dashicons-dismiss%27%3E%3Cpath fill=%27%23a00%27 d=%27M10 2c4.42 0 8 3.58 8 8s-3.58 8-8 8-8-3.58-8-8 3.58-8 8-8m5 11-3-3 3-3-2-2-3 3-3-3-2 2 3 3-3 3 2 2 3-3 3 3z%27/%3E%3C/svg%3E");color:#a00;float:left;margin:0;opacity:0;transition:opacity .1s;visibility:hidden}#learndash-quiz-resultList ul#resultList li:hover input.deleteResult{opacity:1;visibility:visible}#learndash-quiz-resultList #resultList li .expand-arrow{cursor:pointer;float:left;margin-top:3px}#learndash-quiz-resultList #resultList li .expand-arrow-up svg{transform:rotate(-180deg)}.sfwd_options .sfwd_option_label .descripton p{margin-bottom:0}.sfwd_options .sfwd_option_input_full{margin-right:0;margin-left:0}.learndash_navigation_questions_list ul.learndash-quiz-questions li a{font-weight:400;text-decoration:none!important}.learndash_navigation_questions_list ul.learndash-quiz-questions li.ld-question-overview-widget-item-current a{font-weight:700}.learndash_navigation_questions_list .ld-question-overview-widget-add{font-weight:700;text-decoration:none!important}.sfwd_options #learndash-quiz-admin-data-handling-settings_associated_settings_field,.sfwd_options #learndash-quiz-admin-data-handling-settings_emailNotification_field,.sfwd_options #learndash-quiz-admin-data-handling-settings_statisticsIpLock_field,.sfwd_options #learndash-quiz-admin-data-handling-settings_timeLimitCookie_field,.sfwd_options #learndash-quiz-admin-data-handling-settings_toplistDataAddBlock_field,.sfwd_options #learndash-quiz-admin-data-handling-settings_toplistDataShowIn_field,.sfwd_options #learndash-quiz-display-content-settings_quizModus_multiple_questionsPerPage_field,.sfwd_options #learndash-quiz-display-content-settings_quizModus_single_feedback_field,.sfwd_options #learndash-quiz-display-content-settings_showMaxQuestionValue_field,.sfwd_options #learndash-quiz-display-content-settings_showMaxQuestion_field,.sfwd_options #learndash-quiz-results-options_resultText_field{border-right:none;margin-right:0;padding-right:0}.sfwd_options #learndash-course-access-settings_course_access_list_field,.sfwd_options #learndash-course-display-content-settings_course_materials_field,.sfwd_options #learndash-lesson-display-content-settings_lesson_assignment_points_amount_field,.sfwd_options #learndash-lesson-display-content-settings_lesson_materials_field,.sfwd_options #learndash-quiz-display-content-settings_quizModus_single_back_button_field,.sfwd_options #learndash-quiz-display-content-settings_quiz_materials_field,.sfwd_options #learndash-quiz-display-content-settings_showMaxQuestionValue_field,.sfwd_options #learndash-topic-display-content-settings_lesson_assignment_points_amount_field,.sfwd_options #learndash-topic-display-content-settings_topic_materials_field{border-right:none}.sfwd_options #learndash-lesson-access-settings_visible_after_field,.sfwd_options #learndash-lesson-access-settings_visible_after_specific_date_field,.sfwd_options #learndash-quiz-display-content-settings_quizModus_single_back_button_field{border-right:none;padding-right:0}.sfwd_options #learndash-quiz-results-options_resultText_field{padding-right:10px}.sfwd_options input[name=templateLoad],.sfwd_options input[name=templateName]{margin-top:5px}.ld-settings-inner .ld-radio-input__label>span{font-weight:400}.ld-divider{border-bottom:1px solid #eee;margin:20px 0}.sfwd_options .ld-settings-inner .sfwd_option_input,.sfwd_options .ld-settings-inner-lesson_video_display_timing_after .sfwd_option_input{width:40%!important}.sfwd_options #learndash-lesson-access-settings_visible_after_specific_date_field .sfwd_option_input{width:80%!important}.sfwd_options .ld-settings-sub .sfwd_option_label{max-width:285px;width:calc(38% - 15px)}.sfwd_options #learndash-lesson-display-content-settings_assignment_upload_limit_count_field .sfwd_option_label,.sfwd_options #learndash-lesson-display-content-settings_lesson_assignment_deletion_enabled_field .sfwd_option_label{width:35%!important}.sfwd_options #learndash-lesson-access-settings_visible_after_specific_date_field input[type=number]{padding:0!important}.sfwd_options .ld-settings-inner-lesson_video_display_timing_after .sfwd_option_label{width:35%!important}.sfwd_options .ld-settings-inner-quizModus_single .sfwd_option_input{width:65%!important}.sfwd_options .ld-settings-email-header-wrapper{margin-bottom:30px}.sfwd_options .ld-settings-email-header{font-weight:700}.sfwd_options .ld-settings-email-description{font-weight:300}.sfwd_options .learndash_settings_field_invalid label.sfwd_label{color:red}.sfwd_options .learndash_settings_field_invalid input:invalid{border:1px solid red;box-shadow:none}.sfwd_options .learndash_settings_field_invalid .learndash-section-field-error{color:red}#learndash-settings-fields-notice-errors p.errors-header{font-weight:900}#learndash-settings-fields-notice-errors ul.errors-list{list-style:disc}#learndash-settings-fields-notice-errors ul.errors-list li{margin-right:15px}.ld__builder-sidebar-widget .components-checkbox-control__input[type=checkbox]:checked:before{content:url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2020%2020%27%3E%3Cpath%20d%3D%27M14.83%204.89l1.34.94-5.81%208.38H9.02L5.78%209.67l1.34-1.25%202.57%202.4z%27%20fill%3D%27%231e8cbe%27%2F%3E%3C%2Fsvg%3E")}.plugin-update p.ld-plugin-update-notice:before{content:"";margin-left:0}.notice.ld-plugin-update-notice,.plugin-update .ld-plugin-update-notice{margin-top:10px;padding:10px}.ld-plugin-update-notice .version{font-weight:700}.ld-plugin-update-notice .header{font-size:130%;font-weight:700}.ld_settings_postbox .ld-settings-info-banner{display:block;margin:5px 0;padding:5px 10px}.ld_settings_postbox .ld-settings-info-banner p:before{float:right;font:400 20px/1 dashicons}.ld_settings_postbox .ld-settings-info-banner p{font-size:13px;line-height:1.5em;margin:.5em 0;padding:0;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;vertical-align:top}.ld_settings_postbox .ld-settings-info-banner.ld-settings-info-banner-alert{background-color:#fbeaea;border-right:2px solid #dc3232}.ld_settings_postbox .ld-settings-info-banner.ld-settings-info-banner-alert p:before{color:#dc3232;content:"";margin-left:6px}.ld_settings_postbox .ld-settings-info-banner.ld-settings-info-banner-success{border-color:#46b450;border-style:solid;border-width:0 2px 1px 0}ul.learndash-settings-sub{float:none}table.learndash-settings-table th,ul.learndash-settings-sub li.learndash-settings-sub-current a{font-weight:700}table.learndash-settings-table td.col-valign-middle{vertical-align:middle}table.learndash-settings-table-sortable .ui-sortable-helper{display:table}table.learndash-settings-table-sortable td.col-name-move{cursor:grab}.edit-post-sidebar #learndash_group_attributes_metabox select#group_parent_id{max-width:85%;width:100%}#learndash_group_attributes_metabox input#group_menu_order{display:block}.edit-post-sidebar #learndash_group_attributes_metabox .group-menu-order-label-wrapper{margin-top:10px}.ld_settings_postbox .postbox-header{display:block}.edit-post-meta-boxes-area #poststuff #learndash_course_builder .postbox-header .hndle,.edit-post-meta-boxes-area #poststuff #learndash_quiz_builder .postbox-header .hndle,.edit-post-meta-boxes-area #poststuff .ld_settings_postbox .postbox-header .hndle{border-bottom:none;padding:5px 12px;width:auto}.ld_settings_postbox .postbox-header .hndle{display:inline-block}.ld_settings_postbox .postbox-header .handle-actions{display:inline-block;float:left}.ld_settings_postbox .postbox-header .handle-actions .handle-order-higher,.ld_settings_postbox .postbox-header .handle-actions .handle-order-lower,body[data-active-tab=learndash_course_builder] .postbox-header .handle-actions .handle-order-higher,body[data-active-tab=learndash_course_builder] .postbox-header .handle-actions .handle-order-lower,body[data-active-tab=learndash_quiz_builder] .postbox-header .handle-actions .handle-order-higher,body[data-active-tab=learndash_quiz_builder] .postbox-header .handle-actions .handle-order-lower{display:none}.ld_settings_postbox .postbox-header .ld-metabox-description{display:block;padding:0 12px 5px}#certificate-shortcodes.wrap .inside .dashicons,#certificate-shortcodes.wrap .inside .dashicons-before:before,#course-shortcodes.wrap .inside .dashicons,#course-shortcodes.wrap .inside .dashicons-before:before{text-decoration:none}.notice.connect-stripe .learndash-stripe-connect,.sfwd_options .learndash-stripe-connect{align-items:center;background:#6772e5;border-radius:5px;color:#fff;display:flex;font-size:16px;justify-content:center;letter-spacing:.6px;padding:6px 24px;text-decoration:none;transition:all .3s ease;width:200px}.learndash-stripe-connect:focus,.learndash-stripe-connect:hover,.notice.connect-stripe .learndash-stripe-connect:active,.notice.connect-stripe .learndash-stripe-connect:focus,.notice.connect-stripe .learndash-stripe-connect:hover,.sfwd_options .learndash-stripe-connect:active{background:#3f4ddf;color:#fff}.notice.connect-stripe .learndash-stripe-connect .stripe-logo,.sfwd_options .learndash-stripe-connect .stripe-logo{padding:2px 0 0 10px} diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/meta-box.min.css b/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/meta-box.min.css new file mode 100644 index 000000000..c5e79ffa4 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/meta-box.min.css @@ -0,0 +1 @@ +.form-table.sfwd{clear:none}.form-table.sfwd td{font-size:12px;line-height:20px;padding:16px 0 10px;vertical-align:top}.form-table.sfwd th{padding:10px 0 12px 9px;width:200px}.sfwd_help_text_link{align-items:center;display:flex;flex-direction:row-reverse;float:left;justify-content:space-between;max-width:300px;text-align:left;width:100%}.sfwd_help_text_link img{float:left;height:30px;width:30px}.sfwd_label{color:#5f5f5f;flex:1;float:right;font-weight:700;line-height:19px;margin:0;width:60%}.sfwd_help_text_div{margin:10px 0;text-align:left;width:100%}.sfwd_help_text{clear:left;color:#797979;float:left;font-size:12px;font-style:italic;font-weight:lighter;line-height:15px;margin-right:30px}.sfwd_head_tagline{color:#5f5f5f;font-size:13px}.sfwd_head_nav{border-bottom:1px solid #ccc;float:left;font-family:HelveticaNeue-Light,Helvetica Neue Light,Helvetica Neue,sans-serif;font-size:18px;margin:0 0 16px;width:100%}.sfwd_head_nav_tab{border:1px solid #ccc;border-bottom:0 solid #fff;border-radius:4px 4px 0 0;color:#000;float:left;margin:0 0 0 15px;opacity:.5;padding:10px 15px;text-decoration:none;text-shadow:#fff 0 1px 0}.sfwd_head_nav_tab.sfwd_head_nav_active{border-width:1px;margin-bottom:-1px;opacity:1}.sfwd_head_nav_tab:first-child{margin-left:0}.sfwd_head_nav_tab:hover{opacity:1}.sfwd_header{clear:left;float:left}.sfwd_advert{border:1px solid #ddd;height:200px;margin-bottom:20px;padding:10px;width:423px}.sfwd_adverts{float:right}.sfwd_content{clear:left;min-width:760px}.sfwd_options_wrapper .hndle{font-family:Georgia,Times New Roman,Bitstream Charter,Times,serif;font-size:15px;font-weight:400;line-height:1;margin:0;padding:7px 10px}#sfp_feature_manager_metabox.postbox{float:left}.sfwd_advert p{margin:25px 0}#titlediv,#widget-list .widget-top,.postbox,.sfwd_options_wrapper .postarea,.stuffbox,.widget{border-color:#dfdfdf;border-radius:3px;box-shadow:inset 0 1px 0 #fff}.sfwd_advert h3{margin-top:6px;padding:0}.sfwd_metabox_text p{margin:0;width:101%}.sfwd_sidebar{margin-left:10px;width:457px}.sfwd_metabox_text{margin-bottom:0}.sfwd_metabox_wrapper{padding:0}.sfwd_metabox_text :last-child{margin:0}.sfwd_metabox_feature{margin-top:20px}.sfwd_option_label{color:#5f5f5f!important;float:left;margin:5px;max-width:300px;min-width:210px;text-align:right;vertical-align:top;width:38%}.sfwd_metabox_text h2{font-size:14px;font-weight:700;line-height:29px;padding:0}#sfwd-about .sfwd_metabox_text #mc-embedded-subscribe-form h2{font-size:13px}.sfwd input[readonly]{background-color:#eee;margin:5px 0!important}.sfwd_settings_left{float:left;margin:0;padding:0;width:100%}.sfwd_right_sidebar{float:right}.sfwd_options{margin:18px 0 10px;width:100%}.sfwd_input{clear:left;padding:5px;width:100%}.sfwd_option_input{float:left;margin:5px;max-width:900px;min-width:320px;width:58%}#side-sortables .sfwd_option_input{max-width:220px;min-width:220px}.sfwd_no_label .sfwd_option_input,.sfwd_top_label .sfwd_option_input{width:100%}.sfwd_settings_left .postbox{float:left;width:100%}.sfwd_option_setting_label{float:left;max-width:175px;min-height:35px;min-width:125px;width:25%}.sfwd_settings_left .postbox .inside{margin:0;padding:0}#sfwd_opengraph_settings{width:100%}.sfwd_no_label{float:left;margin:0 23px 20px 13px;width:92%}.sfwd_top_label{margin:0 10px;width:96%}.sfwd_hidden_type{height:0;margin:0;padding:0}.sfwd_module.error.below-h2{margin:0 477px 15px 0!important;padding:5px 0}.sfwd_input input[type=checkbox],.sfwd_input input[type=radio]{vertical-align:text-bottom}#sfp{width:100%}.sfwd_input.sfwd_top_label .sfwd_option_input{margin:0 0 10px}.sfwd_error_notice{color:#5f5f5f;font-size:15px;font-style:italic}#sfwd-courses_course_price_billing_cycle select{height:35px;margin-top:-4px}#sfwd-courses_course_price_billing_cycle input{width:40px}.sfwd_help_text ul{margin:15px 0 0 20px}.sfwd_help_text ul li{line-height:20px;margin:0}.sfwd_sidebar #side-sortables{width:98%}.sfwd_header_tabs li{display:inline;margin:0;padding:0}.sfwd_header_nav,.sfwd_header_tabs{margin:0}.sfwd_header_tabs li a.sfwd_header_tab.active{background-color:#fff;background-color:#ffffffbf}.sfwd_header_tabs li a.sfwd_header_tab{border:1px solid #ccc;border-left:none;color:#464646;font-size:15px;margin:0;padding:6px 6px 1px;text-decoration:none}.sfwd_header_tabs li:first-child a.sfwd_header_tab{border-left:1px solid #ccc}.sfwd_tab{background-color:#fff;background-color:#ffffff80;border:1px solid #ccc}.wrap>h2{padding-bottom:14px}#learndash_group_users_search{display:none}table.learndash-group-users-select{width:100%}table.learndash-group-users-select td.td_learndash_group_users_search{width:45%}table.learndash-group-users-select td.td_learndash_group_users_search select{height:150px;min-width:100%}body.post-type-sfwd-assignment .ld-global-header .global-new-entity-button,body.post-type-sfwd-essays .ld-global-header .global-new-entity-button,body.post-type-sfwd-transactions .ld-global-header .global-new-entity-button{display:none}table#learndash-data-reports,table#learndash-data-upgrades{border:0}.learndash-data-reports-status,.learndash-data-upgrades-status{width:100%}.learndash-data-reports-status .progress-meter,.learndash-data-upgrades-status .progress-meter{border:1px solid #000;height:20px;width:100%}.learndash-data-reports-status .progress-meter .progress-meter-image,.learndash-data-upgrades-status .progress-meter .progress-meter-image{background-color:lime;float:left;height:16px;margin:2px 0;width:0}.sfwd_input .sfwd_option_div select[multiple]{min-height:100px;width:100%}table.learndash-support-settings tbody th{padding:5px 0 5px 15px;text-align:left;vertical-align:top}.learndash-settings-page-wrap div.sfwd_options{padding-bottom:30px}.learndash_shortcodes_section .learndash_required_field{color:red}.sfwd_input.learndash-settings-field-error{background-color:#ffdfe0;border-bottom:1px solid #c89797;border-top:1px solid #c89797}.sfwd_input p.ld-clear{clear:left;height:0;padding:0}.edit-post-header__settings .components-popover__content a:hover{color:#007cba}.learndash-settings-page-wrap .error,.learndash-settings-page-wrap .error a{color:red}a.learndash-description-link{color:#000;text-decoration:none}span.learndash-description{display:none}.sfwd_options .sfwd_input p.ld-clear{line-height:0;margin:0}.sfwd_options .ld-setting-field-sub{padding-top:5px}.sfwd_options .ld-setting-field-sub input[type=button]{margin-right:5px}.ld-metabox-description p{color:#666;font-style:italic;font-weight:400;margin:5px 0 0}.sfwd_options .sfwd_option_label .descripton{clear:both;display:block;float:left;font-weight:400;text-align:left}.sfwd_options .ld-settings-sub-level-1 .sfwd_input{border-left:1px solid #ccc;margin-left:10px;padding-left:10px;position:relative}.sfwd_options .ld-settings-sub-level-1 .ld-settings-sub-level-2{border-left:1px solid #ccc;margin-left:10px;padding-left:5px}.sfwd_options .ld-settings-sub-level-1 .ld-settings-sub-level-2 .sfwd_input .sfwd_option_label{max-width:290px;width:calc(38% - 1px)}.sfwd_options .ld-settings-inner .sfwd_input{border-left:1px solid #ccc;margin-left:25px;padding-left:20px}.sfwd_options .ld-settings-inner .sfwd_input .sfwd_option_label{margin-left:0;margin-right:0;max-width:none;min-width:none;padding-right:0;width:30%}.sfwd_options .ld-settings-inner .sfwd_input .sfwd_option_label.sfwd_option_label_full,.sfwd_options .sfwd_input .sfwd_option_label.sfwd_option_label_full{width:100%}.sfwd_options .ld-settings-inner .sfwd_input .sfwd_option_input{max-width:none;min-width:120px;width:65%}.sfwd_options .ld-settings-inner .sfwd_input .sfwd_option_input.sfwd_option_input_full,.sfwd_options .sfwd_option_input.sfwd_option_input_full{width:100%}.sfwd_options .sfwd_input_type_quiz-custom-fields .sfwd_option_input.sfwd_option_input_full{float:none}.sfwd_options .ld-switch-wrapper{display:flex;margin-top:5px}.sfwd_options .ld-switch{margin-right:16px;position:relative}.sfwd_options .ld-switch__input{border:none;height:100%;left:0;margin:0;opacity:0;padding:0;position:absolute;top:0;width:100%;z-index:1}.sfwd_options .ld-switch__track{background-color:#fff;border:2px solid #6c7781;border-radius:9px;box-sizing:border-box;content:"";display:inline-block;height:18px;transition:background .2s ease,border .2s ease;vertical-align:top;width:36px}.sfwd_options .ld-switch__thumb{background-color:#6c7781;border:5px solid #6c7781;border-radius:50%;box-sizing:border-box;display:block;height:10px;left:4px;position:absolute;top:4px;transition:transform .1s ease;width:10px}.sfwd_options .ld-switch__on-off{border:2px solid #6c7781;border-radius:100%;box-sizing:border-box;display:block;height:6px;position:absolute;right:6px;top:6px;width:6px}.sfwd_options .ld-switch__input:checked~.ld-switch__track{background-color:#11a0d2;border-color:#11a0d2}.sfwd_options .ld-switch__input:checked~.ld-switch__thumb{background-color:#fff;border-width:0;transform:translateX(18px)}.sfwd_options .ld-switch__input:checked~.ld-switch__on-off{background-color:#fff;border:0;border-radius:0;height:6px;left:8px;right:auto;width:2px}.sfwd_options .ld-switch__input:focus~.ld-switch__track{box-shadow:0 0 0 2px #fff,0 0 0 3px #6c7781;outline:2px solid #0000;outline-offset:2px}.sfwd_options .ld-switch__input:hover~.ld-switch__track{border-color:#11a0d2}.sfwd_options .ld-switch__input:checked:hover~.ld-switch__track{background-color:#6c7781;border-color:#6c7781}.sfwd_options .ld-switch.-disabled~label,.sfwd_options .ld-switch__input[disabled=disabled]{pointer-events:none}.sfwd_options .ld-switch__input[disabled=disabled]{opacity:0!important}.sfwd_options .ld-switch__input[disabled=disabled]~.ld-switch__track{opacity:.5}.sfwd_options .ld-radio-input{border:0;clip-path:inset(50%);clip:rect(1px,1px,1px,1px);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;word-wrap:normal!important}.sfwd_options .ld-radio-input__label{margin-right:16px}.sfwd_options .ld-radio-input__label:before{border:2px solid #6c7781;border-radius:100%;box-sizing:border-box;content:"";display:inline-block;height:16px;margin-right:10px;vertical-align:middle;width:16px}.sfwd_options .ld-radio-input__label>span{color:#5f5f5f;font-weight:700;vertical-align:middle}.sfwd_options .ld-radio-input:checked+.ld-radio-input__label:before{background-color:#11a0d2;box-shadow:inset 0 0 0 2px #fff}.sfwd_options .ld-radio-input:checked:focus+.ld-radio-input__label:before{box-shadow:inset 0 0 0 2px #fff,0 0 0 2px #fff,0 0 0 3px #6c7781}.sfwd_options .ld-radio-input:focus+.ld-radio-input__label:before{box-shadow:0 0 0 2px #fff,0 0 0 3px #6c7781;outline:2px solid #0000;outline-offset:2px}.sfwd_options .ld-radio-input:hover+.ld-radio-input__label:before{border-color:#11a0d2}.sfwd_options .ld-radio-input[disabled=disabled],.sfwd_options .ld-radio-input[disabled=disabled]+.ld-radio-input__label{pointer-events:none}.sfwd_options .ld-radio-input[disabled=disabled]+.ld-radio-input__label:before{opacity:.5}.sfwd_options .ld-radio-description{color:#666;padding-left:25px}.sfwd_options .ld-checkbox-input{border:0;clip-path:inset(50%);clip:rect(1px,1px,1px,1px);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;word-wrap:normal!important}.sfwd_options .ld-checkbox-input__label{margin-right:16px}.sfwd_options .ld-checkbox-input__label:before{border:2px solid #6c7781;box-sizing:border-box;content:"";display:inline-block;height:16px;margin-right:10px;vertical-align:middle;width:16px}.sfwd_options .ld-checkbox-input__label>span{vertical-align:middle}.sfwd_options .ld-checkbox-input:checked+.ld-checkbox-input__label:before{align-items:center;color:#11a0d2;content:"✓";display:inline-flex;font-weight:900;justify-content:center}.sfwd_options .ld-checkbox-input:focus+.ld-checkbox-input__label:before{box-shadow:0 0 0 2px #fff,0 0 0 3px #6c7781;outline:2px solid #0000;outline-offset:2px}.sfwd_options .ld-checkbox-input:hover+.ld-checkbox-input__label:before{border-color:#11a0d2}.sfwd_options .ld-checkbox-input[disabled=disabled],.sfwd_options .ld-checkbox-input[disabled=disabled]+.ld-checkbox-input__label{pointer-events:none}.sfwd_options .ld-checkbox-input[disabled=disabled]+.ld-checkbox-input__label:before{opacity:.5}.sfwd_options .sfwd_option_input p.learndash-section-field-checkbox-p{margin:3px 0 0;padding:0}.sfwd_options .learndash-section-field-text{border:1px solid #ddd;border-radius:2px;box-shadow:none;box-sizing:border-box;font-size:14px;padding:5px 7px;width:100%}.sfwd_options .learndash-section-field-number.-medium,.sfwd_options .learndash-section-field-text.-medium,.sfwd_options .learndash-section-field-url.-medium{width:50%}.sfwd_options .learndash-section-field-number.-small,.sfwd_options .learndash-section-field-text.-small,.sfwd_options .learndash-section-field-url.-small{width:100px}.sfwd_options .learndash-section-field-number:focus,.sfwd_options .learndash-section-field-text:focus{border-color:#11a0d2;outline:0}.sfwd_options .learndash-section-field-number:hover,.sfwd_options .learndash-section-field-text:hover,.sfwd_options .learndash-section-field-url:hover{border-color:#999}.sfwd_options .learndash-section-field-number.full-text,.sfwd_options .learndash-section-field-text.full-text,.sfwd_options .learndash-section-field-url.full-text{width:100%}.sfwd_options span.learndash_settings_field_text_prefix.-medium{color:#33333380;display:inline-block;padding-bottom:0;padding-top:0;width:75%}.sfwd_options span.learndash_settings_field_text_prefix input[type=text]{border:0;padding-bottom:8px;padding-left:0;width:max-content}.sfwd_options .ld-select{background-color:#fff;border:1px solid #ccc;border-radius:3px;display:inline-block;max-width:450px;overflow:hidden;position:relative;vertical-align:middle;width:100%}.sfwd_options .ld-select:after{border-bottom:0;border-left:5px solid #0000;border-right:5px solid #0000;border-top:5px solid #000;content:"";height:0;pointer-events:none;position:absolute;right:5px;speak:none;top:50%;transform:translateY(-50%);width:0}.sfwd_options .ld-select-multiple:after,.sfwd_options .ld-select2:after{border:none}.select2-container--learndash .select2-selection--single .select2-selection__rendered{color:#72777c!important}.select2-container--learndash .select2-results__option--highlighted[aria-selected]{background-color:#11a0d2!important}.sfwd_options .ld-select-multiple.ld-select2 .select2-container .select2-selection__rendered>:first-child.select2-search--inline,.sfwd_options .ld-select-multiple.ld-select2 .select2-container .select2-selection__rendered>:first-child.select2-search--inline .select2-search__field{width:100%!important}.sfwd_options .ld-select-multiple.ld-select2 .select2-container li{margin-bottom:0}.sfwd_options .select2-container .select2-search--inline .select2-search__field{margin-bottom:2px;margin-top:3px}.sfwd_options .ld-select select{appearance:none;background:none;border:0;font-size:14px;height:100%;margin:0;max-width:100%;padding:5px 10px;width:100%;z-index:2}.sfwd_options .ld-select select:focus{box-shadow:inset 0 0 0 1px #6c7781}.sfwd_options .ld-select select::-ms-expand{display:none}.sfwd_options .ld-select select:-moz-focusring{text-shadow:var(--select--focus-ring--text-shadow)}.sfwd_options .ld-select select option{border:0;width:100%}.sfwd_options .ld-select2 .select2-container--learndash{height:100%;max-width:450px;width:100%!important}.sfwd_options .ld-select2 .select2-container--learndash .select2-selection--single{border:0;height:100%;padding-bottom:3px;padding-top:3px}.sfwd_options .ld-select2 .select2-container--learndash .select2-selection--single .select2-selection__arrow{height:100%}.sfwd_options .ld-select2 .select2-container--learndash .select2-selection--single .select2-selection__arrow b{border-top-color:inherit}.sfwd_options .select2-container--learndash .select2-selection--multiple{border:0 solid #aaa!important}.sfwd_options .select2-container .select2-search--inline .select2-search__field{color:#444!important;padding-top:5px!important}body.edit-php .tablenav.top .select2-container--learndash,body.users-php .tablenav.top .select2-container--learndash{-webkit-appearance:none;border-color:#7e8993;border-radius:3px;box-shadow:none;color:#32373c!important;cursor:pointer;float:left;font-size:14px;line-height:2;margin-left:1px;margin-right:6px;max-width:25rem;min-height:30px;vertical-align:middle}body.edit-php .tablenav.top .select2-container--learndash .select2-selection--single,body.users-php .tablenav.top .select2-container--learndash .select2-selection--single{background-color:#fff;background:#fff url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M5%206l5%205%205-5%202%201-7%207-7-7%202-1z%22%20fill%3D%22%23555%22%2F%3E%3C%2Fsvg%3E") no-repeat right 5px top 55%;background-size:16px 16px;border:1px solid #7e8993;border-radius:4px;box-shadow:0 0 0 #0000;color:#32373c!important;height:30px}body.edit-php .tablenav.top .select2-container--learndash .select2-selection--single .select2-selection__placeholder,body.users-php .tablenav.top .select2-container--learndash .select2-selection--single .select2-selection__placeholder{color:#32373c!important}body.edit-php .tablenav.top .select2-container--learndash .select2-selection--single .select2-selection__arrow,body.users-php .tablenav.top .select2-container--learndash .select2-selection--single .select2-selection__arrow{display:none}.sfwd_options .sfwd_option_div p.ld-radio-input-wrapper{margin-bottom:1px}.sfwd_options .sfwd_input textarea{color:#515151;font-size:14px;line-height:25px;margin:0;width:100%}.sfwd_options .sfwd_input>.sfwd_input:first-child{margin-top:20px}.sfwd_options .sfwd_option_input p{margin-top:0}.sfwd_options .sfwd_option_label{box-sizing:border-box;flex:1 0 100%;font-weight:700;margin-bottom:10px;padding-right:0}.sfwd_options .sfwd_option_input{flex:1 0 100%;margin-bottom:10px}.sfwd_options .sfwd_option_div select[multiple]{min-height:100px;width:100%}.sfwd_options .ld-settings-inner-state-closed,.sfwd_options .ld-settings-sub.ld-settings-sub-state-closed,.sfwd_options .ld-theme-settings-section-state-closed{display:none}.sfwd_options .ld-settings-inner-state-open .sfwd_options .ld-theme-settings-section-state-open,.sfwd_options .ld-settings-sub.ld-settings-sub-state-open{display:block}.sfwd_options .ld-settings-sub-advanced .sfwd_input{border-left:1px solid #ccc;margin-left:1px}.sfwd_options .ld-settings-sub-advanced .ld-settings-sub-advanced-inner-state-closed{display:none}.sfwd_options .ld-settings-sub-advanced .ld-settings-sub-advanced-inner-state-open{display:block}.sfwd_options .ld-settings-sub-advanced .ld-settings-sub-advanced-inner .sfwd_option_input,.sfwd_options .ld-settings-sub-advanced .ld-settings-sub-advanced-inner .sfwd_option_label{width:auto}.sfwd_options .tooltip{display:inline-block;opacity:1;position:relative}.sfwd_options .tooltip .tooltiptext{background-color:#11a0d2;border-radius:6px;bottom:100%;color:#fff;left:50%;margin-bottom:5px;margin-left:-90px;padding:5px 0;position:absolute;text-align:center;visibility:hidden;width:180px;z-index:1}.sfwd_options .-disabled.tooltip:hover .tooltiptext{visibility:visible}.sfwd_options .tooltip .tooltiptext:after{border:5px solid #0000;border-top-color:#11a0d2;content:" ";left:50%;margin-left:-5px;position:absolute;top:100%}.sfwd_options .form_table_wrapper{border:0 solid #c2c2c2;margin-top:0;padding:0}.sfwd_options .form_table_wrapper table{border-collapse:collapse}.sfwd_options .form_table_wrapper #form_add{background-color:#0000;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%27256%27 height=%27256%27%3E%3Cpath fill=%27%23007cba%27 d=%27M185.066 128c0 3.534-2.866 6-6.4 6H134v44.666c0 3.534-2.467 6.399-6 6.399s-6-2.865-6-6.399V134H77.332c-3.535 0-6.4-2.466-6.4-6s2.866-6 6.4-6H122V77.331c0-3.534 2.466-6.4 6-6.4s6 2.866 6 6.4V122h44.666c3.534 0 6.4 2.466 6.4 6M256 128C256 57.42 198.58 0 128 0S0 57.42 0 128s57.42 128 128 128 128-57.42 128-128m-12.8 0c0 63.521-51.679 115.2-115.2 115.2S12.8 191.521 12.8 128 64.478 12.8 128 12.8c63.521 0 115.2 51.678 115.2 115.2%27/%3E%3C/svg%3E");background-position:center left 3px;background-repeat:no-repeat;background-size:16px 16px;border:0;box-shadow:none;color:#007cba;cursor:pointer;font-size:14px;font-weight:700;padding:5px 10px 5px 30px}.sfwd_options .form_table_wrapper #form_add:hover{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%27256%27 height=%27256%27%3E%3Cpath fill=%27%2311a0d2%27 d=%27M185.066 128c0 3.534-2.866 6-6.4 6H134v44.666c0 3.534-2.467 6.399-6 6.399s-6-2.865-6-6.399V134H77.332c-3.535 0-6.4-2.466-6.4-6s2.866-6 6.4-6H122V77.331c0-3.534 2.466-6.4 6-6.4s6 2.866 6 6.4V122h44.666c3.534 0 6.4 2.466 6.4 6M256 128C256 57.42 198.58 0 128 0S0 57.42 0 128s57.42 128 128 128 128-57.42 128-128m-12.8 0c0 63.521-51.679 115.2-115.2 115.2S12.8 191.521 12.8 128 64.478 12.8 128 12.8c63.521 0 115.2 51.678 115.2 115.2%27/%3E%3C/svg%3E");color:#11a0d2}.sfwd_options .form_table_wrapper .form_move{text-decoration:none}.sfwd_options .form_table_wrapper .form_delete{background-color:#0000;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%2720%27 height=%2720%27 aria-hidden=%27true%27 class=%27dashicon dashicons-dismiss%27%3E%3Cpath fill=%27%23a00%27 d=%27M10 2c4.42 0 8 3.58 8 8s-3.58 8-8 8-8-3.58-8-8 3.58-8 8-8m5 11-3-3 3-3-2-2-3 3-3-3-2 2 3 3-3 3 2 2 3-3 3 3z%27/%3E%3C/svg%3E");background-position:center left 3px;background-repeat:no-repeat;border:0;color:#a00;cursor:pointer;font-weight:700;margin:0;opacity:0;padding:5px 10px 5px 30px;transition:opacity .1s;visibility:hidden}.sfwd_options .form_table_wrapper .form_delete:hover{color:red}.sfwd_options .form_table_wrapper tbody.ui-sortable tr:hover .form_delete{opacity:1;visibility:visible}.sfwd_options .form_table_wrapper tbody.ui-sortable tr td,.sfwd_options .form_table_wrapper thead tr th{padding:10px 5px;transition:box-shadow .1s}.sfwd_options .form_table_wrapper tbody.ui-sortable tr:hover td{box-shadow:0 1px 0 0 #11a0d2,0 -1px 0 0 #11a0d2}.sfwd_options .form_table_wrapper tbody.ui-sortable tr:hover td:first-of-type{box-shadow:0 1px 0 0 #11a0d2,0 -1px 0 0 #11a0d2,-1px 0 0 0 #11a0d2}.sfwd_options .form_table_wrapper tbody.ui-sortable tr:hover td:last-of-type{box-shadow:0 1px 0 0 #11a0d2,0 -1px 0 0 #11a0d2,1px 0 0 0 #11a0d2}.sfwd_options .form_table_wrapper tbody.ui-sortable tr td:first-of-type{text-align:center}.sfwd_options .form_table_wrapper .ld-select.-field select{padding:0 10px}.sfwd_options .form_table_wrapper #form_table thead th{text-transform:uppercase}.sfwd_options .form_table_wrapper #form_add_wrapper{margin-left:10px;margin-top:10px}#learndash-quiz-resultList ul#resultList{width:100%}#learndash-quiz-resultList ul#resultList li{border:1px dotted;padding:5px}#learndash-quiz-resultList ul#resultList li .resultHeader{background-color:#ebebeb;margin-bottom:5px;padding:10px}#learndash-quiz-resultList input.addResult{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%27256%27 height=%27256%27%3E%3Cpath fill=%27%23007cba%27 d=%27M185.066 128c0 3.534-2.866 6-6.4 6H134v44.666c0 3.534-2.467 6.399-6 6.399s-6-2.865-6-6.399V134H77.332c-3.535 0-6.4-2.466-6.4-6s2.866-6 6.4-6H122V77.331c0-3.534 2.466-6.4 6-6.4s6 2.866 6 6.4V122h44.666c3.534 0 6.4 2.466 6.4 6M256 128C256 57.42 198.58 0 128 0S0 57.42 0 128s57.42 128 128 128 128-57.42 128-128m-12.8 0c0 63.521-51.679 115.2-115.2 115.2S12.8 191.521 12.8 128 64.478 12.8 128 12.8c63.521 0 115.2 51.678 115.2 115.2%27/%3E%3C/svg%3E");background-size:16px 16px;color:#007cba;font-size:14px}#learndash-quiz-resultList input.addResult,#learndash-quiz-resultList ul#resultList li input.deleteResult{background-color:#0000;background-position:center left 3px;background-repeat:no-repeat;border:0;cursor:pointer;font-weight:700;padding:5px 10px 5px 30px}#learndash-quiz-resultList ul#resultList li input.deleteResult{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%2720%27 height=%2720%27 aria-hidden=%27true%27 class=%27dashicon dashicons-dismiss%27%3E%3Cpath fill=%27%23a00%27 d=%27M10 2c4.42 0 8 3.58 8 8s-3.58 8-8 8-8-3.58-8-8 3.58-8 8-8m5 11-3-3 3-3-2-2-3 3-3-3-2 2 3 3-3 3 2 2 3-3 3 3z%27/%3E%3C/svg%3E");color:#a00;float:right;margin:0;opacity:0;transition:opacity .1s;visibility:hidden}#learndash-quiz-resultList ul#resultList li:hover input.deleteResult{opacity:1;visibility:visible}#learndash-quiz-resultList #resultList li .expand-arrow{cursor:pointer;float:right;margin-top:3px}#learndash-quiz-resultList #resultList li .expand-arrow-up svg{transform:rotate(180deg)}.sfwd_options .sfwd_option_label .descripton p{margin-bottom:0}.sfwd_options .sfwd_option_input_full{margin-left:0;margin-right:0}.learndash_navigation_questions_list ul.learndash-quiz-questions li a{font-weight:400;text-decoration:none!important}.learndash_navigation_questions_list ul.learndash-quiz-questions li.ld-question-overview-widget-item-current a{font-weight:700}.learndash_navigation_questions_list .ld-question-overview-widget-add{font-weight:700;text-decoration:none!important}.sfwd_options #learndash-quiz-admin-data-handling-settings_associated_settings_field,.sfwd_options #learndash-quiz-admin-data-handling-settings_emailNotification_field,.sfwd_options #learndash-quiz-admin-data-handling-settings_statisticsIpLock_field,.sfwd_options #learndash-quiz-admin-data-handling-settings_timeLimitCookie_field,.sfwd_options #learndash-quiz-admin-data-handling-settings_toplistDataAddBlock_field,.sfwd_options #learndash-quiz-admin-data-handling-settings_toplistDataShowIn_field,.sfwd_options #learndash-quiz-display-content-settings_quizModus_multiple_questionsPerPage_field,.sfwd_options #learndash-quiz-display-content-settings_quizModus_single_feedback_field,.sfwd_options #learndash-quiz-display-content-settings_showMaxQuestionValue_field,.sfwd_options #learndash-quiz-display-content-settings_showMaxQuestion_field,.sfwd_options #learndash-quiz-results-options_resultText_field{border-left:none;margin-left:0;padding-left:0}.sfwd_options #learndash-course-access-settings_course_access_list_field,.sfwd_options #learndash-course-display-content-settings_course_materials_field,.sfwd_options #learndash-lesson-display-content-settings_lesson_assignment_points_amount_field,.sfwd_options #learndash-lesson-display-content-settings_lesson_materials_field,.sfwd_options #learndash-quiz-display-content-settings_quizModus_single_back_button_field,.sfwd_options #learndash-quiz-display-content-settings_quiz_materials_field,.sfwd_options #learndash-quiz-display-content-settings_showMaxQuestionValue_field,.sfwd_options #learndash-topic-display-content-settings_lesson_assignment_points_amount_field,.sfwd_options #learndash-topic-display-content-settings_topic_materials_field{border-left:none}.sfwd_options #learndash-lesson-access-settings_visible_after_field,.sfwd_options #learndash-lesson-access-settings_visible_after_specific_date_field,.sfwd_options #learndash-quiz-display-content-settings_quizModus_single_back_button_field{border-left:none;padding-left:0}.sfwd_options #learndash-quiz-results-options_resultText_field{padding-left:10px}.sfwd_options input[name=templateLoad],.sfwd_options input[name=templateName]{margin-top:5px}.ld-settings-inner .ld-radio-input__label>span{font-weight:400}.ld-divider{border-bottom:1px solid #eee;margin:20px 0}.sfwd_options .ld-settings-inner .sfwd_option_input,.sfwd_options .ld-settings-inner-lesson_video_display_timing_after .sfwd_option_input{width:40%!important}.sfwd_options #learndash-lesson-access-settings_visible_after_specific_date_field .sfwd_option_input{width:80%!important}.sfwd_options .ld-settings-sub .sfwd_option_label{max-width:285px;width:calc(38% - 15px)}.sfwd_options #learndash-lesson-display-content-settings_assignment_upload_limit_count_field .sfwd_option_label,.sfwd_options #learndash-lesson-display-content-settings_lesson_assignment_deletion_enabled_field .sfwd_option_label{width:35%!important}.sfwd_options #learndash-lesson-access-settings_visible_after_specific_date_field input[type=number]{padding:0!important}.sfwd_options .ld-settings-inner-lesson_video_display_timing_after .sfwd_option_label{width:35%!important}.sfwd_options .ld-settings-inner-quizModus_single .sfwd_option_input{width:65%!important}.sfwd_options .ld-settings-email-header-wrapper{margin-bottom:30px}.sfwd_options .ld-settings-email-header{font-weight:700}.sfwd_options .ld-settings-email-description{font-weight:300}.sfwd_options .learndash_settings_field_invalid label.sfwd_label{color:red}.sfwd_options .learndash_settings_field_invalid input:invalid{border:1px solid red;box-shadow:none}.sfwd_options .learndash_settings_field_invalid .learndash-section-field-error{color:red}#learndash-settings-fields-notice-errors p.errors-header{font-weight:900}#learndash-settings-fields-notice-errors ul.errors-list{list-style:disc}#learndash-settings-fields-notice-errors ul.errors-list li{margin-left:15px}.ld__builder-sidebar-widget .components-checkbox-control__input[type=checkbox]:checked:before{content:url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2020%2020%27%3E%3Cpath%20d%3D%27M14.83%204.89l1.34.94-5.81%208.38H9.02L5.78%209.67l1.34-1.25%202.57%202.4z%27%20fill%3D%27%231e8cbe%27%2F%3E%3C%2Fsvg%3E")}.plugin-update p.ld-plugin-update-notice:before{content:"";margin-right:0}.notice.ld-plugin-update-notice,.plugin-update .ld-plugin-update-notice{margin-top:10px;padding:10px}.ld-plugin-update-notice .version{font-weight:700}.ld-plugin-update-notice .header{font-size:130%;font-weight:700}.ld_settings_postbox .ld-settings-info-banner{display:block;margin:5px 0;padding:5px 10px}.ld_settings_postbox .ld-settings-info-banner p:before{float:left;font:400 20px/1 dashicons}.ld_settings_postbox .ld-settings-info-banner p{font-size:13px;line-height:1.5em;margin:.5em 0;padding:0;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;vertical-align:top}.ld_settings_postbox .ld-settings-info-banner.ld-settings-info-banner-alert{background-color:#fbeaea;border-left:2px solid #dc3232}.ld_settings_postbox .ld-settings-info-banner.ld-settings-info-banner-alert p:before{color:#dc3232;content:"";margin-right:6px}.ld_settings_postbox .ld-settings-info-banner.ld-settings-info-banner-success{border-color:#46b450;border-style:solid;border-width:0 0 1px 2px}ul.learndash-settings-sub{float:none}table.learndash-settings-table th,ul.learndash-settings-sub li.learndash-settings-sub-current a{font-weight:700}table.learndash-settings-table td.col-valign-middle{vertical-align:middle}table.learndash-settings-table-sortable .ui-sortable-helper{display:table}table.learndash-settings-table-sortable td.col-name-move{cursor:grab}.edit-post-sidebar #learndash_group_attributes_metabox select#group_parent_id{max-width:85%;width:100%}#learndash_group_attributes_metabox input#group_menu_order{display:block}.edit-post-sidebar #learndash_group_attributes_metabox .group-menu-order-label-wrapper{margin-top:10px}.ld_settings_postbox .postbox-header{display:block}.edit-post-meta-boxes-area #poststuff #learndash_course_builder .postbox-header .hndle,.edit-post-meta-boxes-area #poststuff #learndash_quiz_builder .postbox-header .hndle,.edit-post-meta-boxes-area #poststuff .ld_settings_postbox .postbox-header .hndle{border-bottom:none;padding:5px 12px;width:auto}.ld_settings_postbox .postbox-header .hndle{display:inline-block}.ld_settings_postbox .postbox-header .handle-actions{display:inline-block;float:right}.ld_settings_postbox .postbox-header .handle-actions .handle-order-higher,.ld_settings_postbox .postbox-header .handle-actions .handle-order-lower,body[data-active-tab=learndash_course_builder] .postbox-header .handle-actions .handle-order-higher,body[data-active-tab=learndash_course_builder] .postbox-header .handle-actions .handle-order-lower,body[data-active-tab=learndash_quiz_builder] .postbox-header .handle-actions .handle-order-higher,body[data-active-tab=learndash_quiz_builder] .postbox-header .handle-actions .handle-order-lower{display:none}.ld_settings_postbox .postbox-header .ld-metabox-description{display:block;padding:0 12px 5px}#certificate-shortcodes.wrap .inside .dashicons,#certificate-shortcodes.wrap .inside .dashicons-before:before,#course-shortcodes.wrap .inside .dashicons,#course-shortcodes.wrap .inside .dashicons-before:before{text-decoration:none}.notice.connect-stripe .learndash-stripe-connect,.sfwd_options .learndash-stripe-connect{align-items:center;background:#6772e5;border-radius:5px;color:#fff;display:flex;font-size:16px;justify-content:center;letter-spacing:.6px;padding:6px 24px;text-decoration:none;transition:all .3s ease;width:200px}.learndash-stripe-connect:focus,.learndash-stripe-connect:hover,.notice.connect-stripe .learndash-stripe-connect:active,.notice.connect-stripe .learndash-stripe-connect:focus,.notice.connect-stripe .learndash-stripe-connect:hover,.sfwd_options .learndash-stripe-connect:active{background:#3f4ddf;color:#fff}.notice.connect-stripe .learndash-stripe-connect .stripe-logo,.sfwd_options .learndash-stripe-connect .stripe-logo{padding:2px 10px 0 0} diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/style-rtl.css b/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/style-rtl.css new file mode 100644 index 000000000..dd3be693a --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/style-rtl.css @@ -0,0 +1,17 @@ +/*!***************************************************************************************************************************************************************************************************************************************************!*\ + !*** css ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[4].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[4].use[2]!./node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[4].use[3]!./src/assets/scss/style.scss ***! + \***************************************************************************************************************************************************************************************************************************************************/ +.learndash-course-grid .arrow { + all: unset; +} + +.learndash-course-grid .arrow::after { + all: unset; +} + +.learndash-course-grid iframe, +.learndash-course-grid embed, +.learndash-course-grid object, +.learndash-course-grid video { + max-width: 100%; +} diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/style.css b/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/style.css new file mode 100644 index 000000000..d430eb441 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/style.css @@ -0,0 +1,19 @@ +/*!***************************************************************************************************************************************************************************************************************************************************!*\ + !*** css ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[4].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[4].use[2]!./node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[4].use[3]!./src/assets/scss/style.scss ***! + \***************************************************************************************************************************************************************************************************************************************************/ +.learndash-course-grid .arrow { + all: unset; +} + +.learndash-course-grid .arrow::after { + all: unset; +} + +.learndash-course-grid iframe, +.learndash-course-grid embed, +.learndash-course-grid object, +.learndash-course-grid video { + max-width: 100%; +} + +/*# sourceMappingURL=style.css.map*/ \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/style.css.map b/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/style.css.map new file mode 100644 index 000000000..1a553763f --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/style.css.map @@ -0,0 +1 @@ +{"version":3,"file":"../css/style.css","mappings":";;;AAAA;EACC;AACD;;AAEA;EACC;AACD;;AAEA;;;;EAIC;AACD,C","sources":["webpack://learndash-course-grid/./src/assets/scss/style.scss"],"sourcesContent":[".learndash-course-grid .arrow {\n\tall: unset;\n}\n\n.learndash-course-grid .arrow::after {\n\tall: unset;\n}\n\n.learndash-course-grid iframe,\n.learndash-course-grid embed,\n.learndash-course-grid object,\n.learndash-course-grid video {\n\tmax-width: 100%;\n}\n"],"names":[],"sourceRoot":""} \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/style.min-rtl.css b/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/style.min-rtl.css new file mode 100644 index 000000000..991520cb7 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/style.min-rtl.css @@ -0,0 +1 @@ +.learndash-course-grid .arrow,.learndash-course-grid .arrow:after{all:unset}.learndash-course-grid embed,.learndash-course-grid iframe,.learndash-course-grid object,.learndash-course-grid video{max-width:100%} diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/style.min.css b/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/style.min.css new file mode 100644 index 000000000..991520cb7 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/assets/css/style.min.css @@ -0,0 +1 @@ +.learndash-course-grid .arrow,.learndash-course-grid .arrow:after{all:unset}.learndash-course-grid embed,.learndash-course-grid iframe,.learndash-course-grid object,.learndash-course-grid video{max-width:100%} diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/assets/img/question.png b/web/app/plugins/sfwd-lms/includes/course-grid/assets/img/question.png new file mode 100644 index 000000000..f38df12e9 Binary files /dev/null and b/web/app/plugins/sfwd-lms/includes/course-grid/assets/img/question.png differ diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/assets/img/thumbnail.jpg b/web/app/plugins/sfwd-lms/includes/course-grid/assets/img/thumbnail.jpg new file mode 100644 index 000000000..97770a04e Binary files /dev/null and b/web/app/plugins/sfwd-lms/includes/course-grid/assets/img/thumbnail.jpg differ diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/editor.js b/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/editor.js new file mode 100644 index 000000000..e7bc3e87e --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/editor.js @@ -0,0 +1,66 @@ +/******/ (() => { // webpackBootstrap +/*!*************************************************!*\ + !*** ./src/assets/js/admin/gutenberg/editor.js ***! + \*************************************************/ +(function () { + // eslint-disable-next-line camelcase + function init_masonry() { + // Masonry + const wrappers = document.querySelectorAll('.learndash-course-grid[data-skin="masonry"]'); + wrappers.forEach(function (wrapper) { + // eslint-disable-next-line camelcase + const items_wrapper = wrapper.querySelector('.items-wrapper.masonry'); + + // eslint-disable-next-line camelcase + if (items_wrapper) { + // eslint-disable-next-line camelcase + const first_item = items_wrapper.querySelector('.item'); + // eslint-disable-next-line camelcase + if (!first_item) { + return; + } + } + + // eslint-disable-next-line no-undef + learndash_course_grid_init_masonry(items_wrapper); + }); + } + document.addEventListener('click', function (e) { + const el = e.target; + if (el.closest('.learndash-block-inner > .learndash-course-grid') || el.closest('.learndash-block-inner > .learndash-course-grid-filter')) { + e.preventDefault(); + } + }); + setInterval(function () { + // eslint-disable-next-line no-undef + learndash_course_grid_init_grid_responsive_design(); + + // eslint-disable-next-line camelcase + const temp_css = document.querySelectorAll('.learndash-course-grid-temp-css'); + + // eslint-disable-next-line camelcase + if (temp_css) { + // eslint-disable-next-line camelcase + const css_wrapper = document.getElementById('learndash-course-grid-custom-css'); + + // eslint-disable-next-line camelcase + if (css_wrapper) { + let style = ''; + + // eslint-disable-next-line camelcase + temp_css.forEach(function (element) { + style += element.innerText; + }); + + // eslint-disable-next-line camelcase + css_wrapper.innerHTML = style; + } + } + }, 500); + setInterval(function () { + init_masonry(); + }, 2000); +})(); +/******/ })() +; +//# sourceMappingURL=editor.js.map \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/editor.js.map b/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/editor.js.map new file mode 100644 index 000000000..54e53209f --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/editor.js.map @@ -0,0 +1 @@ +{"version":3,"file":"editor.js","mappings":";;;;AAAA,CAAE,YAAY;EACb;EACA,SAASA,YAAYA,CAAA,EAAG;IACvB;IACA,MAAMC,QAAQ,GAAGC,QAAQ,CAACC,gBAAgB,CACzC,6CACD,CAAC;IACDF,QAAQ,CAACG,OAAO,CAAE,UAAWC,OAAO,EAAG;MACtC;MACA,MAAMC,aAAa,GAAGD,OAAO,CAACE,aAAa,CAC1C,wBACD,CAAC;;MAED;MACA,IAAKD,aAAa,EAAG;QACpB;QACA,MAAME,UAAU,GAAGF,aAAa,CAACC,aAAa,CAAE,OAAQ,CAAC;QACzD;QACA,IAAK,CAAEC,UAAU,EAAG;UACnB;QACD;MACD;;MAEA;MACAC,kCAAkC,CAAEH,aAAc,CAAC;IACpD,CAAE,CAAC;EACJ;EAEAJ,QAAQ,CAACQ,gBAAgB,CAAE,OAAO,EAAE,UAAWC,CAAC,EAAG;IAClD,MAAMC,EAAE,GAAGD,CAAC,CAACE,MAAM;IAEnB,IACCD,EAAE,CAACE,OAAO,CAAE,iDAAkD,CAAC,IAC/DF,EAAE,CAACE,OAAO,CACT,wDACD,CAAC,EACA;MACDH,CAAC,CAACI,cAAc,CAAC,CAAC;IACnB;EACD,CAAE,CAAC;EAEHC,WAAW,CAAE,YAAY;IACxB;IACAC,iDAAiD,CAAC,CAAC;;IAEnD;IACA,MAAMC,QAAQ,GAAGhB,QAAQ,CAACC,gBAAgB,CACzC,iCACD,CAAC;;IAED;IACA,IAAKe,QAAQ,EAAG;MACf;MACA,MAAMC,WAAW,GAAGjB,QAAQ,CAACkB,cAAc,CAC1C,kCACD,CAAC;;MAED;MACA,IAAKD,WAAW,EAAG;QAClB,IAAIE,KAAK,GAAG,EAAE;;QAEd;QACAH,QAAQ,CAACd,OAAO,CAAE,UAAWkB,OAAO,EAAG;UACtCD,KAAK,IAAIC,OAAO,CAACC,SAAS;QAC3B,CAAE,CAAC;;QAEH;QACAJ,WAAW,CAACK,SAAS,GAAGH,KAAK;MAC9B;IACD;EACD,CAAC,EAAE,GAAI,CAAC;EAERL,WAAW,CAAE,YAAY;IACxBhB,YAAY,CAAC,CAAC;EACf,CAAC,EAAE,IAAK,CAAC;AACV,CAAC,EAAG,CAAC,C","sources":["webpack://learndash-course-grid/./src/assets/js/admin/gutenberg/editor.js"],"sourcesContent":["( function () {\n\t// eslint-disable-next-line camelcase\n\tfunction init_masonry() {\n\t\t// Masonry\n\t\tconst wrappers = document.querySelectorAll(\n\t\t\t'.learndash-course-grid[data-skin=\"masonry\"]'\n\t\t);\n\t\twrappers.forEach( function ( wrapper ) {\n\t\t\t// eslint-disable-next-line camelcase\n\t\t\tconst items_wrapper = wrapper.querySelector(\n\t\t\t\t'.items-wrapper.masonry'\n\t\t\t);\n\n\t\t\t// eslint-disable-next-line camelcase\n\t\t\tif ( items_wrapper ) {\n\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\tconst first_item = items_wrapper.querySelector( '.item' );\n\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\tif ( ! first_item ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// eslint-disable-next-line no-undef\n\t\t\tlearndash_course_grid_init_masonry( items_wrapper );\n\t\t} );\n\t}\n\n\tdocument.addEventListener( 'click', function ( e ) {\n\t\tconst el = e.target;\n\n\t\tif (\n\t\t\tel.closest( '.learndash-block-inner > .learndash-course-grid' ) ||\n\t\t\tel.closest(\n\t\t\t\t'.learndash-block-inner > .learndash-course-grid-filter'\n\t\t\t)\n\t\t) {\n\t\t\te.preventDefault();\n\t\t}\n\t} );\n\n\tsetInterval( function () {\n\t\t// eslint-disable-next-line no-undef\n\t\tlearndash_course_grid_init_grid_responsive_design();\n\n\t\t// eslint-disable-next-line camelcase\n\t\tconst temp_css = document.querySelectorAll(\n\t\t\t'.learndash-course-grid-temp-css'\n\t\t);\n\n\t\t// eslint-disable-next-line camelcase\n\t\tif ( temp_css ) {\n\t\t\t// eslint-disable-next-line camelcase\n\t\t\tconst css_wrapper = document.getElementById(\n\t\t\t\t'learndash-course-grid-custom-css'\n\t\t\t);\n\n\t\t\t// eslint-disable-next-line camelcase\n\t\t\tif ( css_wrapper ) {\n\t\t\t\tlet style = '';\n\n\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\ttemp_css.forEach( function ( element ) {\n\t\t\t\t\tstyle += element.innerText;\n\t\t\t\t} );\n\n\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\tcss_wrapper.innerHTML = style;\n\t\t\t}\n\t\t}\n\t}, 500 );\n\n\tsetInterval( function () {\n\t\tinit_masonry();\n\t}, 2000 );\n} )();\n"],"names":["init_masonry","wrappers","document","querySelectorAll","forEach","wrapper","items_wrapper","querySelector","first_item","learndash_course_grid_init_masonry","addEventListener","e","el","target","closest","preventDefault","setInterval","learndash_course_grid_init_grid_responsive_design","temp_css","css_wrapper","getElementById","style","element","innerText","innerHTML"],"sourceRoot":""} \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/editor.min.js b/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/editor.min.js new file mode 100644 index 000000000..075404f02 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/editor.min.js @@ -0,0 +1 @@ +document.addEventListener("click",(function(e){const r=e.target;(r.closest(".learndash-block-inner > .learndash-course-grid")||r.closest(".learndash-block-inner > .learndash-course-grid-filter"))&&e.preventDefault()})),setInterval((function(){learndash_course_grid_init_grid_responsive_design();const e=document.querySelectorAll(".learndash-course-grid-temp-css");if(e){const r=document.getElementById("learndash-course-grid-custom-css");if(r){let n="";e.forEach((function(e){n+=e.innerText})),r.innerHTML=n}}}),500),setInterval((function(){document.querySelectorAll('.learndash-course-grid[data-skin="masonry"]').forEach((function(e){const r=e.querySelector(".items-wrapper.masonry");r&&!r.querySelector(".item")||learndash_course_grid_init_masonry(r)}))}),2e3); \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/elementor.js b/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/elementor.js new file mode 100644 index 000000000..53f78e57e --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/elementor.js @@ -0,0 +1,51 @@ +/******/ (() => { // webpackBootstrap +/*!************************************!*\ + !*** ./src/assets/js/elementor.js ***! + \************************************/ +/** + * Elementor compatibility script + */ + +(function () { + let gridFound, masonryFound; + // eslint-disable-next-line no-undef + const gridObserver = new MutationObserver(function (mutations) { + mutations.forEach(function (mutationRecord) { + const grid = mutationRecord.target.querySelector('.learndash-course-grid'), + skin = grid.dataset.skin, + display = mutationRecord.target.style.display; + if ('none' !== display) { + if ('grid' === skin) { + gridFound = true; + } else if ('masonry' === skin) { + masonryFound = true; + } + } + }); + if (gridFound && 'function' === + // eslint-disable-next-line camelcase + typeof learndash_course_grid_init_grid_responsive_design) { + // eslint-disable-next-line no-undef + learndash_course_grid_init_grid_responsive_design(); + } + if (masonryFound && 'function' === + // eslint-disable-next-line camelcase + typeof learndash_course_grid_init_masonry_responsive_design) { + // eslint-disable-next-line no-undef + learndash_course_grid_init_masonry_responsive_design(); + } + }); + const grids = document.querySelectorAll('.learndash-course-grid'); + grids.forEach(function (grid) { + const target = grid.closest('.elementor-tab-content'); + if (target) { + gridObserver.observe(target, { + attributes: true, + attributeFilter: ['style'] + }); + } + }); +})(); +/******/ })() +; +//# sourceMappingURL=elementor.js.map \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/elementor.js.map b/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/elementor.js.map new file mode 100644 index 000000000..a8dbf8377 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/elementor.js.map @@ -0,0 +1 @@ +{"version":3,"file":"elementor.js","mappings":";;;;AAAA;AACA;AACA;;AAEA,CAAE,YAAY;EACb,IAAIA,SAAS,EAAEC,YAAY;EAC3B;EACA,MAAMC,YAAY,GAAG,IAAIC,gBAAgB,CAAE,UAAWC,SAAS,EAAG;IACjEA,SAAS,CAACC,OAAO,CAAE,UAAWC,cAAc,EAAG;MAC9C,MAAMC,IAAI,GAAGD,cAAc,CAACE,MAAM,CAACC,aAAa,CAC9C,wBACD,CAAC;QACDC,IAAI,GAAGH,IAAI,CAACI,OAAO,CAACD,IAAI;QACxBE,OAAO,GAAGN,cAAc,CAACE,MAAM,CAACK,KAAK,CAACD,OAAO;MAE9C,IAAK,MAAM,KAAKA,OAAO,EAAG;QACzB,IAAK,MAAM,KAAKF,IAAI,EAAG;UACtBV,SAAS,GAAG,IAAI;QACjB,CAAC,MAAM,IAAK,SAAS,KAAKU,IAAI,EAAG;UAChCT,YAAY,GAAG,IAAI;QACpB;MACD;IACD,CAAE,CAAC;IAEH,IACCD,SAAS,IACT,UAAU;IACT;IACA,OAAOc,iDAAiD,EACxD;MACD;MACAA,iDAAiD,CAAC,CAAC;IACpD;IAEA,IACCb,YAAY,IACZ,UAAU;IACT;IACA,OAAOc,oDAAoD,EAC3D;MACD;MACAA,oDAAoD,CAAC,CAAC;IACvD;EACD,CAAE,CAAC;EAEH,MAAMC,KAAK,GAAGC,QAAQ,CAACC,gBAAgB,CAAE,wBAAyB,CAAC;EACnEF,KAAK,CAACX,OAAO,CAAE,UAAWE,IAAI,EAAG;IAChC,MAAMC,MAAM,GAAGD,IAAI,CAACY,OAAO,CAAE,wBAAyB,CAAC;IACvD,IAAKX,MAAM,EAAG;MACbN,YAAY,CAACkB,OAAO,CAAEZ,MAAM,EAAE;QAC7Ba,UAAU,EAAE,IAAI;QAChBC,eAAe,EAAE,CAAE,OAAO;MAC3B,CAAE,CAAC;IACJ;EACD,CAAE,CAAC;AACJ,CAAC,EAAG,CAAC,C","sources":["webpack://learndash-course-grid/./src/assets/js/elementor.js"],"sourcesContent":["/**\n * Elementor compatibility script\n */\n\n( function () {\n\tlet gridFound, masonryFound;\n\t// eslint-disable-next-line no-undef\n\tconst gridObserver = new MutationObserver( function ( mutations ) {\n\t\tmutations.forEach( function ( mutationRecord ) {\n\t\t\tconst grid = mutationRecord.target.querySelector(\n\t\t\t\t\t'.learndash-course-grid'\n\t\t\t\t),\n\t\t\t\tskin = grid.dataset.skin,\n\t\t\t\tdisplay = mutationRecord.target.style.display;\n\n\t\t\tif ( 'none' !== display ) {\n\t\t\t\tif ( 'grid' === skin ) {\n\t\t\t\t\tgridFound = true;\n\t\t\t\t} else if ( 'masonry' === skin ) {\n\t\t\t\t\tmasonryFound = true;\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\tif (\n\t\t\tgridFound &&\n\t\t\t'function' ===\n\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\ttypeof learndash_course_grid_init_grid_responsive_design\n\t\t) {\n\t\t\t// eslint-disable-next-line no-undef\n\t\t\tlearndash_course_grid_init_grid_responsive_design();\n\t\t}\n\n\t\tif (\n\t\t\tmasonryFound &&\n\t\t\t'function' ===\n\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\ttypeof learndash_course_grid_init_masonry_responsive_design\n\t\t) {\n\t\t\t// eslint-disable-next-line no-undef\n\t\t\tlearndash_course_grid_init_masonry_responsive_design();\n\t\t}\n\t} );\n\n\tconst grids = document.querySelectorAll( '.learndash-course-grid' );\n\tgrids.forEach( function ( grid ) {\n\t\tconst target = grid.closest( '.elementor-tab-content' );\n\t\tif ( target ) {\n\t\t\tgridObserver.observe( target, {\n\t\t\t\tattributes: true,\n\t\t\t\tattributeFilter: [ 'style' ],\n\t\t\t} );\n\t\t}\n\t} );\n} )();\n"],"names":["gridFound","masonryFound","gridObserver","MutationObserver","mutations","forEach","mutationRecord","grid","target","querySelector","skin","dataset","display","style","learndash_course_grid_init_grid_responsive_design","learndash_course_grid_init_masonry_responsive_design","grids","document","querySelectorAll","closest","observe","attributes","attributeFilter"],"sourceRoot":""} \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/elementor.min.js b/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/elementor.min.js new file mode 100644 index 000000000..36c06e05e --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/elementor.min.js @@ -0,0 +1 @@ +!function(){let e,n;const r=new MutationObserver((function(r){r.forEach((function(r){const t=r.target.querySelector(".learndash-course-grid").dataset.skin;"none"!==r.target.style.display&&("grid"===t?e=!0:"masonry"===t&&(n=!0))})),e&&"function"==typeof learndash_course_grid_init_grid_responsive_design&&learndash_course_grid_init_grid_responsive_design(),n&&"function"==typeof learndash_course_grid_init_masonry_responsive_design&&learndash_course_grid_init_masonry_responsive_design()}));document.querySelectorAll(".learndash-course-grid").forEach((function(e){const n=e.closest(".elementor-tab-content");n&&r.observe(n,{attributes:!0,attributeFilter:["style"]})}))}(); \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/script.js b/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/script.js new file mode 100644 index 000000000..0d83410a2 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/script.js @@ -0,0 +1,459 @@ +/******/ (() => { // webpackBootstrap +/*!*********************************!*\ + !*** ./src/assets/js/script.js ***! + \*********************************/ +(function () { + // eslint-disable-next-line camelcase + function ajax_apply_filter(course_grid, filter) { + const data = { + action: 'ld_cg_apply_filter', + // eslint-disable-next-line camelcase, no-undef + nonce: LearnDash_Course_Grid.nonce.load_posts, + filter: prepare_filter(filter), + course_grid: { + // eslint-disable-next-line camelcase + ...course_grid.dataset + } + }; + data.filter = JSON.stringify(data.filter); + data.course_grid = JSON.stringify(data.course_grid); + + // eslint-disable-next-line camelcase, no-undef + fetch(LearnDash_Course_Grid.ajaxurl, { + method: 'POST', + credentials: 'same-origin', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + body: new URLSearchParams(data) + }).then(response => { + return response.json(); + }) + // eslint-disable-next-line no-shadow + .then(data => { + if (typeof data !== 'undefined') { + // eslint-disable-next-line eqeqeq + if (data.status == 'success') { + // eslint-disable-next-line camelcase + const items_wrapper = + // eslint-disable-next-line camelcase + course_grid.querySelector('.items-wrapper'); + + // eslint-disable-next-line camelcase + items_wrapper.style.visibility = 'hidden'; + // eslint-disable-next-line camelcase + items_wrapper.innerHTML = data.html; + + // eslint-disable-next-line camelcase + course_grid.dataset.page = data.page; + const pagination = + // eslint-disable-next-line camelcase + course_grid.querySelector('.pagination'); + if (!pagination) { + // eslint-disable-next-line camelcase + course_grid.insertAdjacentHTML('beforeend', data.html_pagination); + } + + // eslint-disable-next-line eqeqeq + if (data.html_pagination == '') { + // eslint-disable-next-line no-shadow + const pagination = + // eslint-disable-next-line camelcase + course_grid.querySelector('.pagination'); + if (pagination) { + pagination.remove(); + } + } + + // eslint-disable-next-line camelcase, eqeqeq + if (course_grid.dataset.skin == 'grid') { + setTimeout(function () { + // eslint-disable-next-line no-undef + learndash_course_grid_init_grid_responsive_design(); + }, 500); + // eslint-disable-next-line camelcase, eqeqeq + } else if (course_grid.dataset.skin == 'masonry') { + setTimeout(function () { + // eslint-disable-next-line no-undef + learndash_course_grid_init_masonry( + // eslint-disable-next-line camelcase + course_grid.querySelector('.masonry')); + }, 500); + } else { + setTimeout(function () { + // eslint-disable-next-line camelcase + items_wrapper.style.visibility = 'visible'; + }, 500); + } + } + } + }).catch(error => { + // eslint-disable-next-line no-console + console.log(error); + }); + } + + // eslint-disable-next-line camelcase + function ajax_init_infinite_scrolling(el) { + const wrapper = el.closest('.learndash-course-grid'); + if (!wrapper) { + // eslint-disable-next-line camelcase + infinite_scroll_run = false; + return false; + } + const filter = document.querySelector('.learndash-course-grid-filter[data-course_grid_id="' + wrapper.id + '"]'); + const data = { + action: 'ld_cg_load_more', + // eslint-disable-next-line camelcase, no-undef + nonce: LearnDash_Course_Grid.nonce.load_posts, + course_grid: JSON.stringify(wrapper.dataset), + filter: JSON.stringify(prepare_filter(filter)) + }; + fetch( + // eslint-disable-next-line camelcase, no-undef + LearnDash_Course_Grid.ajaxurl + '?' + new URLSearchParams(data), { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }).then(response => { + return response.json(); + }) + // eslint-disable-next-line no-shadow + .then(data => { + if (typeof data !== 'undefined') { + // eslint-disable-next-line eqeqeq + if (data.status == 'success') { + wrapper.querySelector('.items-wrapper').insertAdjacentHTML('beforeend', data.html); + if (data.page !== 'complete') { + wrapper.dataset.page = data.page; + } + + // eslint-disable-next-line eqeqeq + if (wrapper.dataset.pagination == 'infinite') { + // eslint-disable-next-line camelcase + infinite_scroll_run = false; + } + + // eslint-disable-next-line eqeqeq + if (data.page == 'complete') { + const pagination = wrapper.querySelector('.pagination'); + pagination.remove(); + } + + // eslint-disable-next-line eqeqeq + if (wrapper.dataset.skin == 'grid') { + setTimeout(function () { + // eslint-disable-next-line no-undef + learndash_course_grid_init_grid_responsive_design(); + }, 500); + // eslint-disable-next-line eqeqeq + } else if (wrapper.dataset.skin == 'masonry') { + wrapper.style.visibility = 'hidden'; + setTimeout(function () { + // eslint-disable-next-line no-undef + learndash_course_grid_init_masonry(wrapper.querySelector('.masonry')); + wrapper.style.visibility = 'visible'; + }, 500); + } + } + } + }).catch(error => { + // eslint-disable-next-line no-console + console.log(error); + }); + } + + // eslint-disable-next-line camelcase + function in_viewport(element) { + const pos = element.getBoundingClientRect(); + // eslint-disable-next-line no-undef + return !(pos.top > innerHeight || pos.bottom < 0); + } + + // eslint-disable-next-line camelcase + function prepare_filter(filter) { + const data = {}; + if (!filter) { + return data; + } + const search = filter.querySelector('input[name="search"]'); + // eslint-disable-next-line camelcase + const price_min = filter.querySelector('[name="price_min"]'); + // eslint-disable-next-line camelcase + const price_max = filter.querySelector('[name="price_max"]'); + data.search = search ? search.value : null; + let taxonomies = filter.dataset.taxonomies; + taxonomies = taxonomies.split(',').map(function (value) { + return value.trim(); + }); + + // eslint-disable-next-line camelcase + data.price_min = price_min ? price_min.value : null; + // eslint-disable-next-line camelcase + data.price_max = price_max ? price_max.value : null; + taxonomies.forEach(function (taxonomy) { + const inputs = filter.querySelectorAll('input[name="' + taxonomy + '[]"]:checked'); + const values = []; + inputs.forEach(function (input) { + values.push(input.value); + }); + data[taxonomy] = values; + }); + return data; + } + + // Toggle filter display handler + document.addEventListener('click', function (e) { + const el = e.target; + if (el.matches('.learndash-course-grid .toggle-filter')) { + if (el.nextElementSibling.style.display === 'none' || el.nextElementSibling.style.display === '') { + el.classList.remove('closed'); + el.classList.add('opened'); + el.nextElementSibling.style.display = 'block'; + } else { + el.classList.remove('opened'); + el.classList.add('closed'); + el.nextElementSibling.style.display = 'none'; + } + } + }); + + // Apply filter handler + // eslint-disable-next-line camelcase + const filter_submit = document.querySelectorAll('.learndash-course-grid-filter .button.apply'); + + // eslint-disable-next-line camelcase + if (filter_submit) { + // eslint-disable-next-line camelcase + filter_submit.forEach(function (el) { + el.addEventListener('click', function (e) { + e.preventDefault(); + const filter = this.closest('.learndash-course-grid-filter'); + if (filter) { + // eslint-disable-next-line camelcase + const course_grid = document.getElementById(filter.dataset.course_grid_id); + ajax_apply_filter(course_grid, filter); + } + if (filter.previousElementSibling && filter.previousElementSibling.classList.contains('toggle-filter')) { + filter.previousElementSibling.classList.remove('opened'); + filter.previousElementSibling.classList.add('closed'); + filter.style.display = 'none'; + } + }); + }); + } + + // Clear filter handler + // eslint-disable-next-line camelcase + const filter_clear = document.querySelectorAll('.learndash-course-grid-filter .button.clear'); + + // eslint-disable-next-line camelcase + if (filter_clear) { + // eslint-disable-next-line camelcase + filter_clear.forEach(function (el) { + el.addEventListener('click', function (e) { + e.preventDefault(); + const filter = this.closest('.learndash-course-grid-filter'); + if (filter) { + const search = filter.querySelector('input[name="search"]'); + // eslint-disable-next-line camelcase + const price_min = filter.querySelector('input[name="price_min"]'); + // eslint-disable-next-line camelcase + const price_max = filter.querySelector('input[name="price_max"]'); + // eslint-disable-next-line camelcase + const price_min_range = filter.querySelector('input[name="price_min_range"]'); + // eslint-disable-next-line camelcase + const price_max_range = filter.querySelector('input[name="price_max_range"]'); + if (search) { + filter.querySelector('input[name="search"]').value = ''; + } + + // eslint-disable-next-line camelcase + if (price_min) { + filter.querySelector('input[name="price_min"]').value = ''; + } + + // eslint-disable-next-line camelcase + if (price_max) { + filter.querySelector('input[name="price_max"]').value = ''; + } + + // eslint-disable-next-line camelcase + if (price_min_range) { + filter.querySelector('input[name="price_min_range"]').value = ''; + } + + // eslint-disable-next-line camelcase + if (price_max_range) { + filter.querySelector('input[name="price_max_range"]').value = ''; + } + filter.dataset.taxonomies.split(',').forEach(function (taxonomy) { + taxonomy = taxonomy.trim(); + + // eslint-disable-next-line eqeqeq + if (taxonomy != '') { + filter.querySelectorAll('input[name="' + taxonomy + '[]"]:not([disabled])').forEach(function (input) { + input.checked = false; + }); + } + }); + + // eslint-disable-next-line camelcase + const course_grid = document.getElementById(filter.dataset.course_grid_id); + ajax_apply_filter(course_grid, filter); + if (filter.previousElementSibling && filter.previousElementSibling.classList.contains('toggle-filter')) { + filter.previousElementSibling.classList.remove('opened'); + filter.previousElementSibling.classList.add('closed'); + filter.style.display = 'none'; + } + } + }); + }); + } + + // Dynamic input value update for price filter inputs + document.addEventListener('input', function (e) { + if (e.target.classList.contains('range')) { + const name = e.target.name, + value = e.target.value, + // eslint-disable-next-line camelcase + price_wrapper = e.target.closest('.filter'); + switch (name) { + case 'price_min_range': + // eslint-disable-next-line camelcase + price_wrapper.querySelector('[name="price_min"]').value = value; + break; + case 'price_max_range': + // eslint-disable-next-line camelcase + price_wrapper.querySelector('[name="price_max"]').value = value; + break; + } + } + if (e.target.closest('.number-wrapper') !== null && + // eslint-disable-next-line eqeqeq + e.target.type == 'number') { + const name = e.target.name, + value = e.target.value, + // eslint-disable-next-line camelcase + price_wrapper = e.target.closest('.filter'); + switch (name) { + case 'price_min': + // eslint-disable-next-line camelcase + price_wrapper.querySelector('[name="price_min_range"]').value = value; + break; + case 'price_max': + // eslint-disable-next-line camelcase + price_wrapper.querySelector('[name="price_max_range"]').value = value; + break; + } + } + }); + + /** + * Pagination + */ + + // Load more button pagination handler + document.addEventListener('click', function (e) { + const el = e.target; + if (!el.matches('.learndash-course-grid[data-pagination="button"] .pagination .load-more')) { + return; + } + e.preventDefault(); + const wrapper = el.closest('.learndash-course-grid'); + const filter = document.querySelector('.learndash-course-grid-filter[data-course_grid_id="' + wrapper.id + '"]'); + const data = { + action: 'ld_cg_load_more', + // eslint-disable-next-line camelcase, no-undef + nonce: LearnDash_Course_Grid.nonce.load_posts, + course_grid: JSON.stringify(wrapper.dataset), + filter: JSON.stringify(prepare_filter(filter)) + }; + + // AJAX request + fetch( + // eslint-disable-next-line camelcase, no-undef + LearnDash_Course_Grid.ajaxurl + '?' + new URLSearchParams(data), { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }).then(response => { + return response.json(); + }) + // eslint-disable-next-line no-shadow + .then(data => { + if (typeof data !== 'undefined') { + // eslint-disable-next-line eqeqeq + if (data.status == 'success') { + // eslint-disable-next-line camelcase + const items_wrapper = wrapper.querySelector('.items-wrapper'); + + // eslint-disable-next-line camelcase + items_wrapper.insertAdjacentHTML('beforeend', data.html); + if (data.page !== 'complete') { + wrapper.dataset.page = data.page; + } + + // eslint-disable-next-line eqeqeq + if (data.page == 'complete') { + const pagination = wrapper.querySelector('.pagination'); + if (pagination) { + pagination.remove(); + } + } + if ( + // eslint-disable-next-line eqeqeq + wrapper.dataset.skin == 'grid' && + // eslint-disable-next-line eqeqeq + data.html != '') { + setTimeout(function () { + // eslint-disable-next-line no-undef + learndash_course_grid_init_grid_responsive_design(); + }, 500); + } else if ( + // eslint-disable-next-line eqeqeq + wrapper.dataset.skin == 'masonry' && + // eslint-disable-next-line eqeqeq + data.html != '') { + wrapper.style.visibility = 'hidden'; + setTimeout(function () { + // eslint-disable-next-line no-undef + learndash_course_grid_init_masonry(wrapper.querySelector('.masonry')); + wrapper.style.visibility = 'visible'; + }, 500); + } + } + } + }).catch(error => { + // eslint-disable-next-line no-console + console.log(error); + }); + }); + + // Infinite scrolling handler + // eslint-disable-next-line camelcase + let infinite_scroll_run = false; + document.addEventListener('scroll', function () { + // eslint-disable-next-line camelcase + const infinite_scroll_elements = document.querySelectorAll('.learndash-course-grid[data-pagination="infinite"] .pagination'); + + // eslint-disable-next-line camelcase + if (infinite_scroll_elements) { + // eslint-disable-next-line camelcase + infinite_scroll_elements.forEach(function (infinite_scroll) { + // Make sure the function is called only once + // eslint-disable-next-line camelcase + if (in_viewport(infinite_scroll) && !infinite_scroll_run) { + // eslint-disable-next-line camelcase + infinite_scroll_run = true; + ajax_init_infinite_scrolling(infinite_scroll); + } + }); + } + }); +})(); +/******/ })() +; +//# sourceMappingURL=script.js.map \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/script.js.map b/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/script.js.map new file mode 100644 index 000000000..43dc46548 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/script.js.map @@ -0,0 +1 @@ +{"version":3,"file":"script.js","mappings":";;;;AAAA,CAAE,YAAY;EACb;EACA,SAASA,iBAAiBA,CAAEC,WAAW,EAAEC,MAAM,EAAG;IACjD,MAAMC,IAAI,GAAG;MACZC,MAAM,EAAE,oBAAoB;MAC5B;MACAC,KAAK,EAAEC,qBAAqB,CAACD,KAAK,CAACE,UAAU;MAC7CL,MAAM,EAAEM,cAAc,CAAEN,MAAO,CAAC;MAChCD,WAAW,EAAE;QACZ;QACA,GAAGA,WAAW,CAACQ;MAChB;IACD,CAAC;IAEDN,IAAI,CAACD,MAAM,GAAGQ,IAAI,CAACC,SAAS,CAAER,IAAI,CAACD,MAAO,CAAC;IAC3CC,IAAI,CAACF,WAAW,GAAGS,IAAI,CAACC,SAAS,CAAER,IAAI,CAACF,WAAY,CAAC;;IAErD;IACAW,KAAK,CAAEN,qBAAqB,CAACO,OAAO,EAAE;MACrCC,MAAM,EAAE,MAAM;MACdC,WAAW,EAAE,aAAa;MAC1BC,OAAO,EAAE;QACR,cAAc,EAAE;MACjB,CAAC;MACDC,IAAI,EAAE,IAAIC,eAAe,CAAEf,IAAK;IACjC,CAAE,CAAC,CACDgB,IAAI,CAAIC,QAAQ,IAAM;MACtB,OAAOA,QAAQ,CAACC,IAAI,CAAC,CAAC;IACvB,CAAE;IACF;IAAA,CACCF,IAAI,CAAIhB,IAAI,IAAM;MAClB,IAAK,OAAOA,IAAI,KAAK,WAAW,EAAG;QAClC;QACA,IAAKA,IAAI,CAACmB,MAAM,IAAI,SAAS,EAAG;UAC/B;UACA,MAAMC,aAAa;UAClB;UACAtB,WAAW,CAACuB,aAAa,CAAE,gBAAiB,CAAC;;UAE9C;UACAD,aAAa,CAACE,KAAK,CAACC,UAAU,GAAG,QAAQ;UACzC;UACAH,aAAa,CAACI,SAAS,GAAGxB,IAAI,CAACyB,IAAI;;UAEnC;UACA3B,WAAW,CAACQ,OAAO,CAACoB,IAAI,GAAG1B,IAAI,CAAC0B,IAAI;UAEpC,MAAMC,UAAU;UACf;UACA7B,WAAW,CAACuB,aAAa,CAAE,aAAc,CAAC;UAE3C,IAAK,CAAEM,UAAU,EAAG;YACnB;YACA7B,WAAW,CAAC8B,kBAAkB,CAC7B,WAAW,EACX5B,IAAI,CAAC6B,eACN,CAAC;UACF;;UAEA;UACA,IAAK7B,IAAI,CAAC6B,eAAe,IAAI,EAAE,EAAG;YACjC;YACA,MAAMF,UAAU;YACf;YACA7B,WAAW,CAACuB,aAAa,CAAE,aAAc,CAAC;YAE3C,IAAKM,UAAU,EAAG;cACjBA,UAAU,CAACG,MAAM,CAAC,CAAC;YACpB;UACD;;UAEA;UACA,IAAKhC,WAAW,CAACQ,OAAO,CAACyB,IAAI,IAAI,MAAM,EAAG;YACzCC,UAAU,CAAE,YAAY;cACvB;cACAC,iDAAiD,CAAC,CAAC;YACpD,CAAC,EAAE,GAAI,CAAC;YACR;UACD,CAAC,MAAM,IAAKnC,WAAW,CAACQ,OAAO,CAACyB,IAAI,IAAI,SAAS,EAAG;YACnDC,UAAU,CAAE,YAAY;cACvB;cACAE,kCAAkC;cACjC;cACApC,WAAW,CAACuB,aAAa,CAAE,UAAW,CACvC,CAAC;YACF,CAAC,EAAE,GAAI,CAAC;UACT,CAAC,MAAM;YACNW,UAAU,CAAE,YAAY;cACvB;cACAZ,aAAa,CAACE,KAAK,CAACC,UAAU,GAAG,SAAS;YAC3C,CAAC,EAAE,GAAI,CAAC;UACT;QACD;MACD;IACD,CAAE,CAAC,CACFY,KAAK,CAAIC,KAAK,IAAM;MACpB;MACAC,OAAO,CAACC,GAAG,CAAEF,KAAM,CAAC;IACrB,CAAE,CAAC;EACL;;EAEA;EACA,SAASG,4BAA4BA,CAAEC,EAAE,EAAG;IAC3C,MAAMC,OAAO,GAAGD,EAAE,CAACE,OAAO,CAAE,wBAAyB,CAAC;IAEtD,IAAK,CAAED,OAAO,EAAG;MAChB;MACAE,mBAAmB,GAAG,KAAK;MAC3B,OAAO,KAAK;IACb;IAEA,MAAM5C,MAAM,GAAG6C,QAAQ,CAACvB,aAAa,CACpC,qDAAqD,GACpDoB,OAAO,CAACI,EAAE,GACV,IACF,CAAC;IAED,MAAM7C,IAAI,GAAG;MACZC,MAAM,EAAE,iBAAiB;MACzB;MACAC,KAAK,EAAEC,qBAAqB,CAACD,KAAK,CAACE,UAAU;MAC7CN,WAAW,EAAES,IAAI,CAACC,SAAS,CAAEiC,OAAO,CAACnC,OAAQ,CAAC;MAC9CP,MAAM,EAAEQ,IAAI,CAACC,SAAS,CAAEH,cAAc,CAAEN,MAAO,CAAE;IAClD,CAAC;IAEDU,KAAK;IACJ;IACAN,qBAAqB,CAACO,OAAO,GAAG,GAAG,GAAG,IAAIK,eAAe,CAAEf,IAAK,CAAC,EACjE;MACCW,MAAM,EAAE,KAAK;MACbE,OAAO,EAAE;QACR,cAAc,EAAE;MACjB;IACD,CACD,CAAC,CACCG,IAAI,CAAIC,QAAQ,IAAM;MACtB,OAAOA,QAAQ,CAACC,IAAI,CAAC,CAAC;IACvB,CAAE;IACF;IAAA,CACCF,IAAI,CAAIhB,IAAI,IAAM;MAClB,IAAK,OAAOA,IAAI,KAAK,WAAW,EAAG;QAClC;QACA,IAAKA,IAAI,CAACmB,MAAM,IAAI,SAAS,EAAG;UAC/BsB,OAAO,CACLpB,aAAa,CAAE,gBAAiB,CAAC,CACjCO,kBAAkB,CAAE,WAAW,EAAE5B,IAAI,CAACyB,IAAK,CAAC;UAE9C,IAAKzB,IAAI,CAAC0B,IAAI,KAAK,UAAU,EAAG;YAC/Be,OAAO,CAACnC,OAAO,CAACoB,IAAI,GAAG1B,IAAI,CAAC0B,IAAI;UACjC;;UAEA;UACA,IAAKe,OAAO,CAACnC,OAAO,CAACqB,UAAU,IAAI,UAAU,EAAG;YAC/C;YACAgB,mBAAmB,GAAG,KAAK;UAC5B;;UAEA;UACA,IAAK3C,IAAI,CAAC0B,IAAI,IAAI,UAAU,EAAG;YAC9B,MAAMC,UAAU,GACfc,OAAO,CAACpB,aAAa,CAAE,aAAc,CAAC;YAEvCM,UAAU,CAACG,MAAM,CAAC,CAAC;UACpB;;UAEA;UACA,IAAKW,OAAO,CAACnC,OAAO,CAACyB,IAAI,IAAI,MAAM,EAAG;YACrCC,UAAU,CAAE,YAAY;cACvB;cACAC,iDAAiD,CAAC,CAAC;YACpD,CAAC,EAAE,GAAI,CAAC;YACR;UACD,CAAC,MAAM,IAAKQ,OAAO,CAACnC,OAAO,CAACyB,IAAI,IAAI,SAAS,EAAG;YAC/CU,OAAO,CAACnB,KAAK,CAACC,UAAU,GAAG,QAAQ;YAEnCS,UAAU,CAAE,YAAY;cACvB;cACAE,kCAAkC,CACjCO,OAAO,CAACpB,aAAa,CAAE,UAAW,CACnC,CAAC;cAEDoB,OAAO,CAACnB,KAAK,CAACC,UAAU,GAAG,SAAS;YACrC,CAAC,EAAE,GAAI,CAAC;UACT;QACD;MACD;IACD,CAAE,CAAC,CACFY,KAAK,CAAIC,KAAK,IAAM;MACpB;MACAC,OAAO,CAACC,GAAG,CAAEF,KAAM,CAAC;IACrB,CAAE,CAAC;EACL;;EAEA;EACA,SAASU,WAAWA,CAAEC,OAAO,EAAG;IAC/B,MAAMC,GAAG,GAAGD,OAAO,CAACE,qBAAqB,CAAC,CAAC;IAC3C;IACA,OAAO,EAAID,GAAG,CAACE,GAAG,GAAGC,WAAW,IAAIH,GAAG,CAACI,MAAM,GAAG,CAAC,CAAE;EACrD;;EAEA;EACA,SAAS/C,cAAcA,CAAEN,MAAM,EAAG;IACjC,MAAMC,IAAI,GAAG,CAAC,CAAC;IAEf,IAAK,CAAED,MAAM,EAAG;MACf,OAAOC,IAAI;IACZ;IAEA,MAAMqD,MAAM,GAAGtD,MAAM,CAACsB,aAAa,CAAE,sBAAuB,CAAC;IAC7D;IACA,MAAMiC,SAAS,GAAGvD,MAAM,CAACsB,aAAa,CAAE,oBAAqB,CAAC;IAC9D;IACA,MAAMkC,SAAS,GAAGxD,MAAM,CAACsB,aAAa,CAAE,oBAAqB,CAAC;IAE9DrB,IAAI,CAACqD,MAAM,GAAGA,MAAM,GAAGA,MAAM,CAACG,KAAK,GAAG,IAAI;IAE1C,IAAIC,UAAU,GAAG1D,MAAM,CAACO,OAAO,CAACmD,UAAU;IAC1CA,UAAU,GAAGA,UAAU,CAACC,KAAK,CAAE,GAAI,CAAC,CAACC,GAAG,CAAE,UAAWH,KAAK,EAAG;MAC5D,OAAOA,KAAK,CAACI,IAAI,CAAC,CAAC;IACpB,CAAE,CAAC;;IAEH;IACA5D,IAAI,CAACsD,SAAS,GAAGA,SAAS,GAAGA,SAAS,CAACE,KAAK,GAAG,IAAI;IACnD;IACAxD,IAAI,CAACuD,SAAS,GAAGA,SAAS,GAAGA,SAAS,CAACC,KAAK,GAAG,IAAI;IAEnDC,UAAU,CAACI,OAAO,CAAE,UAAWC,QAAQ,EAAG;MACzC,MAAMC,MAAM,GAAGhE,MAAM,CAACiE,gBAAgB,CACrC,cAAc,GAAGF,QAAQ,GAAG,cAC7B,CAAC;MAED,MAAMG,MAAM,GAAG,EAAE;MACjBF,MAAM,CAACF,OAAO,CAAE,UAAWK,KAAK,EAAG;QAClCD,MAAM,CAACE,IAAI,CAAED,KAAK,CAACV,KAAM,CAAC;MAC3B,CAAE,CAAC;MAEHxD,IAAI,CAAE8D,QAAQ,CAAE,GAAGG,MAAM;IAC1B,CAAE,CAAC;IAEH,OAAOjE,IAAI;EACZ;;EAEA;EACA4C,QAAQ,CAACwB,gBAAgB,CAAE,OAAO,EAAE,UAAWC,CAAC,EAAG;IAClD,MAAM7B,EAAE,GAAG6B,CAAC,CAACC,MAAM;IACnB,IAAK9B,EAAE,CAAC+B,OAAO,CAAE,uCAAwC,CAAC,EAAG;MAC5D,IACC/B,EAAE,CAACgC,kBAAkB,CAAClD,KAAK,CAACmD,OAAO,KAAK,MAAM,IAC9CjC,EAAE,CAACgC,kBAAkB,CAAClD,KAAK,CAACmD,OAAO,KAAK,EAAE,EACzC;QACDjC,EAAE,CAACkC,SAAS,CAAC5C,MAAM,CAAE,QAAS,CAAC;QAC/BU,EAAE,CAACkC,SAAS,CAACC,GAAG,CAAE,QAAS,CAAC;QAC5BnC,EAAE,CAACgC,kBAAkB,CAAClD,KAAK,CAACmD,OAAO,GAAG,OAAO;MAC9C,CAAC,MAAM;QACNjC,EAAE,CAACkC,SAAS,CAAC5C,MAAM,CAAE,QAAS,CAAC;QAC/BU,EAAE,CAACkC,SAAS,CAACC,GAAG,CAAE,QAAS,CAAC;QAC5BnC,EAAE,CAACgC,kBAAkB,CAAClD,KAAK,CAACmD,OAAO,GAAG,MAAM;MAC7C;IACD;EACD,CAAE,CAAC;;EAEH;EACA;EACA,MAAMG,aAAa,GAAGhC,QAAQ,CAACoB,gBAAgB,CAC9C,6CACD,CAAC;;EAED;EACA,IAAKY,aAAa,EAAG;IACpB;IACAA,aAAa,CAACf,OAAO,CAAE,UAAWrB,EAAE,EAAG;MACtCA,EAAE,CAAC4B,gBAAgB,CAAE,OAAO,EAAE,UAAWC,CAAC,EAAG;QAC5CA,CAAC,CAACQ,cAAc,CAAC,CAAC;QAElB,MAAM9E,MAAM,GAAG,IAAI,CAAC2C,OAAO,CAAE,+BAAgC,CAAC;QAE9D,IAAK3C,MAAM,EAAG;UACb;UACA,MAAMD,WAAW,GAAG8C,QAAQ,CAACkC,cAAc,CAC1C/E,MAAM,CAACO,OAAO,CAACyE,cAChB,CAAC;UAEDlF,iBAAiB,CAAEC,WAAW,EAAEC,MAAO,CAAC;QACzC;QAEA,IACCA,MAAM,CAACiF,sBAAsB,IAC7BjF,MAAM,CAACiF,sBAAsB,CAACN,SAAS,CAACO,QAAQ,CAC/C,eACD,CAAC,EACA;UACDlF,MAAM,CAACiF,sBAAsB,CAACN,SAAS,CAAC5C,MAAM,CAAE,QAAS,CAAC;UAC1D/B,MAAM,CAACiF,sBAAsB,CAACN,SAAS,CAACC,GAAG,CAAE,QAAS,CAAC;UACvD5E,MAAM,CAACuB,KAAK,CAACmD,OAAO,GAAG,MAAM;QAC9B;MACD,CAAE,CAAC;IACJ,CAAE,CAAC;EACJ;;EAEA;EACA;EACA,MAAMS,YAAY,GAAGtC,QAAQ,CAACoB,gBAAgB,CAC7C,6CACD,CAAC;;EAED;EACA,IAAKkB,YAAY,EAAG;IACnB;IACAA,YAAY,CAACrB,OAAO,CAAE,UAAWrB,EAAE,EAAG;MACrCA,EAAE,CAAC4B,gBAAgB,CAAE,OAAO,EAAE,UAAWC,CAAC,EAAG;QAC5CA,CAAC,CAACQ,cAAc,CAAC,CAAC;QAElB,MAAM9E,MAAM,GAAG,IAAI,CAAC2C,OAAO,CAAE,+BAAgC,CAAC;QAE9D,IAAK3C,MAAM,EAAG;UACb,MAAMsD,MAAM,GAAGtD,MAAM,CAACsB,aAAa,CAClC,sBACD,CAAC;UACD;UACA,MAAMiC,SAAS,GAAGvD,MAAM,CAACsB,aAAa,CACrC,yBACD,CAAC;UACD;UACA,MAAMkC,SAAS,GAAGxD,MAAM,CAACsB,aAAa,CACrC,yBACD,CAAC;UACD;UACA,MAAM8D,eAAe,GAAGpF,MAAM,CAACsB,aAAa,CAC3C,+BACD,CAAC;UACD;UACA,MAAM+D,eAAe,GAAGrF,MAAM,CAACsB,aAAa,CAC3C,+BACD,CAAC;UAED,IAAKgC,MAAM,EAAG;YACbtD,MAAM,CAACsB,aAAa,CAAE,sBAAuB,CAAC,CAACmC,KAAK,GACnD,EAAE;UACJ;;UAEA;UACA,IAAKF,SAAS,EAAG;YAChBvD,MAAM,CAACsB,aAAa,CACnB,yBACD,CAAC,CAACmC,KAAK,GAAG,EAAE;UACb;;UAEA;UACA,IAAKD,SAAS,EAAG;YAChBxD,MAAM,CAACsB,aAAa,CACnB,yBACD,CAAC,CAACmC,KAAK,GAAG,EAAE;UACb;;UAEA;UACA,IAAK2B,eAAe,EAAG;YACtBpF,MAAM,CAACsB,aAAa,CACnB,+BACD,CAAC,CAACmC,KAAK,GAAG,EAAE;UACb;;UAEA;UACA,IAAK4B,eAAe,EAAG;YACtBrF,MAAM,CAACsB,aAAa,CACnB,+BACD,CAAC,CAACmC,KAAK,GAAG,EAAE;UACb;UAEAzD,MAAM,CAACO,OAAO,CAACmD,UAAU,CACvBC,KAAK,CAAE,GAAI,CAAC,CACZG,OAAO,CAAE,UAAWC,QAAQ,EAAG;YAC/BA,QAAQ,GAAGA,QAAQ,CAACF,IAAI,CAAC,CAAC;;YAE1B;YACA,IAAKE,QAAQ,IAAI,EAAE,EAAG;cACrB/D,MAAM,CACJiE,gBAAgB,CAChB,cAAc,GACbF,QAAQ,GACR,sBACF,CAAC,CACAD,OAAO,CAAE,UAAWK,KAAK,EAAG;gBAC5BA,KAAK,CAACmB,OAAO,GAAG,KAAK;cACtB,CAAE,CAAC;YACL;UACD,CAAE,CAAC;;UAEJ;UACA,MAAMvF,WAAW,GAAG8C,QAAQ,CAACkC,cAAc,CAC1C/E,MAAM,CAACO,OAAO,CAACyE,cAChB,CAAC;UAEDlF,iBAAiB,CAAEC,WAAW,EAAEC,MAAO,CAAC;UAExC,IACCA,MAAM,CAACiF,sBAAsB,IAC7BjF,MAAM,CAACiF,sBAAsB,CAACN,SAAS,CAACO,QAAQ,CAC/C,eACD,CAAC,EACA;YACDlF,MAAM,CAACiF,sBAAsB,CAACN,SAAS,CAAC5C,MAAM,CAC7C,QACD,CAAC;YACD/B,MAAM,CAACiF,sBAAsB,CAACN,SAAS,CAACC,GAAG,CAAE,QAAS,CAAC;YACvD5E,MAAM,CAACuB,KAAK,CAACmD,OAAO,GAAG,MAAM;UAC9B;QACD;MACD,CAAE,CAAC;IACJ,CAAE,CAAC;EACJ;;EAEA;EACA7B,QAAQ,CAACwB,gBAAgB,CAAE,OAAO,EAAE,UAAWC,CAAC,EAAG;IAClD,IAAKA,CAAC,CAACC,MAAM,CAACI,SAAS,CAACO,QAAQ,CAAE,OAAQ,CAAC,EAAG;MAC7C,MAAMK,IAAI,GAAGjB,CAAC,CAACC,MAAM,CAACgB,IAAI;QACzB9B,KAAK,GAAGa,CAAC,CAACC,MAAM,CAACd,KAAK;QACtB;QACA+B,aAAa,GAAGlB,CAAC,CAACC,MAAM,CAAC5B,OAAO,CAAE,SAAU,CAAC;MAE9C,QAAS4C,IAAI;QACZ,KAAK,iBAAiB;UACrB;UACAC,aAAa,CAAClE,aAAa,CAAE,oBAAqB,CAAC,CAACmC,KAAK,GACxDA,KAAK;UACN;QAED,KAAK,iBAAiB;UACrB;UACA+B,aAAa,CAAClE,aAAa,CAAE,oBAAqB,CAAC,CAACmC,KAAK,GACxDA,KAAK;UACN;MACF;IACD;IAEA,IACCa,CAAC,CAACC,MAAM,CAAC5B,OAAO,CAAE,iBAAkB,CAAC,KAAK,IAAI;IAC9C;IACA2B,CAAC,CAACC,MAAM,CAACkB,IAAI,IAAI,QAAQ,EACxB;MACD,MAAMF,IAAI,GAAGjB,CAAC,CAACC,MAAM,CAACgB,IAAI;QACzB9B,KAAK,GAAGa,CAAC,CAACC,MAAM,CAACd,KAAK;QACtB;QACA+B,aAAa,GAAGlB,CAAC,CAACC,MAAM,CAAC5B,OAAO,CAAE,SAAU,CAAC;MAE9C,QAAS4C,IAAI;QACZ,KAAK,WAAW;UACf;UACAC,aAAa,CAAClE,aAAa,CAC1B,0BACD,CAAC,CAACmC,KAAK,GAAGA,KAAK;UACf;QAED,KAAK,WAAW;UACf;UACA+B,aAAa,CAAClE,aAAa,CAC1B,0BACD,CAAC,CAACmC,KAAK,GAAGA,KAAK;UACf;MACF;IACD;EACD,CAAE,CAAC;;EAEH;AACD;AACA;;EAEC;EACAZ,QAAQ,CAACwB,gBAAgB,CAAE,OAAO,EAAE,UAAWC,CAAC,EAAG;IAClD,MAAM7B,EAAE,GAAG6B,CAAC,CAACC,MAAM;IAEnB,IACC,CAAE9B,EAAE,CAAC+B,OAAO,CACX,yEACD,CAAC,EACA;MACD;IACD;IAEAF,CAAC,CAACQ,cAAc,CAAC,CAAC;IAElB,MAAMpC,OAAO,GAAGD,EAAE,CAACE,OAAO,CAAE,wBAAyB,CAAC;IACtD,MAAM3C,MAAM,GAAG6C,QAAQ,CAACvB,aAAa,CACpC,qDAAqD,GACpDoB,OAAO,CAACI,EAAE,GACV,IACF,CAAC;IAED,MAAM7C,IAAI,GAAG;MACZC,MAAM,EAAE,iBAAiB;MACzB;MACAC,KAAK,EAAEC,qBAAqB,CAACD,KAAK,CAACE,UAAU;MAC7CN,WAAW,EAAES,IAAI,CAACC,SAAS,CAAEiC,OAAO,CAACnC,OAAQ,CAAC;MAC9CP,MAAM,EAAEQ,IAAI,CAACC,SAAS,CAAEH,cAAc,CAAEN,MAAO,CAAE;IAClD,CAAC;;IAED;IACAU,KAAK;IACJ;IACAN,qBAAqB,CAACO,OAAO,GAAG,GAAG,GAAG,IAAIK,eAAe,CAAEf,IAAK,CAAC,EACjE;MACCW,MAAM,EAAE,KAAK;MACbE,OAAO,EAAE;QACR,cAAc,EAAE;MACjB;IACD,CACD,CAAC,CACCG,IAAI,CAAIC,QAAQ,IAAM;MACtB,OAAOA,QAAQ,CAACC,IAAI,CAAC,CAAC;IACvB,CAAE;IACF;IAAA,CACCF,IAAI,CAAIhB,IAAI,IAAM;MAClB,IAAK,OAAOA,IAAI,KAAK,WAAW,EAAG;QAClC;QACA,IAAKA,IAAI,CAACmB,MAAM,IAAI,SAAS,EAAG;UAC/B;UACA,MAAMC,aAAa,GAClBqB,OAAO,CAACpB,aAAa,CAAE,gBAAiB,CAAC;;UAE1C;UACAD,aAAa,CAACQ,kBAAkB,CAC/B,WAAW,EACX5B,IAAI,CAACyB,IACN,CAAC;UAED,IAAKzB,IAAI,CAAC0B,IAAI,KAAK,UAAU,EAAG;YAC/Be,OAAO,CAACnC,OAAO,CAACoB,IAAI,GAAG1B,IAAI,CAAC0B,IAAI;UACjC;;UAEA;UACA,IAAK1B,IAAI,CAAC0B,IAAI,IAAI,UAAU,EAAG;YAC9B,MAAMC,UAAU,GACfc,OAAO,CAACpB,aAAa,CAAE,aAAc,CAAC;YAEvC,IAAKM,UAAU,EAAG;cACjBA,UAAU,CAACG,MAAM,CAAC,CAAC;YACpB;UACD;UAEA;UACC;UACAW,OAAO,CAACnC,OAAO,CAACyB,IAAI,IAAI,MAAM;UAC9B;UACA/B,IAAI,CAACyB,IAAI,IAAI,EAAE,EACd;YACDO,UAAU,CAAE,YAAY;cACvB;cACAC,iDAAiD,CAAC,CAAC;YACpD,CAAC,EAAE,GAAI,CAAC;UACT,CAAC,MAAM;UACN;UACAQ,OAAO,CAACnC,OAAO,CAACyB,IAAI,IAAI,SAAS;UACjC;UACA/B,IAAI,CAACyB,IAAI,IAAI,EAAE,EACd;YACDgB,OAAO,CAACnB,KAAK,CAACC,UAAU,GAAG,QAAQ;YAEnCS,UAAU,CAAE,YAAY;cACvB;cACAE,kCAAkC,CACjCO,OAAO,CAACpB,aAAa,CAAE,UAAW,CACnC,CAAC;cAEDoB,OAAO,CAACnB,KAAK,CAACC,UAAU,GAAG,SAAS;YACrC,CAAC,EAAE,GAAI,CAAC;UACT;QACD;MACD;IACD,CAAE,CAAC,CACFY,KAAK,CAAIC,KAAK,IAAM;MACpB;MACAC,OAAO,CAACC,GAAG,CAAEF,KAAM,CAAC;IACrB,CAAE,CAAC;EACL,CAAE,CAAC;;EAEH;EACA;EACA,IAAIO,mBAAmB,GAAG,KAAK;EAC/BC,QAAQ,CAACwB,gBAAgB,CAAE,QAAQ,EAAE,YAAY;IAChD;IACA,MAAMqB,wBAAwB,GAAG7C,QAAQ,CAACoB,gBAAgB,CACzD,gEACD,CAAC;;IAED;IACA,IAAKyB,wBAAwB,EAAG;MAC/B;MACAA,wBAAwB,CAAC5B,OAAO,CAAE,UAAW6B,eAAe,EAAG;QAC9D;QACA;QACA,IAAK5C,WAAW,CAAE4C,eAAgB,CAAC,IAAI,CAAE/C,mBAAmB,EAAG;UAC9D;UACAA,mBAAmB,GAAG,IAAI;UAC1BJ,4BAA4B,CAAEmD,eAAgB,CAAC;QAChD;MACD,CAAE,CAAC;IACJ;EACD,CAAE,CAAC;AACJ,CAAC,EAAG,CAAC,C","sources":["webpack://learndash-course-grid/./src/assets/js/script.js"],"sourcesContent":["( function () {\n\t// eslint-disable-next-line camelcase\n\tfunction ajax_apply_filter( course_grid, filter ) {\n\t\tconst data = {\n\t\t\taction: 'ld_cg_apply_filter',\n\t\t\t// eslint-disable-next-line camelcase, no-undef\n\t\t\tnonce: LearnDash_Course_Grid.nonce.load_posts,\n\t\t\tfilter: prepare_filter( filter ),\n\t\t\tcourse_grid: {\n\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t...course_grid.dataset,\n\t\t\t},\n\t\t};\n\n\t\tdata.filter = JSON.stringify( data.filter );\n\t\tdata.course_grid = JSON.stringify( data.course_grid );\n\n\t\t// eslint-disable-next-line camelcase, no-undef\n\t\tfetch( LearnDash_Course_Grid.ajaxurl, {\n\t\t\tmethod: 'POST',\n\t\t\tcredentials: 'same-origin',\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/x-www-form-urlencoded',\n\t\t\t},\n\t\t\tbody: new URLSearchParams( data ),\n\t\t} )\n\t\t\t.then( ( response ) => {\n\t\t\t\treturn response.json();\n\t\t\t} )\n\t\t\t// eslint-disable-next-line no-shadow\n\t\t\t.then( ( data ) => {\n\t\t\t\tif ( typeof data !== 'undefined' ) {\n\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\tif ( data.status == 'success' ) {\n\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\tconst items_wrapper =\n\t\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\t\tcourse_grid.querySelector( '.items-wrapper' );\n\n\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\titems_wrapper.style.visibility = 'hidden';\n\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\titems_wrapper.innerHTML = data.html;\n\n\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\tcourse_grid.dataset.page = data.page;\n\n\t\t\t\t\t\tconst pagination =\n\t\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\t\tcourse_grid.querySelector( '.pagination' );\n\n\t\t\t\t\t\tif ( ! pagination ) {\n\t\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\t\tcourse_grid.insertAdjacentHTML(\n\t\t\t\t\t\t\t\t'beforeend',\n\t\t\t\t\t\t\t\tdata.html_pagination\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\t\tif ( data.html_pagination == '' ) {\n\t\t\t\t\t\t\t// eslint-disable-next-line no-shadow\n\t\t\t\t\t\t\tconst pagination =\n\t\t\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\t\t\tcourse_grid.querySelector( '.pagination' );\n\n\t\t\t\t\t\t\tif ( pagination ) {\n\t\t\t\t\t\t\t\tpagination.remove();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// eslint-disable-next-line camelcase, eqeqeq\n\t\t\t\t\t\tif ( course_grid.dataset.skin == 'grid' ) {\n\t\t\t\t\t\t\tsetTimeout( function () {\n\t\t\t\t\t\t\t\t// eslint-disable-next-line no-undef\n\t\t\t\t\t\t\t\tlearndash_course_grid_init_grid_responsive_design();\n\t\t\t\t\t\t\t}, 500 );\n\t\t\t\t\t\t\t// eslint-disable-next-line camelcase, eqeqeq\n\t\t\t\t\t\t} else if ( course_grid.dataset.skin == 'masonry' ) {\n\t\t\t\t\t\t\tsetTimeout( function () {\n\t\t\t\t\t\t\t\t// eslint-disable-next-line no-undef\n\t\t\t\t\t\t\t\tlearndash_course_grid_init_masonry(\n\t\t\t\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\t\t\t\tcourse_grid.querySelector( '.masonry' )\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}, 500 );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tsetTimeout( function () {\n\t\t\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\t\t\titems_wrapper.style.visibility = 'visible';\n\t\t\t\t\t\t\t}, 500 );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.catch( ( error ) => {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.log( error );\n\t\t\t} );\n\t}\n\n\t// eslint-disable-next-line camelcase\n\tfunction ajax_init_infinite_scrolling( el ) {\n\t\tconst wrapper = el.closest( '.learndash-course-grid' );\n\n\t\tif ( ! wrapper ) {\n\t\t\t// eslint-disable-next-line camelcase\n\t\t\tinfinite_scroll_run = false;\n\t\t\treturn false;\n\t\t}\n\n\t\tconst filter = document.querySelector(\n\t\t\t'.learndash-course-grid-filter[data-course_grid_id=\"' +\n\t\t\t\twrapper.id +\n\t\t\t\t'\"]'\n\t\t);\n\n\t\tconst data = {\n\t\t\taction: 'ld_cg_load_more',\n\t\t\t// eslint-disable-next-line camelcase, no-undef\n\t\t\tnonce: LearnDash_Course_Grid.nonce.load_posts,\n\t\t\tcourse_grid: JSON.stringify( wrapper.dataset ),\n\t\t\tfilter: JSON.stringify( prepare_filter( filter ) ),\n\t\t};\n\n\t\tfetch(\n\t\t\t// eslint-disable-next-line camelcase, no-undef\n\t\t\tLearnDash_Course_Grid.ajaxurl + '?' + new URLSearchParams( data ),\n\t\t\t{\n\t\t\t\tmethod: 'GET',\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t},\n\t\t\t}\n\t\t)\n\t\t\t.then( ( response ) => {\n\t\t\t\treturn response.json();\n\t\t\t} )\n\t\t\t// eslint-disable-next-line no-shadow\n\t\t\t.then( ( data ) => {\n\t\t\t\tif ( typeof data !== 'undefined' ) {\n\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\tif ( data.status == 'success' ) {\n\t\t\t\t\t\twrapper\n\t\t\t\t\t\t\t.querySelector( '.items-wrapper' )\n\t\t\t\t\t\t\t.insertAdjacentHTML( 'beforeend', data.html );\n\n\t\t\t\t\t\tif ( data.page !== 'complete' ) {\n\t\t\t\t\t\t\twrapper.dataset.page = data.page;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\t\tif ( wrapper.dataset.pagination == 'infinite' ) {\n\t\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\t\tinfinite_scroll_run = false;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\t\tif ( data.page == 'complete' ) {\n\t\t\t\t\t\t\tconst pagination =\n\t\t\t\t\t\t\t\twrapper.querySelector( '.pagination' );\n\n\t\t\t\t\t\t\tpagination.remove();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\t\tif ( wrapper.dataset.skin == 'grid' ) {\n\t\t\t\t\t\t\tsetTimeout( function () {\n\t\t\t\t\t\t\t\t// eslint-disable-next-line no-undef\n\t\t\t\t\t\t\t\tlearndash_course_grid_init_grid_responsive_design();\n\t\t\t\t\t\t\t}, 500 );\n\t\t\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\t\t} else if ( wrapper.dataset.skin == 'masonry' ) {\n\t\t\t\t\t\t\twrapper.style.visibility = 'hidden';\n\n\t\t\t\t\t\t\tsetTimeout( function () {\n\t\t\t\t\t\t\t\t// eslint-disable-next-line no-undef\n\t\t\t\t\t\t\t\tlearndash_course_grid_init_masonry(\n\t\t\t\t\t\t\t\t\twrapper.querySelector( '.masonry' )\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\twrapper.style.visibility = 'visible';\n\t\t\t\t\t\t\t}, 500 );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.catch( ( error ) => {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.log( error );\n\t\t\t} );\n\t}\n\n\t// eslint-disable-next-line camelcase\n\tfunction in_viewport( element ) {\n\t\tconst pos = element.getBoundingClientRect();\n\t\t// eslint-disable-next-line no-undef\n\t\treturn ! ( pos.top > innerHeight || pos.bottom < 0 );\n\t}\n\n\t// eslint-disable-next-line camelcase\n\tfunction prepare_filter( filter ) {\n\t\tconst data = {};\n\n\t\tif ( ! filter ) {\n\t\t\treturn data;\n\t\t}\n\n\t\tconst search = filter.querySelector( 'input[name=\"search\"]' );\n\t\t// eslint-disable-next-line camelcase\n\t\tconst price_min = filter.querySelector( '[name=\"price_min\"]' );\n\t\t// eslint-disable-next-line camelcase\n\t\tconst price_max = filter.querySelector( '[name=\"price_max\"]' );\n\n\t\tdata.search = search ? search.value : null;\n\n\t\tlet taxonomies = filter.dataset.taxonomies;\n\t\ttaxonomies = taxonomies.split( ',' ).map( function ( value ) {\n\t\t\treturn value.trim();\n\t\t} );\n\n\t\t// eslint-disable-next-line camelcase\n\t\tdata.price_min = price_min ? price_min.value : null;\n\t\t// eslint-disable-next-line camelcase\n\t\tdata.price_max = price_max ? price_max.value : null;\n\n\t\ttaxonomies.forEach( function ( taxonomy ) {\n\t\t\tconst inputs = filter.querySelectorAll(\n\t\t\t\t'input[name=\"' + taxonomy + '[]\"]:checked'\n\t\t\t);\n\n\t\t\tconst values = [];\n\t\t\tinputs.forEach( function ( input ) {\n\t\t\t\tvalues.push( input.value );\n\t\t\t} );\n\n\t\t\tdata[ taxonomy ] = values;\n\t\t} );\n\n\t\treturn data;\n\t}\n\n\t// Toggle filter display handler\n\tdocument.addEventListener( 'click', function ( e ) {\n\t\tconst el = e.target;\n\t\tif ( el.matches( '.learndash-course-grid .toggle-filter' ) ) {\n\t\t\tif (\n\t\t\t\tel.nextElementSibling.style.display === 'none' ||\n\t\t\t\tel.nextElementSibling.style.display === ''\n\t\t\t) {\n\t\t\t\tel.classList.remove( 'closed' );\n\t\t\t\tel.classList.add( 'opened' );\n\t\t\t\tel.nextElementSibling.style.display = 'block';\n\t\t\t} else {\n\t\t\t\tel.classList.remove( 'opened' );\n\t\t\t\tel.classList.add( 'closed' );\n\t\t\t\tel.nextElementSibling.style.display = 'none';\n\t\t\t}\n\t\t}\n\t} );\n\n\t// Apply filter handler\n\t// eslint-disable-next-line camelcase\n\tconst filter_submit = document.querySelectorAll(\n\t\t'.learndash-course-grid-filter .button.apply'\n\t);\n\n\t// eslint-disable-next-line camelcase\n\tif ( filter_submit ) {\n\t\t// eslint-disable-next-line camelcase\n\t\tfilter_submit.forEach( function ( el ) {\n\t\t\tel.addEventListener( 'click', function ( e ) {\n\t\t\t\te.preventDefault();\n\n\t\t\t\tconst filter = this.closest( '.learndash-course-grid-filter' );\n\n\t\t\t\tif ( filter ) {\n\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\tconst course_grid = document.getElementById(\n\t\t\t\t\t\tfilter.dataset.course_grid_id\n\t\t\t\t\t);\n\n\t\t\t\t\tajax_apply_filter( course_grid, filter );\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\tfilter.previousElementSibling &&\n\t\t\t\t\tfilter.previousElementSibling.classList.contains(\n\t\t\t\t\t\t'toggle-filter'\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tfilter.previousElementSibling.classList.remove( 'opened' );\n\t\t\t\t\tfilter.previousElementSibling.classList.add( 'closed' );\n\t\t\t\t\tfilter.style.display = 'none';\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t}\n\n\t// Clear filter handler\n\t// eslint-disable-next-line camelcase\n\tconst filter_clear = document.querySelectorAll(\n\t\t'.learndash-course-grid-filter .button.clear'\n\t);\n\n\t// eslint-disable-next-line camelcase\n\tif ( filter_clear ) {\n\t\t// eslint-disable-next-line camelcase\n\t\tfilter_clear.forEach( function ( el ) {\n\t\t\tel.addEventListener( 'click', function ( e ) {\n\t\t\t\te.preventDefault();\n\n\t\t\t\tconst filter = this.closest( '.learndash-course-grid-filter' );\n\n\t\t\t\tif ( filter ) {\n\t\t\t\t\tconst search = filter.querySelector(\n\t\t\t\t\t\t'input[name=\"search\"]'\n\t\t\t\t\t);\n\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\tconst price_min = filter.querySelector(\n\t\t\t\t\t\t'input[name=\"price_min\"]'\n\t\t\t\t\t);\n\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\tconst price_max = filter.querySelector(\n\t\t\t\t\t\t'input[name=\"price_max\"]'\n\t\t\t\t\t);\n\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\tconst price_min_range = filter.querySelector(\n\t\t\t\t\t\t'input[name=\"price_min_range\"]'\n\t\t\t\t\t);\n\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\tconst price_max_range = filter.querySelector(\n\t\t\t\t\t\t'input[name=\"price_max_range\"]'\n\t\t\t\t\t);\n\n\t\t\t\t\tif ( search ) {\n\t\t\t\t\t\tfilter.querySelector( 'input[name=\"search\"]' ).value =\n\t\t\t\t\t\t\t'';\n\t\t\t\t\t}\n\n\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\tif ( price_min ) {\n\t\t\t\t\t\tfilter.querySelector(\n\t\t\t\t\t\t\t'input[name=\"price_min\"]'\n\t\t\t\t\t\t).value = '';\n\t\t\t\t\t}\n\n\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\tif ( price_max ) {\n\t\t\t\t\t\tfilter.querySelector(\n\t\t\t\t\t\t\t'input[name=\"price_max\"]'\n\t\t\t\t\t\t).value = '';\n\t\t\t\t\t}\n\n\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\tif ( price_min_range ) {\n\t\t\t\t\t\tfilter.querySelector(\n\t\t\t\t\t\t\t'input[name=\"price_min_range\"]'\n\t\t\t\t\t\t).value = '';\n\t\t\t\t\t}\n\n\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\tif ( price_max_range ) {\n\t\t\t\t\t\tfilter.querySelector(\n\t\t\t\t\t\t\t'input[name=\"price_max_range\"]'\n\t\t\t\t\t\t).value = '';\n\t\t\t\t\t}\n\n\t\t\t\t\tfilter.dataset.taxonomies\n\t\t\t\t\t\t.split( ',' )\n\t\t\t\t\t\t.forEach( function ( taxonomy ) {\n\t\t\t\t\t\t\ttaxonomy = taxonomy.trim();\n\n\t\t\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\t\t\tif ( taxonomy != '' ) {\n\t\t\t\t\t\t\t\tfilter\n\t\t\t\t\t\t\t\t\t.querySelectorAll(\n\t\t\t\t\t\t\t\t\t\t'input[name=\"' +\n\t\t\t\t\t\t\t\t\t\t\ttaxonomy +\n\t\t\t\t\t\t\t\t\t\t\t'[]\"]:not([disabled])'\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t.forEach( function ( input ) {\n\t\t\t\t\t\t\t\t\t\tinput.checked = false;\n\t\t\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\n\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\tconst course_grid = document.getElementById(\n\t\t\t\t\t\tfilter.dataset.course_grid_id\n\t\t\t\t\t);\n\n\t\t\t\t\tajax_apply_filter( course_grid, filter );\n\n\t\t\t\t\tif (\n\t\t\t\t\t\tfilter.previousElementSibling &&\n\t\t\t\t\t\tfilter.previousElementSibling.classList.contains(\n\t\t\t\t\t\t\t'toggle-filter'\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tfilter.previousElementSibling.classList.remove(\n\t\t\t\t\t\t\t'opened'\n\t\t\t\t\t\t);\n\t\t\t\t\t\tfilter.previousElementSibling.classList.add( 'closed' );\n\t\t\t\t\t\tfilter.style.display = 'none';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t}\n\n\t// Dynamic input value update for price filter inputs\n\tdocument.addEventListener( 'input', function ( e ) {\n\t\tif ( e.target.classList.contains( 'range' ) ) {\n\t\t\tconst name = e.target.name,\n\t\t\t\tvalue = e.target.value,\n\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\tprice_wrapper = e.target.closest( '.filter' );\n\n\t\t\tswitch ( name ) {\n\t\t\t\tcase 'price_min_range':\n\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\tprice_wrapper.querySelector( '[name=\"price_min\"]' ).value =\n\t\t\t\t\t\tvalue;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'price_max_range':\n\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\tprice_wrapper.querySelector( '[name=\"price_max\"]' ).value =\n\t\t\t\t\t\tvalue;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (\n\t\t\te.target.closest( '.number-wrapper' ) !== null &&\n\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\te.target.type == 'number'\n\t\t) {\n\t\t\tconst name = e.target.name,\n\t\t\t\tvalue = e.target.value,\n\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\tprice_wrapper = e.target.closest( '.filter' );\n\n\t\t\tswitch ( name ) {\n\t\t\t\tcase 'price_min':\n\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\tprice_wrapper.querySelector(\n\t\t\t\t\t\t'[name=\"price_min_range\"]'\n\t\t\t\t\t).value = value;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'price_max':\n\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\tprice_wrapper.querySelector(\n\t\t\t\t\t\t'[name=\"price_max_range\"]'\n\t\t\t\t\t).value = value;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t} );\n\n\t/**\n\t * Pagination\n\t */\n\n\t// Load more button pagination handler\n\tdocument.addEventListener( 'click', function ( e ) {\n\t\tconst el = e.target;\n\n\t\tif (\n\t\t\t! el.matches(\n\t\t\t\t'.learndash-course-grid[data-pagination=\"button\"] .pagination .load-more'\n\t\t\t)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\te.preventDefault();\n\n\t\tconst wrapper = el.closest( '.learndash-course-grid' );\n\t\tconst filter = document.querySelector(\n\t\t\t'.learndash-course-grid-filter[data-course_grid_id=\"' +\n\t\t\t\twrapper.id +\n\t\t\t\t'\"]'\n\t\t);\n\n\t\tconst data = {\n\t\t\taction: 'ld_cg_load_more',\n\t\t\t// eslint-disable-next-line camelcase, no-undef\n\t\t\tnonce: LearnDash_Course_Grid.nonce.load_posts,\n\t\t\tcourse_grid: JSON.stringify( wrapper.dataset ),\n\t\t\tfilter: JSON.stringify( prepare_filter( filter ) ),\n\t\t};\n\n\t\t// AJAX request\n\t\tfetch(\n\t\t\t// eslint-disable-next-line camelcase, no-undef\n\t\t\tLearnDash_Course_Grid.ajaxurl + '?' + new URLSearchParams( data ),\n\t\t\t{\n\t\t\t\tmethod: 'GET',\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t},\n\t\t\t}\n\t\t)\n\t\t\t.then( ( response ) => {\n\t\t\t\treturn response.json();\n\t\t\t} )\n\t\t\t// eslint-disable-next-line no-shadow\n\t\t\t.then( ( data ) => {\n\t\t\t\tif ( typeof data !== 'undefined' ) {\n\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\tif ( data.status == 'success' ) {\n\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\tconst items_wrapper =\n\t\t\t\t\t\t\twrapper.querySelector( '.items-wrapper' );\n\n\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\titems_wrapper.insertAdjacentHTML(\n\t\t\t\t\t\t\t'beforeend',\n\t\t\t\t\t\t\tdata.html\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tif ( data.page !== 'complete' ) {\n\t\t\t\t\t\t\twrapper.dataset.page = data.page;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\t\tif ( data.page == 'complete' ) {\n\t\t\t\t\t\t\tconst pagination =\n\t\t\t\t\t\t\t\twrapper.querySelector( '.pagination' );\n\n\t\t\t\t\t\t\tif ( pagination ) {\n\t\t\t\t\t\t\t\tpagination.remove();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\t\t\twrapper.dataset.skin == 'grid' &&\n\t\t\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\t\t\tdata.html != ''\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tsetTimeout( function () {\n\t\t\t\t\t\t\t\t// eslint-disable-next-line no-undef\n\t\t\t\t\t\t\t\tlearndash_course_grid_init_grid_responsive_design();\n\t\t\t\t\t\t\t}, 500 );\n\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\t\t\twrapper.dataset.skin == 'masonry' &&\n\t\t\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\t\t\tdata.html != ''\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\twrapper.style.visibility = 'hidden';\n\n\t\t\t\t\t\t\tsetTimeout( function () {\n\t\t\t\t\t\t\t\t// eslint-disable-next-line no-undef\n\t\t\t\t\t\t\t\tlearndash_course_grid_init_masonry(\n\t\t\t\t\t\t\t\t\twrapper.querySelector( '.masonry' )\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\twrapper.style.visibility = 'visible';\n\t\t\t\t\t\t\t}, 500 );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.catch( ( error ) => {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.log( error );\n\t\t\t} );\n\t} );\n\n\t// Infinite scrolling handler\n\t// eslint-disable-next-line camelcase\n\tlet infinite_scroll_run = false;\n\tdocument.addEventListener( 'scroll', function () {\n\t\t// eslint-disable-next-line camelcase\n\t\tconst infinite_scroll_elements = document.querySelectorAll(\n\t\t\t'.learndash-course-grid[data-pagination=\"infinite\"] .pagination'\n\t\t);\n\n\t\t// eslint-disable-next-line camelcase\n\t\tif ( infinite_scroll_elements ) {\n\t\t\t// eslint-disable-next-line camelcase\n\t\t\tinfinite_scroll_elements.forEach( function ( infinite_scroll ) {\n\t\t\t\t// Make sure the function is called only once\n\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\tif ( in_viewport( infinite_scroll ) && ! infinite_scroll_run ) {\n\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\tinfinite_scroll_run = true;\n\t\t\t\t\tajax_init_infinite_scrolling( infinite_scroll );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t} );\n} )();\n"],"names":["ajax_apply_filter","course_grid","filter","data","action","nonce","LearnDash_Course_Grid","load_posts","prepare_filter","dataset","JSON","stringify","fetch","ajaxurl","method","credentials","headers","body","URLSearchParams","then","response","json","status","items_wrapper","querySelector","style","visibility","innerHTML","html","page","pagination","insertAdjacentHTML","html_pagination","remove","skin","setTimeout","learndash_course_grid_init_grid_responsive_design","learndash_course_grid_init_masonry","catch","error","console","log","ajax_init_infinite_scrolling","el","wrapper","closest","infinite_scroll_run","document","id","in_viewport","element","pos","getBoundingClientRect","top","innerHeight","bottom","search","price_min","price_max","value","taxonomies","split","map","trim","forEach","taxonomy","inputs","querySelectorAll","values","input","push","addEventListener","e","target","matches","nextElementSibling","display","classList","add","filter_submit","preventDefault","getElementById","course_grid_id","previousElementSibling","contains","filter_clear","price_min_range","price_max_range","checked","name","price_wrapper","type","infinite_scroll_elements","infinite_scroll"],"sourceRoot":""} \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/script.min.js b/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/script.min.js new file mode 100644 index 000000000..6bf2eb4c5 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/assets/js/script.min.js @@ -0,0 +1 @@ +!function(){function e(e,n){const i={action:"ld_cg_apply_filter",nonce:LearnDash_Course_Grid.nonce.load_posts,filter:t(n),course_grid:{...e.dataset}};i.filter=JSON.stringify(i.filter),i.course_grid=JSON.stringify(i.course_grid),fetch(LearnDash_Course_Grid.ajaxurl,{method:"POST",credentials:"same-origin",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams(i)}).then((e=>e.json())).then((t=>{if(void 0!==t&&"success"==t.status){const n=e.querySelector(".items-wrapper");if(n.style.visibility="hidden",n.innerHTML=t.html,e.dataset.page=t.page,e.querySelector(".pagination")||e.insertAdjacentHTML("beforeend",t.html_pagination),""==t.html_pagination){const t=e.querySelector(".pagination");t&&t.remove()}"grid"==e.dataset.skin?setTimeout((function(){learndash_course_grid_init_grid_responsive_design()}),500):"masonry"==e.dataset.skin?setTimeout((function(){learndash_course_grid_init_masonry(e.querySelector(".masonry"))}),500):setTimeout((function(){n.style.visibility="visible"}),500)}})).catch((e=>{console.log(e)}))}function t(e){const t={};if(!e)return t;const n=e.querySelector('input[name="search"]'),i=e.querySelector('[name="price_min"]'),r=e.querySelector('[name="price_max"]');t.search=n?n.value:null;let a=e.dataset.taxonomies;return a=a.split(",").map((function(e){return e.trim()})),t.price_min=i?i.value:null,t.price_max=r?r.value:null,a.forEach((function(n){const i=e.querySelectorAll('input[name="'+n+'[]"]:checked'),r=[];i.forEach((function(e){r.push(e.value)})),t[n]=r})),t}document.addEventListener("click",(function(e){const t=e.target;t.matches(".learndash-course-grid .toggle-filter")&&("none"===t.nextElementSibling.style.display||""===t.nextElementSibling.style.display?(t.classList.remove("closed"),t.classList.add("opened"),t.nextElementSibling.style.display="block"):(t.classList.remove("opened"),t.classList.add("closed"),t.nextElementSibling.style.display="none"))}));const n=document.querySelectorAll(".learndash-course-grid-filter .button.apply");n&&n.forEach((function(t){t.addEventListener("click",(function(t){t.preventDefault();const n=this.closest(".learndash-course-grid-filter");n&&e(document.getElementById(n.dataset.course_grid_id),n),n.previousElementSibling&&n.previousElementSibling.classList.contains("toggle-filter")&&(n.previousElementSibling.classList.remove("opened"),n.previousElementSibling.classList.add("closed"),n.style.display="none")}))}));const i=document.querySelectorAll(".learndash-course-grid-filter .button.clear");i&&i.forEach((function(t){t.addEventListener("click",(function(t){t.preventDefault();const n=this.closest(".learndash-course-grid-filter");if(n){const t=n.querySelector('input[name="search"]'),i=n.querySelector('input[name="price_min"]'),r=n.querySelector('input[name="price_max"]'),a=n.querySelector('input[name="price_min_range"]'),s=n.querySelector('input[name="price_max_range"]');t&&(n.querySelector('input[name="search"]').value=""),i&&(n.querySelector('input[name="price_min"]').value=""),r&&(n.querySelector('input[name="price_max"]').value=""),a&&(n.querySelector('input[name="price_min_range"]').value=""),s&&(n.querySelector('input[name="price_max_range"]').value=""),n.dataset.taxonomies.split(",").forEach((function(e){""!=(e=e.trim())&&n.querySelectorAll('input[name="'+e+'[]"]:not([disabled])').forEach((function(e){e.checked=!1}))})),e(document.getElementById(n.dataset.course_grid_id),n),n.previousElementSibling&&n.previousElementSibling.classList.contains("toggle-filter")&&(n.previousElementSibling.classList.remove("opened"),n.previousElementSibling.classList.add("closed"),n.style.display="none")}}))})),document.addEventListener("input",(function(e){if(e.target.classList.contains("range")){const t=e.target.name,n=e.target.value,i=e.target.closest(".filter");switch(t){case"price_min_range":i.querySelector('[name="price_min"]').value=n;break;case"price_max_range":i.querySelector('[name="price_max"]').value=n}}if(null!==e.target.closest(".number-wrapper")&&"number"==e.target.type){const t=e.target.name,n=e.target.value,i=e.target.closest(".filter");switch(t){case"price_min":i.querySelector('[name="price_min_range"]').value=n;break;case"price_max":i.querySelector('[name="price_max_range"]').value=n}}})),document.addEventListener("click",(function(e){const n=e.target;if(!n.matches('.learndash-course-grid[data-pagination="button"] .pagination .load-more'))return;e.preventDefault();const i=n.closest(".learndash-course-grid"),r=document.querySelector('.learndash-course-grid-filter[data-course_grid_id="'+i.id+'"]'),a={action:"ld_cg_load_more",nonce:LearnDash_Course_Grid.nonce.load_posts,course_grid:JSON.stringify(i.dataset),filter:JSON.stringify(t(r))};fetch(LearnDash_Course_Grid.ajaxurl+"?"+new URLSearchParams(a),{method:"GET",headers:{"Content-Type":"application/json"}}).then((e=>e.json())).then((e=>{if(void 0!==e&&"success"==e.status){if(i.querySelector(".items-wrapper").insertAdjacentHTML("beforeend",e.html),"complete"!==e.page&&(i.dataset.page=e.page),"complete"==e.page){const e=i.querySelector(".pagination");e&&e.remove()}"grid"==i.dataset.skin&&""!=e.html?setTimeout((function(){learndash_course_grid_init_grid_responsive_design()}),500):"masonry"==i.dataset.skin&&""!=e.html&&(i.style.visibility="hidden",setTimeout((function(){learndash_course_grid_init_masonry(i.querySelector(".masonry")),i.style.visibility="visible"}),500))}})).catch((e=>{console.log(e)}))}));let r=!1;document.addEventListener("scroll",(function(){const e=document.querySelectorAll('.learndash-course-grid[data-pagination="infinite"] .pagination');e&&e.forEach((function(e){(function(e){const t=e.getBoundingClientRect();return!(t.top>innerHeight||t.bottom<0)})(e)&&!r&&(r=!0,function(e){const n=e.closest(".learndash-course-grid");if(!n)return r=!1,!1;const i=document.querySelector('.learndash-course-grid-filter[data-course_grid_id="'+n.id+'"]'),a={action:"ld_cg_load_more",nonce:LearnDash_Course_Grid.nonce.load_posts,course_grid:JSON.stringify(n.dataset),filter:JSON.stringify(t(i))};fetch(LearnDash_Course_Grid.ajaxurl+"?"+new URLSearchParams(a),{method:"GET",headers:{"Content-Type":"application/json"}}).then((e=>e.json())).then((e=>{void 0!==e&&"success"==e.status&&(n.querySelector(".items-wrapper").insertAdjacentHTML("beforeend",e.html),"complete"!==e.page&&(n.dataset.page=e.page),"infinite"==n.dataset.pagination&&(r=!1),"complete"==e.page&&n.querySelector(".pagination").remove(),"grid"==n.dataset.skin?setTimeout((function(){learndash_course_grid_init_grid_responsive_design()}),500):"masonry"==n.dataset.skin&&(n.style.visibility="hidden",setTimeout((function(){learndash_course_grid_init_masonry(n.querySelector(".masonry")),n.style.visibility="visible"}),500)))})).catch((e=>{console.log(e)}))}(e))}))}))}(); \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/assets/lib/masonry/masonry.pkgd.min.js b/web/app/plugins/sfwd-lms/includes/course-grid/assets/lib/masonry/masonry.pkgd.min.js new file mode 100644 index 000000000..2c52af789 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/assets/lib/masonry/masonry.pkgd.min.js @@ -0,0 +1,2 @@ +/*! For license information please see masonry.pkgd.min.js.LICENSE.txt */ +!function(t,e){"function"==typeof define&&define.amd?define("jquery-bridget/jquery-bridget",["jquery"],(function(i){return e(t,i)})):"object"==typeof module&&module.exports?module.exports=e(t,require("jquery")):t.jQueryBridget=e(t,t.jQuery)}(window,(function(t,e){"use strict";function i(i,r,a){(a=a||e||t.jQuery)&&(r.prototype.option||(r.prototype.option=function(t){a.isPlainObject(t)&&(this.options=a.extend(!0,this.options,t))}),a.fn[i]=function(t){return"string"==typeof t?function(t,e,n){var o,r="$()."+i+'("'+e+'")';return t.each((function(t,h){var u=a.data(h,i);if(u){var d=u[e];if(d&&"_"!=e.charAt(0)){var l=d.apply(u,n);o=void 0===o?l:o}else s(r+" is not a valid method")}else s(i+" not initialized. Cannot call methods, i.e. "+r)})),void 0!==o?o:t}(this,t,o.call(arguments,1)):(function(t,e){t.each((function(t,n){var o=a.data(n,i);o?(o.option(e),o._init()):(o=new r(n,e),a.data(n,i,o))}))}(this,t),this)},n(a))}function n(t){!t||t&&t.bridget||(t.bridget=i)}var o=Array.prototype.slice,r=t.console,s=void 0===r?function(){}:function(t){r.error(t)};return n(e||t.jQuery),i})),function(t,e){"function"==typeof define&&define.amd?define("ev-emitter/ev-emitter",e):"object"==typeof module&&module.exports?module.exports=e():t.EvEmitter=e()}("undefined"!=typeof window?window:this,(function(){function t(){}var e=t.prototype;return e.on=function(t,e){if(t&&e){var i=this._events=this._events||{},n=i[t]=i[t]||[];return-1==n.indexOf(e)&&n.push(e),this}},e.once=function(t,e){if(t&&e){this.on(t,e);var i=this._onceEvents=this._onceEvents||{};return(i[t]=i[t]||{})[e]=!0,this}},e.off=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){var n=i.indexOf(e);return-1!=n&&i.splice(n,1),this}},e.emitEvent=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){i=i.slice(0),e=e||[];for(var n=this._onceEvents&&this._onceEvents[t],o=0;o
+ +
+ + + + + + + + +
+ + +
+
+

+
+
+ + + + + + + + +
+ + > +
+
+

+
+ +
+ + + + + + + + +
+ +
+
+

+
+
+ + + + + + + + +
+ +
+
+

+
+
+ + post_type, Utilities::get_post_types_slugs() ) ) { + return; + } + + if ( wp_is_post_revision( $post_id ) ) { + return; + } + + if ( ! isset( $_POST['learndash_course_grid_nonce'] ) || ! wp_verify_nonce( $_POST['learndash_course_grid_nonce'], 'settings_meta_box' ) ) { + return; + } + + $allowed_html = wp_kses_allowed_html( 'learndash_course_grid_embed_code' ); + + if ( isset( $_POST['learndash_course_grid_short_description'] ) ) { + update_post_meta( $post_id, '_learndash_course_grid_short_description', wp_kses_post( $_POST['learndash_course_grid_short_description'] ) ); + learndash_update_setting( $post_id, 'course_short_description', wp_kses_post( $_POST['learndash_course_grid_short_description'] ) ); + } + + $duration_second = ''; + if ( ! empty( $_POST['learndash_course_grid_duration_hour'] ) || ! empty( $_POST['learndash_course_grid_duration_minute'] ) ) { + $duration_second = ( intval( $_POST['learndash_course_grid_duration_hour'] ) * HOUR_IN_SECONDS ) + ( intval( $_POST['learndash_course_grid_duration_minute'] ) * MINUTE_IN_SECONDS ); + } + + update_post_meta( $post_id, '_learndash_course_grid_duration', $duration_second ); + + if ( isset( $_POST['learndash_course_grid_enable_video_preview'] ) ) { + update_post_meta( $post_id, '_learndash_course_grid_enable_video_preview', wp_filter_kses( $_POST['learndash_course_grid_enable_video_preview'] ) ); + } + + if ( isset( $_POST['learndash_course_grid_video_embed_code'] ) ) { + update_post_meta( $post_id, '_learndash_course_grid_video_embed_code', wp_kses( $_POST['learndash_course_grid_video_embed_code'], $allowed_html ) ); + } + + if ( isset( $_POST['learndash_course_grid_custom_button_text'] ) ) { + update_post_meta( $post_id, '_learndash_course_grid_custom_button_text', sanitize_text_field( trim( $_POST['learndash_course_grid_custom_button_text'] ) ) ); + } + + if ( isset( $_POST['learndash_course_grid_custom_ribbon_text'] ) ) { + update_post_meta( $post_id, '_learndash_course_grid_custom_ribbon_text', sanitize_text_field( trim( $_POST['learndash_course_grid_custom_ribbon_text'] ) ) ); + } + } + + /** + * Enqueue scripts and styles. + * + * @since 4.21.4 + * + * @return void + */ + public function enqueue_scripts() { + $screen = get_current_screen(); + + if ( 'post' === $screen->base && ! defined( 'LEARNDASH_VERSION' ) ) { + wp_enqueue_style( + 'learndash-course-grid-meta-box', + LEARNDASH_COURSE_GRID_PLUGIN_URL . 'assets/css/meta-box.css', + [], + LEARNDASH_VERSION, + 'all' + ); + } + } +} diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/includes/class-ajax.php b/web/app/plugins/sfwd-lms/includes/course-grid/includes/class-ajax.php new file mode 100644 index 000000000..f074ce4f6 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/includes/class-ajax.php @@ -0,0 +1,275 @@ + 'success', + 'html' => '', + 'page' => 'complete', + ] + ); + + wp_die(); + } + } elseif ( $hook === 'apply_filter' ) { + $offset = 0; + $query_args['offset'] = $offset; + } + + $tax_count = 0; + foreach ( $filter as $taxonomy => $values ) { + ++$tax_count; + + if ( ! empty( $values ) && is_array( $values ) ) { + $values = array_map( + function ( $id ) { + return intval( $id ); + }, + $values + ); + + $query_args['tax_query'][] = [ + 'taxonomy' => $taxonomy, + 'field' => 'term_id', + 'terms' => $values, + ]; + + if ( count( $query_args['tax_query'] ) > 1 ) { + $query_args['tax_query']['relation'] = 'OR'; + } + } + } + + /** + * Filters the query arguments for the course grid. + * + * @since 4.21.4 + * + * @param array $query_args The query arguments. + * @param array $atts The shortcode attributes. + * @param array $filter The filter values. + * + * @return array The returned query arguments. + */ + $query_args = apply_filters( 'learndash_course_grid_query_args', $query_args, $atts, $filter ); + + $query = new WP_Query( $query_args ); + + if ( $query->have_posts() ) { + $posts = $query->get_posts(); + } + + $html = ''; + $html_pagination = ''; + if ( ! empty( $posts ) ) { + $card = sanitize_text_field( $atts['card'] ); + $template = Utilities::get_card_layout( $card ); + $has_pagination = false; + + if ( + in_array( $post_type, [ 'sfwd-courses', 'groups' ] ) + && ( isset( $price_min ) || isset( $price_max ) ) + && defined( 'LEARNDASH_VERSION' ) + ) { + // Filter posts + $posts = array_filter( + $posts, + function ( $post ) use ( $price_min, $price_max ) { + $price = false; + $price_number = false; + if ( $post->post_type == 'sfwd-courses' ) { + $price = \learndash_get_course_price( $post->ID ); + $price_number = floatval( $price['price'] ); + } elseif ( $post->post_type == 'groups' ) { + $price = \learndash_get_group_price( $post->ID ); + $price_number = floatval( $price['price'] ); + } + + $price_min_check = true; + if ( $price_min === 0 || $price_min > 0 ) { + $price_min_check = ( $price_number >= $price_min ); + } + + $price_max_check = true; + if ( isset( $price_max ) ) { + $price_max_check = ( $price_number <= $price_max ) || ( $price_max == 0 && $price['type'] == 'free' ); + } + + if ( $price && $price_min_check && $price_max_check ) { + return true; + } else { + return false; + } + } + ); + + $total_posts = count( $posts ); + $max_num_pages = ceil( $total_posts / $per_page ); + + $posts = array_slice( $posts, $offset, $per_page ); + } else { + $posts = $query->get_posts(); + $max_num_pages = $query->max_num_pages; + } + + if ( $max_num_pages > $page ) { + $has_pagination = true; + } + + foreach ( $posts as $post ) { + if ( ! $post instanceof WP_Post ) { + continue; + } + + ob_start(); + learndash_course_grid_load_card_template( $atts, $post ); + + $html .= ob_get_clean(); + } + + $pagination_template = Utilities::get_pagination_template( $pagination ); + + if ( $pagination_template && $has_pagination ) { + ob_start(); + include $pagination_template; + $html_pagination .= ob_get_clean(); + } + } elseif ( $hook === 'apply_filter' ) { + $html .= '

' . __( 'No results found.', 'learndash' ) . '

'; + } + + if ( $hook === 'load_more' ) { + $page = empty( $html ) || ( $page + 2 ) > $max_num_pages ? 'complete' : $page + 1; + } elseif ( $hook === 'apply_filter' ) { + $page = 1; + } + + echo json_encode( + [ + 'status' => 'success', + 'html' => $html, + 'html_pagination' => $html_pagination, + 'page' => $page, + ] + ); + + wp_die(); + } +} diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/includes/class-blocks.php b/web/app/plugins/sfwd-lms/includes/course-grid/includes/class-blocks.php new file mode 100644 index 000000000..cdccc9916 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/includes/class-blocks.php @@ -0,0 +1,108 @@ + 'LearnDash_Course_Grid', + 'learndash_course_grid_filter' => 'LearnDash_Course_Grid_Filter', + ]; + + foreach ( $blocks as $id => $class ) { + $classname = '\\LearnDash\\Course_Grid\\Gutenberg\\Blocks\\' . $class; + $this->$id = new $classname(); + } + } + + /** + * Enqueue Block Editor Assets. + * + * @since 4.21.4 + * + * @return void + */ + public function enqueue_block_editor_assets() { + if ( ! is_admin() ) { + return; + } + + $asset_file = include LEARNDASH_COURSE_GRID_PLUGIN_PATH . 'includes/gutenberg/assets/js/index.asset.php'; + + wp_register_script( 'learndash-course-grid-block-editor-helper', LEARNDASH_COURSE_GRID_PLUGIN_URL . 'assets/js/editor.js', [], LEARNDASH_VERSION, true ); + + wp_enqueue_script( 'learndash-course-grid-block-editor', LEARNDASH_COURSE_GRID_PLUGIN_URL . 'includes/gutenberg/assets/js/index.js', array_merge( $asset_file['dependencies'], [ 'learndash-course-grid-block-editor-helper' ] ), $asset_file['version'], true ); + + learndash_course_grid_load_inline_script_locale_data(); + + wp_localize_script( + 'learndash-course-grid-block-editor', + 'LearnDash_Course_Grid_Block_Editor', + [ + 'post_types' => Utilities::get_post_types_for_block_editor(), + 'skins' => Course_Grid::instance()->skins->get_skins(), + 'cards' => Course_Grid::instance()->skins->get_cards(), + 'editor_fields' => Course_Grid::instance()->skins->get_default_editor_fields(), + 'image_sizes' => Utilities::get_image_sizes_for_block_editor(), + 'orderby' => Utilities::get_orderby_for_block_editor(), + 'taxonomies' => Utilities::get_taxonomies_for_block_editor(), + 'paginations' => Utilities::get_paginations_for_block_editor(), + 'is_learndash_active' => defined( 'LEARNDASH_VERSION' ) ? true : false, + ] + ); + } +} diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/includes/class-compatibility.php b/web/app/plugins/sfwd-lms/includes/course-grid/includes/class-compatibility.php new file mode 100644 index 000000000..2c7db62a6 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/includes/class-compatibility.php @@ -0,0 +1,171 @@ +skins->enqueue_editor_skin_assets(); + } + + /** + * Adds extra course grids to an Elementor post. + * + * @since 4.21.4 + * + * @param array> $course_grids Course grids. + * @param WP_Post $post Post object. + * + * @return array> Course grids. + */ + public function elementor_post_extra_course_grids( $course_grids, $post ) { + if ( ! is_a( $post, 'WP_Post' ) ) { + return $course_grids; + } + + $is_elementor = get_post_meta( $post->ID, '_elementor_edit_mode', true ); + + if ( $is_elementor ) { + global $learndash_course_grid_post_elementor_enabled; + $learndash_course_grid_post_elementor_enabled = true; + + $elementor_data = get_post_meta( $post->ID, '_elementor_data', true ); + if ( $elementor_data ) { + if ( is_string( $elementor_data ) ) { + $elementor_data = json_decode( $elementor_data, true ); + } + $elements = Utilities::associative_list_pluck( $elementor_data, 'elements' ); + + foreach ( $elements as $element ) { + if ( isset( $element['widgetType'] ) ) { + switch ( $element['widgetType'] ) { + case 'tabs': + foreach ( $element['settings']['tabs'] as $tab ) { + $tags = Course_Grid::instance()->skins->parse_content_shortcodes( $tab['tab_content'], [] ); + + $course_grids[] = $tags; + } + break; + } + } + } + } + } + + return $course_grids; + } + + /** + * Enqueues the scripts for Elementor compatibility. + * + * @since 4.21.4 + * + * @return void + */ + public function elementor_assets_loaded() { + global $learndash_course_grid_post_elementor_enabled; + + if ( $learndash_course_grid_post_elementor_enabled ) { + wp_enqueue_script( 'learndash-course-grid-elementor-compatibility', LEARNDASH_COURSE_GRID_PLUGIN_URL . 'assets/js/elementor.js', [], LEARNDASH_VERSION, true ); + } + } + + /** + * Parses the Elementor data. + * + * @since 4.21.4 + * + * @param array $data Elementor data. + * + * @return void + */ + public function parse_elementor_data( $data ) { + $elements = Utilities::associative_list_pluck( $data, 'elements' ); + } +} diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/includes/class-security.php b/web/app/plugins/sfwd-lms/includes/course-grid/includes/class-security.php new file mode 100644 index 000000000..975436e59 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/includes/class-security.php @@ -0,0 +1,86 @@ + $tags List of HTML tags. + * @param string $context String of context. + * + * @return array New allowed HTML tags. + */ + public function filter_allowed_html( $tags, $context ) { + if ( 'learndash_course_grid_embed_code' == $context ) { + $tags['iframe'] = [ + 'allowfullscreen' => true, + 'frameborder' => true, + 'height' => true, + 'src' => true, + 'width' => true, + 'allow' => true, + 'class' => true, + 'data-playerid' => true, + 'allowtransparency' => true, + 'style' => true, + 'name' => true, + 'watch-type' => true, + 'url-params' => true, + 'scrolling' => true, + ]; + + $tags['video'] = [ + 'controls' => true, + 'autoplay' => true, + 'height' => true, + 'width' => true, + 'src' => true, + ]; + + $tags['source'] = [ + 'src' => true, + 'media' => true, + 'sizes' => true, + 'type' => true, + ]; + + $tags['track'] = [ + 'default' => true, + 'src' => true, + 'srclang' => true, + 'kind' => true, + 'label' => true, + ]; + } + + return $tags; + } +} diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/includes/class-shortcodes.php b/web/app/plugins/sfwd-lms/includes/course-grid/includes/class-shortcodes.php new file mode 100644 index 000000000..1828e44c7 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/includes/class-shortcodes.php @@ -0,0 +1,70 @@ + 'LearnDash_Course_Grid', + 'learndash_course_grid_filter' => 'LearnDash_Course_Grid_Filter', + ]; + + foreach ( $shortcodes as $tag => $class ) { + $classname = '\\LearnDash\\Course_Grid\\Shortcodes\\' . $class; + $this->$tag = new $classname(); + } + } +} diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/includes/class-skins.php b/web/app/plugins/sfwd-lms/includes/course-grid/includes/class-skins.php new file mode 100644 index 000000000..079dbf29f --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/includes/class-skins.php @@ -0,0 +1,1261 @@ + + */ + private $registered_skins; + + /** + * Registered cards. + * + * @since 4.21.4 + * + * @var array + */ + private $registered_cards; + + /** + * Constructor. + * + * @since 4.21.4 + */ + public function __construct() { + $this->register_skins(); + $this->register_cards(); + + add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_skin_assets' ] ); + add_action( 'enqueue_block_assets', [ $this, 'enqueue_editor_skin_assets' ] ); + } + + /** + * Gets default editor fields. + * + * @since 4.21.4 + * + * @return array + */ + public function get_default_editor_fields() { + /** + * Filters the default editor fields. + * + * @since 4.21.4 + * + * @param array $fields Default editor fields. + * + * @return array Filtered editor fields. + */ + return apply_filters( + 'learndash_course_grid_editor_fields', + [ + 'post_type', + 'per_page', + 'orderby', + 'order', + 'taxonomies', + 'thumbnail', + 'thumbnail_size', + 'ribbon', + 'content', + 'title', + 'title_clickable', + 'description', + 'description_char_max', + 'post_meta', + 'button', + 'pagination', + 'skin', + 'columns', + 'items_per_row', + 'grid_height_equal', + 'font_family_title', + 'font_family_description', + 'font_size_title', + 'font_size_description', + 'font_color_title', + 'font_color_description', + 'background_color_title', + 'background_color_description', + // Misc + 'class_name', + 'id', + // Filter + 'filter_search', + 'filter_taxonomies', + 'filter_price', + 'filter_price_min', + 'filter_price_max', + ] + ); + } + + /** + * Registers skins. + * + * @since 4.21.4 + * + * @return void + */ + public function register_skins() { + $this->registered_skins = [ + 'grid' => [ + 'slug' => 'grid', + 'label' => __( 'Grid', 'learndash' ), + 'disable' => [ + 'items_per_row', + ], + ], + 'masonry' => [ + 'slug' => 'masonry', + 'label' => __( 'Masonry', 'learndash' ), + 'disable' => [ + 'items_per_row', + 'grid_height_equal', + ], + 'script_dependencies' => [ + 'masonry' => [ + 'url' => LEARNDASH_COURSE_GRID_PLUGIN_ASSET_URL . 'lib/masonry/masonry.pkgd.min.js', + 'version' => '4.2.2', + ], + ], + ], + 'list' => [ + 'slug' => 'list', + 'label' => __( 'List', 'learndash' ), + 'disable' => [ + 'columns', + 'items_per_row', + 'grid_height_equal', + ], + ], + ]; + } + + /** + * Registers cards. + * + * @since 4.21.4 + * + * @return void + */ + public function register_cards() { + $this->registered_cards = [ + 'grid-1' => [ + 'label' => __( 'Grid 1', 'learndash' ), + 'skins' => [ 'grid', 'masonry' ], + 'elements' => [ + 'thumbnail', + 'ribbon', + 'content', + 'title', + 'icon', + 'post_meta', + ], + ], + 'grid-2' => [ + 'label' => __( 'Grid 2', 'learndash' ), + 'skins' => [ 'grid', 'masonry' ], + 'elements' => [ + 'thumbnail', + 'ribbon', + 'content', + 'title', + 'description', + 'post_meta', + 'button', + ], + ], + 'grid-3' => [ + 'label' => __( 'Grid 3', 'learndash' ), + 'skins' => [ 'grid', 'masonry' ], + 'elements' => [ + 'thumbnail', + 'content', + 'title', + 'description', + 'post_meta', + 'button', + ], + ], + 'list-1' => [ + 'label' => __( 'List 1', 'learndash' ), + 'skins' => [ 'list' ], + 'elements' => [ + 'thumbnail', + 'ribbon', + 'content', + 'title', + 'description', + 'post_meta', + 'icon', + 'button', + ], + ], + 'list-2' => [ + 'label' => __( 'List 2', 'learndash' ), + 'skins' => [ 'list' ], + 'elements' => [ + 'thumbnail', + 'ribbon', + 'content', + 'title', + 'description', + 'post_meta', + 'icon', + ], + ], + ]; + } + + /** + * Get registered skins. + * + * @since 4.21.4 + * + * @return array + */ + public function get_skins() { + /** + * Filters the registered skins. + * + * @since 4.21.4 + * + * @param array $skins Registered skins. + * + * @return array Filtered skins. + */ + return apply_filters( 'learndash_course_grid_skins', $this->registered_skins ); + } + + /** + * Gets a particular skin data. + * + * @since 4.21.4 + * + * @param string $skin Skin slug. + * + * @return array|false|mixed + */ + public function get_skin( $skin ) { + $skin_details = $this->registered_skins[ $skin ] ?? false; + + /** + * Filters the skin details. + * + * @since 4.21.4 + * + * @param array|false $skin_details Skin details. + * @param string $skin Skin slug. + * + * @return array|false|mixed Filtered skin details. + */ + return apply_filters( 'learndash_course_grid_skin', $skin_details, $skin ); + } + + /** + * Get registered cards. + * + * @since 4.21.4 + * + * @return array + */ + public function get_cards() { + /** + * Filters the registered cards. + * + * @since 4.21.4 + * + * @param array $cards Registered cards. + * + * @return array Filtered cards. + */ + return apply_filters( 'learndash_course_grid_cards', $this->registered_cards ); + } + + /** + * Gets a particular card data. + * + * @since 4.21.4 + * + * @param string $card Card slug. + * + * @return array|false|mixed + */ + public function get_card( $card ) { + $card_details = $this->registered_cards[ $card ] ?? false; + + /** + * Filters the card details. + * + * @since 4.21.4 + * + * @param array|false $card_details Card details. + * @param string $card Card slug. + * + * @return array|false|mixed Filtered card details. + */ + return apply_filters( 'learndash_course_grid_card', $card_details, $card ); + } + + /** + * Enqueues general assets. + * + * @since 4.21.4 + * + * @param bool $enqueue_script Whether to enqueue the script or not. + * + * @return void + */ + public function enqueue_general_assets( $enqueue_script = true ) { + $script = LEARNDASH_COURSE_GRID_PLUGIN_ASSET_URL . 'js/script.js'; + $script_file = LEARNDASH_COURSE_GRID_PLUGIN_ASSET_PATH . 'js/script.js'; + + if ( file_exists( $script_file ) && $enqueue_script ) { + wp_enqueue_script( 'learndash', $script, [], LEARNDASH_VERSION, true ); + + wp_localize_script( + 'learndash', + 'LearnDash_Course_Grid', + [ + 'ajaxurl' => admin_url( 'admin-ajax.php' ), + 'nonce' => [ + 'load_posts' => wp_create_nonce( 'ld_cg_load_posts' ), + ], + ] + ); + } + + $style = LEARNDASH_COURSE_GRID_PLUGIN_ASSET_URL . 'css/style.css'; + $style_file = LEARNDASH_COURSE_GRID_PLUGIN_ASSET_PATH . 'css/style.css'; + + if ( file_exists( $style_file ) ) { + wp_enqueue_style( 'learndash', $style, [], LEARNDASH_VERSION, 'all' ); + } + } + + /** + * Enqueues filter assets. + * + * @since 4.21.4 + * + * @param bool $enqueue_script Whether to enqueue the script or not. + * + * @return void + */ + public function enqueue_filter_assets( $enqueue_script = true ) { + $filter_style = Utilities::get_template_url( 'filter/style.css' ); + + if ( $filter_style ) { + wp_enqueue_style( 'learndash-course-grid-filter', $filter_style, [ 'dashicons' ], LEARNDASH_VERSION ); + } + } + + /** + * Enqueues pagination assets. + * + * @since 4.21.4 + * + * @param bool $enqueue_script Whether to enqueue the script or not. + * + * @return void + */ + public function enqueue_pagination_assets( $enqueue_script = true ) { + $pagination_style = Utilities::get_pagination_style(); + + if ( $pagination_style ) { + wp_enqueue_style( 'learndash-course-grid-pagination', $pagination_style, [], LEARNDASH_VERSION ); + } + } + + /** + * Parses block tags. + * + * @since 4.21.4 + * + * @param string $content Post content. + * + * @return array[]|mixed + */ + public function parse_block_tags( $content ) { + $block_tags = []; + + /** + * Extract JSON attributes from Gutenberg block comments. Will match on any block. + * + * Examples: + * + * + * + * + */ + preg_match( '//', $content, $matches ); + + if ( ! empty( $matches[1] ) ) { + $block_tags = json_decode( $matches[1], true ); + } + + return $block_tags; + } + + /** + * Parses shortcode tags. + * + * @since 4.21.4 + * + * @param string $content Post content. + * + * @return array[]|mixed + */ + public function parse_shortcode_tags( $content ) { + /** + * Extract key-value pairs from shortcode attributes. + * + * Examples: + * + * [learndash_course_grid skin="grid" card="grid-1"] + * [learndash_course_grid columns=3 skin='masonry'] + * [learndash_course_grid id="my-grid" skin="list" per_page=6] + */ + preg_match_all( '/\s(.*?)=(.*?)(?=\s|\])/', $content, $matches ); + + $returned_matches = []; + foreach ( $matches as $group => $match ) { + foreach ( $match as $key => $value ) { + $returned_matches[ $group ][ $key ] = trim( str_replace( [ '\'', '"' ], '', $value ) ); + } + } + + return $returned_matches; + } + + /** + * Parses content shortcodes. + * + * This method extracts and processes shortcodes from the provided content, + * identifying course grids, skins, and cards used in the content. + * + * @since 4.21.4 + * + * @param string $content The content containing shortcodes. + * @param array $args Optional. Additional arguments for parsing. + * + * @return array Parsed data including course grids, skins, and cards. + */ + public function parse_content_shortcodes( $content, $args = [] ) { + // phpcs:ignore WordPress.PHP.DontExtract.extract_extract -- Extract was used historically, do not change. + extract( $args ); + + if ( ! isset( $course_grids ) ) { + $course_grids = []; + } + + if ( ! isset( $skins ) ) { + $skins = []; + } + + if ( ! isset( $cards ) ) { + $cards = []; + } + + /** + * Find all learndash_course_grid shortcode instances in content. + * + * Examples: + * + * [learndash_course_grid skin="grid" card="grid-1"] + * [learndash_course_grid columns=3 skin='masonry' per_page=6] + * [learndash_course_grid id="my-grid" skin="list"] + */ + preg_match_all( '/\[learndash_course_grid.*?\]/', $content, $matches ); + + foreach ( $matches[0] as $match ) { + $sub_matches = $this->parse_shortcode_tags( $match ); + + $course_grids[] = $sub_matches; + + if ( isset( $sub_matches[1] ) && is_array( $sub_matches[1] ) && in_array( 'skin', $sub_matches[1] ) ) { + $key = array_search( 'skin', $sub_matches[1] ); + if ( $key !== false ) { + $skins[] = $sub_matches[2][ $key ]; + } + } else { + $skins[] = 'grid'; + } + + if ( isset( $sub_matches[1] ) && is_array( $sub_matches[1] ) && in_array( 'card', $sub_matches[1] ) ) { + $key = array_search( 'card', $sub_matches[1] ); + if ( $key !== false ) { + $cards[] = $sub_matches[2][ $key ]; + } + } else { + $cards[] = 'grid-1'; + } + } + + return compact( 'course_grids', 'skins', 'cards' ); + } + + /** + * Parses content blocks. + * + * This method extracts and processes blocks from the provided content, + * identifying course grids, skins, and cards used in the content. + * + * @since 4.21.4 + * + * @param string $content The content containing blocks. + * @param array $args Optional. Additional arguments for parsing. + * + * @return array Parsed data including course grids, skins, and cards. + */ + public function parse_content_blocks( $content, $args ) { + // phpcs:ignore WordPress.PHP.DontExtract.extract_extract -- Extract was used historically, do not change. + extract( $args ); + + /** + * Find all learndash/ld-course-grid Gutenberg block instances in content. + * + * Examples: + * + * + * + * + */ + preg_match_all( '/<\!-- wp:learndash\/ld-course-grid.*?-->/', $content, $matches ); + + foreach ( $matches[0] as $match ) { + $block_tags = $this->parse_block_tags( $match ); + + $course_grids[] = $block_tags; + + if ( ! empty( $block_tags['skin'] ) ) { + $skins[] = $block_tags['skin']; + } else { + $skins[] = 'grid'; + } + + if ( ! empty( $block_tags['card'] ) ) { + $cards[] = $block_tags['card']; + } else { + $cards[] = 'grid-1'; + } + } + + return compact( 'course_grids', 'skins', 'cards' ); + } + + /** + * Enqueues skin assets. + * + * @since 4.21.4 + * @since 4.25.6 Moved asset loading logic to handle_skin_assets(). + * + * @return void + */ + public function enqueue_skin_assets() { + global $post; + + // Initialize shortcode attributes as separate variables. + $skins = []; + $cards = []; + $course_grids = []; + $legacy_v1 = false; + + // Handle content string parsing (original logic). + $content = $post ? $post->post_content : ''; + + // Check widget content to load course grid assets. + $widgets = wp_get_sidebars_widgets(); + + foreach ( $widgets as $sidebar => $widgets_list ) { + if ( $sidebar === 'wp_inactive_widgets' ) { + continue; + } + + foreach ( $widgets_list as $widget ) { + $widget_id = _get_widget_id_base( $widget ); + + preg_match( '/-([0-9]+)$/', $widget, $widget_matches ); + $widget_number = $widget_matches[1] ?? null; + + if ( ! $widget_number ) { + continue; + } + + $widget_options = get_option( 'widget_' . $widget_id ); + + if ( + ! empty( $widget_options[ $widget_number ]['content'] ) + && has_shortcode( $widget_options[ $widget_number ]['content'], 'learndash_course_grid' ) + ) { + $args = $this->parse_content_shortcodes( $widget_options[ $widget_number ]['content'], compact( 'skins', 'course_grids', 'cards' ) ); + // phpcs:ignore WordPress.PHP.DontExtract.extract_extract -- Extract was used historically, do not change. + extract( $args ); + } + + if ( + ! empty( $widget_options[ $widget_number ]['content'] ) + && strpos( $widget_options[ $widget_number ]['content'], ' + * + * + */ + $has_legacy_block = ( + preg_match( '/ + */ + $has_legacy_comment = ( + strpos( $content, '' ) !== false + ); + + return ( + $has_legacy_shortcode + || $has_legacy_block + || $has_legacy_comment + ); + } + + /** + * Generates custom CSS for a course grid based on provided arguments. + * + * This method creates custom CSS for styling course grid elements including columns, + * equal height settings, fonts, colors, and other visual properties. + * + * @since 4.21.4 + * + * @param array $args Arguments for CSS generation. Can be a flat array of key-value pairs + * or a multi-dimensional array where $args[1] contains keys and $args[2] contains values. + * + * @return string|false Generated CSS string or false if no ID is provided. + */ + public function generate_custom_css( $args = [] ) { + // Parse args first + if ( isset( $args[1] ) && $args[2] ) { + $temp_args = []; + foreach ( $args[1] as $index => $key ) { + $temp_args[ $key ] = $args[2][ $index ]; + } + $args = $temp_args; + } + + // Bail if the element doesn't have ID + if ( empty( $args['id'] ) ) { + return false; + } + + $default_atts = Course_Grid::instance()->shortcodes->learndash_course_grid->get_default_atts(); + + $skin = ! empty( $args['skin'] ) ? $args['skin'] : $default_atts['skin']; + $columns = ! empty( $args['columns'] ) ? $args['columns'] : $default_atts['columns']; + $grid_height_equal = ! empty( $args['grid_height_equal'] ) ? $args['grid_height_equal'] : $default_atts['grid_height_equal']; + $grid_height_equal = filter_var( $grid_height_equal, FILTER_VALIDATE_BOOLEAN ); + + $font_family_title = ! empty( $args['font_family_title'] ) ? $args['font_family_title'] : $default_atts['font_family_title']; + $font_size_title = ! empty( $args['font_size_title'] ) ? $args['font_size_title'] : $default_atts['font_size_title']; + $font_color_title = ! empty( $args['font_color_title'] ) ? $args['font_color_title'] : $default_atts['font_color_title']; + $background_color_title = ! empty( $args['background_color_title'] ) ? $args['background_color_title'] : $default_atts['background_color_title']; + + $font_family_description = ! empty( $args['font_family_description'] ) ? $args['font_family_description'] : $default_atts['font_family_description']; + $font_size_description = ! empty( $args['font_size_description'] ) ? $args['font_size_description'] : $default_atts['font_size_description']; + $font_color_description = ! empty( $args['font_color_description'] ) ? $args['font_color_description'] : $default_atts['font_color_description']; + $background_color_description = ! empty( $args['background_color_description'] ) ? $args['background_color_description'] : $default_atts['background_color_description']; + $font_color_ribbon = ! empty( $args['font_color_ribbon'] ) ? $args['font_color_ribbon'] : $default_atts['font_color_ribbon']; + $background_color_ribbon = ! empty( $args['background_color_ribbon'] ) ? $args['background_color_ribbon'] : $default_atts['background_color_ribbon']; + $font_color_icon = ! empty( $args['font_color_icon'] ) ? $args['font_color_icon'] : $default_atts['font_color_icon']; + $background_color_icon = ! empty( $args['background_color_icon'] ) ? $args['background_color_icon'] : $default_atts['background_color_icon']; + $font_color_button = ! empty( $args['font_color_button'] ) ? $args['font_color_button'] : $default_atts['font_color_button']; + $background_color_button = ! empty( $args['background_color_button'] ) ? $args['background_color_button'] : $default_atts['background_color_button']; + + ob_start(); + ?> + + + + { + grid-template-columns: repeat( , minmax( 0, 1fr ) ); + } + + + + + .item > .post'; ?>, + .item .content'; ?> { + display: flex; + flex-direction: column; + height: 100%; + } + + + .item .content > *:last-child'; ?> { + margin-top: auto; + } + + + + .item .content .entry-title'; ?>, + .item .content .entry-title *'; ?> { + + font-family: ; + + + + font-size: ; + + } + + .item .content .entry-title'; ?> { + + padding: 10px; + border-radius: 5px; + background-color: ; + + + + color: ; + + } + + .item .content .entry-title *'; ?> { + + color: ; + + } + + + + .item .content .entry-content'; ?> { + + font-family: ; + + + + font-size: ; + + + + padding: 10px; + border-radius: 5px; + background-color: ; + + } + + .item .content .entry-content *'; ?> { + + color: ; + + } + + + + .item .ribbon'; ?> { + + background-color: ; + + } + + .item .ribbon'; ?> , + .item .ribbon *'; ?> { + + color: ; + + } + + .item .icon'; ?> { + + background-color: ; + + } + + .item .icon'; ?> , + .item .icon *'; ?> { + + color: ; + + } + + .item .button'; ?> , + .item .button *'; ?> { + + background-color: ; + border: none; + + } + + .item .button'; ?> , + .item .button *'; ?> { + + color: ; + + } + + |\"|\')/', '', $custom_css ); + } + + /** + * Enqueues custom CSS assets for course grids. + * + * This method outputs custom CSS styles for each course grid in the provided array. + * It generates the CSS using the generate_custom_css method and wraps all styles + * in a single style tag with the ID 'learndash-course-grid-custom-css'. + * + * @since 4.21.4 + * + * @param array[] $course_grids Array of course grid configurations. + * + * @return void + */ + public function enqueue_custom_assets( $course_grids ) { + ob_start(); + + echo ''; + + $assets = ob_get_clean(); + echo $assets; + } +} diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/includes/class-translations.php b/web/app/plugins/sfwd-lms/includes/course-grid/includes/class-translations.php new file mode 100644 index 000000000..64d376ef7 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/includes/class-translations.php @@ -0,0 +1,116 @@ +settings_page_id = 'learndash_lms_translations'; + + // Used within the Settings API to uniquely identify this section + $this->settings_section_key = 'settings_translations_' . $this->project_slug; + + // Section label/header + $this->settings_section_label = __( 'LearnDash LMS - Course Grid', 'learndash' ); + + // Class LearnDash_Translations add LD v2.5.0 + if ( class_exists( 'LearnDash_Translations' ) ) { + // Method register_translation_slug add LD v2.5.5 + if ( method_exists( 'LearnDash_Translations', 'register_translation_slug' ) ) { + $this->registered = true; + LearnDash_Translations::register_translation_slug( $this->project_slug, LEARNDASH_COURSE_GRID_PLUGIN_PATH . 'languages' ); + } + } + + parent::__construct(); + } + + /** + * Adds meta boxes. + * + * @since 4.21.4 + * @deprecated 4.21.4 + * + * @param string $settings_screen_id Screen ID. + * + * @return void + */ + public function add_meta_boxes( $settings_screen_id = '' ) { + _deprecated_function( __METHOD__, '4.21.4' ); + + if ( ( $settings_screen_id == $this->settings_screen_id ) && ( $this->registered === true ) ) { + parent::add_meta_boxes( $settings_screen_id ); + } + } + + /** + * Outputs meta box. + * + * @since 4.21.4 + * @deprecated 4.21.4 + * + * @return void + */ + public function show_meta_box() { + $ld_translations = new LearnDash_Translations( $this->project_slug ); + $ld_translations->show_meta_box(); + } + } + + add_action( + 'init', + function () { + Translations::add_section_instance(); + } + ); +} diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/includes/class-utilities.php b/web/app/plugins/sfwd-lms/includes/course-grid/includes/class-utilities.php new file mode 100644 index 000000000..acbc34025 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/includes/class-utilities.php @@ -0,0 +1,848 @@ +}> Parsed taxonomy data. + */ + public static function parse_taxonomies( $taxonomies ) { + $taxonomies = ! empty( $taxonomies ) ? array_filter( explode( ';', sanitize_text_field( $taxonomies ) ) ) : []; + + $results = []; + foreach ( $taxonomies as $taxonomy_entry ) { + $taxonomy_parts = explode( ':', $taxonomy_entry ); + + if ( empty( $taxonomy_parts[0] ) || empty( $taxonomy_parts[1] ) ) { + continue; + } + + $taxonomy = trim( $taxonomy_parts[0] ); + $terms = array_map( 'trim', explode( ',', $taxonomy_parts[1] ) ); + + if ( ! empty( $taxonomy ) && ! empty( $terms ) ) { + $results[ $taxonomy ] = [ + 'terms' => $terms, + ]; + } + } + + return $results; + } + + /** + * Build Post Query Args to use based on the provided Args. + * + * @since 4.21.4 + * + * @param array $atts Post Query Args to start with. + * + * @return array Modified Post Query Args. + */ + public static function build_posts_query_args( $atts = [] ) { + if ( empty( $atts['per_page'] ) ) { + $atts['per_page'] = -1; + } + + $tax_query = []; + + $taxonomies = ! empty( $atts['taxonomies'] ) ? array_filter( explode( ';', sanitize_text_field( str_replace( '"', '', wp_unslash( $atts['taxonomies'] ) ) ) ) ) : []; + + foreach ( $taxonomies as $taxonomy_entry ) { + $taxonomy_parts = explode( ':', $taxonomy_entry ); + + if ( empty( $taxonomy_parts[0] ) || empty( $taxonomy_parts[1] ) ) { + continue; + } + + $taxonomy = trim( $taxonomy_parts[0] ); + $terms = array_map( 'trim', explode( ',', $taxonomy_parts[1] ) ); + + if ( ! empty( $taxonomy ) && ! empty( $terms ) ) { + $tax_query[] = [ + 'taxonomy' => $taxonomy, + 'field' => 'slug', + 'terms' => $terms, + ]; + } + } + + $tax_query['relation'] = 'OR'; + + $post__in = null; + if ( in_array( $atts['post_type'], [ 'sfwd-courses', 'groups' ] ) ) { + $user_id = get_current_user_id(); + $post_ids = []; + + if ( isset( $atts['enrollment_status'] ) && $atts['enrollment_status'] == 'enrolled' ) { + $courses = learndash_user_get_enrolled_courses( $user_id ); + + $group_ids = learndash_get_users_group_ids( $user_id ); + $groups_courses = learndash_get_groups_courses_ids( $user_id, $group_ids ); + + $course_ids = array_merge( $courses, $groups_courses ); + + if ( $atts['post_type'] == 'sfwd-courses' ) { + $post_ids = $course_ids; + + if ( isset( $atts['progress_status'] ) && ! empty( $atts['progress_status'] ) ) { + $progress_status = [ strtoupper( $atts['progress_status'] ) ]; + + $activity_query_args = [ + 'post_types' => 'sfwd-courses', + 'activity_types' => 'course', + 'activity_status' => $progress_status, + 'orderby_order' => 'users.ID, posts.post_title', + 'date_format' => 'F j, Y H:i:s', + 'per_page' => '', + ]; + $activity_query_args['user_ids'] = [ $user_id ]; + $activity_query_args['post_ids'] = $post_ids; + + $user_courses_reports = learndash_reports_get_activity( $activity_query_args ); + + $user_courses_ids = []; + if ( ! empty( $user_courses_reports['results'] ) ) { + foreach ( $user_courses_reports['results'] as $result ) { + $user_courses_ids[] = absint( $result->post_id ); + } + + $post_ids = array_unique( $user_courses_ids ); + } else { + // It means course with such progress status doesn't exist, + // we return empty array + $post_ids = []; + } + } + } elseif ( $atts['post_type'] == 'groups' ) { + $post_ids = $group_ids; + } + + if ( empty( $post_ids ) ) { + // Add literal 0 in an array because post__in param + // ignores empty array + $post_ids = [ 0 ]; + } + } elseif ( isset( $atts['enrollment_status'] ) && $atts['enrollment_status'] == 'not-enrolled' ) { + $price_types = [ 'open', 'free', 'paynow', 'subscribe', 'closed' ]; + + $all_posts = []; + foreach ( $price_types as $price_type ) { + $post_ids_by_price_type = learndash_get_posts_by_price_type( $atts['post_type'], $price_type ); + $all_posts = array_merge( $all_posts, $post_ids_by_price_type ); + } + + $courses = learndash_user_get_enrolled_courses( $user_id ); + + $group_ids = learndash_get_users_group_ids( $user_id ); + $groups_courses = learndash_get_groups_courses_ids( $user_id, $group_ids ); + + $course_ids = array_merge( $courses, $groups_courses ); + + if ( $atts['post_type'] == 'sfwd-courses' ) { + $post_ids = array_diff( $all_posts, $course_ids ); + } elseif ( $atts['post_type'] == 'groups' ) { + $post_ids = array_diff( $all_posts, $group_ids ); + } + } elseif ( empty( $atts['enrollment_status'] ) ) { + $price_types = [ + LEARNDASH_PRICE_TYPE_OPEN, + LEARNDASH_PRICE_TYPE_FREE, + LEARNDASH_PRICE_TYPE_PAYNOW, + LEARNDASH_PRICE_TYPE_SUBSCRIBE, + LEARNDASH_PRICE_TYPE_CLOSED, + ]; + + $all_posts = []; + foreach ( $price_types as $price_type ) { + $all_posts = array_merge( + $all_posts, + learndash_get_posts_by_price_type( + $atts['post_type'], + $price_type + ) + ); + } + + $post_ids = array_values( array_unique( $all_posts ) ); + } + + $group_id = Cast::to_int( $atts['group_id'] ?? 0 ); + + if ( + $group_id > 0 + && $atts['post_type'] === LDLMS_Post_Types::get_post_type_slug( LDLMS_Post_Types::COURSE ) + ) { + $group = Group::find( $group_id ); + + if ( $group instanceof Group ) { + $post_ids = array_values( + array_intersect( + $post_ids, + array_map( + static fn( Course $course ) => $course->get_id(), + $group->get_courses() + ) + ) + ); + } + } + + // Add literal 0 in an array because post__in param ignores empty array. + // TODO: Write test to check if it works with all enrollment statuses argument and without it. + $post__in = ! empty( $post_ids ) ? $post_ids : [ 0 ]; + } + + /** + * Filters the query arguments for Course Grid queries. + * + * @since 4.21.4 + * + * @param array $query_args Query arguments for WP_Query. + * @param array $atts Attributes passed to the function. + * @param mixed $filter Additional filter parameter, defaults to null. + * + * @return array Modified query arguments. + */ + $query_args = apply_filters( + 'learndash_course_grid_query_args', + [ + 'post_type' => sanitize_text_field( $atts['post_type'] ), + 'posts_per_page' => intval( $atts['per_page'] ), + 'post_status' => 'publish', + 'orderby' => sanitize_text_field( $atts['orderby'] ?? 'ID' ), + 'order' => sanitize_text_field( $atts['order'] ?? 'DESC' ), + 'tax_query' => $tax_query, + 'post__in' => $post__in, + ], + $atts, + $filter = null + ); + + return $query_args; + } + + /** + * Gets all available post types for use in Course Grid. + * + * @since 4.21.4 + * + * @return array Array of post type objects. + */ + public static function get_post_types() { + $post_types = get_post_types( + [ + 'public' => true, + ], + 'objects' + ); + + $excluded_post_types = self::get_excluded_post_types(); + + $returned_post_types = []; + foreach ( $post_types as $slug => $post_type ) { + if ( in_array( $slug, $excluded_post_types ) ) { + continue; + } + + $returned_post_types[ $slug ] = $post_type; + } + + /** + * Filters the available post types for Course Grid. + * + * @since 4.21.4 + * + * @param array $returned_post_types Array of post type objects. + * + * @return array Filtered array of post type objects. + */ + return apply_filters( 'learndash_course_grid_post_types', $returned_post_types ); + } + + /** + * Gets all available post type slugs for use in Course Grid. + * + * @since 4.21.4 + * + * @return array Array of post type slugs. + */ + public static function get_post_types_slugs() { + $post_types = self::get_post_types(); + $temp_post_types = []; + foreach ( $post_types as $slug => $post_type ) { + $temp_post_types[] = $slug; + } + $post_types = $temp_post_types; + + return $post_types; + } + + /** + * Gets all available post types formatted for block editor. + * + * @since 4.21.4 + * + * @return array Array of post type options for block editor. + */ + public static function get_post_types_for_block_editor() { + $post_types = self::get_post_types(); + + $returned_post_types = []; + foreach ( $post_types as $slug => $post_type ) { + $returned_post_types[] = [ + 'label' => $post_type->label, + 'value' => $slug, + ]; + } + + /** + * Filters the post type options for the block editor. + * + * @since 4.21.4 + * + * @param array $returned_post_types Array of post type options formatted for block editor. + * + * @return array Filtered array of post type options. + */ + return apply_filters( 'learndash_course_grid_block_editor_post_types', $returned_post_types ); + } + + /** + * Get a list of excluded Post Types for queries. + * + * @since 4.21.4 + * + * @return array + */ + public static function get_excluded_post_types() { + /** + * Filters the list of excluded Post Types for queries. + * + * @since 4.21.4 + * + * @param array Excluded post types. + * + * @return Filtered excluded post types. + */ + return apply_filters( + 'learndash_course_grid_excluded_post_types', + [ + 'sfwd-transactions', + 'sfwd-essays', + 'sfwd-assignment', + 'sfwd-certificates', + 'attachment', + ] + ); + } + + /** + * Gets image sizes formatted for block editor. + * + * @since 4.21.4 + * + * @return array Array of image size options for block editor. + */ + public static function get_image_sizes_for_block_editor() { + $sizes = get_intermediate_image_sizes(); + + $image_sizes = []; + foreach ( $sizes as $size ) { + $image_sizes[] = [ + 'label' => $size, + 'value' => $size, + ]; + } + + /** + * Filters image size options for the block editor. + * + * @since 4.21.4 + * + * @param array $image_sizes Array of image size options formatted for block editor. + * + * @return array Filtered array of image size options. + */ + return apply_filters( 'learndash_course_grid_block_editor_image_sizes', $image_sizes ); + } + + /** + * Gets orderby options formatted for block editor. + * + * @since 4.21.4 + * + * @return array Array of orderby options for block editor. + */ + public static function get_orderby_for_block_editor() { + $orderby = [ + [ + 'label' => __( 'ID', 'learndash' ), + 'value' => 'ID', + ], + [ + 'label' => __( 'Title', 'learndash' ), + 'value' => 'title', + ], + [ + 'label' => __( 'Published Date', 'learndash' ), + 'value' => 'date', + ], + [ + 'label' => __( 'Modified Date', 'learndash' ), + 'value' => 'modified', + ], + [ + 'label' => __( 'Author', 'learndash' ), + 'value' => 'author', + ], + [ + 'label' => __( 'Menu Order', 'learndash' ), + 'value' => 'menu_order', + ], + ]; + + /** + * Filters the orderby options available for block editor. + * + * @since 4.21.4 + * + * @param array $orderby Array of orderby options formatted for block editor. + * + * @return array Filtered array of orderby options. + */ + return apply_filters( 'learndash_course_grid_block_editor_orderby', $orderby ); + } + + /** + * Gets taxonomies formatted for block editor. + * + * @since 4.21.4 + * + * @return array Array of taxonomy options for block editor. + */ + public static function get_taxonomies_for_block_editor() { + $taxonomies = get_taxonomies( [ 'public' => true ], 'objects' ); + + $return = []; + foreach ( $taxonomies as $tax ) { + $return[] = [ + 'label' => $tax->label, + 'value' => $tax->name, + ]; + } + + /** + * Filters the taxonomy options available for block editor. + * + * @since 4.21.4 + * + * @param array $return Array of taxonomy options formatted for block editor. + * + * @return array Filtered array of taxonomy options. + */ + return apply_filters( 'learndash_course_grid_block_editor_taxonomies', $return ); + } + + /** + * Gets available pagination types formatted for block editor. + * + * @since 4.21.4 + * + * @return array Array of pagination options for block editor. + */ + public static function get_paginations_for_block_editor() { + /** + * Gets the available pagination types formatted for block editor. + * + * @since 4.21.4 + * + * @return array Array of pagination options for block editor. + */ + return apply_filters( + 'learndash_course_grid_block_editor_paginations', + [ + [ + 'label' => __( 'Load More Button', 'learndash' ), + 'value' => 'button', + ], + [ + 'label' => __( 'Infinite Scrolling', 'learndash' ), + 'value' => 'infinite', + ], + [ + 'label' => __( 'Disable', 'learndash' ), + 'value' => 'false', + ], + ] + ); + } + + /** + * Generates a random ID string for use in Course Grid elements. + * + * @since 4.21.4 + * + * @return string A unique 16 character string prefixed with 'ld-cg-'. + */ + public static function generate_random_id() { + return substr( uniqid( 'ld-cg-' ), 0, 16 ); + } + + /** + * Retrieves the amount of time it takes for the course to be completed. + * + * @since 4.21.4 + * + * @param int $post_id Post ID that the Course Grid saved on. + * @param string $format Format to display the time in. Defaults to "plain", which just outputs the saved value. "Output" will format it as something like "1 hour 30 minutes". + * + * @return string Formatted duration. + */ + public static function get_duration( $post_id, $format = 'plain' ) { + $duration = get_post_meta( $post_id, '_learndash_course_grid_duration', true ); + + if ( ! empty( $duration ) && is_numeric( $duration ) ) { + switch ( $format ) { + case 'plain': + $duration = $duration; + break; + + case 'output': + $duration_h = is_numeric( $duration ) ? floor( $duration / HOUR_IN_SECONDS ) : null; + $duration_m = is_numeric( $duration ) ? floor( ( $duration % HOUR_IN_SECONDS ) / MINUTE_IN_SECONDS ) : null; + $duration = sprintf( _x( '%1$d h %2$d min', 'Duration, e.g. 1 hour 30 minutes', 'learndash' ), $duration_h, $duration_m ); + break; + + default: + $duration = false; + break; + } + } + + return $duration; + } + + /** + * Formats the displayed price for a Course. + * + * @since 4.21.4 + * + * @param string $price Input price. + * @param string $format How to format the price. Defaults to "plain", which does nothing. "output" will format it as currency. + * + * @return string Formatted price. + */ + public static function format_price( $price, $format = 'plain' ) { + if ( $format == 'output' ) { + preg_match( '/(((\d+)[,\.]?)*(\d+)([\.,]?\d+)?)/', $price, $matches ); + + $price = $matches[1]; + + if ( ! empty( $price ) ) { + $match_comma_decimal = preg_match( '/(?:\d+\.?)*\d+(,\d{1,2})$/', $price, $comma_matches ); + + $match_dot_decimal = preg_match( '/(?:\d+,?)*\d+(\.\d{1,2})$/', $price, $dot_matches ); + + if ( $match_comma_decimal ) { + $has_decimal = ! empty( $comma_matches[1] ) ? true : false; + $thousands_separator = '.'; + $decimal_separator = ','; + $price = str_replace( '.', '', $price ); + $price = str_replace( ',', '.', $price ); + } else { + $has_decimal = ! empty( $dot_matches[1] ) ? true : false; + $thousands_separator = ','; + $decimal_separator = '.'; + $price = str_replace( ',', '', $price ); + } + + $price = floatval( $price ); + + if ( $has_decimal ) { + $price = number_format( $price, 2, $decimal_separator, $thousands_separator ); + } else { + $price = number_format( $price, 0, $decimal_separator, $thousands_separator ); + } + } + + return $price; + } + + return $price; + } + + /** + * Helper method similar to checked() that also has the ability to set the given input element as disabled. + * + * @since 4.21.4 + * + * @param mixed $checked Value being searched for. + * @param array $data Value to search within. + * @param bool $disabled Whether to mark the found value as disabled after marking it as checked. + * + * @return void + */ + public static function checked_array( $checked, $data, $disabled = false ) { + $output = ''; + + if ( is_array( $data ) && in_array( $checked, $data ) ) { + $output .= 'checked="checked"'; + + if ( $disabled ) { + $output .= ' disabled="disabled"'; + } + } + + echo $output; + } + + /** + * Recursively extracts values for a specified key from a nested associative array. + * + * This method traverses a multi-dimensional associative array and collects all values + * associated with the specified key. If the value found is an array, it will be flattened + * and each item will be added to the result. + * + * @since 4.21.4 + * + * @param array $list The array to search through. + * @param string $find_key The key to search for. + * @param array $returned_list The array to store results in (passed by reference). + * + * @return array The array of collected values. + */ + public static function associative_list_pluck( $list, $find_key, &$returned_list = [] ) { + foreach ( $list as $key => $value ) { + if ( $key === $find_key ) { + if ( is_array( $value ) ) { + foreach ( $value as $sub_key => $sub_value ) { + if ( isset( $sub_value[ $key ] ) ) { + unset( $sub_value[ $key ] ); + } + + array_push( $returned_list, $sub_value ); + } + } else { + array_push( $returned_list, $value ); + } + } + + if ( is_array( $value ) ) { + $returned_list = self::associative_list_pluck( $value, $find_key, $returned_list ); + } + } + + return $returned_list; + } +} diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/includes/functions.php b/web/app/plugins/sfwd-lms/includes/course-grid/includes/functions.php new file mode 100644 index 000000000..0a9748f5c --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/includes/functions.php @@ -0,0 +1,753 @@ +post_type == 'sfwd-courses' ) { + $course_options = get_post_meta( $post->ID, '_sfwd-courses', true ); + } + + if ( defined( 'LEARNDASH_VERSION' ) ) { + $course_id = $args['course_id'] ?? null; + $course_id = $course_id ?? learndash_get_course_id( $post->ID ); + + if ( $post->post_type == 'sfwd-courses' ) { + $total_steps = learndash_get_course_steps_count( $post->ID ); + $students_count = learndash_course_grid_count_students( $post->ID ); + $lessons_data = learndash_course_get_steps_by_type( $post->ID, 'sfwd-lessons' ); + $topics_data = learndash_course_get_steps_by_type( $post->ID, 'sfwd-topic' ); + $quizzes_data = learndash_course_get_steps_by_type( $post->ID, 'sfwd-quiz' ); + } elseif ( $post->post_type == 'groups' ) { + $students_count = learndash_course_grid_count_students( $post->ID ); + $courses = learndash_group_enrolled_courses( $post->ID ); + } elseif ( $post->post_type == 'sfwd-lessons' ) { + $students_count = learndash_course_grid_count_students( $course_id ); + $topics_data = learndash_course_get_children_of_step( $course_id, $post->ID, 'sfwd-topic' ); + $quizzes_data = learndash_course_get_children_of_step( $course_id, $post->ID, 'sfwd-quiz' ); + } elseif ( $post->post_type == 'sfwd-topic' ) { + $students_count = learndash_course_grid_count_students( $course_id ); + $quizzes_data = learndash_course_get_children_of_step( $course_id, $post->ID, 'sfwd-quiz' ); + } + } + + $ribbon_text = get_post_meta( $post->ID, '_learndash_course_grid_custom_ribbon_text', true ); + $ribbon_text = ! empty( $ribbon_text ) ? $ribbon_text : ''; + + $description = get_post_meta( $post->ID, '_learndash_course_grid_short_description', true ); + + $description = wpautop( do_shortcode( htmlspecialchars_decode( $description ) ) ); + + if ( ! empty( $atts['description_char_max'] ) ) { + $description = strlen( $description ) > $atts['description_char_max'] ? mb_strimwidth( $description, 0, $atts['description_char_max'] ) . '...' : $description; + } + + $video = get_post_meta( $post->ID, '_learndash_course_grid_enable_video_preview', true ); + + $embed_code = get_post_meta( $post->ID, '_learndash_course_grid_video_embed_code', true ); + + // Retrieve oembed HTML if a URL is provided. + if ( preg_match( '/^http/', $embed_code ) ) { + $embed_code = wp_oembed_get( + $embed_code, + array( + 'height' => 600, + 'width' => 400, + ) + ); + } + + if ( defined( 'LEARNDASH_VERSION' ) && learndash_course_grid_is_learndash_post_type( $post->post_type ) ) { + $button_link = learndash_get_step_permalink( $post->ID, $course_id ); + } else { + $button_link = get_permalink( $post->ID ); + } + + /** + * Filters the button link URL for course grid items. + * + * @since 4.21.4 + * + * @param string $button_link The URL that the button will link to. + * @param int $post_id The ID of the current post. + * + * @return string Modified button link URL. + */ + $button_link = apply_filters( 'learndash_course_grid_custom_button_link', $button_link, $post->ID ); + + $duration = Utilities::get_duration( $post->ID, 'output' ); + + switch ( $post->post_type ) { + case 'sfwd-courses': + $cat_taxonomies = [ 'category', 'ld_course_category' ]; + $tag_taxonomies = [ 'post_tag', 'ld_course_tag' ]; + break; + + case 'sfwd-lessons': + $cat_taxonomies = [ 'category', 'ld_lesson_category' ]; + $tag_taxonomies = [ 'post_tag', 'ld_lesson_tag' ]; + break; + + case 'sfwd-topic': + $cat_taxonomies = [ 'category', 'ld_topic_category' ]; + $tag_taxonomies = [ 'post_tag', 'ld_topic_tag' ]; + break; + + case 'sfwd-quiz': + $cat_taxonomies = [ 'category', 'ld_quiz_category' ]; + $tag_taxonomies = [ 'post_tag', 'ld_quiz_tag' ]; + break; + + case 'sfwd-question': + $cat_taxonomies = [ 'category', 'ld_question_category' ]; + $tag_taxonomies = [ 'post_tag', 'ld_question_tag' ]; + break; + + case 'groups': + $cat_taxonomies = [ 'category', 'ld_group_category' ]; + $tag_taxonomies = [ 'post_tag', 'ld_group_tag' ]; + break; + + default: + $cat_taxonomies = [ 'category' ]; + $tag_taxonomies = [ 'post_tag' ]; + break; + } + + if ( isset( $cat_taxonomies ) ) { + $categories_from_db = get_terms( + [ + 'taxonomy' => $cat_taxonomies, + 'object_ids' => $post->ID, + 'orderby' => 'name', + 'fields' => 'names', + ] + ); + + if ( ! is_wp_error( $categories_from_db ) && is_array( $categories_from_db ) ) { + $categories = implode( ', ', $categories_from_db ); + } + } + + if ( isset( $tag_taxonomies ) ) { + $tags_from_db = get_terms( + [ + 'taxonomy' => $tag_taxonomies, + 'object_ids' => $post->ID, + 'orderby' => 'name', + 'fields' => 'names', + ] + ); + + if ( ! is_wp_error( $tags_from_db ) && is_array( $tags_from_db ) ) { + $tags = implode( ', ', $tags_from_db ); + } + } + + if ( defined( 'LEARNDASH_VERSION' ) ) { + if ( isset( $students_count ) ) { + $students = [ + 'count' => $students_count, + ]; + } + + if ( isset( $lessons_data ) && is_array( $lessons_data ) ) { + $lessons = [ + 'count' => count( $lessons_data ), + 'list' => $lessons_data, + ]; + } + + if ( isset( $topics_data ) && is_array( $topics_data ) ) { + $topics = [ + 'count' => count( $topics_data ), + 'list' => $topics_data, + ]; + } + + if ( isset( $quizzes_data ) && is_array( $quizzes_data ) ) { + $quizzes = [ + 'count' => count( $quizzes_data ), + 'list' => $quizzes_data, + ]; + } + } + + if ( function_exists( 'bbpress' ) && defined( 'LEARNDASH_BBPRESS_VERSION' ) ) { + global $wpdb; + + $meta_key = false; + if ( $post->post_type == 'sfwd-courses' ) { + $meta_key = '_ld_associated_courses'; + } elseif ( $post->post_type == 'groups' ) { + $meta_key = '_ld_associated_groups'; + } + + $forums_data = false; + if ( $meta_key ) { + $forums_data = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}postmeta WHERE meta_key = %s AND meta_value LIKE '%%:%d;%%'", $meta_key, $post->ID ) ); + } + + if ( is_array( $forums_data ) && ! empty( $forums_data ) ) { + $forums = [ + 'count' => count( $forums_data ), + 'list' => [], + ]; + + foreach ( $forums_data as $forum ) { + $forums['list'][] = $forum->post_id; + } + } + } + + $currency = ''; + + if ( function_exists( 'learndash_get_currency_symbol' ) ) { + $currency = learndash_get_currency_symbol(); + } else { + $paypal_enabled = class_exists( 'LearnDash_Settings_Section' ) ? LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Section_PayPal', 'enabled' ) : null; + $paypal_currency = class_exists( 'LearnDash_Settings_Section' ) ? LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Section_PayPal', 'paypal_currency' ) : null; + + $stripe_settings = get_option( 'learndash_stripe_settings', [] ); + + if ( class_exists( 'NumberFormatter' ) ) { + if ( $paypal_enabled == 'on' && ! empty( $paypal_currency ) ) { + $locale = get_locale(); + $number_format = new NumberFormatter( $locale . '@currency=' . $paypal_currency, NumberFormatter::CURRENCY ); + $currency = $number_format->getSymbol( NumberFormatter::CURRENCY_SYMBOL ); + } elseif ( isset( $stripe_settings['enabled'] ) && $stripe_settings['enabled'] == 'yes' && ! empty( $stripe_settings['currency'] ) ) { + $locale = get_locale(); + $number_format = new NumberFormatter( $locale . '@currency=' . $stripe_settings['currency'], NumberFormatter::CURRENCY ); + $currency = $number_format->getSymbol( NumberFormatter::CURRENCY_SYMBOL ); + } + } + } + + /** + * Filters the currency symbol used in course grid display. + * + * @since 4.21.4 + * + * @param string $currency Currency symbol. + * @param int $post_id Post ID. + * + * @return string Modified currency symbol. + */ + $currency = apply_filters( 'learndash_course_grid_currency', $currency, $post->ID ); + + $price = ''; + $price_type = ''; + $price_text = ''; + if ( function_exists( 'learndash_get_course_price' ) && function_exists( 'learndash_get_group_price' ) ) { + if ( $post->post_type == 'sfwd-courses' ) { + $price_args = learndash_get_course_price( $post->ID ); + } elseif ( $post->post_type == 'groups' ) { + $price_args = learndash_get_group_price( $post->ID ); + } + + if ( ! empty( $price_args ) ) { + $price = $price_args['price']; + $price_type = $price_args['type']; + + /** + * Filters the format for displaying price text in the course grid. + * + * Default format is '{currency}{price}' where placeholders are replaced with actual values. + * + * @since 4.21.4 + * + * @param string $format The price format string with placeholders. + * + * @return string Modified price format. + */ + $price_format = apply_filters( 'learndash_course_grid_price_text_format', '{currency}{price}' ); + + if ( is_numeric( $price ) && ! empty( $price ) ) { + $price = Utilities::format_price( $price, 'output' ); + + $price_text = str_replace( [ '{currency}', '{price}' ], [ $currency, $price ], $price_format ); + } elseif ( is_string( $price ) && ! empty( $price ) ) { + if ( preg_match( '/(((\d+),?)*(\d+)(\.?\d+)?)/', $price ) ) { + $price = Utilities::format_price( $price, 'output' ); + + $price_text = str_replace( [ '{currency}', '{price}' ], [ $currency, $price ], $price_format ); + } else { + $price_text = $price; + } + } elseif ( empty( $price ) ) { + if ( 'closed' === $price_type || 'open' === $price_type ) { + $price_text = ''; + } else { + $price_text = __( 'Free', 'learndash' ); + } + } + + if ( $price_type == 'subscribe' ) { + $trial_price = $price_args['trial_price'] ?? false; + + $trial_duration = isset( $price_args['trial_interval'] ) && isset( $price_args['trial_frequency'] ) ? $price_args['trial_interval'] . ' ' . $price_args['trial_frequency'] : false; + + if ( isset( $price_args['interval'] ) && isset( $price_args['frequency'] ) ) { + $subscription_duration = $price_args['interval'] > 1 ? $price_args['interval'] . ' ' . $price_args['frequency'] : $price_args['frequency']; + + $price_text = sprintf( '%s%s', $price_text, $subscription_duration ? '/' . $subscription_duration : '' ); + } + } + } + } + + if ( empty( $price ) ) { + $price = __( 'Free', 'learndash' ); + } + + /** + * Filters the course or group price value. + * + * @since 4.21.4 + * + * @param mixed $price The price value (can be numeric or string). + * @param int $post_id The ID of the current post. + * + * @return mixed Modified price value. + */ + $price = apply_filters( 'learndash_course_grid_price', $price, $post->ID ); + + /** + * Filters the reviews for the course grid. + * + * @since 4.21.4 + * + * @param mixed $reviews The reviews data for the course. + * @param int $post_id The ID of the current post. + * + * @return mixed Modified reviews data. + */ + $reviews = apply_filters( 'learndash_course_grid_reviews', $reviews, $post->ID ); + + $user_object = get_user_by( 'ID', $post->post_author ); + + /** + * Filters the author data for the course grid. + * + * @since 4.21.4 + * + * @param array $author The author data containing name and avatar. + * @param int $post_id The ID of the current post. + * @param int $author_id The ID of the post author. + * + * @return array Modified author data. + */ + $author = apply_filters( + 'learndash_course_grid_author', + [ + 'name' => $user_object->display_name, + 'avatar' => get_avatar_url( $post->post_author ), + ], + $post->ID, + $post->post_author + ); + + $is_completed = false; + $ribbon_class = 'ribbon'; + + $has_access = false; + if ( defined( 'LEARNDASH_VERSION' ) ) { + if ( $post->post_type == 'sfwd-courses' ) { + $has_access = sfwd_lms_has_access( $post->ID, $user_id ); + $is_completed = learndash_course_completed( $user_id, $post->ID ); + } elseif ( $post->post_type == 'groups' ) { + $has_access = learndash_is_user_in_group( $user_id, $post->ID ); + $is_completed = learndash_get_user_group_completed_timestamp( $post->ID, $user_id ); + } elseif ( $post->post_type == 'sfwd-lessons' ) { + $parent_course_id = learndash_get_course_id( $post->ID ); + $has_access = is_user_logged_in() && ! empty( $parent_course_id ) ? sfwd_lms_has_access( $post->ID, $user_id ) : false; + $is_completed = learndash_is_lesson_complete( $user_id, $post->ID, $parent_course_id ); + } elseif ( $post->post_type == 'sfwd-topic' ) { + $parent_course_id = learndash_get_course_id( $post->ID ); + $has_access = is_user_logged_in() && ! empty( $parent_course_id ) ? sfwd_lms_has_access( $post->ID, $user_id ) : false; + $is_completed = learndash_is_topic_complete( $user_id, $post->ID, $parent_course_id ); + } + + if ( in_array( $post->post_type, [ 'sfwd-courses', 'groups' ] ) ) { + if ( $price_type != 'open' && empty( $ribbon_text ) ) { + if ( $has_access && ! $is_completed ) { + $ribbon_class .= ' enrolled'; + $ribbon_text = __( 'Enrolled', 'learndash' ); + } elseif ( $has_access && $is_completed ) { + $ribbon_class .= ' completed'; + $ribbon_text = __( 'Completed', 'learndash' ); + } elseif ( ! empty( $price ) ) { + $ribbon_text = $price_text; + } elseif ( $price_type == 'free' ) { + $ribbon_class .= ' free'; + $ribbon_text = __( 'Free', 'learndash' ); + } else { + $ribbon_class .= ' available'; + $ribbon_text = __( 'Available', 'learndash' ); + } + } elseif ( $price_type == 'open' && empty( $ribbon_text ) ) { + if ( is_user_logged_in() && ! $is_completed ) { + $ribbon_class .= ' enrolled'; + $ribbon_text = __( 'Enrolled', 'learndash' ); + } elseif ( is_user_logged_in() && $is_completed ) { + $ribbon_class .= ' completed'; + $ribbon_text = __( 'Completed', 'learndash' ); + } else { + $ribbon_class .= ' free'; + $ribbon_text = __( 'Free', 'learndash' ); + } + } + } elseif ( in_array( $post->post_type, [ 'sfwd-lessons', 'sfwd-topic' ] ) ) { + $has_started = false; + + if ( $post->post_type == 'sfwd-lessons' ) { + $activity_type = 'lesson'; + } elseif ( $post->post_type == 'sfwd-topic' ) { + $activity_type = 'topic'; + } + + $activity = learndash_get_user_activity( + [ + 'course_id' => $course_id, + 'user_id' => $user_id, + 'post_id' => $post->ID, + 'activity_type' => $activity_type, + ] + ); + + if ( ! empty( $activity ) ) { + if ( ! empty( $activity->activity_started ) && ! $activity->activity_completed ) { + $has_started = true; + } + } + + if ( $has_access && $is_completed ) { + $ribbon_class .= ' enrolled completed'; + $ribbon_text = __( 'Completed', 'learndash' ); + } elseif ( $has_access && ! $has_started ) { + $ribbon_class .= ' enrolled not-started'; + $ribbon_text = __( 'Not started', 'learndash' ); + } elseif ( $has_access && $has_started ) { + $ribbon_class .= ' enrolled in-progress'; + $ribbon_text = __( 'In progress', 'learndash' ); + } elseif ( learndash_is_sample( $post->ID ) ) { + $ribbon_class .= ' free'; + $ribbon_text = __( 'Free', 'learndash' ); + } else { + $ribbon_class .= ' not-enrolled'; + $ribbon_text = ''; + } + } + } + + $button_text = get_post_meta( $post->ID, '_learndash_course_grid_custom_button_text', true ); + + if ( empty( $button_text ) ) { + if ( in_array( $post->post_type, [ 'sfwd-courses', 'groups' ] ) && ! $has_access ) { + $button_text = __( 'Enroll Now', 'learndash' ); + } elseif ( in_array( $post->post_type, [ 'sfwd-courses', 'groups' ] ) && $has_access ) { + $button_text = __( 'Continue Study', 'learndash' ); + } else { + $button_text = __( 'See More', 'learndash' ); + } + } + + /** + * Filters the button text for course grid items. + * + * @since 4.21.4 + * + * @param string $button_text The text displayed on the course grid button. + * @param int $post_id The ID of the current post. + * + * @return string Modified button text. + */ + $button_text = apply_filters( 'learndash_course_grid_custom_button_text', $button_text, $post->ID ); + + /** + * Filters the individual course ribbon text. + * + * @since 4.21.4 + * + * @param string $ribbon_text Returned ribbon text + * @param int $post_id Course ID + * @param string $price_type Course price type + * + * @return string Ribbon text. + */ + $ribbon_text = apply_filters( 'learndash_course_grid_ribbon_text', $ribbon_text, $post->ID, $price_type ); + + /** + * Filters the individual course ribbon class names. + * + * @since 4.21.4 + * + * @param string $ribbon_class Returned class names + * @param int $post_id Course ID + * @param array $course_options Course's options + * + * @return string Ribbon class names. + */ + $ribbon_class = apply_filters( 'learndash_course_grid_ribbon_class', $ribbon_class, $post->ID, $course_options ); + + $post_atts = [ + 'user_id' => $user_id, + 'post_type' => $post->post_type, + 'title' => $post->post_title, + 'description' => $description, + 'price' => $price, + 'currency' => $currency, + 'price_text' => $price_text, + 'video' => $video, + 'video_embed_code' => $embed_code, + 'button_link' => $button_link, + 'button_text' => $button_text, + 'ribbon_text' => $ribbon_text, + 'ribbon_class' => $ribbon_class, + 'students' => $students, + 'duration' => $duration, + 'trial_price' => $trial_price, + 'trial_duration' => $trial_duration, + 'subscription_duration' => $subscription_duration, + 'reviews' => $reviews, + 'categories' => $categories, + 'tags' => $tags, + 'author' => $author, + 'total_steps' => $total_steps, + 'courses' => $courses, + 'lessons' => $lessons, + 'topics' => $topics, + 'quizzes' => $quizzes, + 'forums' => $forums, + ]; + + /** + * Filters the post attributes for course grid template. + * + * @since 4.21.4 + * + * @param array $post_atts Array of post attributes prepared for template display. + * @param WP_Post $post The post object. + * @param array $atts The shortcode attributes. + * + * @return array Modified post attributes. + */ + return apply_filters( 'learndash_course_grid_template_post_attributes', $post_atts, $post, $atts ); +} + +/** + * Loads the appropriate course grid card template. + * + * This function retrieves and includes the template file based on the card layout + * specified in the attributes. It prepares post attributes for display in the template. + * + * @since 4.21.4 + * + * @param array $atts The shortcode attributes, must contain 'card' key for template selection. + * @param WP_Post $post The post object for which to load the card template. + * + * @return void + */ +function learndash_course_grid_load_card_template( $atts, $post ) { + $template = Utilities::get_card_layout( $atts['card'] ); + + if ( $template ) { + $post_atts = learndash_course_grid_prepare_template_post_attributes( $post, $atts ); + + /** + * Filters the shortcode attributes to use for the course grid card template. + * + * Some arguments are set at at the shortcode-level, but may be desirable to modify at the card-level. + * + * @since 4.22.0 + * + * @param array $atts The shortcode attributes. + * @param WP_Post $post The post object. + * @param array $post_atts The post attributes. + * + * @return array Modified shortcode attributes. + */ + $atts = apply_filters( + 'learndash_course_grid_template_post_shortcode_attributes', + $atts, + $post, + $post_atts + ); + + extract( $post_atts ); + + include $template; + } +} + +/** + * Loads required CSS and JS resources for Course Grid. + * + * This function enqueues the necessary skin assets from the Course Grid module. + * It also handles loading legacy v1 skin assets for backward compatibility. + * + * @since 4.21.4 + * + * @return void + */ +function learndash_course_grid_load_resources() { + Course_Grid::instance()->skins->enqueue_skin_assets(); + + // Check and load legacy v1 skin assets + $skin = 'legacy-v1'; + $style_file = LearnDash\Course_Grid\Utilities::get_skin_style( $skin ); + + if ( $style_file ) { + wp_enqueue_style( 'learndash-course-grid-skin-' . $skin, $style_file, [], LEARNDASH_VERSION ); + } +} + +/** + * Checks if a post type is a LearnDash post type. + * + * This function determines whether a given post type belongs to LearnDash by + * comparing it against a list of known LearnDash post types. + * + * @since 4.21.4 + * + * @param string $post_type The post type to check. + * + * @return boolean True if it's a LearnDash post type, false otherwise. + */ +function learndash_course_grid_is_learndash_post_type( $post_type ) { + if ( in_array( $post_type, [ 'groups', 'sfwd-courses', 'sfwd-lesson', 'sfwd-topic', 'sfwd-quiz', 'sfwd-certificates', 'ld-exam' ] ) ) { + return true; + } else { + return false; + } +} + +/** + * Loads inline script data for localization. + * + * This function adds translation data to the wp-i18n script to enable + * localization of JavaScript strings in the Course Grid module. It ensures + * the data is only loaded once per page load. + * + * @since 4.21.4 + * + * @return void + */ +function learndash_course_grid_load_inline_script_locale_data() { + static $loaded = false; + + if ( false === $loaded ) { + $loaded = true; + + // Get locale data + $translations = get_translations_for_domain( 'learndash' ); + + $locale_data = array( + '' => array( + 'domain' => 'learndash', + 'lang' => is_admin() ? get_user_locale() : get_locale(), + ), + ); + + if ( ! empty( $translations->headers['Plural-Forms'] ) ) { + $locale_data['']['plural_forms'] = $translations->headers['Plural-Forms']; + } + + foreach ( $translations->entries as $msgid => $entry ) { + $locale_data[ $msgid ] = $entry->translations; + } + + // Add inline locale data + wp_add_inline_script( + 'wp-i18n', + 'wp.i18n.setLocaleData( ' . wp_json_encode( $locale_data ) . ', "learndash" );' + ); + } +} + +/** + * Counts enrolled students for a LearnDash course or group. + * + * This function retrieves the number of users enrolled in a specific course or group. + * It uses caching to improve performance for repeated calls. + * + * @since 4.21.4 + * + * @param int $post_id The ID of the course or group. + * + * @return int|bool The number of enrolled students, or false if not a valid course/group. + */ +function learndash_course_grid_count_students( $post_id ) { + $count = wp_cache_get( $post_id . '_students_count', 'ld_cg' ); + + if ( false === $count ) { + global $wpdb; + + $post_type = get_post_type( $post_id ); + if ( 'sfwd-courses' === $post_type ) { + $meta_key = 'course_%d_access_from'; + } elseif ( 'groups' === $post_type ) { + $meta_key = 'learndash_group_users_%d'; + } else { + return false; + } + + $query = "SELECT COUNT(*) FROM {$wpdb->base_prefix}usermeta WHERE meta_key = '{$meta_key}'"; + $query = $wpdb->prepare( $query, $post_id ); + $count = $wpdb->get_var( $query ); + + wp_cache_set( $post_id . '_students_count', $count, 'ld_cg', HOUR_IN_SECONDS ); + } + + return $count; +} diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/assets/js/index.asset.php b/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/assets/js/index.asset.php new file mode 100644 index 000000000..d29189997 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/assets/js/index.asset.php @@ -0,0 +1 @@ + array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => 'b9f30849395033703cce'); diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/assets/js/index.js b/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/assets/js/index.js new file mode 100644 index 000000000..9f21b2e19 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/assets/js/index.js @@ -0,0 +1 @@ +(()=>{"use strict";var e={n:t=>{var a=t&&t.__esModule?()=>t.default:()=>t;return e.d(a,{a}),a},d:(t,a)=>{for(var l in a)e.o(a,l)&&!e.o(t,l)&&Object.defineProperty(t,l,{enumerable:!0,get:a[l]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)};const t=window.React,a=window.wp.i18n,l=window.wp.blocks,n=window.wp.blockEditor,r=window.wp.element,o=window.wp.components,s=window.wp.serverSideRender;var i=e.n(s);class d extends r.Component{constructor(e){super(e)}render(){const{context:e,course_grid_id:l,search:n,taxonomies:r,price:s,price_min:i,price_max:d,setAttributes:c}=this.props;let _="search",h="taxonomies",u="price",m="price_min",p="price_max";"page"==e&&(_="filter_search",h="filter_taxonomies",u="filter_price",m="filter_price_min",p="filter_price_max");const b=LearnDash_Course_Grid_Block_Editor.taxonomies;return(0,t.createElement)(o.PanelBody,{title:(0,a.__)("Filter","learndash"),initialOpen:"page"!=e},"widget"===e&&(0,t.createElement)(o.TextControl,{label:(0,a.__)("Course Grid ID","learndash"),help:(0,a.__)("Course grid ID the filter is for.","learndash"),value:l||"",type:"text",onChange:e=>c({course_grid_id:e})}),(0,t.createElement)(o.ToggleControl,{label:(0,a.__)("Search","learndash"),checked:n,onChange:e=>{c({[_]:e})}}),(0,t.createElement)(o.BaseControl,null,(0,t.createElement)(o.SelectControl,{multiple:!0,label:(0,a.__)("Taxonomies","learndash"),help:(0,a.__)("Hold ctrl on Windows or cmd on Mac to select multiple values.","learndash"),options:b,value:r||[],onChange:e=>{c({[h]:e})}})),(0,t.createElement)(o.ToggleControl,{label:(0,a.__)("Price","learndash"),checked:s,onChange:e=>{c({[u]:e})}}),(0,t.createElement)(o.BaseControl,null,(0,t.createElement)(o.TextControl,{label:(0,a.__)("Price Min","learndash"),className:"left",value:i||0,type:"number",onChange:e=>{c({[m]:e})}}),(0,t.createElement)(o.TextControl,{label:(0,a.__)("Price Max","learndash"),className:"right",value:d||0,type:"number",onChange:e=>{c({[p]:e})}}),(0,t.createElement)("div",{style:{clear:"both"}})))}}const c=d;class _ extends r.Component{constructor(e){super(e)}render(){const{name:e,value:l,label:n,display_state:r,setAttributes:s}=this.props;return(0,t.createElement)(o.BaseControl,{className:void 0===r[e]||r[e]?"show color-picker":"hide color-picker",label:n},(0,t.createElement)("div",{className:"color-wrapper"},(0,t.createElement)(o.ColorPalette,{colors:[],value:l||"",onChange:t=>{s({[e]:t})},clearable:!1}),(0,t.createElement)(o.Button,{className:"clear-button",variant:"tertiary",onClick:()=>{s({[e]:null})}},(0,a.__)("Clear","learndash")),(0,t.createElement)("div",{className:"clear"})))}}const h=_,u=window.wp.data;function m(){return"ld-cg-"+(Date.now().toString(36)+Math.random().toString(36).substr(2)).substr(0,"10")}(0,l.registerBlockType)("learndash/ld-course-grid",{title:(0,a.__)("LearnDash Course Grid","learndash"),description:(0,a.__)("Build LearnDash course grid easily.","learndash"),icon:"grid-view",category:"learndash-blocks",supports:{customClassName:!0},apiVersion:3,attributes:{post_type:{type:"string",default:LearnDash_Course_Grid_Block_Editor.is_learndash_active?"sfwd-courses":"post"},per_page:{type:"string",default:9},orderby:{type:"string",default:"ID"},order:{type:"string",default:"DESC"},taxonomies:{type:"string",default:""},enrollment_status:{type:"string",default:""},progress_status:{type:"string",default:""},thumbnail:{type:"boolean",default:1},thumbnail_size:{type:"string",default:"course-thumbnail"},ribbon:{type:"boolean",default:1},content:{type:"boolean",default:1},title:{type:"boolean",default:1},title_clickable:{type:"boolean",default:1},description:{type:"boolean",default:1},description_char_max:{type:"string",default:120},post_meta:{type:"boolean",default:1},button:{type:"boolean",default:1},pagination:{type:"string",default:"button"},grid_height_equal:{type:"boolean",default:0},progress_bar:{type:"boolean",default:0},filter:{type:"boolean",default:1},skin:{type:"string",default:"grid"},card:{type:"string",default:"grid-1"},columns:{type:"string",default:3},min_column_width:{type:"string",default:250},items_per_row:{type:"string",default:5},font_family_title:{type:"string"},font_family_description:{type:"string",default:""},font_size_title:{type:"string",default:""},font_size_description:{type:"string",default:""},font_color_title:{type:"string",default:""},font_color_description:{type:"string",default:""},background_color_title:{type:"string",default:""},background_color_description:{type:"string",default:""},background_color_ribbon:{type:"string",default:""},font_color_ribbon:{type:"string",default:""},background_color_icon:{type:"string",default:""},font_color_icon:{type:"string",default:""},background_color_button:{type:"string",default:""},font_color_button:{type:"string",default:""},id:{type:"string",default:""},preview_show:{type:"boolean",default:1},display_state:{type:"object",default:{}},filter_search:{type:"boolean",default:1},filter_taxonomies:{type:"array",default:["category","post_tag"]},filter_price:{type:"boolean",default:1},filter_price_min:{type:"string",default:0},filter_price_max:{type:"string",default:1e3}},edit:e=>{const{attributes:{post_type:l,per_page:s,orderby:d,order:_,taxonomies:p,enrollment_status:b,progress_status:g,thumbnail:f,thumbnail_size:y,ribbon:C,content:E,title:v,title_clickable:w,description:k,description_char_max:x,post_meta:B,button:O,pagination:N,grid_height_equal:T,progress_bar:P,filter:D,skin:S,card:A,columns:F,min_column_width:z,items_per_row:G,font_family_title:I,font_family_description:L,font_size_title:j,font_size_description:M,font_color_title:q,font_color_description:H,background_color_title:R,background_color_description:W,background_color_ribbon:V,font_color_ribbon:Q,background_color_icon:U,font_color_icon:J,background_color_button:K,font_color_button:X,id:Y,display_state:Z,preview_show:$,filter_search:ee,filter_taxonomies:te,filter_price:ae,filter_price_min:le,filter_price_max:ne},className:re,clientId:oe,setAttributes:se}=e,ie=(0,n.useBlockProps)();if(Y&&""!==Y){if(function(e,t){return(0,u.select)("core/block-editor").getClientIdsWithDescendants().some((a=>{const{id:l}=(0,u.select)("core/block-editor").getBlockAttributes(a);return t!==a&&e===l}))}(Y,oe)){const e=m();se({id:e})}}else{const e=m();se({id:e})}const de=LearnDash_Course_Grid_Block_Editor.post_types,ce=LearnDash_Course_Grid_Block_Editor.paginations,_e=LearnDash_Course_Grid_Block_Editor.skins,he=LearnDash_Course_Grid_Block_Editor.cards,ue=[],me={};for(const e in _e)if(Object.hasOwnProperty.call(_e,e)){const t={label:_e[e].label,value:_e[e].slug};ue.push(t),Object.hasOwnProperty.call(_e[e],"disable")&&(me[_e[e].slug]=_e[e].disable)}const pe=[],be=[],ge={},fe={};for(const e in he)if(Object.hasOwnProperty.call(he,e)&&(Object.hasOwnProperty.call(he[e],"disable")&&(fe[he[e]]=he[e].disable),Object.hasOwnProperty.call(he[e],"skins")&&he[e].skins.forEach((function(t){ge[t]=ge[t]||[],ge[t].push(e)})),void 0!==he[e].skins&&he[e].skins.indexOf(S)>-1)){const t={label:he[e].label,value:e};pe.push(t),be.push(e)}const ye=LearnDash_Course_Grid_Block_Editor.image_sizes,Ce=LearnDash_Course_Grid_Block_Editor.orderby,Ee=[{label:(0,a.__)("Ascending","learndash"),value:"ASC"},{label:(0,a.__)("Descending","learndash"),value:"DESC"}],ve=[{value:"",label:(0,a.__)("All","learndash")},{value:"enrolled",label:(0,a.__)("Enrolled","learndash")},{value:"not-enrolled",label:(0,a.__)("Not Enrolled","learndash")}],we=[{value:"",label:(0,a.__)("All","learndash")},{value:"completed",label:(0,a.__)("Completed","learndash")},{value:"in_progress",label:(0,a.__)("In Progress","learndash")},{value:"not_started",label:(0,a.__)("Not Started","learndash")}];xe(e);const ke=(0,t.createElement)(r.Fragment,{key:"learndash-course-grid-settings"},(0,t.createElement)(n.InspectorControls,{key:"controls"},(0,t.createElement)(o.Panel,{className:"learndash-course-grid-panel"},(0,t.createElement)(o.PanelBody,{title:(0,a.__)("Template","learndash"),initialOpen:!0},(0,t.createElement)(o.BaseControl,{className:void 0===Z.skin||Z.skin?"show":"hide"},(0,t.createElement)(o.SelectControl,{label:(0,a.__)("Skin","learndash"),options:ue,value:S||"",onChange:t=>{se({skin:t}),xe(e)}})),(0,t.createElement)(o.BaseControl,{className:void 0===Z.card||Z.card?"show":"hide"},(0,t.createElement)(o.SelectControl,{label:(0,a.__)("Card","learndash"),options:pe,value:A||"",onChange:e=>{se({card:e})}})),(0,t.createElement)(o.TextControl,{label:(0,a.__)("Columns","learndash"),value:F||"",type:"number",onChange:e=>se({columns:e}),className:void 0===Z.columns||Z.columns?"show":"hide"}),["grid","masonry"].indexOf(S)>-1&&(0,t.createElement)(o.TextControl,{label:(0,a.__)("Min Column Width (in pixel)","learndash"),value:z,type:"number",help:(0,a.__)("If column width reach value lower than this, the grid columns number will automatically be adjusted on display.","learndash"),onChange:e=>se({min_column_width:e}),className:void 0===Z.min_column_width||Z.min_column_width?"show":"hide"}),(0,t.createElement)(o.TextControl,{label:(0,a.__)("Items Per Row","learndash"),help:(0,a.__)("Number of items per row. Certain skins use this to customize the design.","learndash"),value:G||"",type:"number",onChange:e=>se({items_per_row:e}),className:void 0===Z.items_per_row||Z.items_per_row?"show":"hide"})),(0,t.createElement)(o.PanelBody,{title:(0,a.__)("Query","learndash"),initialOpen:!1},(0,t.createElement)(o.BaseControl,{className:void 0===Z.post_type||Z.post_type?"show":"hide"},(0,t.createElement)(o.SelectControl,{label:(0,a.__)("Post Type","learndash"),options:de,value:l||"",onChange:e=>se({post_type:e})})),(0,t.createElement)(o.TextControl,{label:(0,a.__)("Posts per page","learndash"),help:(0,a.__)("Enter 0 show all items.","learndash"),value:s||"",type:"number",onChange:e=>se({per_page:e}),className:void 0===Z.per_page||Z.per_page?"show":"hide"}),(0,t.createElement)(o.BaseControl,{className:void 0===Z.orderby||Z.orderby?"show":"hide"},(0,t.createElement)(o.SelectControl,{label:(0,a.__)("Order By","learndash"),options:Ce,value:d||"",onChange:e=>se({orderby:e})})),(0,t.createElement)(o.BaseControl,{className:void 0===Z.order||Z.order?"show":"hide"},(0,t.createElement)(o.SelectControl,{label:(0,a.__)("Order","learndash"),options:Ee,value:_||"",onChange:e=>se({order:e})})),(0,t.createElement)(o.TextControl,{label:(0,a.__)("Taxonomies","learndash"),help:(0,a.__)("Format:","learndash")+" taxonomy1:term1,term2; taxonomy2:term1,term2;",value:p||"",onChange:e=>se({taxonomies:e}),className:void 0===Z.taxonomies||Z.taxonomies?"show taxonomies":"hide"}),["sfwd-courses","groups"].indexOf(l)>-1&&(0,t.createElement)(o.BaseControl,{className:void 0===Z.enrollment_status||Z.enrollment_status?"show":"hide"},(0,t.createElement)(o.SelectControl,{label:(0,a.__)("Enrollment Status","learndash"),options:ve,value:b,onChange:e=>se({enrollment_status:e})})),["sfwd-courses"].indexOf(l)>-1&&"enrolled"==b&&(0,t.createElement)(o.BaseControl,{className:void 0===Z.progress_status||Z.progress_status?"show":"hide"},(0,t.createElement)(o.SelectControl,{label:(0,a.__)("Progress Status","learndash"),options:we,value:g,onChange:e=>se({progress_status:e})}))),(0,t.createElement)(o.PanelBody,{title:(0,a.__)("Elements","learndash"),initialOpen:!1},he[A].elements.indexOf("thumbnail")>-1&&(0,t.createElement)(o.ToggleControl,{label:(0,a.__)("Thumbnail","learndash"),checked:f,onChange:e=>se({thumbnail:e}),className:void 0===Z.thumbnail||Z.thumbnail?"show":"hide"}),he[A].elements.indexOf("thumbnail")>-1&&f&&(0,t.createElement)(o.BaseControl,{className:void 0===Z.thumbnail_size||Z.thumbnail_size?"show":"hide"},(0,t.createElement)(o.SelectControl,{label:(0,a.__)("Thumbnail Size","learndash"),options:ye,value:y||"",onChange:e=>se({thumbnail_size:e})})),he[A].elements.indexOf("ribbon")>-1&&(0,t.createElement)(o.ToggleControl,{label:(0,a.__)("Ribbon","learndash"),checked:C,onChange:e=>se({ribbon:e}),className:void 0===Z.ribbon||Z.ribbon?"show":"hide"}),he[A].elements.indexOf("content")>-1&&(0,t.createElement)(o.ToggleControl,{label:(0,a.__)("Content","learndash"),help:(0,a.__)("Content includes elements in the area outside of the thumbnail.","learndash"),checked:E,onChange:e=>se({content:e}),className:void 0===Z.content||Z.content?"show":"hide"}),he[A].elements.indexOf("title")>-1&&(0,t.createElement)(o.ToggleControl,{label:(0,a.__)("Title","learndash"),checked:v,onChange:e=>se({title:e}),className:void 0===Z.title||Z.title?"show":"hide"}),he[A].elements.indexOf("title")>-1&&v&&(0,t.createElement)(o.ToggleControl,{label:(0,a.__)("Clickable Title","learndash"),checked:w,onChange:e=>se({title_clickable:e}),className:void 0===Z.title_clickable||Z.title_clickable?"show":"hide"}),he[A].elements.indexOf("description")>-1&&(0,t.createElement)(o.ToggleControl,{label:(0,a.__)("Description","learndash"),checked:k,onChange:e=>se({description:e}),className:void 0===Z.description||Z.description?"show":"hide"}),he[A].elements.indexOf("description")>-1&&k&&(0,t.createElement)(o.TextControl,{label:(0,a.__)("Max Description Character Count","learndash"),value:x||"",type:"number",onChange:e=>{se({description_char_max:e})}}),he[A].elements.indexOf("post_meta")>-1&&(0,t.createElement)(o.ToggleControl,{label:(0,a.__)("Meta","learndash"),checked:B,onChange:e=>se({post_meta:e}),className:void 0===Z.post_meta||Z.post_meta?"show":"hide"}),he[A].elements.indexOf("button")>-1&&(0,t.createElement)(o.ToggleControl,{label:(0,a.__)("Button","learndash"),checked:O,onChange:e=>se({button:e}),className:void 0===Z.button||Z.button?"show":"hide"}),(0,t.createElement)(o.ToggleControl,{label:(0,a.__)("Progress Bar","learndash"),help:(0,a.__)("Available for LearnDash course and group.","learndash"),checked:P,onChange:e=>se({progress_bar:e}),className:void 0===Z.progress_bar||Z.progress_bar?"show":"hide"}),(0,t.createElement)(o.BaseControl,{className:void 0===Z.pagination||Z.pagination?"show":"hide"},(0,t.createElement)(o.SelectControl,{label:(0,a.__)("Pagination","learndash"),options:ce,value:N||"",onChange:e=>se({pagination:e})})),(0,t.createElement)(o.ToggleControl,{label:(0,a.__)("Filter","learndash"),checked:D,onChange:e=>{se({filter:e})},className:void 0===Z.filter||Z.filter?"show":"hide"})),D&&(0,t.createElement)(c,{context:"page",course_grid_id:Y,search:ee,taxonomies:te,price:ae,price_min:le,price_max:ne,setAttributes:se}),(0,t.createElement)(o.PanelBody,{title:(0,a.__)("Styles","learndash"),initialOpen:!1},"grid"===S&&(0,t.createElement)("div",{className:"grid-style"},(0,t.createElement)("h3",null,(0,a.__)("Grid","learndash")),(0,t.createElement)(o.ToggleControl,{label:(0,a.__)("Equal Grid Height","learndash"),checked:T,onChange:e=>se({grid_height_equal:e}),className:void 0===Z.grid_height_equal||Z.grid_height_equal?"show":"hide"})),he[A].elements.indexOf("title")>-1&&v&&(0,t.createElement)(r.Fragment,{key:"title-styles"},(0,t.createElement)("h3",null,(0,a.__)("Heading","learndash")),(0,t.createElement)(o.TextControl,{label:(0,a.__)("Heading Font Family","learndash"),value:I||"",onChange:e=>se({font_family_title:e}),className:void 0===Z.font_family_title||Z.font_family_title?"show":"hide"}),(0,t.createElement)(o.TextControl,{label:(0,a.__)("Heading Font Size","learndash"),help:(0,a.__)("Accepts full format, e.g. 18px, 2rem","learndash"),value:j||"",onChange:e=>se({font_size_title:e}),className:void 0===Z.font_size_title||Z.font_size_title?"show":"hide"}),(0,t.createElement)(h,{name:"font_color_title",value:q,label:(0,a.__)("Heading Font Color","learndash"),display_state:Z,setAttributes:se}),(0,t.createElement)(h,{name:"background_color_title",value:R,label:(0,a.__)("Heading Background Color","learndash"),display_state:Z,setAttributes:se})),he[A].elements.indexOf("description")>-1&&k&&(0,t.createElement)(r.Fragment,{key:"description-styles"},(0,t.createElement)("h3",null,(0,a.__)("Description","learndash")),(0,t.createElement)(o.TextControl,{label:(0,a.__)("Description Font Family","learndash"),value:L||"",onChange:e=>se({font_family_description:e}),className:void 0===Z.font_family_description||Z.font_family_description?"show":"hide"}),(0,t.createElement)(o.TextControl,{label:(0,a.__)("Description Font Size","learndash"),help:(0,a.__)("Accepts full format, e.g. 18px, 2rem","learndash"),value:M||"",onChange:e=>se({font_size_description:e}),className:void 0===Z.font_size_description||Z.font_size_description?"show":"hide"}),(0,t.createElement)(h,{name:"font_color_description",value:H,label:(0,a.__)("Description Font Color","learndash"),display_state:Z,setAttributes:se}),(0,t.createElement)(h,{name:"background_color_description",value:W,label:(0,a.__)("Description Background Color","learndash"),display_state:Z,setAttributes:se})),(0,t.createElement)("h3",null,(0,a.__)("Elements","learndash")),he[A].elements.indexOf("ribbon")>-1&&C&&(0,t.createElement)(r.Fragment,{key:"ribbon-styles"},(0,t.createElement)(h,{name:"font_color_ribbon",value:Q,label:(0,a.__)("Ribbon Font Color","learndash"),display_state:Z,setAttributes:se}),(0,t.createElement)(h,{name:"background_color_ribbon",value:V,label:(0,a.__)("Ribbon Background Color","learndash"),display_state:Z,setAttributes:se})),he[A].elements.indexOf("icon")>-1&&(0,t.createElement)(r.Fragment,{key:"icon-styles"},(0,t.createElement)(h,{name:"font_color_icon",value:J,label:(0,a.__)("Icon Color","learndash"),display_state:Z,setAttributes:se}),(0,t.createElement)(h,{name:"background_color_icon",value:U,label:(0,a.__)("Icon Background Color","learndash"),display_state:Z,setAttributes:se})),he[A].elements.indexOf("button")>-1&&O&&(0,t.createElement)(r.Fragment,{key:"button-styles"},(0,t.createElement)(h,{name:"font_color_button",value:X,label:(0,a.__)("Button Font Color","learndash"),display_state:Z,setAttributes:se}),(0,t.createElement)(h,{name:"background_color_button",value:K,label:(0,a.__)("Button Background Color","learndash"),display_state:Z,setAttributes:se}))),(0,t.createElement)(o.PanelBody,{title:(0,a.__)("Preview","learndash"),initialOpen:!1},(0,t.createElement)(o.ToggleControl,{label:(0,a.__)("Show Preview","learndash"),checked:!!$,onChange:e=>se({preview_show:e})})))),(0,t.createElement)(n.InspectorAdvancedControls,null,(0,t.createElement)(o.TextControl,{label:(0,a.__)("ID"),help:(0,a.__)("Unique ID for CSS styling purpose.","learndash"),value:Y||"",onChange:e=>se({id:e}),className:void 0===Z.id||Z.id?"show":"hide"})));function xe(e){const{attributes:t={skin:S,card:A,display_state:Z},setAttributes:a}=e;let l=[];if(void 0!==me[S]&&(l=me[S]),LearnDash_Course_Grid_Block_Editor.editor_fields.forEach((e=>{const t=Z;t[e]=!0,a({display_state:t})})),l.forEach((e=>{const t=Z;t[e]=!1,a({display_state:t})})),-1==be.indexOf(A)&&Object.prototype.hasOwnProperty.call(ge,"skin")&&Object.prototype.hasOwnProperty.call(ge[S],0)){let e=A;e=ge[S][0],a({card:e})}}return(0,t.createElement)("div",{...ie},ke,(0,t.createElement)(o.Disabled,null,1==(Be=e.attributes).preview_show?(0,t.createElement)(i(),{block:"learndash/ld-course-grid",attributes:Be,key:"learndash/ld-course-grid"}):(0,a.__)("[learndash_course_grid] shortcode output shown here","learndash")));var Be},save:e=>{}}),(0,l.registerBlockType)("learndash/ld-course-grid-filter",{title:(0,a.__)("LearnDash Course Grid Filter","learndash"),description:(0,a.__)("LearnDash course grid filter widget.","learndash"),icon:"filter",category:"learndash-blocks",supports:{customClassName:!1},apiVersion:3,attributes:{course_grid_id:{type:"string",default:""},search:{type:"boolean",default:1},taxonomies:{type:"array",default:["category","post_tag"]},price:{type:"boolean",default:1},price_min:{type:"string",default:0},price_max:{type:"string",default:1e3},preview_show:{type:"boolean",default:1}},edit:e=>{const{attributes:{course_grid_id:l,search:s,taxonomies:d,price:_,price_min:h,price_max:u,preview_show:m},setAttributes:p}=e,b=(0,n.useBlockProps)(),g=(LearnDash_Course_Grid_Block_Editor.taxonomies,(0,t.createElement)(r.Fragment,{key:"learndash-course-grid-filter-settings"},(0,t.createElement)(n.InspectorControls,{key:"controls"},(0,t.createElement)(o.Panel,{className:"learndash-course-grid-filter-panel"},(0,t.createElement)(c,{context:"widget",course_grid_id:l,search:s,taxonomies:d,price:_,price_min:h,price_max:u,setAttributes:p}),(0,t.createElement)(o.PanelBody,{title:(0,a.__)("Preview","learndash"),initialOpen:!1},(0,t.createElement)(o.ToggleControl,{label:(0,a.__)("Show Preview","learndash"),checked:!!m,onChange:e=>p({preview_show:e})}))))));return(0,t.createElement)("div",{...b},g,(0,t.createElement)(o.Disabled,null,1==(f=e.attributes).preview_show?(0,t.createElement)(i(),{block:"learndash/ld-course-grid-filter",attributes:f,key:"learndash/ld-course-grid-filter"}):(0,a.__)("[learndash_course_grid_filter] shortcode output shown here","learndash")));var f},save:e=>{}})})(); \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/blocks/components/color-palette.js b/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/blocks/components/color-palette.js new file mode 100644 index 000000000..55ee32fe9 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/blocks/components/color-palette.js @@ -0,0 +1,67 @@ +/** + * Custom ColorPalette component. + * + * @since 4.21.4 + */ + +import { Component } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; +import { + BaseControl, + Button, + ColorPalette as GBColorPalette, +} from '@wordpress/components'; + +class ColorPalette extends Component { + // eslint-disable-next-line no-useless-constructor + constructor( props ) { + super( props ); + } + + render() { + // eslint-disable-next-line camelcase + const { name, value, label, display_state, setAttributes } = this.props; + + return ( + // eslint-disable-next-line @wordpress/no-base-control-with-label-without-id + +
+ { + // eslint-disable-next-line camelcase + setAttributes( { [ name ]: new_value } ); + } } + clearable={ false } + /> + +
+
+
+ ); + } +} + +export default ColorPalette; diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/blocks/components/filter-panel-body.js b/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/blocks/components/filter-panel-body.js new file mode 100644 index 000000000..4857be265 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/blocks/components/filter-panel-body.js @@ -0,0 +1,187 @@ +/** + * FilterPanelBody component + * + * @since 4.21.4 + */ + +/** + * Internal block libraries + */ +import { Component } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; +import { + PanelBody, + TextControl, + ToggleControl, + SelectControl, + BaseControl, +} from '@wordpress/components'; + +class FilterPanelBody extends Component { + // eslint-disable-next-line no-useless-constructor + constructor( props ) { + super( props ); + } + + render() { + const { + context, + // eslint-disable-next-line camelcase + course_grid_id, + search, + taxonomies, + price, + // eslint-disable-next-line camelcase + price_min, + // eslint-disable-next-line camelcase + price_max, + setAttributes, + } = this.props; + + // eslint-disable-next-line camelcase + let search_key = 'search'; + // eslint-disable-next-line camelcase + let taxonomies_key = 'taxonomies'; + // eslint-disable-next-line camelcase + let price_key = 'price'; + // eslint-disable-next-line camelcase + let price_min_key = 'price_min'; + // eslint-disable-next-line camelcase + let price_max_key = 'price_max'; + + // eslint-disable-next-line eqeqeq + if ( context == 'page' ) { + // eslint-disable-next-line camelcase + search_key = 'filter_search'; + // eslint-disable-next-line camelcase + taxonomies_key = 'filter_taxonomies'; + // eslint-disable-next-line camelcase + price_key = 'filter_price'; + // eslint-disable-next-line camelcase + price_min_key = 'filter_price_min'; + // eslint-disable-next-line camelcase + price_max_key = 'filter_price_max'; + } + + // eslint-disable-next-line camelcase + const taxonomies_options = + // eslint-disable-next-line camelcase, no-undef + LearnDash_Course_Grid_Block_Editor.taxonomies; + + return ( + + { context === 'widget' && ( + + // eslint-disable-next-line camelcase + setAttributes( { course_grid_id } ) + } + /> + ) } + { + // eslint-disable-next-line camelcase + const search_obj = { + // eslint-disable-next-line camelcase + [ search_key ]: search, + }; + + setAttributes( search_obj ); + } } + /> + + { + // eslint-disable-next-line camelcase + const taxonomies_obj = { + // eslint-disable-next-line camelcase + [ taxonomies_key ]: taxonomies, + }; + + setAttributes( taxonomies_obj ); + } } + /> + + { + // eslint-disable-next-line camelcase + const price_obj = { + // eslint-disable-next-line camelcase + [ price_key ]: price, + }; + + setAttributes( price_obj ); + } } + /> + + { + // eslint-disable-next-line camelcase + const price_min_obj = { + // eslint-disable-next-line camelcase + [ price_min_key ]: price_min, + }; + + setAttributes( price_min_obj ); + } } + /> + { + // eslint-disable-next-line camelcase + const price_max_obj = { + // eslint-disable-next-line camelcase + [ price_max_key ]: price_max, + }; + + setAttributes( price_max_obj ); + } } + /> +
+
+
+ ); + } +} + +export default FilterPanelBody; diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/blocks/index.js b/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/blocks/index.js new file mode 100644 index 000000000..dc8f84774 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/blocks/index.js @@ -0,0 +1,5 @@ +/** + * Import blocks + */ +import './learndash-course-grid'; +import './learndash-course-grid-filter'; diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/blocks/ldlms.js b/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/blocks/ldlms.js new file mode 100644 index 000000000..e2428155d --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/blocks/ldlms.js @@ -0,0 +1,195 @@ +/** + * LearnDash Block Functions + * + * This is a collection of common functions used within the LeanDash blocks + * + * @since 4.21.4 + */ + +/** + * Will retrieve meta information about the post being edited. For now + * this is only loaded on post edit screen for Gutenberg. So no checks + * are made to ensure that a post is being edited. + * + * @since 4.21.4 + * + * @param {string} token Token to return from meta array. If not provided will array is returned. + * + * @return {any} Meta information about the post being edited. + */ +// eslint-disable-next-line camelcase +export function ldlms_get_post_edit_meta( token ) { + // eslint-disable-next-line eqeqeq + if ( typeof token !== 'undefined' && token != '' ) { + // eslint-disable-next-line camelcase, no-undef + if ( typeof ldlms_settings.meta.post[ token ] !== 'undefined' ) { + // eslint-disable-next-line camelcase, no-undef + return ldlms_settings.meta.post[ token ]; + } + // eslint-disable-next-line camelcase, no-undef + } else if ( typeof ldlms_settings.meta.post !== 'undefined' ) { + // eslint-disable-next-line camelcase, no-undef + return ldlms_settings.meta.post; + } +} + +/** + * Will retrieve meta information about the post being edited. For now + * this is only loaded on post edit screen for Gutenberg. So no checks + * are made to ensure that a post is being edited. + * + * @since 4.21.4 + * + * @param {string} token Token to return from meta array. If not provided will array is returned. + * @param {string} default_value + * + * @return {any} Meta information about the post being edited. + */ +// eslint-disable-next-line camelcase +export function ldlms_get_setting( token, default_value ) { + if ( + typeof token !== 'undefined' && + // eslint-disable-next-line eqeqeq + token != '' && + // eslint-disable-next-line camelcase, no-undef + typeof ldlms_settings.settings[ token ] !== 'undefined' + ) { + // eslint-disable-next-line camelcase, no-unused-vars, no-undef + const token_value = ldlms_settings.settings[ token ]; + // eslint-disable-next-line camelcase, no-undef + return ldlms_settings.settings[ token ]; + } + // eslint-disable-next-line camelcase + return default_value; +} + +/** + * Returns the label for custom label element + * + * @since 4.21.4 + * + * @param {string} token Will represent the custom label field to retrieve Course, Courses, Lesson, Quiz. + * + * @return {string} Label for custom label element. + */ +// eslint-disable-next-line camelcase +export function ldlms_get_custom_label( token ) { + // eslint-disable-next-line camelcase, no-undef, eqeqeq + if ( typeof ldlms_settings.meta.post !== 'undefined' && token != '' ) { + if ( + // eslint-disable-next-line camelcase, no-undef + typeof ldlms_settings.settings.custom_labels[ token ] !== + 'undefined' + ) { + // eslint-disable-next-line camelcase, no-undef + token = ldlms_settings.settings.custom_labels[ token ]; + } + } + return token; +} + +/** + * Returns the lowercase label for custom label element + * + * @since 4.21.4 + * + * @param {string} token Will represent the custom label field to retrieve Course, Courses, Lesson, Quiz. + * + * @return {string} Label for custom label element. + */ +// eslint-disable-next-line camelcase +export function ldlms_get_custom_label_lower( token ) { + // eslint-disable-next-line camelcase, no-undef, eqeqeq + if ( typeof ldlms_settings.meta.post !== 'undefined' && token != '' ) { + if ( + // eslint-disable-next-line camelcase, no-undef + typeof ldlms_settings.settings.custom_labels[ token + '_lower' ] !== + 'undefined' + ) { + // eslint-disable-next-line camelcase, no-undef + token = ldlms_settings.settings.custom_labels[ token + '_lower' ]; + } + } + return token; +} + +/** + * Returns the slug for custom label element + * + * @since 4.21.4 + * + * @param {string} token Will represent the custom label field to retrieve Course, Courses, Lesson, Quiz. + * + * @return {string} Slug for custom label element. + */ +// eslint-disable-next-line camelcase +export function ldlms_get_custom_label_slug( token ) { + // eslint-disable-next-line eqeqeq + if ( token != '' ) { + if ( + // eslint-disable-next-line camelcase, no-undef + typeof ldlms_settings.settings.custom_labels[ token + '_slug' ] !== + 'undefined' + ) { + // eslint-disable-next-line camelcase, no-undef + token = ldlms_settings.settings.custom_labels[ token + '_slug' ]; + } + } + return token; +} + +/** + * Will retrieve meta information about the post being edited. For now + * this is only loaded on post edit screen for Gutenberg. So no checks + * are made to ensure that a post is being edited. + * + * @since 4.21.4 + * + * @param {string} token Token to return from meta array. If not provided will array is returned. + * + * @return {number|void} Per page value or void if not found. + */ +// eslint-disable-next-line camelcase +export function ldlms_get_per_page( token ) { + // eslint-disable-next-line eqeqeq + if ( typeof token !== 'undefined' && token != '' ) { + if ( + // eslint-disable-next-line camelcase, no-undef + typeof ldlms_settings.settings.per_page[ token ] !== 'undefined' + ) { + // eslint-disable-next-line camelcase, no-undef + return ldlms_settings.settings.per_page[ token ]; + } + // eslint-disable-next-line camelcase, no-undef + } else if ( typeof ldlms_settings.meta.posts_per_page !== 'undefined' ) { + // eslint-disable-next-line camelcase, no-undef + return ldlms_settings.meta.posts_per_page; + } +} + +/** + * Returns integer value for variable. + * + * @since 4.21.4 + * + * @param {any} var_value Variable to determine integer from. + * + * @return {number} Value or zero. + */ +// eslint-disable-next-line camelcase +export function ldlms_get_integer_value( var_value ) { + // eslint-disable-next-line camelcase + if ( typeof var_value === 'undefined' ) { + // eslint-disable-next-line camelcase + var_value = 0; + } + // eslint-disable-next-line camelcase + var_value = parseInt( var_value ); + if ( isNaN( var_value ) ) { + // eslint-disable-next-line camelcase + var_value = 0; + } + + // eslint-disable-next-line camelcase + return var_value; +} diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/blocks/learndash-course-grid-filter/index.js b/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/blocks/learndash-course-grid-filter/index.js new file mode 100644 index 000000000..c14aeaa71 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/blocks/learndash-course-grid-filter/index.js @@ -0,0 +1,174 @@ +/** + * LearnDash Block ld-course-grid-filter + * + * @since 4.21.4 + */ + +/** + * Internal block libraries + */ +// eslint-disable-next-line no-unused-vars +import { __, _x, sprintf } from '@wordpress/i18n'; +import { registerBlockType } from '@wordpress/blocks'; +import { + InspectorControls, + // eslint-disable-next-line no-unused-vars + InspectorAdvancedControls, + useBlockProps, +} from '@wordpress/block-editor'; +import { Fragment } from '@wordpress/element'; +import { + Panel, + PanelBody, + // eslint-disable-next-line no-unused-vars + TextControl, + ToggleControl, + // eslint-disable-next-line no-unused-vars + SelectControl, + // eslint-disable-next-line no-unused-vars + ColorPalette, + // eslint-disable-next-line no-unused-vars + ColorIndicator, + // eslint-disable-next-line no-unused-vars + BaseControl, + Disabled, +} from '@wordpress/components'; +import ServerSideRender from '@wordpress/server-side-render'; +import FilterPanelBody from '../components/filter-panel-body.js'; + +registerBlockType( 'learndash/ld-course-grid-filter', { + title: __( 'LearnDash Course Grid Filter', 'learndash' ), + description: __( 'LearnDash course grid filter widget.', 'learndash' ), + icon: 'filter', + category: 'learndash-blocks', + supports: { + customClassName: false, + }, + apiVersion: 3, + attributes: { + course_grid_id: { + type: 'string', + default: '', + }, + search: { + type: 'boolean', + default: 1, + }, + taxonomies: { + type: 'array', + default: [ 'category', 'post_tag' ], + }, + price: { + type: 'boolean', + default: 1, + }, + price_min: { + type: 'string', + default: 0, + }, + price_max: { + type: 'string', + default: 1000, + }, + preview_show: { + type: 'boolean', + default: 1, + }, + }, + + edit: ( props ) => { + const { + attributes: { + // eslint-disable-next-line camelcase + course_grid_id, + search, + taxonomies, + price, + // eslint-disable-next-line camelcase + price_min, + // eslint-disable-next-line camelcase + price_max, + // eslint-disable-next-line camelcase + preview_show, + }, + setAttributes, + } = props; + + const blockProps = useBlockProps(); + + // eslint-disable-next-line camelcase, no-unused-vars + const taxonomies_options = + // eslint-disable-next-line camelcase, no-undef + LearnDash_Course_Grid_Block_Editor.taxonomies; + + const inspectorControls = ( + + + + + + + // eslint-disable-next-line camelcase + setAttributes( { preview_show } ) + } + /> + + + + + ); + + // eslint-disable-next-line camelcase + function do_serverside_render( attributes ) { + // eslint-disable-next-line eqeqeq + if ( attributes.preview_show == true ) { + // We add the meta so the server knowns what is being edited. + // attributes.meta = ldlms_get_post_edit_meta() + + return ( + + ); + } + return __( + '[learndash_course_grid_filter] shortcode output shown here', + 'learndash' + ); + } + + return ( +
+ { inspectorControls } + + { do_serverside_render( props.attributes ) } + +
+ ); + }, + + // eslint-disable-next-line no-unused-vars + save: ( props ) => {}, +} ); diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/blocks/learndash-course-grid-filter/index.php b/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/blocks/learndash-course-grid-filter/index.php new file mode 100644 index 000000000..898bd6324 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/blocks/learndash-course-grid-filter/index.php @@ -0,0 +1,153 @@ +shortcode_slug = 'learndash_course_grid_filter'; + $this->block_slug = 'ld-course-grid-filter'; + $this->block_attributes = [ + 'course_grid_id' => [ + 'type' => 'string', + ], + 'search' => [ + 'type' => 'boolean', + 'default' => true, + ], + 'taxonomies' => [ + 'type' => 'array', + 'default' => [ 'category', 'post_tag' ], + ], + 'price' => [ + 'type' => 'boolean', + 'default' => true, + ], + 'price_min' => [ + 'type' => 'integer', + 'default' => 0, + ], + 'price_max' => [ + 'type' => 'integer', + 'default' => 1000, + ], + 'preview_show' => [ + 'type' => 'boolean', + 'default' => true, + ], + ]; + + $this->self_closing = true; + + $this->init(); + } + + /** + * Renders block. + * + * This function is called per the register_block_type() function above. This function will output + * the block rendered content. + * + * @since 4.21.4 + * + * @param array $attributes Shortcode attributes. + * @param string $block_content Block content. + * @param WP_Block|null $block Block object. + * + * @return string Block output. + */ + public function render_block( $attributes = array(), $block_content = '', ?WP_Block $block = null ) { + $attributes = $this->preprocess_block_attributes( $attributes ); + + /** + * Filters block attributes before processing. + * + * @since 4.21.4 + * + * @param array $attributes Block attributes. + * + * @return array Processed block attributes. + */ + $attributes = apply_filters( 'learndash_block_markers_shortcode_atts', $attributes, $this->shortcode_slug, $this->block_slug, '' ); + + $shortcode_params_str = ''; + foreach ( $attributes as $key => $val ) { + if ( is_null( $val ) ) { + continue; + } + + if ( is_array( $val ) ) { + $val = implode( ',', $val ); + } + + if ( ! empty( $shortcode_params_str ) ) { + $shortcode_params_str .= ' '; + } + $shortcode_params_str .= $key . '="' . esc_attr( $val ) . '"'; + } + + $shortcode_params_str = '[' . $this->shortcode_slug . ' ' . $shortcode_params_str . ']'; + + $shortcode_out = do_shortcode( $shortcode_params_str ); + + if ( ( empty( $shortcode_out ) ) ) { + $shortcode_out = '[' . $this->shortcode_slug . '] placeholder output.'; + } + + return $this->render_block_wrap( $shortcode_out, true ); + } + + /** + * Called from the LD function learndash_convert_block_markers_shortcode() when parsing the block content. + * + * @since 4.21.4 + * + * @param array $attributes The array of attributes parsed from the block content. + * @param string $shortcode_slug This will match the related LD shortcode ld_profile, ld_course_list, etc. + * @param string $block_slug This is the block token being processed. Normally same as the shortcode but underscore replaced with dash. + * @param string $content This is the original full content being parsed. + * + * @return array $attributes. + */ + public function learndash_block_markers_shortcode_atts_filter( $attributes = array(), $shortcode_slug = '', $block_slug = '', $content = '' ) { + if ( $shortcode_slug === $this->shortcode_slug ) { + if ( isset( $shortcode_slug['preview_show'] ) ) { + unset( $attributes['preview_show'] ); + } + + foreach ( $attributes as $key => $value ) { + if ( is_array( $value ) ) { + $attributes[ $key ] = implode( ', ', $value ); + } elseif ( is_string( $value ) ) { + // Remove quotes to prevent the attributes from being stripped out. + $attributes[ $key ] = str_replace( [ '"', '\'' ], '', $attributes[ $key ] ); + } + } + } + + return $attributes; + } +} diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/blocks/learndash-course-grid/index.js b/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/blocks/learndash-course-grid/index.js new file mode 100644 index 000000000..858d316fc --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/blocks/learndash-course-grid/index.js @@ -0,0 +1,1545 @@ +/** + * LearnDash Block ld-course-grid + * + * @since 4.21.4 + */ + +/** + * Internal block libraries + */ +// eslint-disable-next-line no-unused-vars +import { __, _x, sprintf } from '@wordpress/i18n'; +import { registerBlockType } from '@wordpress/blocks'; +import { + InspectorControls, + InspectorAdvancedControls, + useBlockProps, +} from '@wordpress/block-editor'; +import { Fragment } from '@wordpress/element'; +import { + Panel, + PanelBody, + TextControl, + ToggleControl, + SelectControl, + // eslint-disable-next-line no-unused-vars + Button, + BaseControl, + Disabled, +} from '@wordpress/components'; +import ServerSideRender from '@wordpress/server-side-render'; +import FilterPanelBody from '../components/filter-panel-body.js'; +import ColorPalette from '../components/color-palette.js'; +import { select } from '@wordpress/data'; + +// eslint-disable-next-line camelcase +function generate_unique_id() { + const id = + Date.now().toString( 36 ) + Math.random().toString( 36 ).substr( 2 ); + return 'ld-cg-' + id.substr( 0, '10' ); +} + +// eslint-disable-next-line camelcase +function is_block_id_reserved( id, clientId ) { + const blocksClientIds = + select( 'core/block-editor' ).getClientIdsWithDescendants(); + return blocksClientIds.some( ( _clientId ) => { + const { id: _id } = + select( 'core/block-editor' ).getBlockAttributes( _clientId ); + return clientId !== _clientId && id === _id; + } ); +} + +registerBlockType( 'learndash/ld-course-grid', { + title: __( 'LearnDash Course Grid', 'learndash' ), + description: __( 'Build LearnDash course grid easily.', 'learndash' ), + icon: 'grid-view', + category: 'learndash-blocks', + supports: { + customClassName: true, + }, + apiVersion: 3, + attributes: { + // Query + post_type: { + type: 'string', + // eslint-disable-next-line camelcase, no-undef + default: LearnDash_Course_Grid_Block_Editor.is_learndash_active + ? 'sfwd-courses' + : 'post', + }, + per_page: { + type: 'string', + default: 9, + }, + orderby: { + type: 'string', + default: 'ID', + }, + order: { + type: 'string', + default: 'DESC', + }, + taxonomies: { + type: 'string', + default: '', + }, + enrollment_status: { + type: 'string', + default: '', + }, + progress_status: { + type: 'string', + default: '', + }, + // Elements + thumbnail: { + type: 'boolean', + default: 1, + }, + thumbnail_size: { + type: 'string', + default: 'course-thumbnail', + }, + ribbon: { + type: 'boolean', + default: 1, + }, + content: { + type: 'boolean', + default: 1, + }, + title: { + type: 'boolean', + default: 1, + }, + title_clickable: { + type: 'boolean', + default: 1, + }, + description: { + type: 'boolean', + default: 1, + }, + description_char_max: { + type: 'string', + default: 120, + }, + post_meta: { + type: 'boolean', + default: 1, + }, + button: { + type: 'boolean', + default: 1, + }, + pagination: { + type: 'string', + default: 'button', + }, + grid_height_equal: { + type: 'boolean', + default: 0, + }, + progress_bar: { + type: 'boolean', + default: 0, + }, + filter: { + type: 'boolean', + default: 1, + }, + // Templates + skin: { + type: 'string', + default: 'grid', + }, + card: { + type: 'string', + default: 'grid-1', + }, + columns: { + type: 'string', + default: 3, + }, + min_column_width: { + type: 'string', + default: 250, + }, + items_per_row: { + type: 'string', + default: 5, + }, + // Styles + font_family_title: { + type: 'string', + }, + font_family_description: { + type: 'string', + default: '', + }, + font_size_title: { + type: 'string', + default: '', + }, + font_size_description: { + type: 'string', + default: '', + }, + font_color_title: { + type: 'string', + default: '', + }, + font_color_description: { + type: 'string', + default: '', + }, + background_color_title: { + type: 'string', + default: '', + }, + background_color_description: { + type: 'string', + default: '', + }, + background_color_ribbon: { + type: 'string', + default: '', + }, + font_color_ribbon: { + type: 'string', + default: '', + }, + background_color_icon: { + type: 'string', + default: '', + }, + font_color_icon: { + type: 'string', + default: '', + }, + background_color_button: { + type: 'string', + default: '', + }, + font_color_button: { + type: 'string', + default: '', + }, + // Misc + id: { + type: 'string', + default: '', + }, + preview_show: { + type: 'boolean', + default: 1, + }, + display_state: { + type: 'object', + default: {}, + }, + // Filter + filter_search: { + type: 'boolean', + default: 1, + }, + filter_taxonomies: { + type: 'array', + default: [ 'category', 'post_tag' ], + }, + filter_price: { + type: 'boolean', + default: 1, + }, + filter_price_min: { + type: 'string', + default: 0, + }, + filter_price_max: { + type: 'string', + default: 1000, + }, + }, + + edit: ( props ) => { + const { + attributes: { + // eslint-disable-next-line camelcase + post_type, + // eslint-disable-next-line camelcase + per_page, + orderby, + order, + taxonomies, + // eslint-disable-next-line camelcase + enrollment_status, + // eslint-disable-next-line camelcase + progress_status, + thumbnail, + // eslint-disable-next-line camelcase + thumbnail_size, + ribbon, + content, + title, + // eslint-disable-next-line camelcase + title_clickable, + description, + // eslint-disable-next-line camelcase + description_char_max, + // eslint-disable-next-line camelcase + post_meta, + button, + pagination, + // eslint-disable-next-line camelcase + grid_height_equal, + // eslint-disable-next-line camelcase + progress_bar, + filter, + skin, + card, + columns, + // eslint-disable-next-line camelcase + min_column_width, + // eslint-disable-next-line camelcase + items_per_row, + // eslint-disable-next-line camelcase + font_family_title, + // eslint-disable-next-line camelcase + font_family_description, + // eslint-disable-next-line camelcase + font_size_title, + // eslint-disable-next-line camelcase + font_size_description, + // eslint-disable-next-line camelcase + font_color_title, + // eslint-disable-next-line camelcase + font_color_description, + // eslint-disable-next-line camelcase + background_color_title, + // eslint-disable-next-line camelcase + background_color_description, + // eslint-disable-next-line camelcase + background_color_ribbon, + // eslint-disable-next-line camelcase + font_color_ribbon, + // eslint-disable-next-line camelcase + background_color_icon, + // eslint-disable-next-line camelcase + font_color_icon, + // eslint-disable-next-line camelcase + background_color_button, + // eslint-disable-next-line camelcase + font_color_button, + // Misc + id, + // eslint-disable-next-line camelcase + display_state, + // eslint-disable-next-line camelcase + preview_show, + // eslint-disable-next-line camelcase + filter_search, + // eslint-disable-next-line camelcase + filter_taxonomies, + // eslint-disable-next-line camelcase + filter_price, + // eslint-disable-next-line camelcase + filter_price_min, + // eslint-disable-next-line camelcase + filter_price_max, + }, + // eslint-disable-next-line no-unused-vars + className, + clientId, + setAttributes, + } = props; + + const blockProps = useBlockProps(); + + if ( ! id || id === '' ) { + // eslint-disable-next-line camelcase + const temp_id = generate_unique_id(); + // eslint-disable-next-line camelcase + setAttributes( { id: temp_id } ); + } else if ( is_block_id_reserved( id, clientId ) ) { + // eslint-disable-next-line camelcase + const new_id = generate_unique_id(); + // eslint-disable-next-line camelcase + setAttributes( { id: new_id } ); + } + + // eslint-disable-next-line camelcase, no-undef + const post_type_options = LearnDash_Course_Grid_Block_Editor.post_types; + + // eslint-disable-next-line camelcase + const pagination_options = + // eslint-disable-next-line camelcase, no-undef + LearnDash_Course_Grid_Block_Editor.paginations; + + // eslint-disable-next-line camelcase, no-undef + const skins = LearnDash_Course_Grid_Block_Editor.skins; + // eslint-disable-next-line camelcase, no-undef + const cards = LearnDash_Course_Grid_Block_Editor.cards; + + // eslint-disable-next-line camelcase + const skin_options = [], + // eslint-disable-next-line camelcase + skin_disabled_fields = {}; + // eslint-disable-next-line no-shadow + for ( const id in skins ) { + if ( Object.hasOwnProperty.call( skins, id ) ) { + const element = { + label: skins[ id ].label, + value: skins[ id ].slug, + }; + + // eslint-disable-next-line camelcase + skin_options.push( element ); + + if ( Object.hasOwnProperty.call( skins[ id ], 'disable' ) ) { + // eslint-disable-next-line camelcase + skin_disabled_fields[ skins[ id ].slug ] = + skins[ id ].disable; + } + } + } + + // eslint-disable-next-line camelcase + const card_options = [], + // eslint-disable-next-line camelcase + card_values = [], + // eslint-disable-next-line camelcase + skin_cards = {}, + // eslint-disable-next-line camelcase + card_disabled_fields = {}; + // eslint-disable-next-line no-shadow + for ( const id in cards ) { + if ( Object.hasOwnProperty.call( cards, id ) ) { + if ( Object.hasOwnProperty.call( cards[ id ], 'disable' ) ) { + // eslint-disable-next-line camelcase + card_disabled_fields[ cards[ id ] ] = cards[ id ].disable; + } + + if ( Object.hasOwnProperty.call( cards[ id ], 'skins' ) ) { + // eslint-disable-next-line camelcase + cards[ id ].skins.forEach( function ( temp_skin ) { + // eslint-disable-next-line camelcase + skin_cards[ temp_skin ] = skin_cards[ temp_skin ] || []; + + // eslint-disable-next-line camelcase + skin_cards[ temp_skin ].push( id ); + } ); + } + + if ( + typeof cards[ id ].skins !== 'undefined' && + cards[ id ].skins.indexOf( skin ) > -1 + ) { + const element = { + label: cards[ id ].label, + value: id, + }; + + // eslint-disable-next-line camelcase + card_options.push( element ); + // eslint-disable-next-line camelcase + card_values.push( id ); + } + } + } + + // eslint-disable-next-line camelcase + const thumbnail_size_options = + // eslint-disable-next-line camelcase, no-undef + LearnDash_Course_Grid_Block_Editor.image_sizes; + + // eslint-disable-next-line camelcase, no-undef + const orderby_options = LearnDash_Course_Grid_Block_Editor.orderby; + + // eslint-disable-next-line camelcase + const order_options = [ + { label: __( 'Ascending', 'learndash' ), value: 'ASC' }, + { label: __( 'Descending', 'learndash' ), value: 'DESC' }, + ]; + + // eslint-disable-next-line camelcase + const enrollment_status_options = [ + { value: '', label: __( 'All', 'learndash' ) }, + { value: 'enrolled', label: __( 'Enrolled', 'learndash' ) }, + { value: 'not-enrolled', label: __( 'Not Enrolled', 'learndash' ) }, + ]; + + // eslint-disable-next-line camelcase + const progress_status_options = [ + { value: '', label: __( 'All', 'learndash' ) }, + { value: 'completed', label: __( 'Completed', 'learndash' ) }, + { value: 'in_progress', label: __( 'In Progress', 'learndash' ) }, + { value: 'not_started', label: __( 'Not Started', 'learndash' ) }, + ]; + + selectSkin( props ); + + const inspectorControls = ( + + + + + + { + setAttributes( { skin } ); + selectSkin( props ); + } } + /> + + + { + setAttributes( { card } ); + } } + /> + + + setAttributes( { columns } ) + } + className={ + // eslint-disable-next-line camelcase + typeof display_state.columns !== + // eslint-disable-next-line camelcase + 'undefined' && ! display_state.columns + ? 'hide' + : 'show' + } + /> + { [ 'grid', 'masonry' ].indexOf( skin ) > -1 && ( + + // eslint-disable-next-line camelcase + setAttributes( { min_column_width } ) + } + className={ + // eslint-disable-next-line camelcase + typeof display_state.min_column_width !== + 'undefined' && + // eslint-disable-next-line camelcase + ! display_state.min_column_width + ? 'hide' + : 'show' + } + /> + ) } + + // eslint-disable-next-line camelcase + setAttributes( { items_per_row } ) + } + className={ + // eslint-disable-next-line camelcase + typeof display_state.items_per_row !== + 'undefined' && + // eslint-disable-next-line camelcase + ! display_state.items_per_row + ? 'hide' + : 'show' + } + /> + + + + + // eslint-disable-next-line camelcase + setAttributes( { post_type } ) + } + /> + + + // eslint-disable-next-line camelcase + setAttributes( { per_page } ) + } + className={ + // eslint-disable-next-line camelcase + typeof display_state.per_page !== + // eslint-disable-next-line camelcase + 'undefined' && ! display_state.per_page + ? 'hide' + : 'show' + } + /> + + + setAttributes( { orderby } ) + } + /> + + + + setAttributes( { order } ) + } + /> + + + setAttributes( { taxonomies } ) + } + className={ + // eslint-disable-next-line camelcase + typeof display_state.taxonomies !== + 'undefined' && + // eslint-disable-next-line camelcase + ! display_state.taxonomies + ? 'hide' + : 'show' + ' taxonomies' + } + /> + { [ 'sfwd-courses', 'groups' ].indexOf( + post_type + ) > -1 && ( + + + setAttributes( { + // eslint-disable-next-line camelcase + enrollment_status, + } ) + } + /> + + ) } + { [ 'sfwd-courses' ].indexOf( post_type ) > -1 && + // eslint-disable-next-line camelcase, eqeqeq + enrollment_status == 'enrolled' && ( + + + setAttributes( { + // eslint-disable-next-line camelcase + progress_status, + } ) + } + /> + + ) } + + + { cards[ card ].elements.indexOf( 'thumbnail' ) > + -1 && ( + + setAttributes( { thumbnail } ) + } + className={ + // eslint-disable-next-line camelcase + typeof display_state.thumbnail !== + 'undefined' && + // eslint-disable-next-line camelcase + ! display_state.thumbnail + ? 'hide' + : 'show' + } + /> + ) } + { cards[ card ].elements.indexOf( 'thumbnail' ) > + -1 && + thumbnail && ( + + + setAttributes( { + // eslint-disable-next-line camelcase + thumbnail_size, + } ) + } + /> + + ) } + { cards[ card ].elements.indexOf( 'ribbon' ) > + -1 && ( + + setAttributes( { ribbon } ) + } + className={ + // eslint-disable-next-line camelcase + typeof display_state.ribbon !== + 'undefined' && + // eslint-disable-next-line camelcase + ! display_state.ribbon + ? 'hide' + : 'show' + } + /> + ) } + { cards[ card ].elements.indexOf( 'content' ) > + -1 && ( + + setAttributes( { content } ) + } + className={ + // eslint-disable-next-line camelcase + typeof display_state.content !== + 'undefined' && + // eslint-disable-next-line camelcase + ! display_state.content + ? 'hide' + : 'show' + } + /> + ) } + { cards[ card ].elements.indexOf( 'title' ) > + -1 && ( + + setAttributes( { title } ) + } + className={ + // eslint-disable-next-line camelcase + typeof display_state.title !== + // eslint-disable-next-line camelcase + 'undefined' && ! display_state.title + ? 'hide' + : 'show' + } + /> + ) } + { cards[ card ].elements.indexOf( 'title' ) > -1 && + title && ( + + // eslint-disable-next-line camelcase + setAttributes( { title_clickable } ) + } + className={ + // eslint-disable-next-line camelcase + typeof display_state.title_clickable !== + 'undefined' && + // eslint-disable-next-line camelcase + ! display_state.title_clickable + ? 'hide' + : 'show' + } + /> + ) } + { cards[ card ].elements.indexOf( 'description' ) > + -1 && ( + + setAttributes( { description } ) + } + className={ + // eslint-disable-next-line camelcase + typeof display_state.description !== + 'undefined' && + // eslint-disable-next-line camelcase + ! display_state.description + ? 'hide' + : 'show' + } + /> + ) } + { cards[ card ].elements.indexOf( 'description' ) > + -1 && + description && ( + { + setAttributes( { + // eslint-disable-next-line camelcase + description_char_max, + } ); + } } + /> + ) } + { cards[ card ].elements.indexOf( 'post_meta' ) > + -1 && ( + + // eslint-disable-next-line camelcase + setAttributes( { post_meta } ) + } + className={ + // eslint-disable-next-line camelcase + typeof display_state.post_meta !== + 'undefined' && + // eslint-disable-next-line camelcase + ! display_state.post_meta + ? 'hide' + : 'show' + } + /> + ) } + { cards[ card ].elements.indexOf( 'button' ) > + -1 && ( + + setAttributes( { button } ) + } + className={ + // eslint-disable-next-line camelcase + typeof display_state.button !== + 'undefined' && + // eslint-disable-next-line camelcase + ! display_state.button + ? 'hide' + : 'show' + } + /> + ) } + + // eslint-disable-next-line camelcase + setAttributes( { progress_bar } ) + } + className={ + // eslint-disable-next-line camelcase + typeof display_state.progress_bar !== + 'undefined' && + // eslint-disable-next-line camelcase + ! display_state.progress_bar + ? 'hide' + : 'show' + } + /> + + + setAttributes( { pagination } ) + } + /> + + { + setAttributes( { filter } ); + } } + className={ + // eslint-disable-next-line camelcase + typeof display_state.filter !== + // eslint-disable-next-line camelcase + 'undefined' && ! display_state.filter + ? 'hide' + : 'show' + } + /> + + { filter && ( + + ) } + + { skin === 'grid' && ( +
+

{ __( 'Grid', 'learndash' ) }

+ + setAttributes( { + // eslint-disable-next-line camelcase + grid_height_equal, + } ) + } + className={ + // eslint-disable-next-line camelcase + typeof display_state.grid_height_equal !== + 'undefined' && + // eslint-disable-next-line camelcase + ! display_state.grid_height_equal + ? 'hide' + : 'show' + } + /> +
+ ) } + { cards[ card ].elements.indexOf( 'title' ) > -1 && + title && ( + +

+ { __( 'Heading', 'learndash' ) } +

+ + setAttributes( { + // eslint-disable-next-line camelcase + font_family_title, + } ) + } + className={ + // eslint-disable-next-line camelcase + typeof display_state.font_family_title !== + 'undefined' && + // eslint-disable-next-line camelcase + ! display_state.font_family_title + ? 'hide' + : 'show' + } + /> + + setAttributes( { + // eslint-disable-next-line camelcase + font_size_title, + } ) + } + className={ + // eslint-disable-next-line camelcase + typeof display_state.font_size_title !== + 'undefined' && + // eslint-disable-next-line camelcase + ! display_state.font_size_title + ? 'hide' + : 'show' + } + /> + + +
+ ) } + { cards[ card ].elements.indexOf( 'description' ) > + -1 && + description && ( + +

+ { __( 'Description', 'learndash' ) } +

+ + setAttributes( { + // eslint-disable-next-line camelcase + font_family_description, + } ) + } + className={ + // eslint-disable-next-line camelcase + typeof display_state.font_family_description !== + 'undefined' && + // eslint-disable-next-line camelcase + ! display_state.font_family_description + ? 'hide' + : 'show' + } + /> + + setAttributes( { + // eslint-disable-next-line camelcase + font_size_description, + } ) + } + className={ + // eslint-disable-next-line camelcase + typeof display_state.font_size_description !== + 'undefined' && + // eslint-disable-next-line camelcase + ! display_state.font_size_description + ? 'hide' + : 'show' + } + /> + + +
+ ) } +

{ __( 'Elements', 'learndash' ) }

+ { cards[ card ].elements.indexOf( 'ribbon' ) > -1 && + ribbon && ( + + + + + ) } + { cards[ card ].elements.indexOf( 'icon' ) > -1 && ( + + + + + ) } + { cards[ card ].elements.indexOf( 'button' ) > -1 && + button && ( + + + + + ) } +
+ + + // eslint-disable-next-line camelcase + setAttributes( { preview_show } ) + } + /> + +
+
+ + setAttributes( { id } ) } + className={ + // eslint-disable-next-line camelcase + typeof display_state.id !== 'undefined' && + // eslint-disable-next-line camelcase + ! display_state.id + ? 'hide' + : 'show' + } + /> + +
+ ); + + // eslint-disable-next-line camelcase + function do_serverside_render( attributes ) { + // eslint-disable-next-line eqeqeq + if ( attributes.preview_show == true ) { + return ( + + ); + } + return __( + '[learndash_course_grid] shortcode output shown here', + 'learndash' + ); + } + + // eslint-disable-next-line no-shadow + function selectSkin( props ) { + const { + // eslint-disable-next-line no-unused-vars + attributes = { + skin, + card, + // eslint-disable-next-line camelcase + display_state, + }, + // eslint-disable-next-line no-shadow + setAttributes, + } = props; + + // eslint-disable-next-line camelcase + let disabled_fields = []; + // eslint-disable-next-line camelcase + if ( typeof skin_disabled_fields[ skin ] !== 'undefined' ) { + // eslint-disable-next-line camelcase + disabled_fields = skin_disabled_fields[ skin ]; + } + + // eslint-disable-next-line camelcase, no-undef + LearnDash_Course_Grid_Block_Editor.editor_fields.forEach( + ( field ) => { + // eslint-disable-next-line camelcase + const temp_display_state = display_state; + // eslint-disable-next-line camelcase + temp_display_state[ field ] = true; + + setAttributes( { + // eslint-disable-next-line camelcase + display_state: temp_display_state, + } ); + } + ); + + // eslint-disable-next-line camelcase + disabled_fields.forEach( ( field ) => { + // eslint-disable-next-line camelcase + const temp_display_state = display_state; + // eslint-disable-next-line camelcase + temp_display_state[ field ] = false; + + setAttributes( { + // eslint-disable-next-line camelcase + display_state: temp_display_state, + } ); + } ); + + if ( + // eslint-disable-next-line camelcase, eqeqeq + card_values.indexOf( card ) == -1 && + Object.prototype.hasOwnProperty.call( skin_cards, 'skin' ) && + // eslint-disable-next-line camelcase + Object.prototype.hasOwnProperty.call( skin_cards[ skin ], 0 ) + ) { + // eslint-disable-next-line camelcase + let temp_card = card; + // eslint-disable-next-line camelcase + temp_card = skin_cards[ skin ][ 0 ]; + + setAttributes( { + // eslint-disable-next-line camelcase + card: temp_card, + } ); + } + } + + // eslint-disable-next-line no-unused-vars + function setDisplayState( key, value ) { + // eslint-disable-next-line camelcase, no-shadow + const { display_state } = props.attributes; + + // eslint-disable-next-line camelcase + display_state[ key ] = value; + + setAttributes( { + // eslint-disable-next-line camelcase + display_state, + } ); + } + + return ( +
+ { inspectorControls } + + { do_serverside_render( props.attributes ) } + +
+ ); + }, + + // eslint-disable-next-line no-unused-vars + save: ( props ) => {}, +} ); diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/blocks/learndash-course-grid/index.php b/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/blocks/learndash-course-grid/index.php new file mode 100644 index 000000000..502a5dbe2 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/includes/gutenberg/blocks/learndash-course-grid/index.php @@ -0,0 +1,338 @@ +shortcode_slug = 'learndash_course_grid'; + $this->block_slug = 'ld-course-grid'; + $this->block_attributes = array( + 'post_type' => array( + 'type' => 'string', + 'default' => function_exists( 'learndash_get_post_type_slug' ) + ? learndash_get_post_type_slug( LDLMS_Post_Types::COURSE ) + : 'post', + ), + 'per_page' => array( + 'type' => 'integer', + 'default' => 9, + ), + 'orderby' => array( + 'type' => 'string', + 'default' => 'ID', + ), + 'order' => array( + 'type' => 'string', + 'default' => 'DESC', + ), + 'taxonomies' => array( + 'type' => 'string', + ), + 'enrollment_status' => array( + 'type' => 'string', + ), + 'progress_status' => array( + 'type' => 'string', + ), + 'thumbnail' => array( + 'type' => 'boolean', + 'default' => true, + ), + 'thumbnail_size' => array( + 'type' => 'string', + 'default' => 'course-thumbnail', + ), + 'ribbon' => array( + 'type' => 'boolean', + 'default' => true, + ), + 'content' => array( + 'type' => 'boolean', + 'default' => true, + ), + 'title' => array( + 'type' => 'boolean', + 'default' => true, + ), + 'title_clickable' => array( + 'type' => 'boolean', + 'default' => true, + ), + 'description' => array( + 'type' => 'boolean', + 'default' => true, + ), + 'description_char_max' => array( + 'type' => 'integer', + 'default' => 120, + ), + 'post_meta' => array( + 'type' => 'boolean', + 'default' => true, + ), + 'button' => array( + 'type' => 'boolean', + 'default' => true, + ), + 'pagination' => array( + 'type' => 'string', + 'default' => 'button', + ), + 'grid_height_equal' => array( + 'type' => 'boolean', + 'default' => false, + ), + 'progress_bar' => array( + 'type' => 'boolean', + 'default' => false, + ), + 'filter' => array( + 'type' => 'boolean', + 'default' => true, + ), + 'skin' => array( + 'type' => 'string', + 'default' => 'grid', + ), + 'card' => array( + 'type' => 'string', + 'default' => 'grid-1', + ), + 'columns' => array( + 'type' => 'integer', + 'default' => 3, + ), + 'min_column_width' => array( + 'type' => 'string', + 'default' => 250, + ), + 'items_per_row' => array( + 'type' => 'integer', + 'default' => 5, + ), + 'font_family_title' => array( + 'type' => 'string', + ), + 'font_family_description' => array( + 'type' => 'string', + ), + 'font_size_title' => array( + 'type' => 'string', + ), + 'font_size_description' => array( + 'type' => 'string', + ), + 'font_color_title' => array( + 'type' => 'string', + ), + 'font_color_description' => array( + 'type' => 'string', + ), + 'background_color_title' => array( + 'type' => 'string', + ), + 'background_color_description' => array( + 'type' => 'string', + ), + 'background_color_ribbon' => array( + 'type' => 'string', + ), + 'font_color_ribbon' => array( + 'type' => 'string', + ), + 'background_color_icon' => array( + 'type' => 'string', + ), + 'font_color_icon' => array( + 'type' => 'string', + ), + 'background_color_button' => array( + 'type' => 'string', + ), + 'font_color_button' => array( + 'type' => 'string', + ), + // Misc. + 'id' => array( + 'type' => 'string', + ), + 'className' => array( + 'type' => 'string', + ), + 'preview_show' => array( + 'type' => 'boolean', + 'default' => true, + ), + 'display_state' => array( + 'type' => 'object', + ), + // Filter. + 'filter_search' => [ + 'type' => 'boolean', + 'default' => true, + ], + 'filter_taxonomies' => [ + 'type' => 'array', + 'default' => [ 'category', 'post_tag' ], + ], + 'filter_price' => [ + 'type' => 'boolean', + 'default' => true, + ], + 'filter_price_min' => [ + 'type' => 'string', + 'default' => '0', + ], + 'filter_price_max' => [ + 'type' => 'string', + 'default' => '1000', + ], + ); + + $this->self_closing = true; + + $this->init(); + } + + /** + * Renders block. + * + * This function is called per the register_block_type() function above. This function will output + * the block rendered content. + * + * @since 4.21.4 + * + * @param array $attributes Shortcode attributes. + * @param string $block_content Block content. + * @param WP_Block|null $block Block object. + * + * @return string Block output. + */ + public function render_block( $attributes = array(), $block_content = '', ?WP_Block $block = null ) { + $attributes = $this->preprocess_block_attributes( $attributes ); + + /** + * Filters the block attributes before processing the shortcode. + * + * @since 4.21.4 + * + * @param array $attributes The block attributes. + * @param string $shortcode_slug The shortcode slug. + * @param string $block_slug The block slug. + * @param string $content The block content. + * + * @return array Returned block attributes. + */ + $attributes = apply_filters( 'learndash_block_markers_shortcode_atts', $attributes, $this->shortcode_slug, $this->block_slug, '' ); + + $shortcode_params_str = ''; + foreach ( $attributes as $key => $val ) { + if ( is_null( $val ) ) { + continue; + } + + if ( is_array( $val ) ) { + $val = implode( ',', $val ); + } + + if ( ! empty( $shortcode_params_str ) ) { + $shortcode_params_str .= ' '; + } + $shortcode_params_str .= $key . '="' . esc_attr( $val ) . '"'; + } + + $shortcode_params_str = '[' . $this->shortcode_slug . ' ' . $shortcode_params_str . ']'; + + $args = Course_Grid::instance()->skins->parse_shortcode_tags( $shortcode_params_str ); + + $style = Course_Grid::instance()->skins->generate_custom_css( $args ); + + ob_start(); + ?> + + shortcode_slug . '] placeholder output.'; + } + + return $this->render_block_wrap( $shortcode_out, true ); + } + + /** + * Called from the LD function learndash_convert_block_markers_shortcode() when parsing the block content. + * + * @since 4.21.4 + * + * @param array $attributes The array of attributes parsed from the block content. + * @param string $shortcode_slug This will match the related LD shortcode ld_profile, ld_course_list, etc. + * @param string $block_slug This is the block token being processed. Normally same as the shortcode but underscore replaced with dash. + * @param string $content This is the original full content being parsed. + * + * @return array $attributes. + */ + public function learndash_block_markers_shortcode_atts_filter( $attributes = array(), $shortcode_slug = '', $block_slug = '', $content = '' ) { + if ( $shortcode_slug === $this->shortcode_slug ) { + if ( isset( $attributes['preview_show'] ) ) { + unset( $attributes['preview_show'] ); + } + + if ( isset( $attributes['className'] ) ) { + $attributes['class_name'] = $attributes['className']; + unset( $attributes['className'] ); + } + + if ( isset( $attributes['display_state'] ) ) { + unset( $attributes['display_state'] ); + } + + if ( ! isset( $attributes['filter_taxonomies'] ) ) { + $attributes['filter_taxonomies'] = ''; + } + + foreach ( $attributes as $key => $value ) { + if ( is_array( $value ) ) { + $attributes[ $key ] = implode( ', ', $value ); + } elseif ( is_string( $value ) ) { + // Remove quotes to prevent the attributes from being stripped out. + $attributes[ $key ] = str_replace( [ '"', '\'' ], '', $attributes[ $key ] ); + } + } + } + + return $attributes; + } +} diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/includes/lib/class-learndash-gutenberg-block.php b/web/app/plugins/sfwd-lms/includes/course-grid/includes/lib/class-learndash-gutenberg-block.php new file mode 100644 index 000000000..ded872b34 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/includes/lib/class-learndash-gutenberg-block.php @@ -0,0 +1,804 @@ +block_base . '/' . $this->block_slug, + array( + 'render_callback' => array( $this, 'render_block' ), + 'attributes' => $this->block_attributes, + ) + ); + } + + /** + * Hook into 'the_content' WP filter and parse out our block. We want to convert the Gutenberg Block notation to a normal LD shortcode. + * Called at high priority BEFORE do_shortcode() and do_blocks(). + * + * @since 4.21.4 + * + * @param string $content The post content that contains all the inline HTML and blocks. + * + * @return string Post content. + */ + public function the_content_filter( $content = '' ) { + if ( ( is_admin() ) && ( ( isset( $_REQUEST['post'] ) ) && ( ! empty( $_REQUEST['post'] ) ) ) && ( ( isset( $_REQUEST['action'] ) ) && ( 'edit' === $_REQUEST['action'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + return $content; + } + + if ( ! empty( $content ) ) { + $content = $this->convert_block_markers_to_shortcode( $content, $this->block_slug, $this->shortcode_slug, $this->self_closing ); + } + return $content; + } + + /** + * Render Block + * + * This function is called per the register_block_type() function above. This function will output + * the block rendered content. This is called from within the admin edit post type page via an + * AJAX-type call to the server. + * + * Each sub-subclassed instance should provide its own version of this function. + * + * @since 4.21.4 + * + * @param array $block_attributes The block attributes. + * @param string $block_content The block content. + * @param WP_Block|null $block The block object. + * + * @return void The output is echoed. + */ + public function render_block( $block_attributes = array(), $block_content = '', ?WP_Block $block = null ) { + } + + /** + * Add wrapper content around content to be returned to server. + * + * @since 4.21.4 + * + * @param string $content Content text to be wrapper. + * @param boolean $with_inner Flag to control inclusion of inner block div element. + * + * @return string wrapped content. + */ + public function render_block_wrap( $content = '', $with_inner = true ) { + $return_content = ''; + $return_content .= ''; + + if ( true === $with_inner ) { + /** + * Temp hack until we update all the block/shortcodes. + */ + $extra_classes = ''; + if ( ! strstr( $content, 'learndash-wrap' ) ) { + $extra_classes = ' learndash-wrap'; + } + if ( ! strstr( $content, 'learndash-wrapper' ) ) { + $extra_classes = ' learndash-wrapper'; + } + $return_content .= '
'; + } + + $return_content .= $content; + + if ( true === $with_inner ) { + $return_content .= '
'; + } + + $return_content .= ''; + + return $return_content; + } + + /** + * Pre-Process the block attributes before render. + * + * @since 4.21.4 + * + * @param array $block_attributes Shortcode attributes. + * + * @return array $block_attributes + */ + protected function preprocess_block_attributes( $block_attributes = array() ) { + $block_attributes_new = array(); + + foreach ( $block_attributes as $key => $val ) { + if ( ( empty( $key ) ) || ( is_null( $val ) ) ) { + continue; + } + + // Ignore any block attributes not part of out set. + if ( ! isset( $this->block_attributes[ $key ] ) ) { + continue; + } + + if ( 'editing_post_meta' === $key ) { + $block_attributes_new[ $key ] = (array) $val; + } else { + if ( isset( $this->block_attributes[ $key ]['type'] ) ) { + $attribute_type = $this->block_attributes[ $key ]['type']; + } else { + $attribute_type = 'string'; + } + + if ( 'string' === $attribute_type ) { + $block_attributes_new[ $key ] = esc_attr( $val ); + } elseif ( 'boolean' === $attribute_type ) { + $block_attributes_new[ $key ] = (bool) $val; + } elseif ( 'integer' === $attribute_type ) { + $block_attributes_new[ $key ] = intval( $val ); + } elseif ( 'array' === $attribute_type ) { + $block_attributes_new[ $key ] = (array) $val; + } elseif ( 'object' === $attribute_type ) { + $block_attributes_new[ $key ] = (object) $val; + } else { + $block_attributes_new[ $key ] = $val; + } + } + } + + return $block_attributes_new; + } + + /** + * Build the block shortcode from attributes string. + * + * @since 4.21.4 + * + * @param array $block_attributes Block attributes array. + * @param string $block_content Used for inner blocks. + * + * @return string $shortcode_str. + */ + protected function build_block_shortcode( $block_attributes = array(), $block_content = '' ) { + $shortcode_str = '[' . $this->shortcode_slug; + foreach ( $block_attributes as $key => $val ) { + if ( substr( $key, 0, strlen( 'preview_' ) ) == 'preview_' ) { + continue; + } + + if ( substr( $key, 0, strlen( 'editing_' ) ) == 'editing_' ) { + continue; + } + + if ( ( empty( $key ) ) || ( '' == $val ) || ( is_null( $val ) ) ) { + continue; + } + + if ( ! empty( $shortcode_str ) ) { + $shortcode_str .= ' '; + } + $shortcode_str .= $key . '="' . esc_attr( $val ) . '"'; + } + $shortcode_str .= ']'; + + if ( false === $this->self_closing ) { + if ( ! empty( $block_content ) ) { + $shortcode_str .= $block_content; + } + $shortcode_str .= '[/' . $this->shortcode_slug . ']'; + } + + return $shortcode_str; + } + + + /** + * Utility function to parse the WP Block content looking for specific token patterns. + * + * @since 4.21.4 + * + * @param string $content Full page/post content to be searched. + * @param string $block_slug This is the block token pattern to search for. Ex: ld-user-meta, ld-visitor, ld-profile. + * @param string $shortcode_slug This is the actual shortcode token to be used. + * @param boolean $self_closing true if not an inner block. + * + * @return string Post content. + */ + public function convert_block_markers_to_shortcode( $content = '', $block_slug = '', $shortcode_slug = '', $self_closing = false ) { + if ( ( ! empty( $content ) ) && ( ! empty( $block_slug ) ) && ( ! empty( $shortcode_slug ) ) ) { + $pattern_atts_array = array(); + if ( true === $self_closing ) { + preg_match_all( '##is', $content, $ar ); + if ( ( isset( $ar[0] ) ) && ( is_array( $ar[0] ) ) && ( ! empty( $ar[0] ) ) ) { + if ( ( isset( $ar[1] ) ) && ( is_array( $ar[1] ) ) && ( ! empty( $ar[1] ) ) ) { + foreach ( $ar[1] as $pattern_key => $pattern_atts_json ) { + $replacement_text = '[' . $shortcode_slug; + + if ( ! empty( $pattern_atts_json ) ) { + $pattern_atts_array = (array) json_decode( $pattern_atts_json ); + if ( ( is_array( $pattern_atts_array ) ) && ( ! empty( $pattern_atts_array ) ) ) { + foreach ( $pattern_atts_array as $attr_key => $attr_value ) { + if ( 'meta' === $attr_key ) { + continue; + } + + /** + * Only accept our known block attributes. + * + * @since 4.21.4 + */ + if ( ! isset( $this->block_attributes[ $attr_key ] ) ) { + unset( $pattern_atts_array[ $attr_key ] ); + } + } + } + + /** This filter is documented in includes/gutenberg/blocks/ld-course-list/index.php */ + $pattern_atts_array = apply_filters( 'learndash_block_markers_shortcode_atts', $pattern_atts_array, $shortcode_slug, $block_slug, $content ); + if ( ( is_array( $pattern_atts_array ) ) && ( ! empty( $pattern_atts_array ) ) ) { + $shortcode_atts = ''; + foreach ( $pattern_atts_array as $attr_key => $attr_value ) { + if ( 'meta' === $attr_key ) { + continue; + } + + if ( '' !== $attr_value ) { + if ( ! empty( $shortcode_atts ) ) { + $shortcode_atts .= ' '; + } + + if ( is_array( $attr_value ) ) { + $attr_value = implode( ',', $attr_value ); + } + + $shortcode_atts .= $attr_key . '="' . $attr_value . '"'; + } + } + + if ( ! empty( $shortcode_atts ) ) { + $replacement_text .= ' ' . $shortcode_atts; + } + } + } + + // If we have built a replacement text then replace it in the main $content. + if ( ! empty( $replacement_text ) ) { + $replacement_text .= ']'; + $content = str_replace( $ar[0][ $pattern_key ], $replacement_text, $content ); + /** + * Filters the shortcode content after converting it from WordPress block content. + * + * @param string $content Shortcode content after conversion. + * @param array $pattern_atts_array An array of pattern attributes to use for conversion. + * @param string $shortcode_slug The slug of shortcode. + * @param string $block_slug The slug of gutenberg block. + */ + $content = apply_filters( 'learndash_convert_block_markers_to_shortcode_content', $content, $pattern_atts_array, $shortcode_slug, $block_slug ); + } + } + } + } + } else { + /** + * A non-self closing WP block will look like the following for the ld-student. The + * patter will have an outer wrapper of the block which will be converted into a shortcode + * wrapper like [ld_student][/ld_student] + * + * + * + *

This is the inner content.

+ * + * + */ + preg_match_all( '#(.*?)#is', $content, $ar ); + if ( ( isset( $ar[0] ) ) && ( is_array( $ar[0] ) ) && ( ! empty( $ar[0] ) ) ) { + if ( ( isset( $ar[1] ) ) && ( is_array( $ar[1] ) ) && ( ! empty( $ar[1] ) ) ) { + foreach ( $ar[1] as $pattern_key => $pattern_atts_json ) { + $pattern_atts_json = trim( $pattern_atts_json ); + + // Ensure the inner content is not empty. + if ( ( isset( $ar[2][ $pattern_key ] ) ) && ( ! empty( $ar[2][ $pattern_key ] ) ) ) { + $replacement_text = '[' . $shortcode_slug; + + if ( ! empty( $pattern_atts_json ) ) { + $pattern_atts_array = (array) json_decode( $pattern_atts_json ); + + if ( ( is_array( $pattern_atts_array ) ) && ( ! empty( $pattern_atts_array ) ) ) { + foreach ( $pattern_atts_array as $attr_key => $attr_value ) { + if ( 'meta' === $attr_key ) { + continue; + } + + /** + * Only accept our known block attributes. + * + * @since 4.21.4 + */ + if ( ! isset( $this->block_attributes[ $attr_key ] ) ) { + unset( $pattern_atts_array[ $attr_key ] ); + } + } + } + + /** This filter is documented in includes/gutenberg/blocks/ld-course-list/index.php */ + $pattern_atts_array = apply_filters( 'learndash_block_markers_shortcode_atts', $pattern_atts_array, $shortcode_slug, $block_slug, $content ); + + $shortcode_atts = ''; + + if ( ( is_array( $pattern_atts_array ) ) && ( ! empty( $pattern_atts_array ) ) ) { + foreach ( $pattern_atts_array as $attr_key => $attr_value ) { + if ( 'meta' === $attr_key ) { + continue; + } + + if ( '' !== $attr_value ) { + if ( ! empty( $shortcode_atts ) ) { + $shortcode_atts .= ' '; + } + + if ( is_array( $attr_value ) ) { + $attr_value = implode( ',', $attr_value ); + } + + $shortcode_atts .= $attr_key . '="' . $attr_value . '"'; + } + } + } + if ( ! empty( $shortcode_atts ) ) { + $replacement_text .= ' ' . $shortcode_atts; + } + } + $replacement_text .= ']' . $ar[2][ $pattern_key ] . '[/' . $shortcode_slug . ']'; + + // If we have built a replacement text then replace it in the main $content. + if ( ! empty( $replacement_text ) ) { + $content = str_replace( $ar[0][ $pattern_key ], $replacement_text, $content ); + /** This filter is documented in includes/gutenberg/lib/class-learndash-gutenberg-block.php */ + $content = apply_filters( 'learndash_convert_block_markers_to_shortcode_content', $content, $pattern_atts_array, $shortcode_slug, $block_slug ); + } + } + } + } + } + } + } + + return $content; + } + + /** + * Called from the LD function learndash_convert_block_markers_shortcode() when parsing the block content. + * Each sub-subclassed instance should provide its own version of this function. + * + * @since 4.21.4 + * + * @param array $block_attributes The array of attributes parse from the block content. + * @param string $shortcode_slug This will match the related LD shortcode ld_profile, ld_course_list, etc. + * @param string $block_slug This is the block token being processed. Normally same as the shortcode but underscore replaced with dash. + * @param string $content This is the original full content being parsed. + * + * @return array $block_attributes. + */ + public function learndash_block_markers_shortcode_atts_filter( $block_attributes = array(), $shortcode_slug = '', $block_slug = '', $content = '' ) { + return $block_attributes; + } + + /** + * Called from the LD function convert_block_markers_to_shortcode() when parsing the block content. + * This function allows hooking into the converted content. + * + * @since 4.21.4 + * + * @param string $content This is the original full content being parsed. + * @param array $block_attributes The array of attributes parse from the block content. + * @param string $shortcode_slug This will match the related LD shortcode ld_profile, ld_course_list, etc. + * @param string $block_slug This is the block token being processed. Normally same as the shortcode but underscore replaced with dash. + * + * @return string $content. + */ + public function convert_block_markers_to_shortcode_content_filter( $content = '', $block_attributes = array(), $shortcode_slug = '', $block_slug = '' ) { + return $content; + } + + /** + * Common function used by the ld_course_list, ld_lesson_list, ld_topic_list, + * and ld_quiz_list called from the render_block short/block processing function. + * Converts the array of attributes to a normalized shortcode parameter string. + * + * @since 4.21.4 + * @param array $block_attributes Array of block attributes. + * @return string. + */ + protected function prepare_course_list_atts_to_param( $block_attributes = array() ) { + $shortcode_params_str = ''; + + foreach ( $block_attributes as $key => $val ) { + if ( ( empty( $key ) ) || ( is_null( $val ) ) ) { + continue; + } + + if ( ( 'preview_show' === $key ) || ( 'editing_post_meta' === $key ) ) { + continue; + } elseif ( 'preview_user_id' === $key ) { + if ( ( ! isset( $block_attributes['user_id'] ) ) && ( 'preview_user_id' === $key ) && ( '' !== $val ) ) { + if ( ! learndash_is_admin_user( get_current_user_id() ) ) { + if ( learndash_is_group_leader_user( get_current_user_id() ) ) { + // If group leader user we ensure the preview user_id is within their group(s). + if ( ! learndash_is_group_leader_of_user( get_current_user_id(), $val ) ) { + continue; + } + } else { + // If neither admin or group leader then we don't see the user_id for the shortcode. + continue; + } + } + $key = str_replace( 'preview_', '', $key ); + $val = absint( $val ); + } + } elseif ( 'per_page' === $key ) { + if ( '' === $val ) { + continue; + } + $key = 'num'; + $val = (int) $val; + } elseif ( ( 'show_content' === $key ) || ( 'show_thumbnail' === $key ) || ( 'course_grid' === $key ) || ( 'progress_bar' === $key ) ) { + if ( ( 1 === $val ) || ( true === $val ) || ( 'true' === $val ) ) { + $val = 'true'; + } else { + $val = 'false'; + } + } elseif ( 'col' === $key ) { + if ( defined( 'LEARNDASH_COURSE_GRID_FILE' ) ) { + $val = absint( $val ); + if ( $val < 1 ) { + $val = 3; + } + } else { + continue; + } + } elseif ( 'lesson_id' === $key ) { + if ( '' === $val ) { + continue; + } + } elseif ( 'status' === $key ) { + if ( empty( $val ) ) { + continue; + } + + $val_str = implode( ',', $val ); + $val = $val_str; + } elseif ( 'price_type' === $key ) { + if ( empty( $val ) ) { + continue; + } + + $val_str = implode( ',', $val ); + $val = $val_str; + } elseif ( empty( $val ) ) { + continue; + } + + if ( ! empty( $shortcode_params_str ) ) { + $shortcode_params_str .= ' '; + } + $shortcode_params_str .= $key . '="' . esc_attr( $val ) . '"'; + } + + return $shortcode_params_str; + } + + /** + * Get example user ID. This is used as part of WP 5.3 Gutenberg Block Example / Preview. + * + * @since 4.21.4 + * + * @return integer $user_id User ID. + */ + public function get_example_user_id() { + $user_id = 0; + /** + * Filters gutenberg block example ID. + * + * @param int $id The ID of the resource. + * @param string $context The context of the resource. + * @param string $post_type The post type slug of the resource. + * @param string $block_slug The slug of the block. + */ + $user_id = apply_filters( 'learndash_gutenberg_block_example_id', $user_id, 'user_id', 'user', $this->block_slug ); + $user_id = absint( $user_id ); + if ( ! empty( $user_id ) ) { + $user = get_user_by( 'ID', $user_id ); + if ( ( ! $user ) || ( ! is_a( $user, 'WP_User' ) ) ) { + $user_id = 0; + } + } + + if ( empty( $user_id ) ) { + if ( is_user_logged_in() ) { + $user_id = get_current_user_id(); + } + } + + return $user_id; + } + + /** + * Get example post ID. This is used as part of WP 5.3 Gutenberg Block Example / Preview. + * + * @since 4.21.4 + * + * @param string $post_type Post Type Slug to retrieve. + * + * @return integer $post_id Post ID. + */ + public function get_example_post_id( $post_type = '' ) { + $post_id = 0; + /** This filter is documented in includes/gutenberg/lib/class-learndash-gutenberg-block.php */ + $post_id = apply_filters( 'learndash_gutenberg_block_example_id', $post_id, 'post_id', $post_type, $this->block_slug ); + $post_id = absint( $post_id ); + if ( ! empty( $post_id ) ) { + $_post = get_post( $post_id ); + if ( ( ! $_post ) || ( ! is_a( $_post, 'WP_Post' ) ) ) { + $course_id = 0; + } + } + + if ( empty( $post_id ) ) { + $post_id = learndash_get_single_post( $post_type ); + } + + return $post_id; + } + + /** + * Utility function to check if we are editing a post. + * + * @since 4.21.4 + * + * @param array $block_attributes The block attributes. + * + * @return boolean true if we are editing a post. + */ + protected function block_attributes_is_editing_post( $block_attributes = array() ) { + if ( isset( $block_attributes['editing_post_meta']['editing'] ) ) { + if ( ( 'true' === $block_attributes['editing_post_meta']['editing'] ) || ( true === $block_attributes['editing_post_meta']['editing'] ) ) { + return true; + } + } + return false; + } + + /** + * Utility function to determine the Post ID from the block attributes. + * + * @since 4.21.4 + * + * @param array $block_attributes The block attributes. + * @param string $post_prefix The post prefix to use. Example: 'course', 'quiz', 'group', etc. + * + * @return int Post ID. + */ + protected function block_attributes_get_post_id( $block_attributes = array(), $post_prefix = '' ) { + if ( ! empty( $post_prefix ) ) { + if ( ( isset( $block_attributes[ $post_prefix . '_id' ] ) ) && ( '' != $block_attributes[ $post_prefix . '_id' ] ) ) { + return absint( $block_attributes[ $post_prefix . '_id' ] ); + } + + if ( $this->block_attributes_is_editing_post( $block_attributes ) ) { + if ( ( isset( $block_attributes[ 'preview_' . $post_prefix . '_id' ] ) ) && ( '' != $block_attributes[ 'preview_' . $post_prefix . '_id' ] ) ) { + return absint( $block_attributes[ 'preview_' . $post_prefix . '_id' ] ); + } + } + } + + return ''; + } + + /** + * Utility function to determine the User ID from the block attributes. + * + * @since 4.21.4 + * + * @param array $block_attributes The block attributes. + * + * @return int User ID. + */ + protected function block_attributes_get_user_id( $block_attributes = array() ) { + $user_id = ''; + if ( ( isset( $block_attributes['user_id'] ) ) && ( '' != $block_attributes['user_id'] ) ) { + $user_id = absint( $block_attributes['user_id'] ); + } + + if ( $this->block_attributes_is_editing_post( $block_attributes ) ) { + if ( ( isset( $block_attributes['preview_user_id'] ) ) && ( '' != $block_attributes['preview_user_id'] ) ) { + $user_id = absint( $block_attributes['preview_user_id'] ); + } + } + + if ( ! empty( $user_id ) ) { + if ( ! learndash_is_admin_user( get_current_user_id() ) ) { + if ( learndash_is_group_leader_user( get_current_user_id() ) ) { + // If group leader user we ensure the preview user_id is within their group(s). + if ( ! learndash_is_group_leader_of_user( get_current_user_id(), $user_id ) ) { + $user_id = ''; + } + } elseif ( (int) get_current_user_id() !== (int) $block_attributes['user_id'] ) { + $user_id = ''; + } + } + } + + return $user_id; + } + + /** + * Utility function to determine the Edit Post Type. + * + * @since 4.21.4 + * + * @param array $block_attributes The block attributes. + * + * @return string Preview Post Type. + */ + protected function block_attributes_get_editing_post_type( $block_attributes = array() ) { + return $this->block_attributes_get_editing_post_data( $block_attributes, 'post_type' ); + } + + /** + * Utility function to determine the Edit Post ID. + * + * @since 4.21.4 + * + * @param array $block_attributes The block attributes. + * + * @return int Edit Post ID. + */ + protected function block_attributes_get_editing_post_id( $block_attributes = array() ) { + return $this->block_attributes_get_editing_post_data( $block_attributes, 'post_id' ); + } + + /** + * Utility function to determine the Edit Course Post ID. + * + * @since 4.21.4 + * + * @param array $block_attributes The block attributes. + * + * @return int Edit Course Post ID. + */ + protected function block_attributes_get_editing_course_id( $block_attributes = array() ) { + return $this->block_attributes_get_editing_post_data( $block_attributes, 'course_id' ); + } + + /** + * Utility function to determine the Edit Post Data. + * + * @since 4.21.4 + * + * @param array $block_attributes The block attributes. + * @param string $return_key The post data key value to return. + * + * @return array Preview Post Data. + */ + protected function block_attributes_get_editing_post_data( $block_attributes = array(), $return_key = '' ) { + $editing_post_data = array( + 'post_id' => 0, + 'post_type' => '', + 'course_id' => 0, + ); + + if ( $this->block_attributes_is_editing_post( $block_attributes ) ) { + if ( isset( $block_attributes['editing_post_meta']['post_type'] ) ) { + $editing_post_data['post_type'] = esc_attr( $block_attributes['editing_post_meta']['post_type'] ); + } + + if ( isset( $block_attributes['editing_post_meta']['post_id'] ) ) { + $editing_post_data['post_id'] = absint( $block_attributes['editing_post_meta']['post_id'] ); + } + + if ( isset( $block_attributes['editing_post_meta']['course_id'] ) ) { + $editing_post_data['course_id'] = absint( $block_attributes['editing_post_meta']['course_id'] ); + } + } + + if ( ! empty( $return_key ) ) { + if ( isset( $editing_post_data[ $return_key ] ) ) { + return $editing_post_data[ $return_key ]; + } + } + return $editing_post_data; + } + + // End of functions. +} diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/includes/shortcodes/class-base.php b/web/app/plugins/sfwd-lms/includes/course-grid/includes/shortcodes/class-base.php new file mode 100644 index 000000000..a9e5426c2 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/includes/shortcodes/class-base.php @@ -0,0 +1,130 @@ +register(); + } + + /** + * Register shortcode. + * + * @since 4.21.4 + * + * @return void + */ + private function register() { + add_shortcode( $this->tag, [ $this, 'render' ] ); + } + + /** + * Render shortcode. + * + * @since 4.21.4 + * + * @param array $atts Shortcode attributes. + * @param string $content Shortcode content. + * + * @return string Shortcode output. + */ + abstract protected function render( $atts, $content ); + + /** + * Get default shortcode attributes. + * + * @since 4.21.4 + * + * @return array + */ + abstract protected function get_default_atts(); + + /** + * Validate attributes type. + * + * @since 4.21.4 + * + * @param array $atts Attributes. + * + * @return array + */ + protected function validate_atts_type( array $atts ): array { + $default_atts = $this->get_default_atts(); + + foreach ( $default_atts as $key => $value ) { + $type = gettype( $value ); + $value_type = gettype( $atts[ $key ] ); + + if ( $type !== $value_type ) { + switch ( $type ) { + case 'boolean': + $atts[ $key ] = 'true' === $atts[ $key ] || true === $atts[ $key ] || '1' === $atts[ $key ] || 1 === $atts[ $key ]; + break; + + case 'integer': + $atts[ $key ] = intval( $atts[ $key ] ); + break; + + case 'double': + $atts[ $key ] = floatval( $atts[ $key ] ); + break; + } + } + } + + return $atts; + } + + /** + * Process attributes as HTML data attributes. + * + * @since 4.21.4 + * + * @param array $atts Attributes. + * + * @return string + */ + protected function process_attributes_as_html_attributes( array $atts = [] ): string { + $attributes = ''; + + foreach ( $atts as $key => $value ) { + if ( is_array( $value ) ) { + $value = implode( ',', $value ); + } + + $attributes .= ' data-' . $key . '="' . $value . '"'; + } + + return $attributes; + } +} diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/includes/shortcodes/class-learndash-course-grid-filter.php b/web/app/plugins/sfwd-lms/includes/course-grid/includes/shortcodes/class-learndash-course-grid-filter.php new file mode 100644 index 000000000..28bb9f595 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/includes/shortcodes/class-learndash-course-grid-filter.php @@ -0,0 +1,119 @@ + + */ + public function get_default_atts() { + /** + * Returns the default attributes for the course grid filter shortcode. + * + * @since 4.21.4 + * + * @return array Array of default shortcode attributes. + */ + return apply_filters( + 'learndash_course_grid_filter_default_shortcode_attributes', + [ + 'course_grid_id' => '', + 'search' => true, + 'taxonomies' => 'category, post_tag', + 'default_taxonomies' => '', + 'price' => true, + 'price_min' => 0, + 'price_max' => 1000, + ] + ); + } + + /** + * Render shortcode. + * + * @since 4.21.4 + * + * @param array $shortcode_atts Shortcode attributes. + * @param string $content Shortcode content. + * + * @return string + */ + public function render( $shortcode_atts = [], $content = '' ) { + $atts = shortcode_atts( $this->get_default_atts(), $shortcode_atts, $this->tag ); + + $atts = $this->validate_atts_type( $atts ); + + if ( empty( $atts['course_grid_id'] ) ) { + $output = __( 'Missing course_grid_id attribute.', 'learndash' ); + return $output; + } + + $default_taxonomies = Utilities::parse_taxonomies( $atts['default_taxonomies'] ); + + // Get the template file + $template = Utilities::get_template( 'filter/layout' ); + + // Include the template file + ob_start(); + + echo '
'; + + $atts['taxonomies'] = array_map( + function ( $tax ) { + return trim( $tax ); + }, + array_filter( explode( ',', $atts['taxonomies'] ) ) + ); + + if ( '' === $atts['price_min'] ) { + $atts['price_min'] = 0; + } + + if ( '' === $atts['price_max'] ) { + $atts['price_max'] = 1000; + } + + $atts['price_step'] = ( $atts['price_max'] - $atts['price_min'] ) / 2 / 10; + $atts['price_step'] = ceil( $atts['price_step'] ); + + if ( $template ) { + include $template; + } + + echo '
'; + + // Return the template HTML string + return ob_get_clean(); + } +} diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/includes/shortcodes/class-learndash-course-grid.php b/web/app/plugins/sfwd-lms/includes/course-grid/includes/shortcodes/class-learndash-course-grid.php new file mode 100644 index 000000000..244195475 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/includes/shortcodes/class-learndash-course-grid.php @@ -0,0 +1,218 @@ + + */ + public function get_default_atts() { + /** + * Filters the default attributes for the course grid shortcode. + * + * @since 4.21.4 + * + * @param array $attrs Array of default shortcode attributes. + * + * @return array Array of default shortcode attributes. + */ + return apply_filters( + 'learndash_course_grid_default_shortcode_attributes', + [ + // Query + 'post_type' => defined( 'LEARNDASH_VERSION' ) ? 'sfwd-courses' : 'post', + 'per_page' => 9, + 'orderby' => 'ID', + 'order' => 'DESC', + 'taxonomies' => '', + 'enrollment_status' => '', + 'progress_status' => '', + // Used to filter courses by group. Defaults to 0 to not filter by group. + 'group_id' => 0, + // Elements + 'thumbnail' => true, + 'thumbnail_size' => 'thumbnail', + 'ribbon' => true, + 'video' => false, + /** + * Content includes title, description and button + */ + 'content' => true, + 'title' => true, + 'title_clickable' => true, + 'description' => true, + 'description_char_max' => 120, + 'button' => true, + 'filter' => true, + /** + * Accepts: + * + * 'button' : Load more button + * 'infinite' : Infinite scrolling + * 'pages' : Normal AJAX pagination with number 1, 2, 3, and so on + * 'false' : Doesn't have pagination + */ + 'pagination' => 'button', + 'grid_height_equal' => false, + 'progress_bar' => false, + 'post_meta' => true, + // Template + /** + * Accepts: + * + * All values available in templates/skins + */ + 'skin' => 'grid', + 'card' => 'grid-1', + /** + * Only used in certain skin such as 'grid' and 'masonry' + */ + 'columns' => 3, + 'min_column_width' => 250, + /** + * Only used in certain skin such as 'carousel' + */ + 'items_per_row' => 3, + // Styles + 'font_family_title' => '', + 'font_family_description' => '', + 'font_size_title' => '', + 'font_size_description' => '', + 'font_color_title' => '', + 'font_color_description' => '', + 'background_color_title' => '', + 'background_color_description' => '', + 'background_color_ribbon' => '', + 'font_color_ribbon' => '', + 'background_color_icon' => '', + 'font_color_icon' => '', + 'background_color_button' => '', + 'font_color_button' => '', + // Misc + 'class_name' => '', + /** + * Random unique ID for CSS styling purpose + */ + 'id' => '', + // Filter + 'filter_search' => true, + 'filter_taxonomies' => '', + 'filter_price' => true, + 'filter_price_min' => 0, + 'filter_price_max' => 1000, + ] + ); + } + + /** + * Render shortcode. + * + * @since 4.21.4 + * + * @param array $atts Shortcode attributes. + * @param string $content Shortcode content. + * + * @return string Shortcode output. + */ + public function render( $atts = [], $content = '' ) { + $atts = shortcode_atts( $this->get_default_atts(), $atts, $this->tag ); + + $atts = $this->validate_atts_type( $atts ); + + // Enqueue skin assets for this shortcode instance. + Course_Grid::instance()->skins->handle_skin_assets( $atts ); + + $query_args = Utilities::build_posts_query_args( $atts ); + + // Query the posts. + $query = new WP_Query( $query_args ); + + $posts = $query->get_posts(); + $max_num_pages = $query->max_num_pages; + + if ( $max_num_pages > 1 ) { + $has_pagination = true; + } else { + $has_pagination = false; + } + + $empty_id = false; + if ( empty( $atts['id'] ) ) { + $empty_id = true; + $atts['id'] = Utilities::generate_random_id(); + } + + $filter = filter_var( $atts['filter'], FILTER_VALIDATE_BOOLEAN ); + + // Get the template file + $template = Utilities::get_skin_layout( $atts['skin'] ); + $pagination_template = Utilities::get_pagination_template( $atts['pagination'] ); + + // Include the template file + ob_start(); + + if ( $empty_id ) { + printf( + '', + esc_html__( + 'The LearnDash course grid element below does not have an `id` attribute set in the shortcode so it is generated randomly each time it renders. Please set the `id` attribute in the shortcode so it will be consistent each time it renders. If it is not consistent, custom CSS rules in the site that uses the element particular ID may not work.', + 'learndash' + ) + ); + } + + echo '
process_attributes_as_html_attributes( $atts ) . '>'; + + if ( $filter === true ) { + echo ''; + + echo do_shortcode( '[learndash_course_grid_filter course_grid_id="' . esc_attr( $atts['id'] ) . '" search="' . esc_attr( $atts['filter_search'] ) . '" taxonomies="' . esc_attr( $atts['filter_taxonomies'] ) . '" default_taxonomies="' . esc_attr( $atts['taxonomies'] ) . '" price="' . esc_attr( $atts['filter_price'] ) . '" price_min="' . esc_attr( $atts['filter_price_min'] ) . '" price_max="' . esc_attr( $atts['filter_price_max'] ) . '"]' ); + } + + if ( $template ) { + include $template; + } + + if ( $pagination_template && $has_pagination ) { + include $pagination_template; + } + + echo '
'; + + // Return the template HTML string. + return ob_get_clean(); + } +} diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/learndash_course_grid.php b/web/app/plugins/sfwd-lms/includes/course-grid/learndash_course_grid.php new file mode 100644 index 000000000..a1d0959d0 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/learndash_course_grid.php @@ -0,0 +1,259 @@ +define_constants(); + + spl_autoload_register( [ $this, 'autoload' ] ); + + $this->security = new Security(); + $this->skins = new Skins(); + $this->ajax = new AJAX(); + $this->shortcodes = new Shortcodes(); + $this->blocks = new Blocks(); + $this->compatibility = new Compatibility(); + + // Include files manually. + include_once LEARNDASH_COURSE_GRID_PLUGIN_PATH . 'includes/functions.php'; + + // Admin. + if ( is_admin() ) { + $this->admin = new stdClass(); + $this->admin->meta_boxes = new Meta_Boxes(); + } + } + + /** + * Defines constants used by the plugin + * + * @since 4.21.4 + * + * @return void + */ + public function define_constants() { + if ( ! defined( 'LEARNDASH_COURSE_GRID_FILE' ) ) { + define( 'LEARNDASH_COURSE_GRID_FILE', __FILE__ ); + } + + if ( ! defined( 'LEARNDASH_COURSE_GRID_PLUGIN_PATH' ) ) { + define( 'LEARNDASH_COURSE_GRID_PLUGIN_PATH', plugin_dir_path( __FILE__ ) ); + } + + if ( ! defined( 'LEARNDASH_COURSE_GRID_PLUGIN_URL' ) ) { + define( 'LEARNDASH_COURSE_GRID_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); + } + + if ( ! defined( 'LEARNDASH_COURSE_GRID_PLUGIN_TEMPLATE_PATH' ) ) { + define( 'LEARNDASH_COURSE_GRID_PLUGIN_TEMPLATE_PATH', LEARNDASH_COURSE_GRID_PLUGIN_PATH . 'templates/' ); + } + + if ( ! defined( 'LEARNDASH_COURSE_GRID_PLUGIN_TEMPLATE_URL' ) ) { + define( 'LEARNDASH_COURSE_GRID_PLUGIN_TEMPLATE_URL', LEARNDASH_COURSE_GRID_PLUGIN_URL . 'templates/' ); + } + + if ( ! defined( 'LEARNDASH_COURSE_GRID_PLUGIN_ASSET_PATH' ) ) { + define( 'LEARNDASH_COURSE_GRID_PLUGIN_ASSET_PATH', LEARNDASH_COURSE_GRID_PLUGIN_PATH . 'assets/' ); + } + + if ( ! defined( 'LEARNDASH_COURSE_GRID_PLUGIN_ASSET_URL' ) ) { + define( 'LEARNDASH_COURSE_GRID_PLUGIN_ASSET_URL', LEARNDASH_COURSE_GRID_PLUGIN_URL . 'assets/' ); + } + + // Added for backward compatibility. + if ( ! defined( 'LEARNDASH_COURSE_GRID_COLUMNS' ) ) { + define( 'LEARNDASH_COURSE_GRID_COLUMNS', 3 ); + } + } + + /** + * Autoload function for dynamically loading classes based on the LearnDash Course Grid namespace. + * + * @since 4.21.4 + * + * @param string $class The fully-qualified class name to be autoloaded. + * + * @return void + */ + public function autoload( $class ) { + $class_components = explode( '\\', $class ); + $class_file = str_replace( '_', '-', strtolower( $class_components[ count( $class_components ) - 1 ] ) ); + $filename = $class_file . '.php'; + + $file = false; + + if ( strpos( $class, 'LearnDash\\Course_Grid\\Shortcodes\\' ) !== false ) { + $file = 'includes/shortcodes/class-' . $filename; + } elseif ( strpos( $class, 'LearnDash\\Course_Grid\\Gutenberg\\Blocks\\' ) !== false ) { + $file = 'includes/gutenberg/blocks/' . $class_file . '/index.php'; + } elseif ( strpos( $class, 'LearnDash\\Course_Grid\\Admin\\' ) !== false ) { + $file = 'includes/admin/class-' . $filename; + } elseif ( strpos( $class, 'LearnDash\\Course_Grid\\Lib' ) !== false ) { + $file = 'includes/lib/class-' . $filename; + } elseif ( strpos( $class, 'LearnDash\\Course_Grid\\' ) !== false ) { + $file = 'includes/class-' . $filename; + } + + if ( $file && file_exists( LEARNDASH_COURSE_GRID_PLUGIN_PATH . $file ) ) { + include_once LEARNDASH_COURSE_GRID_PLUGIN_PATH . $file; + } + } + + /** + * Load translations. + * + * @since 4.21.4 + * @deprecated 4.21.4 + * + * @return void + */ + public function load_translations() { + _deprecated_function( __METHOD__, '4.21.4' ); + } +} + +/** + * Returns the main instance of the plugin. + * + * @since 4.21.4 + * @deprecated 4.21.4 + * + * @return Course_Grid + */ +function course_grid() { + _deprecated_function( __FUNCTION__, '4.21.4' ); + + return Course_Grid::instance(); +} + +// Initialize the plugin. +Course_Grid::instance(); diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/grid-1/layout.php b/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/grid-1/layout.php new file mode 100644 index 000000000..9d76de61c --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/grid-1/layout.php @@ -0,0 +1,184 @@ + +
+
ID ); ?>> + +
+ +
+ +
+ + + +
+ +
+ ID ) ) : ?> + + ID ) ) : ?> +
+ +
+ +
+ + + +
+
+ +

+ + + + + + + +

+ + +
+ +
+ + + +
+ + + + $reviews_floored && floatval( $reviews_number ) > $reviews_floored && $i <= $reviews_ceil ) { + $star_class = 'star-half'; + } else { + $star_class = 'star-empty'; + } + ?> + + + +
+ + +
+ + +
+ +
+ +
+
+ +
+ + + + + + + + + +
+ + +
+ + + + + + + + + +
+ + +
+ + + + + + + + + +
+ + +
+ + + + + + + + + +
+ +
+ + + post_type == 'sfwd-courses' ) : ?> + ID . '" user_id="' . $user_id . '"]' ); ?> + post_type == 'groups' ) : ?> +
+ ID, $user_id ); ?> + 'group', + 'user_id' => $user_id, + 'group_id' => $post->ID, + ), + true + ); + ?> +
+ + +
+ +
+
diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/grid-1/style.css b/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/grid-1/style.css new file mode 100644 index 000000000..9692139f2 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/grid-1/style.css @@ -0,0 +1,156 @@ +.learndash-course-grid .items-wrapper .grid-1 .post { + line-height: 1.428571429; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 4px; + -webkit-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; + display: inline-block; + max-width: 100%; + height: auto; + display: block; + position: relative; + padding: 0; + margin: 0; + box-shadow: 2px 2px 2px 1px rgb(0 0 0 / 5%); + -moz-box-shadow: 2px 2px 2px 1px rgb(0 0 0 / 5%); + -webkit-box-shadow: 2px 2px 2px 1px rgb(0 0 0 / 5%); +} + +.learndash-course-grid .items-wrapper .grid-1 .ribbon { + text-shadow: 0 1px rgb( 0 0 0 / 30% ); + position: absolute; + z-index: 2; + top: 20px; + right: 20px; + left: auto; + padding: 10px 12px; + border-radius: 6px; + color: #fff; + background: #fd6703; + font-weight: bold; + font-size: 1rem; +} + +.learndash-course-grid .items-wrapper .grid-1 .ribbon::before { + +} + +.learndash-course-grid .items-wrapper .grid-1 .thumbnail { + margin: 0; + padding: 0; +} + +.learndash-course-grid .items-wrapper .grid-1 .video > * { + border-radius: 5px; +} + +.learndash-course-grid .items-wrapper .grid-1 .thumbnail img { + margin: 0 auto; + padding: 0; + width: 100%; + height: auto; +} + +.learndash-course-grid .items-wrapper .grid-1 .content { + padding: 30px 22px; + color: #333333; +} + +.learndash-course-grid .items-wrapper .grid-1 .content > *:not(:last-child) { + margin-bottom: 20px; +} + +.learndash-course-grid .items-wrapper .grid-1 .content .top-meta > *:not(:last-child) { + margin-bottom: 20px; +} + +.learndash-course-grid .items-wrapper .grid-1 .content .entry-title { + font-size: 1.2rem; + font-weight: bold; + line-height: 1.2; + color: #333; +} + +.learndash-course-grid .items-wrapper .grid-1 .content .entry-title a { + text-decoration: none; + color: #333; + font-size: 1.2rem; + line-height: 1.2; + font-weight: bold; +} + +.learndash-course-grid .items-wrapper .grid-1 .content .entry-content { + margin-bottom: 20px ; +} + +.learndash-course-grid .items-wrapper .grid-1 .content .entry-content > * { + margin: 0; +} + +.learndash-course-grid .items-wrapper .grid-1 .content .author { + font-size: 0.875rem; + color: #949ca1; +} + +.learndash-course-grid .items-wrapper .grid-1 .content .reviews, +.learndash-course-grid .items-wrapper .grid-1 .content .categories { + font-size: 0.875rem; + display: flex; + align-items: center; +} + +.learndash-course-grid .items-wrapper .grid-1 .icon { + justify-content: center; + margin-right: 3px; +} + +.learndash-course-grid .items-wrapper .grid-1 .content .categories .icon { + font-size: 0.875rem; + display: flex; + align-items: center; +} + + +.learndash-course-grid .items-wrapper .grid-1 .content .reviews .label { + margin-right: 10px; +} + +.learndash-course-grid .items-wrapper .grid-1 .content .reviews .stars { + color: #ffb703; +} + +.learndash-course-grid .items-wrapper .grid-1 .bottom-meta { + display: grid; + grid-template-columns: repeat( 2, minmax( 0, 1fr ) ); + font-size: 0.75rem; + gap: 15px; +} + +.learndash-course-grid .items-wrapper .grid-1 .bottom-meta .section { + display: flex; + align-items: center; +} + +.learndash-course-grid .items-wrapper .grid-1 .bottom-meta .section .icon { + width: auto; + height: auto; + display: block; + font-size: 1rem; + padding: 5px; + background: #00bcb6; + color: #fff; + border-radius: 5px; +} + +.learndash-course-grid .items-wrapper .grid-1 .bottom-meta .section .wrapper { + margin-left: 5px; +} + +.learndash-course-grid .items-wrapper .grid-1 .bottom-meta .section .wrapper .label { + font-weight: bold; +} + +.learndash-course-grid .items-wrapper .grid-1 .bottom-meta .section .wrapper > * { + display: block; +} \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/grid-2/layout.php b/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/grid-2/layout.php new file mode 100644 index 000000000..c426b1747 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/grid-2/layout.php @@ -0,0 +1,137 @@ + +
+
ID ); ?>> + +
+ +
+ +
+ + +
+ +
+ ID ) ) : ?> + + ID ) ) : ?> +
+ +
+ + + +
+ + +
+ +
+ +
+ <?php echo $author['name']; ?> +
+ + + + + + + + + +
+
+ +
+ + +

+ + + + + + + +

+ + +
+ +
+ + + post_type == 'sfwd-courses' ) : ?> + ID . '" user_id="' . $user_id . '"]' ); ?> + post_type == 'groups' ) : ?> +
+ ID, $user_id ); ?> + 'group', + 'user_id' => $user_id, + 'group_id' => $post->ID, + ), + true + ); + ?> +
+ + + +
+ + + +
+ +
+ +
+
diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/grid-2/style.css b/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/grid-2/style.css new file mode 100644 index 000000000..6d17fe3e0 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/grid-2/style.css @@ -0,0 +1,183 @@ +.learndash-course-grid .items-wrapper .grid-2 .post { + line-height: 1.428571429; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 4px; + -webkit-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; + display: inline-block; + max-width: 100%; + height: auto; + display: block; + position: relative; + padding: 0; + margin: 0; + box-shadow: 2px 2px 2px 1px rgb(0 0 0 / 5%); + -moz-box-shadow: 2px 2px 2px 1px rgb(0 0 0 / 5%); + -webkit-box-shadow: 2px 2px 2px 1px rgb(0 0 0 / 5%); +} + +.learndash-course-grid .items-wrapper .grid-2 .ribbon { + text-shadow: 0 1px rgb( 0 0 0 / 30% ); + position: absolute; + z-index: 2; + top: 20px; + right: 15px; + left: auto; + padding: 10px 12px; + border-radius: 6px; + color: #fff; + background: #0f69aa; + font-weight: bold; + font-size: 1rem; +} + +.learndash-course-grid .items-wrapper .grid-2 .ribbon::before { + +} + +.learndash-course-grid .items-wrapper .grid-2 .thumbnail { + margin: 0; + padding: 0; + position: relative; +} + +.learndash-course-grid .items-wrapper .grid-2 .thumbnail img { + margin: 0 auto; + padding: 0; + width: 100%; + height: auto; +} + +.learndash-course-grid .items-wrapper .grid-2 .thumbnail .arrow { + position: absolute; + right: 10px; + bottom: -18px; + left: initial; + top: initial; + overflow: visible; + z-index: 1000; + height: auto; + width: auto; + margin: 0; + padding: 0; + border-radius: 100px; +} + +.learndash-course-grid .items-wrapper .grid-2 .thumbnail .arrow a { + border-radius: 100px; + display: block; +} + +.learndash-course-grid .items-wrapper .grid-2 .thumbnail .arrow * { + text-decoration: none; +} + +.learndash-course-grid .items-wrapper .grid-2 .thumbnail .arrow .dashicons { + background: #fd9752; + color: #fff; + font-size: 25px; + width: auto; + height: auto; + padding: 5px; + border-radius: 100px; +} + +.learndash-course-grid .items-wrapper .grid-2 .content { + padding: 30px 22px; + color: #333333; +} + +.learndash-course-grid .items-wrapper .grid-2 .content > *:not(:last-child) { + margin-bottom: 20px; +} + +.learndash-course-grid .items-wrapper .grid-2 .content .author { + display: flex; + gap: 15px; +} + +.learndash-course-grid .items-wrapper .grid-2 .content .author .avatar { + width: 43px; + height: 43px; + border-radius: 30px; + display: block; +} + +.learndash-course-grid .items-wrapper .grid-2 .content .author .wrapper { + display: grid; + width: 100%; +} + +.learndash-course-grid .items-wrapper .grid-2 .content .author .name { + font-weight: bold; + font-size: 1rem; +} + +.learndash-course-grid .items-wrapper .grid-2 .content .author .wrapper .lessons { + float: right; +} + +.learndash-course-grid .items-wrapper .grid-2 .content .entry-title { + font-size: 1.2rem; + font-weight: bold; + line-height: 1.2; + color: #333; +} + +.learndash-course-grid .items-wrapper .grid-2 .content .entry-title a { + text-decoration: none; + color: #333; + font-size: 1.2rem; + line-height: 1.2; + font-weight: bold; +} + +.learndash-course-grid .items-wrapper .grid-2 .content .entry-content { + margin-bottom: 20px; + color: #949ca1; + font-size: 0.875rem; +} + +.learndash-course-grid .items-wrapper .grid-2 .content .entry-content > * { + margin: 0; +} + +.learndash-course-grid .items-wrapper .grid-2 .content .author { + font-size: 0.875rem; + color: #949ca1; +} + +.learndash-course-grid .items-wrapper .grid-2 .content .button { + margin: 0; + padding: 0; + background: none; + border: none; + border-radius: 5px; + width: 100%; +} + +.learndash-course-grid .items-wrapper .grid-2 .content .button a { + color: #ffffff; + font-weight: bold; + text-decoration: none; + -webkit-transition: all 0.3s ease; + transition: all 0.3s ease; + text-align: center; + display: -ms-flexbox; + display: flex; + justify-content: center; + -ms-flex-align: center; + align-items: center; + cursor: pointer; + background-color: #143f5e; + border-color: #143f5e; + border-radius: 5px; + font-size: 1rem; + padding: 12px 0; +} + +.learndash-course-grid .items-wrapper .grid-2 .content .button a:hover { + background: #29648f; + border-color: #29648f; +} \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/grid-3/layout.php b/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/grid-3/layout.php new file mode 100644 index 000000000..c471c02e3 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/grid-3/layout.php @@ -0,0 +1,134 @@ + +
+
ID ); ?>> + +
+ +
+ +
+ ID ) ) : ?> + + ID ) ) : ?> +
+ +
+ +
+ + +
+ +

+ + + + + + + +

+ + +
+ +
+ <?php echo esc_attr( $author['name'] ); ?> + ' . $author['name'] . '' ); ?> +
+ + +
+ +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+ +
+ +
+ +
+ + + post_type == 'sfwd-courses' ) : ?> + ID . '" user_id="' . $user_id . '"]' ); ?> + post_type == 'groups' ) : ?> +
+ ID, $user_id ); ?> + 'group', + 'user_id' => $user_id, + 'group_id' => $post->ID, + ), + true + ); + ?> +
+ + + +
+ + + +
+ +
+ +
+
diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/grid-3/style.css b/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/grid-3/style.css new file mode 100644 index 000000000..853651c70 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/grid-3/style.css @@ -0,0 +1,143 @@ +.learndash-course-grid .items-wrapper .grid-3 .post { + line-height: 1.428571429; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 5px; + -webkit-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; + display: inline-block; + max-width: 100%; + height: auto; + display: block; + position: relative; + padding: 20px; + margin: 0; + box-shadow: 2px 2px 2px 1px rgb(0 0 0 / 5%); + -moz-box-shadow: 2px 2px 2px 1px rgb(0 0 0 / 5%); + -webkit-box-shadow: 2px 2px 2px 1px rgb(0 0 0 / 5%); +} + +.learndash-course-grid .items-wrapper .grid-3 .thumbnail { + margin: 0; + padding: 0; +} + +.learndash-course-grid .items-wrapper .grid-3 .thumbnail img { + margin: 0 auto; + padding: 0; + width: 100%; + height: auto; + border-radius: 5px; +} + +.learndash-course-grid .items-wrapper .grid-3 .content { + padding: 30px 0 0; + color: #333333; +} + +.learndash-course-grid .items-wrapper .grid-3 .content .entry-title { + font-size: 1.2rem; + font-weight: bold; + line-height: 1.2; + color: #333; + margin-bottom: 15px; +} + +.learndash-course-grid .items-wrapper .grid-3 .content .entry-title a { + text-decoration: none; + color: #333; + font-size: 1.2rem; + line-height: 1.2; + font-weight: bold; +} + +.learndash-course-grid .items-wrapper .grid-3 .content .entry-content { + margin-bottom: 20px ; + color: #949ca1; + font-size: 0.875rem; +} + +.learndash-course-grid .items-wrapper .grid-3 .content .entry-content > * { + margin: 0; +} + +.learndash-course-grid .items-wrapper .grid-3 .content .meta { + display: flex; + align-items: center; + gap: 10px; + color: #949ca1; + font-size: 0.875rem; + margin-bottom: 20px; +} + +.learndash-course-grid .items-wrapper .grid-3 .content .author { + display: flex; + align-items: center; + gap: 10px; +} + +.learndash-course-grid .items-wrapper .grid-3 .content .author img { + width: 30px; + height: 30px; + display: block; + border-radius: 30px; + border: 2px solid #fd8739; +} + +.learndash-course-grid .items-wrapper .grid-3 .content .author .name { + font-weight: bold; +} + +.learndash-course-grid .items-wrapper .grid-3 .content .price-wrapper { + display: flex; + align-items: center; + justify-content: space-between; + color: #333333; +} + +.learndash-course-grid .items-wrapper .grid-3 .content .price-wrapper > * { + width: 50%; +} + +.learndash-course-grid .items-wrapper .grid-3 .content .price-wrapper .trial { + text-align: left; +} + +.learndash-course-grid .items-wrapper .grid-3 .content .price-wrapper .price { + text-align: right; +} + +.learndash-course-grid .items-wrapper .grid-3 .content .button { + margin: 0; + padding: 0; + background: none; + border: none; + width: 100%; +} + +.learndash-course-grid .items-wrapper .grid-3 .content .button a { + text-decoration: none; + -webkit-transition: all 0.3s ease; + transition: all 0.3s ease; + text-align: center; + display: -ms-flexbox; + display: flex; + justify-content: center; + -ms-flex-align: center; + align-items: center; + cursor: pointer; + color: #ffffff; + background-color: #fd6906; + border-color: #fd6906; + border-radius: 5px; + font-size: 1rem; + font-weight: bold; + padding: 6px 0; + margin: 0 auto; + max-width: 70%; +} + +.learndash-course-grid .items-wrapper .grid-3 .content .button a:hover { + background: #fd8739; + border-color: #fd8739; +} \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/list-1/layout.php b/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/list-1/layout.php new file mode 100644 index 000000000..36cd163d5 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/list-1/layout.php @@ -0,0 +1,169 @@ + +
+
ID ); ?>> + +
+ +
+ + +
+ + + +
+ +
+ ID ) ) : ?> + + ID ) ) : ?> +
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ <?php echo $author['name']; ?> + ' . $author['name'] . '' ); ?> +
+ +

+ + + + + + + +

+ +
+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + +
+ +
+ + + post_type == 'sfwd-courses' ) : ?> + ID . '" user_id="' . $user_id . '"]' ); ?> + post_type == 'groups' ) : ?> +
+ ID, $user_id ); ?> + 'group', + 'user_id' => $user_id, + 'group_id' => $post->ID, + ), + true + ); + ?> +
+ + + +
+ + + + +
+ +
+
+
diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/list-1/style.css b/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/list-1/style.css new file mode 100644 index 000000000..894e638bc --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/list-1/style.css @@ -0,0 +1,243 @@ +.learndash-course-grid .items-wrapper .list-1 .post { + display: flex; + flex-direction: row; + gap: 60px; + margin-bottom: 60px; +} + +.learndash-course-grid .items-wrapper .list-1 .ribbon { + text-shadow: 0 1px rgb( 0 0 0 / 30% ); + position: absolute; + z-index: 2; + top: 0; + right: 0; + left: auto; + padding: 10px 12px; + color: #fff; + background: #00bcb6; + font-weight: bold; + font-size: 1rem; + border-radius: 5px; + display: flex; + align-items: center; + justify-content: center; +} + +.learndash-course-grid .items-wrapper .list-1 .ribbon::before { + +} + +.learndash-course-grid .items-wrapper .list-1 .thumbnail { + margin: 0; + padding: 0; + position: relative; + width: 50%; +} + +.learndash-course-grid .items-wrapper .list-1 .thumbnail .reviews { + position: absolute; + right: 24px; + top: 14px; + padding: 5px 10px; + display: flex; + gap: 5px; + align-items: center; + background: #ffb703; + color: #fff; + border-radius: 5px; +} + +.learndash-course-grid .items-wrapper .list-1 .icon { + justify-content: center; + margin-right: 3px; +} + +.learndash-course-grid .items-wrapper .list-1 .thumbnail .reviews .icon { + font-size: 1rem; + display: flex; + align-items: center; +} + +.learndash-course-grid .items-wrapper .list-1 .thumbnail img { + margin: 0 auto; + padding: 0; + width: 100%; + height: 100%; + max-height: 280px; +} + +.learndash-course-grid .items-wrapper .list-1 .thumbnail .arrow { + position: absolute; + right: 17px; + bottom: -18px; +} + +.learndash-course-grid .items-wrapper .list-1 .arrow::after { + display: none; +} + +.learndash-course-grid .items-wrapper .list-1 .thumbnail .arrow * { + text-decoration: none; +} + +.learndash-course-grid .items-wrapper .list-1 .thumbnail .arrow .icon { + background: #fd9752; + color: #fff; + font-size: 25px; + width: auto; + height: auto; + padding: 5px; + border-radius: 100px; +} + +.learndash-course-grid .items-wrapper .list-1 .content { + color: #333333; + position: relative; + width: 50%; +} + +.learndash-course-grid .items-wrapper .list-1 .content .categories { + color: #fd8534; + font-weight: bold; + margin-bottom: 20px; +} + +.learndash-course-grid .items-wrapper .list-1 .content .author { + display: flex; + gap: 5px; + font-size: 0.875rem; + color: #949ca1; + margin-bottom: 25px; + align-items: center; +} + +.learndash-course-grid .items-wrapper .list-1 .content .author .avatar { + width: 30px; + height: 30px; + border-radius: 30px; + display: block; + border: 2px solid #ff7e55; +} + +.learndash-course-grid .items-wrapper .list-1 .content .author .wrapper { + display: grid; + width: 100%; +} + +.learndash-course-grid .items-wrapper .list-1 .content .author .name { + font-weight: bold; +} + +.learndash-course-grid .items-wrapper .list-1 .content .author .wrapper .lessons { + float: right; +} + +.learndash-course-grid .items-wrapper .list-1 .content .meta { + display: flex; + gap: 15px; + font-size: 0.875rem; + color: #b1b2b2; + margin-bottom: 20px; +} + +.learndash-course-grid .items-wrapper .list-1 .content .meta > div { + display: flex; + align-items: center; +} + +.learndash-course-grid .items-wrapper .list-1 .content .meta .icon { + font-size: 1rem; + display: flex; + align-items: center; +} + +.learndash-course-grid .items-wrapper .list-1 .content .entry-title { + font-size: 1.4rem; + font-weight: bold; + line-height: 1.2; + color: #333; + margin-bottom: 10px; +} + +.learndash-course-grid .items-wrapper .list-1 .content .entry-title a { + text-decoration: none; + color: #333; + font-size: 1.4rem; + line-height: 1.2; + font-weight: bold; +} + +.learndash-course-grid .items-wrapper .list-1 .content .entry-content { + margin-bottom: 20px; + color: #b1b2b2; + font-size: 0.875rem; +} + +.learndash-course-grid .items-wrapper .list-1 .content .entry-content > * { + margin: 0; +} + +.learndash-course-grid .items-wrapper .list-1 .content .button-wrapper { + display: flex; + align-items: center; +} + +.learndash-course-grid .items-wrapper .list-1 .content a.link { + background: none; + color: #a9aaaa; + text-decoration: none; + padding-bottom: 5px; + border-bottom: 2px solid #a9aaaa; +} + +.learndash-course-grid .items-wrapper .list-1 .content .button { + background: none; + border: none; + border-radius: 5px; + padding: 0; + display: flex; + justify-content: space-between; + align-items: center; + margin-left: auto; + min-height: 30px; +} + +.learndash-course-grid .items-wrapper .list-1 .content .button a:hover { + color: #d5d6d6; +} + +.learndash-course-grid .items-wrapper .list-1 .content .button .arrow { + background: #f6617b; + padding: 0px 10px; + color: #fff; + border-radius: 5px; + + width: initial; + height: initial; + overflow: initial; + position: initial; + margin: initial +} + +.learndash-course-grid .items-wrapper .list-1 .content .button .arrow a { + text-decoration: none; + color: #fff; + border: none; + padding: 0; + display: flex; + align-items: center; +} + +@media only screen and ( max-width: 768px ) { + .learndash-course-grid .items-wrapper .list-1 .post { + flex-direction: column; + } + + .learndash-course-grid .items-wrapper .list-1 .thumbnail { + width: 100%; + } + + .learndash-course-grid .items-wrapper .list-1 .content { + width: 100%; + } +} \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/list-2/layout.php b/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/list-2/layout.php new file mode 100644 index 000000000..8df46dc46 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/list-2/layout.php @@ -0,0 +1,153 @@ + +
+
ID ); ?>> + +
+ +
+ +
+ ID ) ) : ?> + + ID ) ) : ?> +
+ +
+ +
+ +
+
+
+ +

+ + + + + + + +

+ +
+ +
+ +
+ + +
+ +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + + +
+ + + + $reviews_floored && floatval( $reviews_number ) > $reviews_floored && $i <= $reviews_ceil ) { + $star_class = 'star-half'; + } else { + $star_class = 'star-empty'; + } + ?> + + + +
+ +
+ + + post_type == 'sfwd-courses' ) : ?> + ID . '" user_id="' . $user_id . '"]' ); ?> + post_type == 'groups' ) : ?> +
+ ID, $user_id ); ?> + 'group', + 'user_id' => $user_id, + 'group_id' => $post->ID, + ), + true + ); + ?> +
+ + +
+
+
diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/list-2/style.css b/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/list-2/style.css new file mode 100644 index 000000000..12df01940 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/templates/cards/list-2/style.css @@ -0,0 +1,286 @@ +.learndash-course-grid .items-wrapper .list-2 .post { + display: flex; + flex-direction: row; + gap: 50px; + margin-bottom: 60px; + padding: 20px; + border-radius: 20px; + box-shadow: 3px 4px 4px 4px rgb(0 0 0 / 10%); + -moz-box-shadow: 3px 4px 4px 4px rgb(0 0 0 / 10%); + -webkit-box-shadow: 3px 4px 4px 4px rgb(0 0 0 / 10%); +} + +.learndash-course-grid .items-wrapper .list-2 .ribbon { + text-shadow: 0 1px rgb( 0 0 0 / 30% ); + position: absolute; + z-index: 2; + top: 0; + right: 0; + left: auto; + padding: 10px 12px; + color: #fff; + background: #f43e5e; + font-weight: bold; + font-size: 1rem; + border-radius: 5px; + display: flex; + align-items: center; + justify-content: center; + max-width: 20%; +} + +.learndash-course-grid .items-wrapper .list-2 .thumbnail { + margin: 0; + padding: 0; + position: relative; +} + +.learndash-course-grid .items-wrapper .list-2 .thumbnail .reviews { + position: absolute; + right: 24px; + top: 14px; + padding: 5px 10px; + display: flex; + gap: 5px; + align-items: center; + background: #ffb703; + color: #fff; + border-radius: 5px; +} + +.learndash-course-grid .items-wrapper .list-2 .content .reviews { + margin-left: auto; +} + +.learndash-course-grid .items-wrapper .list-2 .icon { + justify-content: center; + margin-right: 3px; +} + +.learndash-course-grid .items-wrapper .list-2 .reviews .icon { + font-size: 1rem; + display: flex; + align-items: center; + color: #ffb703; +} + +.learndash-course-grid .items-wrapper .list-2 .thumbnail > div { + height: 100%; + width: auto; + display: flex; + align-items: center; +} + +.learndash-course-grid .items-wrapper .list-2 .thumbnail img { + margin: 0 auto; + padding: 0; + margin: 0 auto; + padding: 0; + height: 150px; + width: 150px; + max-width: initial; + border-radius: 20px; +} + +.learndash-course-grid .items-wrapper .list-2 .thumbnail .arrow { + position: absolute; + right: 17px; + bottom: -18px; +} + +.learndash-course-grid .items-wrapper .list-2 .arrow::after { + display: none; +} + +.learndash-course-grid .items-wrapper .list-2 .thumbnail .arrow * { + text-decoration: none; +} + +.learndash-course-grid .items-wrapper .list-2 .thumbnail .arrow .icon { + background: #fd9752; + color: #fff; + font-size: 25px; + width: auto; + height: auto; + padding: 5px; + border-radius: 100px; +} + +.learndash-course-grid .items-wrapper .list-2 .content { + color: #333333; + position: relative; + width: 100%; + display: flex; + flex-direction: column; +} + +.learndash-course-grid .items-wrapper .list-2 .content > .wrapper { + display: flex; + flex-wrap: wrap; +} + +.learndash-course-grid .items-wrapper .list-2 .content .top-meta { + display: flex; + flex-wrap: wrap; + gap: 15px; + align-items: center; + font-size: 0.875rem; +} + +.learndash-course-grid .items-wrapper .list-2 .content .categories { + color: #949ca1; +} + +.learndash-course-grid .items-wrapper .list-2 .content .author { + color: #949ca1; +} + +.learndash-course-grid .items-wrapper .list-2 .content .author .name { + font-weight: bold; +} + +.learndash-course-grid .items-wrapper .list-2 .content .author .wrapper .lessons { + float: right; +} + +.learndash-course-grid .items-wrapper .list-2 .content .meta { + display: flex; + gap: 15px; + font-size: 0.875rem; + color: #b1b2b2; +} + +.learndash-course-grid .items-wrapper .list-2 .content .meta > div { + display: flex; + align-items: center; +} + +.learndash-course-grid .items-wrapper .list-2 .content .meta .icon { + font-size: 1rem; + display: flex; + align-items: center; +} + +.learndash-course-grid .items-wrapper .list-2 .content .meta .reviews { + gap: 5px; +} + +.learndash-course-grid .items-wrapper .list-2 .content .meta .stars { + display: flex; + align-items: center; +} + +.learndash-course-grid .items-wrapper .list-2 .content .bottom-meta { + margin-top: auto; + margin-bottom: 0; +} + +.learndash-course-grid .items-wrapper .list-2 .content .title-wrapper { + margin-bottom: 25px; + max-width: 75%; +} + +.learndash-course-grid .items-wrapper .list-2 .content .entry-title { + font-size: 1.4rem; + font-weight: bold; + line-height: 1.2; + color: #333; + margin-bottom: 10px; +} + +.learndash-course-grid .items-wrapper .list-2 .content .entry-title a { + text-decoration: none; + color: #333; + font-size: 1.4rem; + line-height: 1.2; + font-weight: bold; +} + +.learndash-course-grid .items-wrapper .list-2 .content .entry-content { + margin-bottom: 20px; + color: #b1b2b2; + font-size: 0.875rem; +} + +.learndash-course-grid .items-wrapper .list-2 .content .entry-content > * { + margin: 0; +} + +.learndash-course-grid .items-wrapper .list-2 .content .button { + background: none; + border: none; + padding: 0; + display: flex; + justify-content: space-between; + align-items: center; +} + +.learndash-course-grid .items-wrapper .list-2 .content .button a { + background: none; + color: #a9aaaa; + text-decoration: none; + padding-bottom: 5px; + border-bottom: 2px solid #a9aaaa; +} + +.learndash-course-grid .items-wrapper .list-2 .content .button a:hover { + color: #d5d6d6; +} + +.learndash-course-grid .items-wrapper .list-2 .content .button .arrow { + background: #f6617b; + padding: 5px 10px; + color: #fff; + border-radius: 5px; + + width: initial; + height: initial; + overflow: initial; + position: initial; + margin: initial +} + +.learndash-course-grid .items-wrapper .list-2 .content .button .arrow a { + text-decoration: none; + color: #fff; + border: none; + padding: 0; + display: flex; + align-items: center; +} + +@media only screen and ( max-width: 768px ) { + .learndash-course-grid .items-wrapper .list-2 .post { + flex-direction: column; + gap: 25px; + } + + .learndash-course-grid .items-wrapper .list-2 .thumbnail { + width: 100%; + } + + .learndash-course-grid .items-wrapper .list-2 .thumbnail > div { + display: initial; + } + + .learndash-course-grid .items-wrapper .list-2 .thumbnail img { + width: 100%; + height: auto; + } + + .learndash-course-grid .items-wrapper .list-2 .content { + width: 100%; + } + + .learndash-course-grid .items-wrapper .list-2 .content .title-wrapper { + margin-bottom: 10px; + } + + .learndash-course-grid .items-wrapper .list-2 .content .meta { + flex-wrap: wrap; + } + + .learndash-course-grid .items-wrapper .list-2 .content .ribbon { + display: none; + } +} \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/filter/layout.php b/web/app/plugins/sfwd-lms/includes/course-grid/templates/filter/layout.php new file mode 100644 index 000000000..d035c31ea --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/templates/filter/layout.php @@ -0,0 +1,99 @@ + +
+
+ + + + + + +
+
+ + $taxonomy, + 'orderby' => 'name', + 'order' => 'ASC', + 'hide_empty' => false, + ] + ); + + ?> + +
+ +
    + +
  • + +
  • + +
+
+ + +
+
+ + + +
+ +
+ + +
+
+
+ + +
+
+ + +
+
+
+ + +
+ + +
+
+
diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/filter/style.css b/web/app/plugins/sfwd-lms/includes/course-grid/templates/filter/style.css new file mode 100644 index 000000000..07ccfea4a --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/templates/filter/style.css @@ -0,0 +1,280 @@ +.toggle-filter { + position: sticky; + left: 100%; + margin-bottom: 20px; +} + +.toggle-filter.opened::before { + content: "\f158"; + font-family: 'Dashicons'; + padding-right: 10px; + top: 1px; + position: relative; +} + +.learndash-course-grid { + position: relative; +} + +.learndash-course-grid .learndash-course-grid-filter { + position: absolute; + max-width: 300px; +} + +.learndash-course-grid .learndash-course-grid-filter { + display: none; +} + +.learndash-course-grid-filter { + max-width: 300px; + min-width: 300px; + background: white; + padding: 15px 20px; + border-radius: 5px; + z-index: 2000; + margin: 0 auto; + border: 2px solid #ddd; +} + +.learndash-course-grid .learndash-course-grid-filter { + right: 0; + position: absolute; +} + +.learndash-course-grid-filter form { + margin: 0; +} + +.learndash-course-grid-filter form input:focus, +.learndash-course-grid-filter form select:focus { + outline: none; +} + +/* Range Input */ + +.learndash-course-grid-filter form input[type=range] { + -webkit-appearance: none; + margin: 18px 0; + width: 100%; +} + +.learndash-course-grid-filter form input[type=range]:focus { + outline: none; +} + +.learndash-course-grid-filter form input[type=range]::-webkit-slider-runnable-track { + width: 100%; + height: 8.4px; + cursor: pointer; + background: #0077ff; + border-radius: 1.3px; +} + +.learndash-course-grid-filter form input[type="range"]:first-child::-webkit-slider-runnable-track { + border-top-left-radius: 10px; + border-bottom-left-radius: 10px; + border-right: none; +} + +.learndash-course-grid-filter form input[type="range"]:nth-child(2)::-webkit-slider-runnable-track { + border-top-right-radius: 10px; + border-bottom-right-radius: 10px; + border-left: none; +} + +.learndash-course-grid-filter form input[type=range]::-webkit-slider-thumb { + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; + border: 1px solid #000000; + height: 16px; + width: 16px; + border-radius: 10px; + background: #ffffff; + cursor: pointer; + -webkit-appearance: none; + margin-top: -5px; +} + +.learndash-course-grid-filter form input[type=range]:focus::-webkit-slider-runnable-track { + background: #0077ff; +} + +.learndash-course-grid-filter form input[type=range]::-moz-range-track { + width: 100%; + height: 8.4px; + cursor: pointer; + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; + background: #0077ff; + border-radius: 1.3px; + border: 0.2px solid #010101; +} + +.learndash-course-grid-filter form input[type=range]::-moz-range-thumb { + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; + border: 1px solid #000000; + height: 16px; + width: 16px; + border-radius: 10px; + background: #ffffff; + cursor: pointer; +} + +.learndash-course-grid-filter form input[type=range]::-ms-track { + width: 100%; + height: 8.4px; + cursor: pointer; + background: transparent; + border-color: transparent; + border-width: 16px 0; + color: transparent; +} + +.learndash-course-grid-filter form input[type=range]::-ms-fill-lower { + background: #2a6495; + border: 0.2px solid #010101; + border-radius: 2.6px; + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; +} + +.learndash-course-grid-filter form input[type=range]::-ms-fill-upper { + background: #0077ff; + border: 0.2px solid #010101; + border-radius: 2.6px; + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; +} + +.learndash-course-grid-filter form input[type=range]::-ms-thumb { + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; + border: 1px solid #000000; + height: 16px; + width: 16px; + border-radius: 10px; + background: #ffffff; + cursor: pointer; +} + +.learndash-course-grid-filter form input[type=range]:focus::-ms-fill-lower { + background: #0077ff; +} + +.learndash-course-grid-filter form input[type=range]:focus::-ms-fill-upper { + background: #0077ff; +} + +/* End Range Input */ + +.learndash-course-grid-filter .filter { + margin-bottom: 15px; +} + +.learndash-course-grid-filter .taxonomies-wrapper .terms { + list-style-type: none; + padding: 0 0 15px 20px; + margin: 0; + max-height: 150px; + overflow: auto; +} + +.learndash-course-grid-filter .filter.price label { + display: block; +} + +/* .learndash-course-grid-filter .filter.price .range-wrapper { + position: relative; + left: 8px; +} */ + +.learndash-course-grid-filter .filter.price .range-wrapper :first-child { + width: 50%; + float: left; +} + +.learndash-course-grid-filter .filter.price .range-wrapper :nth-child(2) { + width: 50%; + float: right; +} + +.learndash-course-grid-filter .filter.price .number-wrapper.left { + float: left; + text-align: left; +} + +.learndash-course-grid-filter .filter.price .number-wrapper.right { + float: right; + text-align: right; +} + +.learndash-course-grid-filter .filter.price .number-wrapper label, +.learndash-course-grid-filter .filter.price .number-wrapper input { + display: block; +} + +.learndash-course-grid-filter .filter.price .number-wrapper input { + width: 80px; +} + +.learndash-course-grid-filter .filter.price input[type="range"] { + margin-bottom: 10px; +} + +.learndash-course-grid-filter input[type="text"], +.learndash-course-grid-filter input[type="range"] { + display: block; + width: 100%; +} + +.learndash-course-grid-filter input[type="text"] { + padding: 5px; +} + +.learndash-course-grid-filter .buttons { + margin-top: 0; +} + +.toggle-filter, +.learndash-course-grid-filter .buttons .button { + display: block; + margin-bottom: 10px; + border-radius: 3px; + padding: 0.5rem 1rem; + font-weight: 600; + text-decoration: none; + font-size: 1rem; + border: 3px solid #ddd; + -webkit-transition: all 0.3s ease; + transition: all 0.3s ease; + text-align: center; + display: -ms-flexbox; + display: flex; + justify-content: center; + -ms-flex-align: center; + align-items: center; + cursor: pointer; +} + +.learndash-course-grid-filter .buttons .button { + width: 100%; +} + +.learndash-course-grid-filter .buttons .button.blue { + color: #ffffff; + background-color: #235af4; + border-color: #235af4; +} + +.learndash-course-grid-filter .buttons .button.blue:hover { + background: #0d9dff; + border-color: #0d9dff; +} + +.toggle-filter, +.learndash-course-grid-filter .buttons .button.grey { + color: #333333; + background-color: #eeeeee; + border-color: #eeeeee; +} + +.toggle-filter:hover, +.learndash-course-grid-filter .buttons .button.grey:hover { + background-color: #d5d5d5; + border-color: #d5d5d5; +} \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/pagination/button.php b/web/app/plugins/sfwd-lms/includes/course-grid/templates/pagination/button.php new file mode 100644 index 000000000..2fd3aeeeb --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/templates/pagination/button.php @@ -0,0 +1,17 @@ + + diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/pagination/infinite.php b/web/app/plugins/sfwd-lms/includes/course-grid/templates/pagination/infinite.php new file mode 100644 index 000000000..f560af695 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/templates/pagination/infinite.php @@ -0,0 +1,17 @@ + + diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/pagination/style.css b/web/app/plugins/sfwd-lms/includes/course-grid/templates/pagination/style.css new file mode 100644 index 000000000..6c349fd8d --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/templates/pagination/style.css @@ -0,0 +1,42 @@ +.learndash-course-grid .pagination { + text-align: center; + border: 0; + margin: 0; + padding: 0; +} + +.learndash-course-grid .pagination::before, +.learndash-course-grid .pagination::after { + display: none; +} + +.learndash-course-grid .pagination .load-more { + margin: 0 auto; + border-radius: 3px; + background-color: #fd6703; + color: #ffffff; + padding: 10px 50px; + padding: 0.75rem 2rem; + font-weight: 600; + text-decoration: none; + font-size: 1.4rem; + border: 3px solid #fd6703; + -webkit-transition: all 0.3s ease; + transition: all 0.3s ease; + text-align: center; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + cursor: pointer; +} + +.learndash-course-grid .pagination .load-more:hover { + background-color: #f7883e; + border-color: #f7883e; +} \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/grid/layout.php b/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/grid/layout.php new file mode 100644 index 000000000..c4e4103ad --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/grid/layout.php @@ -0,0 +1,24 @@ +get_posts(). + * @var array $atts Shortcode/Block editor attributes that call this template. + */ + +if ( ! defined( 'ABSPATH' ) ) { + exit(); +} +?> +
+ + + +
diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/grid/script.js b/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/grid/script.js new file mode 100644 index 000000000..03a887090 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/grid/script.js @@ -0,0 +1,65 @@ +/** +* Responsive design +*/ +function learndash_course_grid_init_grid_responsive_design() { + const wrappers = document.querySelectorAll( '.learndash-course-grid[data-skin="grid"]' ); + + wrappers.forEach( function( wrapper ) { + const items_wrapper = wrapper.querySelector( '.items-wrapper.grid' ); + + if ( ! items_wrapper ) { + return; + } + + const first_item = items_wrapper.firstElementChild; + + if ( ! first_item ) { + return; + } + + // Set columns + const min_width = wrapper.dataset.min_column_width; + + let columns = wrapper.dataset.columns; + columns = parseInt( columns ); + let new_columns = wrapper.dataset.new_columns || columns; + new_columns = parseInt( new_columns ); + + const wrapper_width = wrapper.offsetWidth; + let upper_columns = new_columns + 1; + upper_columns = upper_columns > columns ? columns : upper_columns; + const min_item_width = wrapper_width / upper_columns; + + new_columns = Math.floor( wrapper_width / min_width ); + + let item_width = first_item.offsetWidth; + + if ( item_width < min_width ) { + new_columns = new_columns > columns ? columns : new_columns; + new_columns = new_columns < 1 ? 1 : new_columns; + wrapper.dataset.new_columns = new_columns; + items_wrapper.style.gridTemplateColumns = 'repeat( ' + new_columns + ', minmax( 0, 1fr ) )'; + } else if ( min_item_width > min_width ) { + new_columns = new_columns > columns ? columns : new_columns; + new_columns = new_columns < 1 ? 1 : new_columns; + wrapper.dataset.new_columns = new_columns; + items_wrapper.style.gridTemplateColumns = 'repeat( ' + new_columns + ', minmax( 0, 1fr ) )'; + } + + const items = items_wrapper.querySelectorAll( '.item' ); + items.forEach( function( item ) { + // Display item + item.style.visibility = 'visible'; + } ); + } ); +} + +( function() { + window.addEventListener( 'resize', function() { + learndash_course_grid_init_grid_responsive_design(); + } ); + + window.addEventListener( 'load', function() { + learndash_course_grid_init_grid_responsive_design(); + } ); +} )(); diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/grid/style.css b/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/grid/style.css new file mode 100644 index 000000000..b471ca5ce --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/grid/style.css @@ -0,0 +1,17 @@ +.learndash-course-grid .items-wrapper.grid { + display: grid; + grid-template-columns: repeat( 3, minmax( 0, 1fr ) ); + column-gap: 30px; + row-gap: 30px; + margin-bottom: 30px; +} + +.learndash-course-grid .items-wrapper.grid .item { + visibility: hidden; +} + +.learndash-course-grid .items-wrapper.grid .item .content .entry-content { + float: none; + margin: auto; + width: auto; +} \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/legacy-v1/item.php b/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/legacy-v1/item.php new file mode 100644 index 000000000..cc1b542f1 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/legacy-v1/item.php @@ -0,0 +1,174 @@ + 6 ? 6 : $col; +$smcol = $col == 1 ? 1 : $col / 2; +$col = 12 / $col; +$smcol = intval( ceil( 12 / $smcol ) ); +$col = is_float( $col ) ? number_format( $col, 1 ) : $col; +$col = str_replace( '.', '-', $col ); + +global $post; +$post_id = $post->ID; + +$post_atts = learndash_course_grid_prepare_template_post_attributes( $post, [], $shortcode_atts ); + +extract( $post_atts ); + +$post_type = get_post_type( $post->ID ); + +$course_id = $post_id; +$user_id = get_current_user_id(); + +// Retrieve oembed HTML if a URL is provided. +if ( preg_match( '/^http/', $video_embed_code ) ) { + $video_embed_code = wp_oembed_get( + $video_embed_code, + array( + 'height' => 600, + 'width' => 400, + ) + ); +} + +$course_options = get_post_meta( $post_id, '_sfwd-courses', true ); + +/** + * Filters the individual grid classes. + * + * @since 4.21.4 + * + * @param string $class_names Class names. + * @param int $course_id Course ID. + * @param array $course_options Course options. + * + * @return string Class names. + */ +$grid_class = apply_filters( 'learndash_course_grid_class', '', $course_id, $course_options ); + +/** + * Filters the course class in course grid. + * + * @since 4.21.4 + * + * @param string $class_name Course class names. + * @param int $course_id Course ID. + * @param array $course_options Course options. + * + * @return string Course class names. + */ +$course_class = apply_filters( 'learndash_course_grid_course_class', '', $course_id, $course_options ); + +$thumb_size = isset( $shortcode_atts['thumb_size'] ) && ! empty( $shortcode_atts['thumb_size'] ) ? $shortcode_atts['thumb_size'] : 'medium'; + +ob_start(); +?> +
+
> + + +
+ +
+ + + +
+ +
+ + + + + + + + +
+

+ +
+ +
+ + + +
+ + + + +
+ + 'group', + 'user_id' => $user_id, + 'group_id' => $post_id, + ), + true + ); + ?> +
+ + +
+ +
+
+'; + +/** + * Filters the course grid HTML output. + * + * @since 4.21.4 + * + * @param string $output Individual course grid HTML output + * @param object $post LD course WP_Post object + * @param array $shortcode_atts Shortcode attributes used for this course grid output + * @param int $user_id Current user ID this course grid is displayed to + * + * @return string Filtered course grid HTML output + */ +echo apply_filters( 'learndash_course_grid_html_output', $tag . ob_get_clean(), $post, $shortcode_atts, $user_id ); diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/legacy-v1/style.css b/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/legacy-v1/style.css new file mode 100644 index 000000000..ed5936a4e --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/legacy-v1/style.css @@ -0,0 +1,1093 @@ +/** + * Bootstrap styles + */ + +.ld-course-list-items .container { + width: 100%; + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} + + +@media (min-width: 576px) { + .ld-course-list-items .container { + max-width: 540px; + } +} + +@media (min-width: 768px) { + .ld-course-list-items .container { + max-width: 720px; + } +} + +@media (min-width: 992px) { + .ld-course-list-items .container { + max-width: 960px; + } +} + +@media (min-width: 1200px) { + .ld-course-list-items .container { + max-width: 1140px; + } +} + +.ld-course-list-items .container-fluid { + width: 100%; + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} + +.ld-course-list-items.row { + display: flex; + flex-wrap: wrap; + margin-right: -15px; + margin-left: -15px; +} + +.ld-course-list-items .no-gutters { + margin-right: 0; + margin-left: 0; +} + +.ld-course-list-items .no-gutters > .col, +.ld-course-list-items .no-gutters > [class*=col-] { + padding-right: 0; + padding-left: 0; +} + +.ld-course-list-items .col-xl, +.ld-course-list-items .col-xl-auto, .ld-course-list-items .col-xl-12, .ld-course-list-items .col-xl-11, .ld-course-list-items .col-xl-10, .ld-course-list-items .col-xl-9, .ld-course-list-items .col-xl-8, .ld-course-list-items .col-xl-7, .ld-course-list-items .col-xl-6, .ld-course-list-items .col-xl-5, .ld-course-list-items .col-xl-4, .ld-course-list-items .col-xl-3, .ld-course-list-items .col-xl-2, .ld-course-list-items .col-xl-1, .ld-course-list-items .col-lg, +.ld-course-list-items .col-lg-auto, .ld-course-list-items .col-lg-12, .ld-course-list-items .col-lg-11, .ld-course-list-items .col-lg-10, .ld-course-list-items .col-lg-9, .ld-course-list-items .col-lg-8, .ld-course-list-items .col-lg-7, .ld-course-list-items .col-lg-6, .ld-course-list-items .col-lg-5, .ld-course-list-items .col-lg-4, .ld-course-list-items .col-lg-3, .ld-course-list-items .col-lg-2, .ld-course-list-items .col-lg-1, .ld-course-list-items .col-md, +.ld-course-list-items .col-md-auto, .ld-course-list-items .col-md-12, .ld-course-list-items .col-md-11, .ld-course-list-items .col-md-10, .ld-course-list-items .col-md-9, .ld-course-list-items .col-md-8, .ld-course-list-items .col-md-7, .ld-course-list-items .col-md-6, .ld-course-list-items .col-md-5, .ld-course-list-items .col-md-4, .ld-course-list-items .col-md-3, .ld-course-list-items .col-md-2, .ld-course-list-items .col-md-1, .ld-course-list-items .col-sm, +.ld-course-list-items .col-sm-auto, .ld-course-list-items .col-sm-12, .ld-course-list-items .col-sm-11, .ld-course-list-items .col-sm-10, .ld-course-list-items .col-sm-9, .ld-course-list-items .col-sm-8, .ld-course-list-items .col-sm-7, .ld-course-list-items .col-sm-6, .ld-course-list-items .col-sm-5, .ld-course-list-items .col-sm-4, .ld-course-list-items .col-sm-3, .ld-course-list-items .col-sm-2, .ld-course-list-items .col-sm-1, .ld-course-list-items .col, +.ld-course-list-items .col-auto, .ld-course-list-items .col-12, .ld-course-list-items .col-11, .ld-course-list-items .col-10, .ld-course-list-items .col-9, .ld-course-list-items .col-8, .ld-course-list-items .col-7, .ld-course-list-items .col-6, .ld-course-list-items .col-5, .ld-course-list-items .col-4, .ld-course-list-items .col-3, .ld-course-list-items .col-2, .ld-course-list-items .col-1 { + position: relative; + width: 100%; + min-height: 1px; + padding-right: 15px; + padding-left: 15px; +} + +.ld-course-list-items .col { + flex-basis: 0; + flex-grow: 1; + max-width: 100%; +} + +.ld-course-list-items .col-auto { + flex: 0 0 auto; + width: auto; + max-width: none; +} + +.ld-course-list-items .col-1 { + flex: 0 0 8.3333333333%; + max-width: 8.3333333333%; +} + +.ld-course-list-items .col-2 { + flex: 0 0 16.6666666667%; + max-width: 16.6666666667%; +} + +.ld-course-list-items .col-3 { + flex: 0 0 25%; + max-width: 25%; +} + +.ld-course-list-items .col-4 { + flex: 0 0 33.3333333333%; + max-width: 33.3333333333%; +} + +.ld-course-list-items .col-5 { + flex: 0 0 41.6666666667%; + max-width: 41.6666666667%; +} + +.ld-course-list-items .col-6 { + flex: 0 0 50%; + max-width: 50%; +} + +.ld-course-list-items .col-7 { + flex: 0 0 58.3333333333%; + max-width: 58.3333333333%; +} + +.ld-course-list-items .col-8 { + flex: 0 0 66.6666666667%; + max-width: 66.6666666667%; +} + +.ld-course-list-items .col-9 { + flex: 0 0 75%; + max-width: 75%; +} + +.ld-course-list-items .col-10 { + flex: 0 0 83.3333333333%; + max-width: 83.3333333333%; +} + +.ld-course-list-items .col-11 { + flex: 0 0 91.6666666667%; + max-width: 91.6666666667%; +} + +.ld-course-list-items .col-12 { + flex: 0 0 100%; + max-width: 100%; +} + +.ld-course-list-items .order-first { + order: -1; +} + +.ld-course-list-items .order-last { + order: 13; +} + +.ld-course-list-items .order-0 { + order: 0; +} + +.ld-course-list-items .order-1 { + order: 1; +} + +.ld-course-list-items .order-2 { + order: 2; +} + +.ld-course-list-items .order-3 { + order: 3; +} + +.ld-course-list-items .order-4 { + order: 4; +} + +.ld-course-list-items .order-5 { + order: 5; +} + +.ld-course-list-items .order-6 { + order: 6; +} + +.ld-course-list-items .order-7 { + order: 7; +} + +.ld-course-list-items .order-8 { + order: 8; +} + +.ld-course-list-items .order-9 { + order: 9; +} + +.ld-course-list-items .order-10 { + order: 10; +} + +.ld-course-list-items .order-11 { + order: 11; +} + +.ld-course-list-items .order-12 { + order: 12; +} + +.ld-course-list-items .offset-1 { + margin-left: 8.3333333333%; +} + +.ld-course-list-items .offset-2 { + margin-left: 16.6666666667%; +} + +.ld-course-list-items .offset-3 { + margin-left: 25%; +} + +.ld-course-list-items .offset-4 { + margin-left: 33.3333333333%; +} + +.ld-course-list-items .offset-5 { + margin-left: 41.6666666667%; +} + +.ld-course-list-items .offset-6 { + margin-left: 50%; +} + +.ld-course-list-items .offset-7 { + margin-left: 58.3333333333%; +} + +.ld-course-list-items .offset-8 { + margin-left: 66.6666666667%; +} + +.ld-course-list-items .offset-9 { + margin-left: 75%; +} + +.ld-course-list-items .offset-10 { + margin-left: 83.3333333333%; +} + +.ld-course-list-items .offset-11 { + margin-left: 91.6666666667%; +} + +@media (min-width: 576px) { + .ld-course-list-items .col-sm { + flex-basis: 0; + flex-grow: 1; + max-width: 100%; + } + .ld-course-list-items .col-sm-auto { + flex: 0 0 auto; + width: auto; + max-width: none; + } + .ld-course-list-items .col-sm-1 { + flex: 0 0 8.3333333333%; + max-width: 8.3333333333%; + } + .ld-course-list-items .col-sm-2 { + flex: 0 0 16.6666666667%; + max-width: 16.6666666667%; + } + .ld-course-list-items .col-sm-3 { + flex: 0 0 25%; + max-width: 25%; + } + .ld-course-list-items .col-sm-4 { + flex: 0 0 33.3333333333%; + max-width: 33.3333333333%; + } + .ld-course-list-items .col-sm-5 { + flex: 0 0 41.6666666667%; + max-width: 41.6666666667%; + } + .ld-course-list-items .col-sm-6 { + flex: 0 0 50%; + max-width: 50%; + } + .ld-course-list-items .col-sm-7 { + flex: 0 0 58.3333333333%; + max-width: 58.3333333333%; + } + .ld-course-list-items .col-sm-8 { + flex: 0 0 66.6666666667%; + max-width: 66.6666666667%; + } + .ld-course-list-items .col-sm-9 { + flex: 0 0 75%; + max-width: 75%; + } + .ld-course-list-items .col-sm-10 { + flex: 0 0 83.3333333333%; + max-width: 83.3333333333%; + } + .ld-course-list-items .col-sm-11 { + flex: 0 0 91.6666666667%; + max-width: 91.6666666667%; + } + .ld-course-list-items .col-sm-12 { + flex: 0 0 100%; + max-width: 100%; + } + .ld-course-list-items .order-sm-first { + order: -1; + } + .ld-course-list-items .order-sm-last { + order: 13; + } + .ld-course-list-items .order-sm-0 { + order: 0; + } + .ld-course-list-items .order-sm-1 { + order: 1; + } + .ld-course-list-items .order-sm-2 { + order: 2; + } + .ld-course-list-items .order-sm-3 { + order: 3; + } + .ld-course-list-items .order-sm-4 { + order: 4; + } + .ld-course-list-items .order-sm-5 { + order: 5; + } + .ld-course-list-items .order-sm-6 { + order: 6; + } + .ld-course-list-items .order-sm-7 { + order: 7; + } + .ld-course-list-items .order-sm-8 { + order: 8; + } + .ld-course-list-items .order-sm-9 { + order: 9; + } + .ld-course-list-items .order-sm-10 { + order: 10; + } + .ld-course-list-items .order-sm-11 { + order: 11; + } + .ld-course-list-items .order-sm-12 { + order: 12; + } + .ld-course-list-items .offset-sm-0 { + margin-left: 0; + } + .ld-course-list-items .offset-sm-1 { + margin-left: 8.3333333333%; + } + .ld-course-list-items .offset-sm-2 { + margin-left: 16.6666666667%; + } + .ld-course-list-items .offset-sm-3 { + margin-left: 25%; + } + .ld-course-list-items .offset-sm-4 { + margin-left: 33.3333333333%; + } + .ld-course-list-items .offset-sm-5 { + margin-left: 41.6666666667%; + } + .ld-course-list-items .offset-sm-6 { + margin-left: 50%; + } + .ld-course-list-items .offset-sm-7 { + margin-left: 58.3333333333%; + } + .ld-course-list-items .offset-sm-8 { + margin-left: 66.6666666667%; + } + .ld-course-list-items .offset-sm-9 { + margin-left: 75%; + } + .ld-course-list-items .offset-sm-10 { + margin-left: 83.3333333333%; + } + .ld-course-list-items .offset-sm-11 { + margin-left: 91.6666666667%; + } +} + +@media (min-width: 768px) { + .ld-course-list-items .col-md { + flex-basis: 0; + flex-grow: 1; + max-width: 100%; + } + .ld-course-list-items .col-md-auto { + flex: 0 0 auto; + width: auto; + max-width: none; + } + .ld-course-list-items .col-md-1 { + flex: 0 0 8.3333333333%; + max-width: 8.3333333333%; + } + .ld-course-list-items .col-md-2 { + flex: 0 0 16.6666666667%; + max-width: 16.6666666667%; + } + .ld-course-list-items .col-md-3 { + flex: 0 0 25%; + max-width: 25%; + } + .ld-course-list-items .col-md-4 { + flex: 0 0 33.3333333333%; + max-width: 33.3333333333%; + } + .ld-course-list-items .col-md-5 { + flex: 0 0 41.6666666667%; + max-width: 41.6666666667%; + } + .ld-course-list-items .col-md-6 { + flex: 0 0 50%; + max-width: 50%; + } + .ld-course-list-items .col-md-7 { + flex: 0 0 58.3333333333%; + max-width: 58.3333333333%; + } + .ld-course-list-items .col-md-8 { + flex: 0 0 66.6666666667%; + max-width: 66.6666666667%; + } + .ld-course-list-items .col-md-9 { + flex: 0 0 75%; + max-width: 75%; + } + .ld-course-list-items .col-md-10 { + flex: 0 0 83.3333333333%; + max-width: 83.3333333333%; + } + .ld-course-list-items .col-md-11 { + flex: 0 0 91.6666666667%; + max-width: 91.6666666667%; + } + .ld-course-list-items .col-md-12 { + flex: 0 0 100%; + max-width: 100%; + } + .ld-course-list-items .order-md-first { + order: -1; + } + .ld-course-list-items .order-md-last { + order: 13; + } + .ld-course-list-items .order-md-0 { + order: 0; + } + .ld-course-list-items .order-md-1 { + order: 1; + } + .ld-course-list-items .order-md-2 { + order: 2; + } + .ld-course-list-items .order-md-3 { + order: 3; + } + .ld-course-list-items .order-md-4 { + order: 4; + } + .ld-course-list-items .order-md-5 { + order: 5; + } + .ld-course-list-items .order-md-6 { + order: 6; + } + .ld-course-list-items .order-md-7 { + order: 7; + } + .ld-course-list-items .order-md-8 { + order: 8; + } + .ld-course-list-items .order-md-9 { + order: 9; + } + .ld-course-list-items .order-md-10 { + order: 10; + } + .ld-course-list-items .order-md-11 { + order: 11; + } + .ld-course-list-items .order-md-12 { + order: 12; + } + .ld-course-list-items .offset-md-0 { + margin-left: 0; + } + .ld-course-list-items .offset-md-1 { + margin-left: 8.3333333333%; + } + .ld-course-list-items .offset-md-2 { + margin-left: 16.6666666667%; + } + .ld-course-list-items .offset-md-3 { + margin-left: 25%; + } + .ld-course-list-items .offset-md-4 { + margin-left: 33.3333333333%; + } + .ld-course-list-items .offset-md-5 { + margin-left: 41.6666666667%; + } + .ld-course-list-items .offset-md-6 { + margin-left: 50%; + } + .ld-course-list-items .offset-md-7 { + margin-left: 58.3333333333%; + } + .ld-course-list-items .offset-md-8 { + margin-left: 66.6666666667%; + } + .ld-course-list-items .offset-md-9 { + margin-left: 75%; + } + .ld-course-list-items .offset-md-10 { + margin-left: 83.3333333333%; + } + .ld-course-list-items .offset-md-11 { + margin-left: 91.6666666667%; + } +} + +@media (min-width: 992px) { + .ld-course-list-items .col-lg { + flex-basis: 0; + flex-grow: 1; + max-width: 100%; + } + .ld-course-list-items .col-lg-auto { + flex: 0 0 auto; + width: auto; + max-width: none; + } + .ld-course-list-items .col-lg-1 { + flex: 0 0 8.3333333333%; + max-width: 8.3333333333%; + } + .ld-course-list-items .col-lg-2 { + flex: 0 0 16.6666666667%; + max-width: 16.6666666667%; + } + .ld-course-list-items .col-lg-3 { + flex: 0 0 25%; + max-width: 25%; + } + .ld-course-list-items .col-lg-4 { + flex: 0 0 33.3333333333%; + max-width: 33.3333333333%; + } + .ld-course-list-items .col-lg-5 { + flex: 0 0 41.6666666667%; + max-width: 41.6666666667%; + } + .ld-course-list-items .col-lg-6 { + flex: 0 0 50%; + max-width: 50%; + } + .ld-course-list-items .col-lg-7 { + flex: 0 0 58.3333333333%; + max-width: 58.3333333333%; + } + .ld-course-list-items .col-lg-8 { + flex: 0 0 66.6666666667%; + max-width: 66.6666666667%; + } + .ld-course-list-items .col-lg-9 { + flex: 0 0 75%; + max-width: 75%; + } + .ld-course-list-items .col-lg-10 { + flex: 0 0 83.3333333333%; + max-width: 83.3333333333%; + } + .ld-course-list-items .col-lg-11 { + flex: 0 0 91.6666666667%; + max-width: 91.6666666667%; + } + .ld-course-list-items .col-lg-12 { + flex: 0 0 100%; + max-width: 100%; + } + .ld-course-list-items .order-lg-first { + order: -1; + } + .ld-course-list-items .order-lg-last { + order: 13; + } + .ld-course-list-items .order-lg-0 { + order: 0; + } + .ld-course-list-items .order-lg-1 { + order: 1; + } + .ld-course-list-items .order-lg-2 { + order: 2; + } + .ld-course-list-items .order-lg-3 { + order: 3; + } + .ld-course-list-items .order-lg-4 { + order: 4; + } + .ld-course-list-items .order-lg-5 { + order: 5; + } + .ld-course-list-items .order-lg-6 { + order: 6; + } + .ld-course-list-items .order-lg-7 { + order: 7; + } + .ld-course-list-items .order-lg-8 { + order: 8; + } + .ld-course-list-items .order-lg-9 { + order: 9; + } + .ld-course-list-items .order-lg-10 { + order: 10; + } + .ld-course-list-items .order-lg-11 { + order: 11; + } + .ld-course-list-items .order-lg-12 { + order: 12; + } + .ld-course-list-items .offset-lg-0 { + margin-left: 0; + } + .ld-course-list-items .offset-lg-1 { + margin-left: 8.3333333333%; + } + .ld-course-list-items .offset-lg-2 { + margin-left: 16.6666666667%; + } + .ld-course-list-items .offset-lg-3 { + margin-left: 25%; + } + .ld-course-list-items .offset-lg-4 { + margin-left: 33.3333333333%; + } + .ld-course-list-items .offset-lg-5 { + margin-left: 41.6666666667%; + } + .ld-course-list-items .offset-lg-6 { + margin-left: 50%; + } + .ld-course-list-items .offset-lg-7 { + margin-left: 58.3333333333%; + } + .ld-course-list-items .offset-lg-8 { + margin-left: 66.6666666667%; + } + .ld-course-list-items .offset-lg-9 { + margin-left: 75%; + } + .ld-course-list-items .offset-lg-10 { + margin-left: 83.3333333333%; + } + .ld-course-list-items .offset-lg-11 { + margin-left: 91.6666666667%; + } +} + +@media (min-width: 1200px) { + .ld-course-list-items .col-xl { + flex-basis: 0; + flex-grow: 1; + max-width: 100%; + } + .ld-course-list-items .col-xl-auto { + flex: 0 0 auto; + width: auto; + max-width: none; + } + .ld-course-list-items .col-xl-1 { + flex: 0 0 8.3333333333%; + max-width: 8.3333333333%; + } + .ld-course-list-items .col-xl-2 { + flex: 0 0 16.6666666667%; + max-width: 16.6666666667%; + } + .ld-course-list-items .col-xl-3 { + flex: 0 0 25%; + max-width: 25%; + } + .ld-course-list-items .col-xl-4 { + flex: 0 0 33.3333333333%; + max-width: 33.3333333333%; + } + .ld-course-list-items .col-xl-5 { + flex: 0 0 41.6666666667%; + max-width: 41.6666666667%; + } + .ld-course-list-items .col-xl-6 { + flex: 0 0 50%; + max-width: 50%; + } + .ld-course-list-items .col-xl-7 { + flex: 0 0 58.3333333333%; + max-width: 58.3333333333%; + } + .ld-course-list-items .col-xl-8 { + flex: 0 0 66.6666666667%; + max-width: 66.6666666667%; + } + .ld-course-list-items .col-xl-9 { + flex: 0 0 75%; + max-width: 75%; + } + .ld-course-list-items .col-xl-10 { + flex: 0 0 83.3333333333%; + max-width: 83.3333333333%; + } + .ld-course-list-items .col-xl-11 { + flex: 0 0 91.6666666667%; + max-width: 91.6666666667%; + } + .ld-course-list-items .col-xl-12 { + flex: 0 0 100%; + max-width: 100%; + } + .ld-course-list-items .order-xl-first { + order: -1; + } + .ld-course-list-items .order-xl-last { + order: 13; + } + .ld-course-list-items .order-xl-0 { + order: 0; + } + .ld-course-list-items .order-xl-1 { + order: 1; + } + .ld-course-list-items .order-xl-2 { + order: 2; + } + .ld-course-list-items .order-xl-3 { + order: 3; + } + .ld-course-list-items .order-xl-4 { + order: 4; + } + .ld-course-list-items .order-xl-5 { + order: 5; + } + .ld-course-list-items .order-xl-6 { + order: 6; + } + .ld-course-list-items .order-xl-7 { + order: 7; + } + .ld-course-list-items .order-xl-8 { + order: 8; + } + .ld-course-list-items .order-xl-9 { + order: 9; + } + .ld-course-list-items .order-xl-10 { + order: 10; + } + .ld-course-list-items .order-xl-11 { + order: 11; + } + .ld-course-list-items .order-xl-12 { + order: 12; + } + .ld-course-list-items .offset-xl-0 { + margin-left: 0; + } + .ld-course-list-items .offset-xl-1 { + margin-left: 8.3333333333%; + } + .ld-course-list-items .offset-xl-2 { + margin-left: 16.6666666667%; + } + .ld-course-list-items .offset-xl-3 { + margin-left: 25%; + } + .ld-course-list-items .offset-xl-4 { + margin-left: 33.3333333333%; + } + .ld-course-list-items .offset-xl-5 { + margin-left: 41.6666666667%; + } + .ld-course-list-items .offset-xl-6 { + margin-left: 50%; + } + .ld-course-list-items .offset-xl-7 { + margin-left: 58.3333333333%; + } + .ld-course-list-items .offset-xl-8 { + margin-left: 66.6666666667%; + } + .ld-course-list-items .offset-xl-9 { + margin-left: 75%; + } + .ld-course-list-items .offset-xl-10 { + margin-left: 83.3333333333%; + } + .ld-course-list-items .offset-xl-11 { + margin-left: 91.6666666667%; + } +} + +.ld-course-list-items .col-md-2-4 { + position: relative; + width: 100%; + min-height: 1px; + padding-right: 15px; + padding-left: 15px; + flex: 0 0 100%; + max-width: 100%; +} + +@media (min-width: 576px) { + .ld-course-list-items .col-md-2-4 { + flex: 0 0 33.3333333333%; + max-width: 33.3333333333%; + } +} + +@media (min-width: 768px) { + .ld-course-list-items .col-md-2-4 { + flex: 0 0 20%; + max-width: 20%; + } +} + +/** + * Element styles + */ + + .ld-course-list-items, + .ld-course-list-items * { + box-sizing: border-box; +} + +#ld_categorydropdown { + margin-bottom: 20px; +} + +.ld-course-list-items { + clear: both; +} + +.ld-course-list-items .ld_course_grid { + margin-bottom: 20px; +} + +.ld-course-list-items .ld_course_grid .thumbnail.course { + line-height: 1.428571429; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 4px; + -webkit-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; + display: inline-block; + max-width: 100%; + height: auto; + display: block; + position: relative; + padding: 0; + margin: 0; +} + +.ld-course-list-items .ld_course_grid .thumbnail.course .ribbon { + background: #5cb85c; + box-shadow: 0 1px rgba(0,0,0,0.2); + -moz-box-shadow: 0 1px rgba(0,0,0,0.2); + -webkit-box-shadow: 0 1px rgba(0,0,0,0.2); + color: #fff; + text-shadow: 0 1px rgba(0,0,0,0.3); + position: absolute; + font-size: 14px; + left: -8px; + top: 10px; + padding: 3px 10px; + z-index: 2; + font-weight: bold; +} + +.ld-course-list-items .ld_course_grid .thumbnail.course .ribbon.enrolled { + background: #428bca; +} + +.ld-course-list-items .ld_course_grid .thumbnail.course .ribbon:before { + border: 4px solid transparent; + border-top: 4px solid #348c34; + border-right: 4px solid #348c34; + content: ""; + position: absolute; + left: 0; + bottom: -8px; +} + +.ld-course-list-items .ld_course_grid .thumbnail.course .ribbon.enrolled:before { + border-top: 4px solid #357ebd; + border-right: 4px solid #357ebd; +} + +.ld-course-list-items .ld_course_grid .entry-title { + margin: 0 !important; +} + +.ld-course-list-items .ld_course_grid .entry-content { + margin-bottom: 10px; + padding: 0; +} + +.ld-course-list-items .ld_course_grid .ld_course_grid_button { + margin: 5px 0 !important; + width: 100%; +} + +.ld-course-list-items .ld_course_grid .ld_course_grid_button a { + text-decoration: none !important; + width: 100%; +} + +.ld-course-list-items .ld_course_grid .thumbnail.course a.btn-primary { + color: white; +} + +.ld-course-list-items .ld_course_grid .btn { + display: inline-block; + padding: 6px 12px; + margin-bottom: 0; + font-size: 14px; + font-weight: normal; + line-height: 1.428571429; + text-align: center; + vertical-align: middle; + cursor: pointer; + border: 1px solid transparent; + border-radius: 4px; + white-space: nowrap; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; +} + +.ld-course-list-items .ld_course_grid .btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.ld-course-list-items .ld_course_grid .btn:hover, +.ld-course-list-items .ld_course_grid .btn:focus { + color: #333333; + text-decoration: none; +} + +.ld-course-list-items .ld_course_grid .btn:active, +.ld-course-list-items .ld_course_grid .btn.active { + outline: 0; + background-image: none; + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} + +.ld-course-list-items .ld_course_grid .btn.disabled, +.ld-course-list-items .ld_course_grid .btn[disabled], +.ld-course-list-items .ld_course_grid fieldset[disabled] .btn { + cursor: not-allowed; + pointer-events: none; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + box-shadow: none; +} + +.ld-course-list-items .ld_course_grid .btn-primary { + color: #ffffff; + background-color: #428bca; + border-color: #357ebd; +} + +.ld-course-list-items .ld_course_grid .btn-primary:hover, +.ld-course-list-items .ld_course_grid .btn-primary:focus, +.ld-course-list-items .ld_course_grid .btn-primary:active, +.ld-course-list-items .ld_course_grid .btn-primary.active, +.ld-course-list-items .ld_course_grid .open .dropdown-toggle.btn-primary { + color: #ffffff; + background-color: #3276b1; + border-color: #285e8e; +} + +.ld-course-list-items .ld_course_grid .btn-primary:active, +.ld-course-list-items .ld_course_grid .btn-primary.active, +.ld-course-list-items .ld_course_grid .open .dropdown-toggle.btn-primary { + background-image: none; +} + +.ld-course-list-items .ld_course_grid .btn-primary.disabled, +.ld-course-list-items .ld_course_grid .btn-primary[disabled], +.ld-course-list-items .ld_course_grid fieldset[disabled] .btn-primary, +.ld-course-list-items .ld_course_grid .btn-primary.disabled:hover, +.ld-course-list-items .ld_course_grid .btn-primary[disabled]:hover, +.ld-course-list-items .ld_course_grid fieldset[disabled] .btn-primary:hover, +.ld-course-list-items .ld_course_grid .btn-primary.disabled:focus, +.ld-course-list-items .ld_course_grid .btn-primary[disabled]:focus, +.ld-course-list-items .ld_course_grid fieldset[disabled] .btn-primary:focus, +.ld-course-list-items .ld_course_grid .btn-primary.disabled:active, +.ld-course-list-items .ld_course_grid .btn-primary[disabled]:active, +.ld-course-list-items .ld_course_grid fieldset[disabled] .btn-primary:active, +.ld-course-list-items .ld_course_grid .btn-primary.disabled.active, +.ld-course-list-items .ld_course_grid .btn-primary[disabled].active, +.ld-course-list-items .ld_course_grid fieldset[disabled] .btn-primary.active { + background-color: #428bca; + border-color: #357ebd; +} + +.ld-course-list-items .ld_course_grid .btn-primary { + color: white; + text-decoration: none; +} + +.ld-course-list-items .ld_course_grid .btn-primary:hover { + color: white; +} + +.ld-course-list-items .ld_course_grid .ld_course_grid_video_embed { + background-color: #F5F5F5; + padding: 1px; + width: 100%; +} + +.ld-course-list-items .ld_course_grid .ld_course_grid_video_embed > * { + width: 100%; + margin-bottom: 0; +} + +.ld-course-list-items .ld_course_grid .thumbnail.course img { + display: block; + max-width: 100%; + width: 100%; + height: auto; + margin-left: auto; + margin-right: auto; + box-shadow: none; +} + +.ld-course-list-items .ld-course-list-items .ld_course_grid a.thumbnail:hover, +.ld-course-list-items .ld_course_grid a.thumbnail:focus { + border-color: #428bca; +} + +.ld-course-list-items .ld_course_grid .thumbnail a, +.ld-course-list-items .ld_course_grid .thumbnail a:hover { + box-shadow: none; +} + +.ld-course-list-items .ld_course_grid .thumbnail .caption { + padding: 9px; + color: #333333; +} + +.ld-course-list-items .ld_course_grid .thumbnail .caption a { + text-decoration: none !important; +} + +.ld-course-list-items .ld_course_grid .thumbnail .caption p { + float: none !important; + margin: 15px 0 0 !important; + width: 100% !important; +} + +.ld-course-list-items .ld_course_grid dd.course_progress { + width: 100%; +} + +.ld-course-list-items .ld_course_grid .ld-progress-steps { + display: none; +} \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/list/layout.php b/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/list/layout.php new file mode 100644 index 000000000..73157cf69 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/list/layout.php @@ -0,0 +1,24 @@ +get_posts(). + * @var array $atts Shortcode/Block editor attributes that call this template. + */ + +if ( ! defined( 'ABSPATH' ) ) { + exit(); +} +?> +
+ + + +
diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/list/style.css b/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/list/style.css new file mode 100644 index 000000000..e69de29bb diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/masonry/layout.php b/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/masonry/layout.php new file mode 100644 index 000000000..d8bb0ac68 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/masonry/layout.php @@ -0,0 +1,24 @@ +get_posts(). + * @var array $atts Shortcode/Block editor attributes that call this template. + */ + +if ( ! defined( 'ABSPATH' ) ) { + exit(); +} +?> +
+ + + +
diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/masonry/script.js b/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/masonry/script.js new file mode 100644 index 000000000..0e8fe6e53 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/masonry/script.js @@ -0,0 +1,50 @@ +function learndash_course_grid_init_masonry( items_wrapper ) { + const course_grid = items_wrapper.closest( '.learndash-course-grid' ); + const columns = parseInt( course_grid.dataset.columns ); + const min_width = parseInt( course_grid.dataset.min_column_width ); + + const width = items_wrapper.offsetWidth; + const items = items_wrapper.querySelectorAll( '.item' ); + + if ( items.length < 1 ) { + return; + } + + const padding = 10; + + let max_columns = Math.floor( width / min_width ); + max_columns = max_columns > columns ? columns : max_columns; + + items.forEach( function( item ) { + item.style.padding = padding + 'px'; + item.style.maxWidth = ( width / max_columns ) + 'px'; + item.style.width = ( width / max_columns ) + 'px'; + + item.style.visibility = 'visible'; + } ); + + const masonry = new Masonry( items_wrapper, { + itemSelector: '.item', + fitWidth: true, + horizontalOrder: true, + } ); +} + +function learndash_course_grid_init_masonry_responsive_design() { + const wrappers = document.querySelectorAll( '.learndash-course-grid[data-skin="masonry"]' ); + wrappers.forEach( function( wrapper ) { + const items_wrapper = wrapper.querySelector( '.items-wrapper.masonry' ); + + learndash_course_grid_init_masonry( items_wrapper ); + } ); +} + +( function() { + window.addEventListener( 'resize', function() { + learndash_course_grid_init_masonry_responsive_design(); + } ); + + window.addEventListener( 'load', function() { + learndash_course_grid_init_masonry_responsive_design(); + } ); +} )(); \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/masonry/style.css b/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/masonry/style.css new file mode 100644 index 000000000..194f102c1 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-grid/templates/skins/masonry/style.css @@ -0,0 +1,13 @@ +.learndash-course-grid .masonry { + display: grid; + grid-template-columns: repeat( 3, minmax( 0, 1fr ) ); + column-gap: 30px; + row-gap: 30px; + margin: 0 auto; + margin-bottom: 30px; + width: 100% !important; +} + +.learndash-course-grid .items-wrapper.masonry .item { + visibility: hidden; +} \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-reviews/core/admin/class-learndash-course-reviews-comment-edit.php b/web/app/plugins/sfwd-lms/includes/course-reviews/core/admin/class-learndash-course-reviews-comment-edit.php new file mode 100644 index 000000000..cecc345e6 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-reviews/core/admin/class-learndash-course-reviews-comment-edit.php @@ -0,0 +1,140 @@ +comment_ID ), + 'rating', + true + ); + + ?> + + + + 5 + || $post_data['rating'] < 0 + ) { + return $data; + } + + update_comment_meta( + Cast::to_int( $data['comment_ID'] ), + 'rating', + Cast::to_int( + wp_unslash( $post_data['rating'] ) + ) + ); + + return $data; + } +} + +$instance = new LearnDash_Course_Reviews_Comment_Edit(); diff --git a/web/app/plugins/sfwd-lms/includes/course-reviews/core/class-learndash-course-reviews-loader.php b/web/app/plugins/sfwd-lms/includes/course-reviews/core/class-learndash-course-reviews-loader.php new file mode 100644 index 000000000..eaf2c4cb3 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-reviews/core/class-learndash-course-reviews-loader.php @@ -0,0 +1,248 @@ + $tabs Tabs to display on the page. + * @param string $context Context. + * @param int $course_id Course ID. + * @param int $user_id User ID. + * + * @return array Tabs to display on the page + */ + public function add_reviews_tab( $tabs, $context, $course_id, $user_id ) { + if ( $context !== 'course' ) { + return $tabs; + } + + if ( ! learndash_course_reviews_is_review_enabled( $course_id ) ) { + return $tabs; + } + + ob_start(); + learndash_course_reviews_locate_template( + 'reviews.php', + array( + 'course_id' => $course_id, + ) + ); + $content = strval( ob_get_clean() ); + + $tabs[] = array( + 'id' => 'reviews', + 'icon' => 'star-blank', + 'label' => __( 'Reviews', 'learndash' ), + 'content' => $content, + ); + + return $tabs; + } + + /** + * Outputs the Average Review Score. + * + * @since 4.25.1 + * + * @param int $course_id Course ID. + * + * @return void + */ + public function output_average_review_template( $course_id ) { + learndash_course_reviews_locate_template( + 'average-review.php', + array( + 'course_id' => $course_id, + ) + ); + } + + /** + * Outputs the Review List. + * + * @since 4.25.1 + * + * @param int $course_id Course ID. + * + * @return void + */ + public function output_review_list_template( $course_id ) { + learndash_course_reviews_locate_template( + 'review-list.php', + array( + 'course_id' => $course_id, + ) + ); + } + + /** + * Output the Review Form. + * + * @since 4.25.1 + * + * @param int $course_id Course ID. + * + * @return void + */ + public function output_review_form_template( $course_id ) { + learndash_course_reviews_locate_template( + 'reviews-form.php', + array( + 'course_id' => $course_id, + ) + ); + } + + /** + * Output the Review Replace Form. + * + * @since 4.25.1 + * + * @param int $course_id Course ID. + * + * @return void + */ + public function output_review_reply_template( $course_id ) { + learndash_course_reviews_locate_template( + 'reviews-reply.php', + array( + 'course_id' => $course_id, + ) + ); + } + + /** + * Loads JS and CSS where necessary. + * + * @since 4.25.1 + * + * @return void + */ + public function enqueue_scripts() { + if ( get_post_type() !== 'sfwd-courses' ) { + return; + } + + wp_enqueue_script( 'learndash-course-reviews' ); + wp_enqueue_style( 'learndash-course-reviews' ); + } + + /** + * Ensure that Reviews are only output when explicitly asked for. + * + * @since 4.25.1 + * + * @param WP_Comment_Query $comment_query Comment Query Object. + * + * @return void + */ + public function remove_reviews_from_general_comments( &$comment_query ): void { + // We want to display Reviews within the Admin Dashboard under Comments. + if ( is_admin() ) { + return; + } + + if ( + ! empty( $comment_query->query_vars['type'] ) + && ( + ( + is_string( $comment_query->query_vars['type'] ) + && $comment_query->query_vars['type'] !== 'all' + ) + || ( + is_array( $comment_query->query_vars['type'] ) + && ! in_array( + 'all', + $comment_query->query_vars['type'], + true + ) + ) + ) + ) { + return; + } + + $comment_query->query_vars['type__not_in'] = (array) $comment_query->query_vars['type__not_in']; + + $comment_query->query_vars['type__not_in'][] = 'ld_review'; + } + + /** + * Fix the displayed Comment Count for a given Post. + * + * @since 4.25.1 + * + * @param int|string $comment_count Comment Count, pulled from wp_posts. + * @param int $post_id Post ID. + * + * @return int|string Comment Count. Returns string when > 0, int 0 otherwise, matching WordPress core behavior. + */ + public function fix_comment_counts( $comment_count, $post_id ) { + $comments = get_comments( + [ + 'post_id' => $post_id, + 'fields' => 'ids', + ] + ); + + if ( ! is_array( $comments ) ) { + return $comment_count; + } + + $count = count( $comments ); + + // Match WordPress core behavior: return string when > 0, int 0 otherwise. + if ( $count > 0 ) { + return (string) $count; + } + + return 0; + } +} + +$instance = new LearnDash_Course_Reviews_Loader(); diff --git a/web/app/plugins/sfwd-lms/includes/course-reviews/core/class-learndash-course-reviews-rest.php b/web/app/plugins/sfwd-lms/includes/course-reviews/core/class-learndash-course-reviews-rest.php new file mode 100644 index 000000000..5f9670811 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-reviews/core/class-learndash-course-reviews-rest.php @@ -0,0 +1,168 @@ +\d+)', + array( + 'methods' => 'POST', + 'callback' => array( $this, 'add_review' ), + 'permission_callback' => function ( $request ) { + if ( ! $request instanceof WP_REST_Request ) { + return false; + } + + return learndash_course_reviews_user_has_started_course( + Cast::to_int( + $request->get_param( 'course_id' ) + ) + ) + && self::permission_callback_filterable( $request, 'add_review' ); + }, + ) + ); + } + + /** + * Add a Review for a Course. + * + * @since 4.25.1 + * + * @param WP_REST_Request> $request Request Object. + * + * @return WP_REST_Response + */ + public function add_review( $request ) { + if ( ! $request->get_param( 'rating' ) ) { + return self::error_message( + __( 'A Rating must be included in your review', 'learndash' ) + ); + } + + if ( ! $request->get_param( 'review_title' ) ) { + return self::error_message( + __( 'A Title must be included in your review', 'learndash' ) + ); + } + + $result = learndash_course_reviews_add_review( + array( + 'comment_post_ID' => $request->get_param( 'course_id' ), + 'rating' => $request->get_param( 'rating' ), + 'review_title' => $request->get_param( 'review_title' ), + 'comment_content' => ( $request->get_param( 'review_content' ) ) ? $request->get_param( 'review_content' ) : '', + ) + ); + + if ( is_wp_error( $result ) ) { + return self::error_message( + implode( ';', $result->get_error_messages() ) + ); + } + + return new WP_REST_Response( + array( + 'comment_id' => $result, + ) + ); + } + + /** + * Outputs an Error Message as HTML. + * + * @since 4.25.1 + * + * @param string $message Error Message. Defaults to empty string. + * @param string $notice_type Notice type. Defaults to "alert". + * @param int $status_code Status code. Defaults to 500 (same as what WP_Error would choose). + * + * @return WP_REST_Response + */ + public static function error_message( string $message = '', string $notice_type = 'alert', int $status_code = 500 ): WP_REST_Response { + ob_start(); + + learndash_course_reviews_locate_template( + 'notice.php', + array( + 'message' => $message, + 'type' => $notice_type, + ) + ); + + return new WP_REST_Response( + array( + 'html' => ob_get_clean(), + ), + $status_code + ); + } + + /** + * This allows 3rd party integrations to force API calls to fail under certain conditions. + * + * This will force a 403, so it should only be used when you're trying to prevent abuse by someone who is being sneaky by attempting to run API calls for something they do not have access to. + * + * @since 4.25.1 + * + * @param WP_REST_Request $request Request object. + * @param string $method Method Name. + * + * @return bool Whether this API call should be allowed or not. + */ + public static function permission_callback_filterable( $request, string $method ): bool { + /** + * Filters the permission callback for a request. + * + * @since 4.25.1 + * + * @param bool $bool Allow/Disallow. + * @param WP_REST_Request $request Current Request Object. + * + * @return bool Allow/Disallow. + */ + return apply_filters( + "learndash_course_reviews_permission_callback_$method", + true, + $request + ); + } +} + +$instance = new LearnDash_Course_Reviews_REST(); diff --git a/web/app/plugins/sfwd-lms/includes/course-reviews/core/class-learndash-course-reviews-walker.php b/web/app/plugins/sfwd-lms/includes/course-reviews/core/class-learndash-course-reviews-walker.php new file mode 100644 index 000000000..d14a44708 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-reviews/core/class-learndash-course-reviews-walker.php @@ -0,0 +1,309 @@ +html5_comment( $comment, $depth, $args ); + $output .= ob_get_clean(); + } + + /** + * Output a comment in the HTML5 format. + * + * @since 4.25.1 + * + * @see wp_list_comments() + * + * @param WP_Comment $comment Comment to display. + * @param int $depth Depth of comment. + * @param array{avatar_size?: int, style?: string} $args An array of arguments. + * + * @return void + */ + protected function html5_comment( $comment, $depth, $args ) { + $args = wp_parse_args( + $args, + array( + 'style' => 'div', + 'avatar_size' => 0, + ) + ); + + $tag = ( 'div' === $args['style'] ) ? 'div' : 'li'; + + ob_start(); + + /** + * Runs before starting the output of each Review. Anything echo'd here will be placed before the Review HTML. + * + * @since 4.25.1 + * + * @param WP_Comment $comment Comment data object. + * @param int $depth Depth of comment in reference to parents. + * @param array $args An array of arguments. + */ + do_action( + 'learndash_course_reviews_before_review', + $comment, + $depth, + $args + ); + ?> + + + < id="ld-review-" has_children ? 'parent' : '' ); ?>> + +
+ +
+
+ comment_author_email, + 100, + '', + '', + array( + 'class' => 'alignleft', + ) + ) + ) + ); + ?> + + +
+ + + comment_ID ), + 'review_title', + true + ) + ) + ); + ?> + + + + + comment_ID ), + 'rating', + true + ) + ) + ); + ?> + +
+ + +
+ + comment_approved ) : ?> +

+ + + +

+ +
+ +
+ +
+ +
+ array( + 'type' => true, + ), + ) + ) + ); + } + + /** + * Ends the element output, if needed. + * + * @since 4.25.1 + * + * @see Walker::end_el() + * @see wp_list_comments() + * + * @param string $output Used to append additional content. Passed by reference. + * @param WP_Comment $comment The current comment object. Default current comment. + * @param int $depth Optional. Depth of the current comment. Default 0. + * @param array{style?: string, end-callback?: callable} $args Optional. An array of arguments. Default empty array. + * + * @return void + */ + public function end_el( &$output, $comment, $depth = 0, $args = array() ) { + if ( ! empty( $args['end-callback'] ) ) { + ob_start(); + + call_user_func( + $args['end-callback'], + $comment, + $args, + $depth + ); + + $output .= ob_get_clean(); + return; + } + + $args = wp_parse_args( + $args, + array( + 'style' => 'div', + ) + ); + + $tag = ( 'div' === $args['style'] ) ? 'div' : 'li'; + + $output .= '\n"; + + ob_start(); + + /** + * Runs after finishing the output of each Review. Anything echo'd here will be placed after the Review HTML. + * + * @since 4.25.1 + * + * @param WP_Comment $comment Comment data object. + * @param int $depth Depth of comment in reference to parents. + * @param array $args An array of arguments. + */ + do_action( + 'learndash_course_reviews_after_review', + $comment, + $depth, + $args + ); + + $output .= ob_get_clean(); + } +} diff --git a/web/app/plugins/sfwd-lms/includes/course-reviews/core/learndash-course-reviews-functions.php b/web/app/plugins/sfwd-lms/includes/course-reviews/core/learndash-course-reviews-functions.php new file mode 100644 index 000000000..5cffe9d0e --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-reviews/core/learndash-course-reviews-functions.php @@ -0,0 +1,413 @@ + $args Array of variables to pass into the template file. + * + * @return void + */ +function learndash_course_reviews_locate_template( $template_name, $args = array() ) { + /** + * Filter the template name to be located. + * + * @since 4.25.1 + * + * @param string $template_name Template path, relative to the src/views directory. + * @param array $args Array of variables to pass into the template file. + * + * @return string Template path, relative to the src/views directory. + */ + $template_name = apply_filters( + 'learndash_course_reviews_locate_template_name', + $template_name, + $args + ); + + /** + * Filter the args to use in the template. + * + * @since 4.25.1 + * + * @param array $args Array of variables to pass into the template file. + * @param string $template_name Template path, relative to the src/views directory. + * + * @return array Array of variables to pass into the template file. + */ + $args = apply_filters( + 'learndash_course_reviews_locate_template_args', + $args, + $template_name + ); + + // phpcs:ignore WordPress.PHP.DontExtract.extract_extract -- TODO: Replace template loading logic to not require extract(). + extract( + $args, + EXTR_SKIP + ); + + $template_file = ''; + $theme_file = locate_template( "/learndash-course-reviews/{$template_name}" ); + + if ( $theme_file ) { + $template_file = $theme_file; + } else { + $template_file = LEARNDASH_COURSE_REVIEWS_DIR . "src/views/{$template_name}"; + } + + /** + * Filter the template file to be located. + * + * @since 4.25.1 + * + * @param string $template_file Absolute template path to be loaded. + * @param string $template_name Template path, relative to the src/views directory. + * @param array $args Array of variables to pass into the template file. + * + * @return string Absolute template path to be loaded. + */ + $template_file = apply_filters( + 'learndash_course_reviews_locate_template', + $template_file, + $template_name, + $args + ); + + include $template_file; +} + +/** + * Check whether the Student has started the Course. + * + * @since 4.25.1 + * + * @param int $course_id Course ID. + * @param int $user_id User ID. + * + * @return bool + */ +function learndash_course_reviews_user_has_started_course( int $course_id, int $user_id = 0 ): bool { + $result = false; + + if ( $user_id <= 0 ) { + $user_id = get_current_user_id(); + } + + // User is not logged in, they cannot have started the Course. + if ( $user_id === 0 ) { + return false; + } + + // Note: If LearnDash is set up to wipe their Course Progress on expiration, we are unable to know whether they have started the Course or not so this will not find any completed Course Steps. + $course_progress = learndash_course_progress( + array( + 'array' => true, + 'course_id' => $course_id, + 'user_id' => $user_id, + ) + ); + + $result = ! empty( $course_progress['completed'] ); + + // Useful to include in our Filter. + $has_access = sfwd_lms_has_access( $course_id, $user_id ); + + /** + * Filters whether the Student has started the Course. + * + * @since 4.25.1 + * + * @param bool $result Whether the Student has started the Course. + * @param int $course_id Course ID. + * @param int $user_id User ID. + * @param bool $has_access Whether the Student has access to the Course. + * @param string|array $course_progress Course Progress. + * + * @return bool Whether the Student has started the Course. + */ + return apply_filters( + 'learndash_course_reviews_user_has_started_course', + $result, + $course_id, + $user_id, + $has_access, + $course_progress + ); +} + +/** + * Output the Stars Input for the Review Form. + * + * @since 4.25.1 + * + * @return void + */ +function learndash_course_reviews_stars_input(): void { + learndash_course_reviews_locate_template( 'stars-input.php' ); +} + +/** + * Outputs the Star Rating for a Review. + * + * @since 4.25.1 + * + * @param float $rating Rating. + * + * @return void + */ +function learndash_course_reviews_star_rating( float $rating = 0 ): void { + if ( ! is_numeric( $rating ) ) { + $rating = 0; + } + + learndash_course_reviews_locate_template( + 'star-rating.php', + array( + 'rating' => $rating, + ) + ); +} + +/** + * Creates a Review based on passed Args. + * + * @since 4.25.1 + * + * @param array $args wp_insert_comment() args, with the addition of our own. + * + * @return int|false|WP_Error Integer on success, False on not logged in, WP_Error on failure. + */ +function learndash_course_reviews_add_review( array $args ) { + if ( ! is_user_logged_in() ) { + return false; + } + + $user = wp_get_current_user(); + + $review_author = wp_slash( $user->display_name ); + $review_author_email = wp_slash( $user->user_email ); + $review_author_url = wp_slash( $user->user_url ); + + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- WP Core does this too, see wp_new_comment(). + $comment_author_ip = wp_unslash( $_SERVER['REMOTE_ADDR'] ); + $comment_author_ip = preg_replace( '/[^0-9a-fA-F:., ]/', '', $comment_author_ip ); + + $comment_agent = ''; + if ( ! empty( $_SERVER['HTTP_USER_AGENT'] ) ) { + $comment_agent = sanitize_text_field( + wp_unslash( + $_SERVER['HTTP_USER_AGENT'] + ) + ); + } + + $args = wp_parse_args( + $args, + array( + 'comment_type' => 'ld_review', + 'comment_parent' => '', + 'comment_approved' => true, + 'comment_date' => current_time( 'mysql' ), + 'comment_date_gmt' => current_time( 'mysql', true ), + 'user_id' => get_current_user_id(), + 'comment_author' => $review_author, + 'comment_author_email' => $review_author_email, + 'comment_author_url' => $review_author_url, + 'comment_author_IP' => $comment_author_ip, + 'comment_agent' => $comment_agent, + ) + ); + + $comment_allowed = wp_allow_comment( $args, true ); + + if ( is_wp_error( $comment_allowed ) ) { + return $comment_allowed; + } + + $review_id = wp_insert_comment( $args ); + + if ( ! $review_id ) { + return $review_id; + } + + add_comment_meta( + $review_id, + 'rating', + $args['rating'] + ); + + add_comment_meta( + $review_id, + 'review_title', + $args['review_title'] + ); + + return $review_id; +} + +/** + * Checks if the given Email Address has submitted a Review before for a given Course. + * + * If no Email Address is defined, then the currently logged in User will be used. + * + * @since 4.25.1 + * + * @param int $course_id Course ID. + * @param string $email_address Email Address. + * + * @return int|false Comment ID or false if not found. + */ +function learndash_course_reviews_get_user_review( int $course_id, string $email_address = '' ) { + $args = array( + 'type' => 'ld_review', + 'post_id' => $course_id, + 'parent' => 0, + 'number' => 1, + ); + + if ( empty( $email_address ) ) { + if ( ! is_user_logged_in() ) { + return false; + } + + $args['user_id'] = get_current_user_id(); + } else { + $args['author_email'] = $email_address; + } + + $comments = get_comments( $args ); + + if ( ! is_array( $comments ) ) { + return false; + } + + $comments = array_values( + array_filter( + $comments, + function ( $comment ) { + return $comment instanceof WP_Comment; + } + ) + ); + + if ( empty( $comments ) ) { + return false; + } + + return Cast::to_int( $comments[0]->comment_ID ); +} + +/** + * Gets an Average Review Score for a given Course. + * + * @param int $course_id Course ID. + * @param array $args get_comments() args. + * + * @since 4.25.1 + * @return float|false Average Review Score, false if no reviews found. + */ +function learndash_course_reviews_get_average_review_score( int $course_id, array $args = array() ) { + $reviews = get_comments( + wp_parse_args( + $args, + array( + 'post_id' => $course_id, + 'type' => 'ld_review', + 'status' => 'approve', + 'fields' => 'ids', + ) + ) + ); + + if ( ! is_array( $reviews ) ) { + return false; + } + + $reviews = array_filter( + $reviews, + 'is_int' + ); + + if ( empty( $reviews ) ) { + return false; + } + + $sum = 0; + + foreach ( $reviews as $comment_id ) { + $rating = get_comment_meta( $comment_id, 'rating', true ); + + if ( ! is_numeric( $rating ) ) { + $rating = 0; + } + + $sum = $sum + $rating; + } + + return $sum / count( $reviews ); +} + +/** + * Checks if reviews are enabled for a given course. + * + * @since 4.25.1 + * + * @param int $course_id Course ID. + * + * @return bool Whether reviews are enabled for the course. + */ +function learndash_course_reviews_is_review_enabled( int $course_id ): bool { + $settings = learndash_get_setting( $course_id ); + + if ( + is_array( $settings ) + && isset( $settings['show_reviews'] ) + ) { + return $settings['show_reviews'] === 'yes'; + } else { + // Check the legacy meta field for backwards compatibility. + $legacy_show_reviews = get_post_meta( $course_id, 'rbm_ld_reviews_show_reviews', true ); + + return $legacy_show_reviews === 'y'; + } +} diff --git a/web/app/plugins/sfwd-lms/includes/course-reviews/dist/scripts.js b/web/app/plugins/sfwd-lms/includes/course-reviews/dist/scripts.js new file mode 100644 index 000000000..c16730a3d --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-reviews/dist/scripts.js @@ -0,0 +1 @@ +(()=>{var e={32:()=>{var e;0!==(e=jQuery)(".learndash-course-reviews-stars-input").length&&e(document).on("change",".learndash-course-reviews-stars-input .review-star input",function(){let s=-1;e(this).prop("checked")&&(s=parseInt(e(this).val())-1),e(this).closest(".learndash-course-reviews-stars-input").find(" .review-star").each(function(r,a){r>s?e(a).removeClass("active"):e(a).addClass("active")})})}},s={};function r(a){var t=s[a];if(void 0!==t)return t.exports;var i=s[a]={exports:{}};return e[a](i,i.exports,r),i.exports}(()=>{"use strict";var e,s;r(32),e=jQuery,s=learndashCourseReviews,e('form[name="learndash_course_reviews"]').length<1||e(document).on("submit",'form[name="learndash_course_reviews"]',function(r){r.preventDefault();const a=function(e){const s={};for(const r in e)s[e[r].name]=e[r].value;return s}(e(this).serializeArray()),t=this,i=e(t).find('input[type="submit"]'),n=i.val();i.val(i.data("saving_text")).attr("disabled",!0).addClass("disabled"),e.ajax({method:"POST",url:s.restURL+"addReview/"+a.course_id,data:a,cache:!1,success(s){i.val(n).attr("disabled",!1).removeClass("disabled"),t.reset(),e(t).find(".learndash-course-reviews-stars-input input").trigger("change"),window.location.href=window.location.href.replace(/#.*?$/g,"")+"#ld-review-"+s.comment_id,window.location.reload(!0)},error(s){const r=JSON.parse(s.responseText);if(void 0!==r.html){const s=e(t).closest(".learndash-course-reviews-form").find(".notices-container");s.append(r.html),s[0].scrollIntoView({behavior:"smooth"})}else void 0!==r.message&&console.error(r.message);i.val(n).attr("disabled",!1).removeClass("disabled")}})})})()})(); \ No newline at end of file diff --git a/web/app/plugins/sfwd-lms/includes/course-reviews/dist/styles-rtl.css b/web/app/plugins/sfwd-lms/includes/course-reviews/dist/styles-rtl.css new file mode 100644 index 000000000..c12884b8d --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-reviews/dist/styles-rtl.css @@ -0,0 +1 @@ +.callout{background-color:#fff;border:1px solid #0a0a0a40;border-radius:0;color:#0a0a0a;margin:0 0 1rem;padding:1rem;position:relative}.callout>:first-child{margin-top:0}.callout>:last-child{margin-bottom:0}.callout.primary{background-color:#d7ecfa;color:#0a0a0a}.callout.secondary{background-color:#eaeaea;color:#0a0a0a}.callout.success{background-color:#e1faea;color:#0a0a0a}.callout.warning{background-color:#fff3d9;color:#0a0a0a}.callout.alert{background-color:#f7e4e1;color:#0a0a0a}.callout.small{padding:.5rem}.callout.large{padding:3rem}.close-button{color:#8a8a8a;cursor:pointer;position:absolute;z-index:10}[data-whatinput=mouse] .close-button{outline:0}.close-button:focus,.close-button:hover{color:#0a0a0a}.close-button.small{font-size:1.5em;line-height:1;right:.66rem;top:.33em}.close-button,.close-button.medium{font-size:2em;line-height:1;right:1rem;top:.5rem}.learndash-course-reviews-review-stars{color:#aaa;display:inline-block;font-family:Times,serif;font-size:2.5em;line-height:1;position:relative}.learndash-course-reviews-review-stars:after{bottom:0;color:#f1c40f;content:"★★★★★";left:0;overflow:hidden;position:absolute;right:0;top:0;white-space:nowrap}.learndash-course-reviews-container .reviews-list .ld_review{border-bottom:.125rem solid #aaa;padding:2rem 0}.learndash-course-reviews-container .reviews-list .ld_review:last-child{border-bottom:0}.learndash-course-reviews-container .reviews-list .ld_review .learndash-course-reviews-author{display:block;margin-bottom:1em;overflow:hidden}.learndash-course-reviews-container .reviews-list .ld_review p:last-of-type{margin-bottom:0}.learndash-course-reviews-container .average-review{margin-bottom:2rem}.learndash-course-reviews-container .average-review .average-review-label{font-size:1.5em;line-height:2.5}@keyframes star-animation{0%{opacity:0;transform:scale(1)}50%{opacity:.5}to{left:.0625em;opacity:0;top:.0625em;transform:scale(2)}}@keyframes star-background{0%{color:inherit}to{color:#f1c40f}}.learndash-course-reviews-container .learndash-course-reviews-stars-input .review-star{display:inline-block;font-family:Times,serif;line-height:1;margin-bottom:1rem}.learndash-course-reviews-container .learndash-course-reviews-stars-input .review-star input{display:block!important;height:2em;position:absolute;width:auto;clip:rect(0,0,0,0)}.learndash-course-reviews-container .learndash-course-reviews-stars-input .review-star label{color:#aaa;font-size:2.5em;margin-left:0;position:relative}.learndash-course-reviews-container .learndash-course-reviews-stars-input .review-star label:after{color:#f1c40f;content:"★";display:inline-block;height:1em;left:0;opacity:0;position:absolute;top:-.0625rem;width:1em;z-index:-2}.learndash-course-reviews-container .learndash-course-reviews-stars-input .review-star.active label{animation:star-background .25s 1;animation-fill-mode:forwards}.learndash-course-reviews-container .learndash-course-reviews-stars-input .review-star.active label:after{animation:star-animation .25s 1} diff --git a/web/app/plugins/sfwd-lms/includes/course-reviews/dist/styles.css b/web/app/plugins/sfwd-lms/includes/course-reviews/dist/styles.css new file mode 100644 index 000000000..c12884b8d --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-reviews/dist/styles.css @@ -0,0 +1 @@ +.callout{background-color:#fff;border:1px solid #0a0a0a40;border-radius:0;color:#0a0a0a;margin:0 0 1rem;padding:1rem;position:relative}.callout>:first-child{margin-top:0}.callout>:last-child{margin-bottom:0}.callout.primary{background-color:#d7ecfa;color:#0a0a0a}.callout.secondary{background-color:#eaeaea;color:#0a0a0a}.callout.success{background-color:#e1faea;color:#0a0a0a}.callout.warning{background-color:#fff3d9;color:#0a0a0a}.callout.alert{background-color:#f7e4e1;color:#0a0a0a}.callout.small{padding:.5rem}.callout.large{padding:3rem}.close-button{color:#8a8a8a;cursor:pointer;position:absolute;z-index:10}[data-whatinput=mouse] .close-button{outline:0}.close-button:focus,.close-button:hover{color:#0a0a0a}.close-button.small{font-size:1.5em;line-height:1;right:.66rem;top:.33em}.close-button,.close-button.medium{font-size:2em;line-height:1;right:1rem;top:.5rem}.learndash-course-reviews-review-stars{color:#aaa;display:inline-block;font-family:Times,serif;font-size:2.5em;line-height:1;position:relative}.learndash-course-reviews-review-stars:after{bottom:0;color:#f1c40f;content:"★★★★★";left:0;overflow:hidden;position:absolute;right:0;top:0;white-space:nowrap}.learndash-course-reviews-container .reviews-list .ld_review{border-bottom:.125rem solid #aaa;padding:2rem 0}.learndash-course-reviews-container .reviews-list .ld_review:last-child{border-bottom:0}.learndash-course-reviews-container .reviews-list .ld_review .learndash-course-reviews-author{display:block;margin-bottom:1em;overflow:hidden}.learndash-course-reviews-container .reviews-list .ld_review p:last-of-type{margin-bottom:0}.learndash-course-reviews-container .average-review{margin-bottom:2rem}.learndash-course-reviews-container .average-review .average-review-label{font-size:1.5em;line-height:2.5}@keyframes star-animation{0%{opacity:0;transform:scale(1)}50%{opacity:.5}to{left:.0625em;opacity:0;top:.0625em;transform:scale(2)}}@keyframes star-background{0%{color:inherit}to{color:#f1c40f}}.learndash-course-reviews-container .learndash-course-reviews-stars-input .review-star{display:inline-block;font-family:Times,serif;line-height:1;margin-bottom:1rem}.learndash-course-reviews-container .learndash-course-reviews-stars-input .review-star input{display:block!important;height:2em;position:absolute;width:auto;clip:rect(0,0,0,0)}.learndash-course-reviews-container .learndash-course-reviews-stars-input .review-star label{color:#aaa;font-size:2.5em;margin-left:0;position:relative}.learndash-course-reviews-container .learndash-course-reviews-stars-input .review-star label:after{color:#f1c40f;content:"★";display:inline-block;height:1em;left:0;opacity:0;position:absolute;top:-.0625rem;width:1em;z-index:-2}.learndash-course-reviews-container .learndash-course-reviews-stars-input .review-star.active label{animation:star-background .25s 1;animation-fill-mode:forwards}.learndash-course-reviews-container .learndash-course-reviews-stars-input .review-star.active label:after{animation:star-animation .25s 1} diff --git a/web/app/plugins/sfwd-lms/includes/course-reviews/learndash-course-reviews.php b/web/app/plugins/sfwd-lms/includes/course-reviews/learndash-course-reviews.php new file mode 100644 index 000000000..51ca78c12 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-reviews/learndash-course-reviews.php @@ -0,0 +1,136 @@ +require_necessities(); + + // Register our CSS/JS for the whole plugin. + add_action( 'wp_enqueue_scripts', array( $this, 'register_scripts' ), 1 ); + } + + /** + * Includes different aspects of the plugin. + * + * @access private + * @since 4.25.1 + * + * @return void + */ + private function require_necessities() { + require_once LEARNDASH_COURSE_REVIEWS_DIR . 'core/class-learndash-course-reviews-walker.php'; + + require_once LEARNDASH_COURSE_REVIEWS_DIR . 'core/class-learndash-course-reviews-loader.php'; + + require_once LEARNDASH_COURSE_REVIEWS_DIR . 'core/class-learndash-course-reviews-rest.php'; + + require_once LEARNDASH_COURSE_REVIEWS_DIR . 'core/admin/class-learndash-course-reviews-comment-edit.php'; + } + + /** + * Outputs Admin Notices. + * + * This is useful if you're too early in execution to use the add_settings_error() + * function as you can save them for later. + * + * @access public + * @since 4.25.1 + * @deprecated 4.25.1 + * + * @return void + */ + public function admin_notices() { + _deprecated_function( __FUNCTION__, '4.25.1' ); + } + + /** + * Registers our CSS/JS to use later. + * + * @access public + * @since 4.25.1 + * + * @return void + */ + public function register_scripts() { + wp_register_style( + 'learndash-course-reviews', + LEARNDASH_COURSE_REVIEWS_URL . 'dist/styles.css', + array(), + defined( 'LEARNDASH_SCRIPT_DEBUG' ) && LEARNDASH_SCRIPT_DEBUG ? strval( time() ) : LEARNDASH_VERSION + ); + + wp_register_script( + 'learndash-course-reviews', + LEARNDASH_COURSE_REVIEWS_URL . 'dist/scripts.js', + array( 'jquery' ), + defined( 'LEARNDASH_SCRIPT_DEBUG' ) && LEARNDASH_SCRIPT_DEBUG ? strval( time() ) : LEARNDASH_VERSION, + true + ); + + wp_localize_script( + 'learndash-course-reviews', + 'learndashCourseReviews', + array( + 'restURL' => esc_url_raw( rest_url() ) . 'learndashCourseReviews/v1/', + ) + ); + } + } +} // End Class Exists Check + +add_action( 'learndash_init', 'learndash_course_reviews_load' ); diff --git a/web/app/plugins/sfwd-lms/includes/course-reviews/src/views/average-review.php b/web/app/plugins/sfwd-lms/includes/course-reviews/src/views/average-review.php new file mode 100644 index 000000000..5c6657ab3 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-reviews/src/views/average-review.php @@ -0,0 +1,31 @@ + + +
+ + + + + + + +
diff --git a/web/app/plugins/sfwd-lms/includes/course-reviews/src/views/notice.php b/web/app/plugins/sfwd-lms/includes/course-reviews/src/views/notice.php new file mode 100644 index 000000000..e1990bfb2 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-reviews/src/views/notice.php @@ -0,0 +1,26 @@ + + +
+ + + + + +
diff --git a/web/app/plugins/sfwd-lms/includes/course-reviews/src/views/review-list.php b/web/app/plugins/sfwd-lms/includes/course-reviews/src/views/review-list.php new file mode 100644 index 000000000..e0d3cb4b2 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-reviews/src/views/review-list.php @@ -0,0 +1,138 @@ + + +
+ + $course_id, + 'type' => 'ld_review', + 'status' => 'approve', + ) + ); + + if ( ! is_array( $reviews ) ) { + $reviews = array(); + } + + $reviews = array_values( + array_filter( + $reviews, + function ( $review ) { + return $review instanceof WP_Comment; + } + ) + ); + + $comments_per_page = Cast::to_int( get_option( 'comments_per_page' ) ); + + if ( $comments_per_page <= 0 ) { + $comments_per_page = 1; + } + + $total_pages = Cast::to_int( + ceil( + count( $reviews ) / get_option( 'comments_per_page' ) + ) + ); + + $cpage = Cast::to_int( get_query_var( 'cpage' ) ); + $cpage = ( $cpage > 0 ) ? $cpage : 1; + + /** + * Fires before outputting the list of Reviews. + * + * @since 4.25.1 + * + * @param int $course_id Course ID. + * @param array $reviews Array of Comment Objects. + */ + do_action( + 'learndash_course_reviews_before_reviews', + $course_id, + $reviews + ); + + wp_list_comments( + /** + * Filters the args passed to wp_list_comments() for outputting Reviews. + * + * @since 4.25.1 + * + * @param array{walker?: Walker, max_depth?: int, callback?: callable, end-callback?: callable, type?: string, page?: int, per_page?: int, avatar_size?: int, reverse_top_level?: bool, reverse_children?: bool, format?: string, short_ping?: bool, echo?: bool} $args wp_list_comment $args. + * + * @return array{walker?: Walker, max_depth?: int, callback?: callable, end-callback?: callable, type?: string, page?: int, per_page?: int, avatar_size?: int, reverse_top_level?: bool, reverse_children?: bool, format?: string, short_ping?: bool, echo?: bool} wp_list_comment $args. + */ + apply_filters( + 'learndash_course_reviews_render_reviews_args', + array( + 'walker' => new LearnDash_Course_Reviews_Walker(), + 'style' => 'div', + 'echo' => true, + ) + ), + $reviews + ); + + /** + * Fires after outputting the list of Reviews. + * + * @since 4.25.1 + * + * @param int $course_id Course ID. + * @param array $reviews Array of Comment Objects. + */ + do_action( + 'learndash_course_reviews_after_reviews', + $course_id, + $reviews + ); + + paginate_comments_links( + array( + 'base' => add_query_arg( 'cpage', '%#%' ), + 'total' => $total_pages, + 'current' => $cpage, + 'echo' => true, + 'add_fragment' => '#ld-reviews', + ) + ); + + /** + * Fires after outputting the Review pagination. + * + * @since 4.25.1 + * + * @param int $course_id Course ID. + * @param array $reviews Array of Comment Objects. + * @param int $total_pages Total number of pages. + * @param int $cpage Current page. + */ + do_action( + 'learndash_course_reviews_after_review_pagination', + $course_id, + $reviews, + $total_pages, + $cpage + ); + + ?> + +
diff --git a/web/app/plugins/sfwd-lms/includes/course-reviews/src/views/reviews-form.php b/web/app/plugins/sfwd-lms/includes/course-reviews/src/views/reviews-form.php new file mode 100644 index 000000000..702cee560 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-reviews/src/views/reviews-form.php @@ -0,0 +1,177 @@ + + +
+ + +
+ +
+ + + + + +
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+
+ + +

+ +

+ +

+ +

+ + true, + ) + ); + } + ?> + +
diff --git a/web/app/plugins/sfwd-lms/includes/course-reviews/src/views/reviews-reply.php b/web/app/plugins/sfwd-lms/includes/course-reviews/src/views/reviews-reply.php new file mode 100644 index 000000000..7b8fa5949 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-reviews/src/views/reviews-reply.php @@ -0,0 +1,56 @@ + + + diff --git a/web/app/plugins/sfwd-lms/includes/course-reviews/src/views/reviews.php b/web/app/plugins/sfwd-lms/includes/course-reviews/src/views/reviews.php new file mode 100644 index 000000000..a3657bf19 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-reviews/src/views/reviews.php @@ -0,0 +1,77 @@ + + +
+ + + + + + + + + +
diff --git a/web/app/plugins/sfwd-lms/includes/course-reviews/src/views/star-rating.php b/web/app/plugins/sfwd-lms/includes/course-reviews/src/views/star-rating.php new file mode 100644 index 000000000..9e206bf3c --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-reviews/src/views/star-rating.php @@ -0,0 +1,88 @@ + + + + +
+ + ★ + +
+ + array( + 'type' => true, + ), + ) + ) +); diff --git a/web/app/plugins/sfwd-lms/includes/course-reviews/src/views/stars-input.php b/web/app/plugins/sfwd-lms/includes/course-reviews/src/views/stars-input.php new file mode 100644 index 000000000..1e7402ea8 --- /dev/null +++ b/web/app/plugins/sfwd-lms/includes/course-reviews/src/views/stars-input.php @@ -0,0 +1,34 @@ + + +
+ + +
+ + +
+ + +
diff --git a/web/app/plugins/sfwd-lms/includes/course/ld-activity-functions.php b/web/app/plugins/sfwd-lms/includes/course/ld-activity-functions.php index df6af06c0..1e19dcbbb 100644 --- a/web/app/plugins/sfwd-lms/includes/course/ld-activity-functions.php +++ b/web/app/plugins/sfwd-lms/includes/course/ld-activity-functions.php @@ -7,6 +7,9 @@ * @package LearnDash\Activity */ +use LearnDash\Core\Utilities\Cast; +use StellarWP\Learndash\StellarWP\DB\DB; + if ( ! defined( 'ABSPATH' ) ) { exit; } @@ -58,7 +61,7 @@ function learndash_update_user_activity( $args = array() ) { 'user_id' => 0, // Will be the token stats that described the status_times array (next argument) Can be most anything. - // From 'course', 'lesson', 'topic', 'access' or 'expired'. Unique key part 4/4. + // From 'course', 'lesson', 'topic', 'access', 'group_progress', 'exam', or 'expired'. Unique key part 4/4. 'activity_type' => '', // true if the lesson, topic, course, quiz is complete. False if not complete. null if not started. @@ -374,9 +377,9 @@ function learndash_get_user_activity_meta( $activity_id = 0, $activity_meta_key * * @global wpdb $wpdb WordPress database abstraction object. * - * @param int $activity_id Optional. Activity ID. Default 0. - * @param string $meta_key Optional. The activity meta key to get. Default empty. - * @param string|null $meta_value Optional. Activity meta value. Default null. + * @param int $activity_id Optional. Activity ID. Default 0. + * @param string $meta_key Optional. The activity meta key to get. Default empty. + * @param string|mixed[]|null $meta_value Optional. Activity meta value. Default null. */ function learndash_update_user_activity_meta( $activity_id = 0, $meta_key = '', $meta_value = null ) { global $wpdb; @@ -616,21 +619,6 @@ function learndash_activity_start_course( $user_id = 0, $course_id = 0, $start_t return $activity; } -/** - * Set the course activity completed record. - * - * @since 3.5.0 - * - * @param int $user_id User ID. - * @param int $course_id Course ID. - * @param int $complete_time Activity complete timestamp (GMT). - * - * @return object Instance of LDLMS_Model_Activity or null; - */ -function learndash_activity_complete_course( $user_id = 0, $course_id = 0, $complete_time = 0 ) { - return learndash_activity_complete_step( $user_id, $course_id, $course_id, 'course', $complete_time ); -} - /** * Set the lesson activity started record. * @@ -711,22 +699,6 @@ function learndash_activity_start_quiz( $user_id = 0, $course_id = 0, $quiz_id = return learndash_activity_start_step( $user_id, $course_id, $quiz_id, 'quiz', $start_time ); } -/** - * Set the quiz activity completed record. - * - * @since 3.5.0 - * - * @param int $user_id User ID. - * @param int $course_id Course ID. - * @param int $quiz_id Quiz ID. - * @param int $complete_time Activity complete timestamp (GMT). - * - * @return object Instance of LDLMS_Model_Activity or null; - */ -function learndash_activity_complete_quiz( $user_id = 0, $course_id = 0, $quiz_id = 0, $complete_time = 0 ) { - return learndash_activity_complete_step( $user_id, $course_id, $quiz_id, 'quiz', $complete_time ); -} - /** * Update activity meta set. * @@ -768,3 +740,174 @@ function learndash_activity_course_get_latest_completed_step( $user_id = 0, $cou return $activity_item; } } + +/** + * Bulk creates course access activity records for user/course combinations. + * + * Handles efficient creation of 'access' type activity records: + * 1. Queries existing records to avoid duplicates + * 2. Filters to find only missing combinations + * 3. Bulk inserts in chunks for efficiency + * + * @since 5.0.1 + * + * @param int[] $user_ids Array of user IDs. + * @param int[] $course_ids Array of course IDs. + * @param int $group_id Optional. Group ID for looking up accurate enrollment timestamps. + * When provided, uses the later of user-group or course-group enrollment dates. + * When omitted, uses current time. + * + * @return int Number of activity records created. + */ +function learndash_bulk_create_course_access_activities( array $user_ids, array $course_ids, int $group_id = 0 ): int { + if ( + /** + * Filters whether to skip bulk creation of course access activities. + * + * @since 5.0.1 + * + * @param bool $skip Whether to skip bulk creation of course access activities. Default false. + * @param int[] $user_ids Array of user IDs. + * @param int[] $course_ids Array of course IDs. + * @param int $group_id Group ID. + * + * @return bool Whether to skip bulk creation of course access activities. Default false. + */ + apply_filters( 'learndash_bulk_create_course_access_activities_skip', false, $user_ids, $course_ids, $group_id ) + || empty( $user_ids ) + || empty( $course_ids ) + ) { + return 0; + } + + $activity_table = LDLMS_DB::get_table_name( 'user_activity' ); + + // Query existing 'access' activity records to avoid duplicates. + $existing_records = DB::table( DB::raw( $activity_table ) ) + ->select( 'user_id', 'course_id' ) + ->whereIn( 'user_id', $user_ids ) + ->whereIn( 'course_id', $course_ids ) + ->where( 'activity_type', 'access' ) + ->getAll(); + + if ( ! is_array( $existing_records ) ) { + $existing_records = []; + } + + // Build a hash set of existing combinations for O(1) lookup. + $existing_set = []; + foreach ( $existing_records as $record ) { + $existing_set[ $record->user_id . '_' . $record->course_id ] = true; + } + + // Find combinations that need new activity records. + $current_time = time(); + $new_records = []; + + // Pre-fetch course-group enrollment timestamps if group_id is provided. + $course_group_times = []; + if ( $group_id > 0 ) { + foreach ( $course_ids as $course_id ) { + $course_group_times[ $course_id ] = (int) learndash_group_course_access_from( $group_id, $course_id ); + } + } + + foreach ( $user_ids as $user_id ) { + // Get user-group enrollment timestamp if group_id is provided. + $user_group_time = 0; + if ( $group_id > 0 ) { + $user_group_time = (int) learndash_group_access_from( $group_id, $user_id ); + } + + foreach ( $course_ids as $course_id ) { + $key = $user_id . '_' . $course_id; + + if ( isset( $existing_set[ $key ] ) ) { + continue; + } + + // Determine the access timestamp. + // When group_id is provided, use the later of user-group or course-group enrollment. + // This represents when both conditions were met for the user to access the course. + $access_time = $current_time; + if ( $group_id > 0 ) { + $course_time = $course_group_times[ $course_id ] ?? 0; + if ( + $user_group_time > 0 + && $course_time > 0 + ) { + $access_time = max( $user_group_time, $course_time ); + } elseif ( $user_group_time > 0 ) { + $access_time = $user_group_time; + } elseif ( $course_time > 0 ) { + $access_time = $course_time; + } + } + + $new_records[] = [ + 'user_id' => $user_id, + 'course_id' => $course_id, + 'post_id' => $course_id, + 'activity_type' => 'access', + 'activity_started' => $access_time, + 'activity_status' => 0, + 'activity_updated' => $access_time, + ]; + } + } + + if ( empty( $new_records ) ) { + return 0; + } + + /** + * Filters the chunk size for bulk course access activity creation. + * + * @since 5.0.1 + * + * @param int $chunk_size The number of records to insert per database query. Default 500. + * + * @return int The number of records to insert per database query. Default 500. + */ + $chunk_size = max( 1, Cast::to_int( apply_filters( 'learndash_group_access_activity_chunk_size', 500 ) ) ); + $created_count = 0; + + foreach ( array_chunk( $new_records, $chunk_size ) as $chunk ) { + $values = []; + $placeholders = []; + + foreach ( $chunk as $record ) { + $placeholders[] = '(%d, %d, %d, %s, %d, %d, %d)'; + $values[] = $record['user_id']; + $values[] = $record['course_id']; + $values[] = $record['post_id']; + $values[] = $record['activity_type']; + $values[] = $record['activity_started']; + $values[] = $record['activity_status']; + $values[] = $record['activity_updated']; + } + + // Bulk insert. QueryBuilder::insert() cannot be used as wpdb::insert() only can insert one row at a time. + $sql = sprintf( + 'INSERT INTO %s (user_id, course_id, post_id, activity_type, activity_started, activity_status, activity_updated) VALUES %s', + $activity_table, + implode( ', ', $placeholders ) + ); + + // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $sql is built with placeholders above. + $prepared_sql = Cast::to_string( DB::prepare( $sql, ...$values ) ); + + if ( empty( $prepared_sql ) ) { + continue; + } + + // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Prepared above, bulk insert requires direct query, no caching needed for inserts. + $inserted = DB::query( $prepared_sql ); + + if ( false !== $inserted ) { + $created_count += count( $chunk ); + } + } + + return $created_count; +} diff --git a/web/app/plugins/sfwd-lms/includes/course/ld-course-functions-legacy.php b/web/app/plugins/sfwd-lms/includes/course/ld-course-functions-legacy.php index bca5dec27..cb8b9f07a 100644 --- a/web/app/plugins/sfwd-lms/includes/course/ld-course-functions-legacy.php +++ b/web/app/plugins/sfwd-lms/includes/course/ld-course-functions-legacy.php @@ -13,11 +13,11 @@ exit; } -// cspell:ignore accessable . - /** * Gets the lesson list for a course. * + * Important: This function is not recommended. Use `Course::get_lessons` instead. + * * @global wpdb $wpdb WordPress database abstraction object. * @global WP_Post $post Global post object. * @@ -104,1605 +104,3 @@ function learndash_get_lesson_list( $id = null, $atts = array() ) { return array(); } - -/** - * LEGACY: Gets the lesson list output for a course. - * - * Replaced by `learndash_get_course_lessons_list` in 3.4.0. - * - * @since 2.1.0 - * - * @param int|WP_Post|null $course Optional. The `WP_Post` course object or course ID. Default null. - * @param int|null $user_id Optional. User ID. Default null. - * @param array $lessons_args Optional. An array of query arguments to get lesson list. Default empty array. - * - * @return array The lesson list array. - */ -function learndash_get_course_lessons_list_legacy( $course = null, $user_id = null, $lessons_args = array() ) { - if ( empty( $course ) ) { - $course_id = learndash_get_course_id(); - } - - if ( is_numeric( $course ) ) { - $course_id = $course; - $course = get_post( $course_id ); - } - - if ( empty( $course->ID ) ) { - return array(); - } - - $course_settings = learndash_get_setting( $course ); - $lessons_options = learndash_get_option( 'sfwd-lessons' ); - - $orderby = ( empty( $course_settings['course_lesson_orderby'] ) ) ? ( $lessons_options['orderby'] ?? '' ) : $course_settings['course_lesson_orderby']; - $order = ( empty( $course_settings['course_lesson_order'] ) ) ? ( $lessons_options['order'] ?? '' ) : $course_settings['course_lesson_order']; - - $lesson_query_pagination = 'true'; - if ( ( isset( $lessons_args['num'] ) ) && ( $lessons_args['num'] !== false ) ) { - if ( intval( $lessons_args['num'] ) == 0 ) { - $lesson_query_pagination = ''; - $posts_per_page = -1; - } else { - $posts_per_page = intval( $lessons_args['num'] ); - } - } else { - $posts_per_page = learndash_get_course_lessons_per_page( $course->ID ); - if ( empty( $posts_per_page ) ) { - $posts_per_page = -1; - $lesson_query_pagination = ''; - } - } - - $lesson_paged = 1; - if ( isset( $lessons_args['paged'] ) ) { - $lesson_paged = intval( $lessons_args['paged'] ); - } elseif ( isset( $_GET['ld-lesson-page'] ) ) { - $lesson_paged = intval( $_GET['ld-lesson-page'] ); - } - - if ( empty( $lesson_paged ) ) { - $lesson_paged = 1; - } - - $opt = array( - 'post_type' => 'sfwd-lessons', - 'meta_key' => 'course_id', - 'meta_value' => $course->ID, - 'order' => $order, - 'orderby' => $orderby, - 'posts_per_page' => $posts_per_page, - 'paged' => $lesson_paged, - 'pagination' => $lesson_query_pagination, - 'pager_context' => 'course_lessons', - 'return' => 'array', - 'user_id' => $user_id, - 'course_id' => $course->ID, - ); - $opt = wp_parse_args( $lessons_args, $opt ); - - if ( learndash_is_course_shared_steps_enabled() ) { - $ld_course_steps_object = LDLMS_Factory_Post::course_steps( $course->ID ); - - $lesson_ids = $ld_course_steps_object->get_children_steps( $course->ID, $opt['post_type'] ); - if ( ! empty( $lesson_ids ) ) { - $opt['include'] = implode( ',', $lesson_ids ); - $opt['orderby'] = 'post__in'; - $opt['course_id'] = $course->ID; - - unset( $opt['order'] ); - unset( $opt['meta_key'] ); - unset( $opt['meta_value'] ); - } else { - return array(); - } - } - - $lessons = SFWD_CPT::loop_shortcode( $opt ); - return $lessons; -} - -/** - * LEGACY: Gets the topics list for a lesson. - * - * Replaced by `learndash_get_topic_list` in 3.4.0. - * - * @since 2.1.0 - * - * @param int|null $for_lesson_id Optional. The ID of the lesson to get topics. - * @param int|null $course_id Optional. Course ID. - * - * @return array An array of topics list. - */ -function learndash_get_topic_list_legacy( $for_lesson_id = null, $course_id = null ) { - if ( empty( $course_id ) ) { - $course_id = learndash_get_course_id( $for_lesson_id ); - } - - if ( ( ! empty( $for_lesson_id ) ) && ( ! empty( $course_id ) ) ) { - $transient_key = 'learndash_lesson_topics_' . $course_id . '_' . $for_lesson_id; - } elseif ( ! empty( $for_lesson_id ) ) { - $transient_key = 'learndash_lesson_topics_' . $for_lesson_id; - } else { - $transient_key = 'learndash_lesson_topics_all'; - } - - $topics_array = LDLMS_Transients::get( $transient_key ); - - if ( false === $topics_array ) { - - if ( ! empty( $for_lesson_id ) ) { - - $lessons_options = sfwd_lms_get_post_options( 'sfwd-lessons' ); - $orderby = $lessons_options['orderby']; - $order = $lessons_options['order']; - - if ( ! empty( $course_id ) ) { - $course_lessons_args = learndash_get_course_lessons_order( $course_id ); - $orderby = isset( $course_lessons_args['orderby'] ) ? $course_lessons_args['orderby'] : 'title'; - $order = isset( $course_lessons_args['order'] ) ? $course_lessons_args['order'] : 'ASC'; - } - } else { - $orderby = 'name'; - $order = 'ASC'; - } - - $topics_query_args = array( - 'post_type' => 'sfwd-topic', - 'numberposts' => -1, - 'orderby' => $orderby, - 'order' => $order, - ); - - if ( ! empty( $for_lesson_id ) ) { - $topics_query_args['meta_key'] = 'lesson_id'; - $topics_query_args['meta_value'] = $for_lesson_id; - $topics_query_args['meta_compare'] = '='; - } - - if ( learndash_is_course_shared_steps_enabled() ) { - if ( ! empty( $course_id ) ) { - - $ld_course_steps_object = LDLMS_Factory_Post::course_steps( $course_id ); - $ld_course_steps_object->load_steps(); - $steps = $ld_course_steps_object->get_steps(); - - if ( ( isset( $steps['sfwd-lessons'][ $for_lesson_id ]['sfwd-topic'] ) ) && ( ! empty( $steps['sfwd-lessons'][ $for_lesson_id ]['sfwd-topic'] ) ) ) { - $topic_ids = array_keys( $steps['sfwd-lessons'][ $for_lesson_id ]['sfwd-topic'] ); - $topics_query_args['include'] = $topic_ids; - $topics_query_args['orderby'] = 'post__in'; - - unset( $topics_query_args['order'] ); - unset( $topics_query_args['meta_key'] ); - unset( $topics_query_args['meta_value'] ); - unset( $topics_query_args['meta_compare'] ); - } else { - return array(); - } - } - } - - $topics = get_posts( $topics_query_args ); - - if ( ! empty( $topics ) ) { - if ( empty( $for_lesson_id ) ) { - $topics_array = array(); - - foreach ( $topics as $topic ) { - if ( learndash_is_course_shared_steps_enabled() ) { - $course_id = learndash_get_course_id( $topic->ID ); - $lesson_id = learndash_course_get_single_parent_step( $course_id, $topic->ID ); - } else { - $lesson_id = learndash_get_setting( $topic, 'lesson' ); - } - - if ( ! empty( $lesson_id ) ) { - // Need to clear out the post_content before transient storage. - $topic->post_content = 'EMPTY'; - $topics_array[ $lesson_id ][] = $topic; - } - } - LDLMS_Transients::set( $transient_key, $topics_array, MINUTE_IN_SECONDS ); - return $topics_array; - } else { - LDLMS_Transients::set( $transient_key, $topics, MINUTE_IN_SECONDS ); - return $topics; - } - } - } else { - return $topics_array; - } - - return array(); -} - -/** - * LEGACY: Gets the quiz list output for a course. - * - * Replaced by `learndash_get_course_quiz_list` in 3.4.0. - * - * @since 2.1.0 - * - * @param int|WP_Post|null $course Optional. The `WP_Post` course object or course ID. Default null. - * @param int|null $user_id Optional. User ID. Default null. - * - * @return array|string The quiz list HTML output. - */ -function learndash_get_course_quiz_list_legacy( $course = null, $user_id = null ) { - if ( empty( $course ) ) { - $course_id = learndash_get_course_id(); - $course = get_post( $course_id ); - } - - if ( is_numeric( $course ) ) { - $course_id = $course; - $course = get_post( $course_id ); - } - - if ( empty( $course->ID ) ) { - return array(); - } - - $course_settings = learndash_get_setting( $course ); - $lessons_options = learndash_get_option( 'sfwd-lessons' ); - $orderby = ( empty( $course_settings['course_lesson_orderby'] ) ) ? ( $lessons_options['orderby'] ?? '' ) : $course_settings['course_lesson_orderby']; - $order = ( empty( $course_settings['course_lesson_order'] ) ) ? ( $lessons_options['order'] ?? '' ) : $course_settings['course_lesson_order']; - $opt = array( - 'post_type' => 'sfwd-quiz', - 'meta_key' => 'course_id', - 'meta_value' => $course->ID, - 'order' => $order, - 'orderby' => $orderby, - 'posts_per_page' => -1, - 'user_id' => $user_id, - 'return' => 'array', - ); - - if ( learndash_is_course_shared_steps_enabled() ) { - $ld_course_steps_object = LDLMS_Factory_Post::course_steps( $course->ID ); - - $lesson_ids = $ld_course_steps_object->get_children_steps( $course->ID, $opt['post_type'] ); - - if ( ! empty( $lesson_ids ) ) { - $opt['include'] = implode( ',', $lesson_ids ); - $opt['orderby'] = 'post__in'; - $opt['course_id'] = $course->ID; - - unset( $opt['order'] ); - unset( $opt['meta_key'] ); - unset( $opt['meta_value'] ); - } else { - return array(); - } - } - $quizzes = SFWD_CPT::loop_shortcode( $opt ); - return $quizzes; -} - -/** - * LEGACY: Gets the quiz list output for a lesson. - * - * Replaced by `learndash_get_lesson_quiz_list` in 3.4.0. - * - * @since 2.1.0 - * - * @param int|WP_Post $lesson The `WP_Post` lesson object or lesson ID. - * @param int|null $user_id Optional. User ID. Default null. - * @param int|null $course_id Optional. Course ID. Default null. - * - * @return array|string The lesson quiz list HTML output. - */ -function learndash_get_lesson_quiz_list_legacy( $lesson, $user_id = null, $course_id = null ) { - if ( is_numeric( $lesson ) ) { - $lesson_id = $lesson; - $lesson = get_post( $lesson_id ); - } - - if ( empty( $lesson->ID ) ) { - return array(); - } - - if ( empty( $course_id ) ) { - $course_id = learndash_get_course_id( $lesson ); - } - - $course_settings = learndash_get_setting( $course_id ); - $lessons_options = learndash_get_option( 'sfwd-lessons' ); - $orderby = ( empty( $course_settings['course_lesson_orderby'] ) ) ? ( $lessons_options['orderby'] ?? '' ) : $course_settings['course_lesson_orderby']; - $order = ( empty( $course_settings['course_lesson_order'] ) ) ? ( $lessons_options['order'] ?? '' ) : $course_settings['course_lesson_order']; - $opt = array( - 'post_type' => 'sfwd-quiz', - 'meta_key' => 'lesson_id', - 'meta_value' => $lesson->ID, - 'order' => $order, - 'orderby' => $orderby, - 'posts_per_page' => -1, - 'user_id' => $user_id, - 'return' => 'array', - 'course_id' => $course_id, - ); - - if ( learndash_is_course_shared_steps_enabled() ) { - $ld_course_steps_object = LDLMS_Factory_Post::course_steps( $course_id ); - if ( $ld_course_steps_object ) { - $quiz_ids = $ld_course_steps_object->get_children_steps( $lesson->ID, $opt['post_type'] ); - if ( ! empty( $quiz_ids ) ) { - $opt['include'] = implode( ',', $quiz_ids ); - $opt['orderby'] = 'post__in'; - - unset( $opt['order'] ); - unset( $opt['meta_key'] ); - unset( $opt['meta_value'] ); - } else { - return array(); - } - } - } - - $quizzes = SFWD_CPT::loop_shortcode( $opt ); - return $quizzes; -} - -/** - * LEGACY: Gets the quiz list for a resource. - * - * Replaced by `learndash_get_global_quiz_list` in 3.4.0. - * - * @global WP_Post $post Global post object. - * - * @since 2.1.0 - * - * @param int|null $id Optional. An ID of the resource. - * - * @return array An array of quizzes. - */ -function learndash_get_global_quiz_list_legacy( $id = null ) { - global $post; - - if ( empty( $id ) ) { - if ( ! empty( $post->ID ) ) { - $id = $post->ID; - } else { - return array(); - } - } - - // COURSE ID CHANGE. - $course_id = learndash_get_course_id( $id ); - if ( ! empty( $course_id ) ) { - if ( learndash_is_course_shared_steps_enabled() ) { - $quiz_ids = learndash_course_get_children_of_step( $course_id, $course_id, 'sfwd-quiz' ); - if ( ! empty( $quiz_ids ) ) { - return get_posts( - array( - 'post_type' => 'sfwd-quiz', - 'posts_per_page' => -1, - 'include' => $quiz_ids, - 'orderby' => 'post__in', - 'order' => 'ASC', - ) - ); - - } - } else { - $transient_key = 'learndash_quiz_course_' . $course_id; - $quizzes_new = LDLMS_Transients::get( $transient_key ); - if ( false === $quizzes_new ) { - - $course_settings = learndash_get_setting( $course_id ); - $lessons_options = learndash_get_option( 'sfwd-lessons' ); - $orderby = ( empty( $course_settings['course_lesson_orderby'] ) ) ? ( $lessons_options['orderby'] ?? '' ) : $course_settings['course_lesson_orderby']; - $order = ( empty( $course_settings['course_lesson_order'] ) ) ? ( $lessons_options['order'] ?? '' ) : $course_settings['course_lesson_order']; - - $quizzes = get_posts( - array( - 'post_type' => 'sfwd-quiz', - 'posts_per_page' => -1, - 'meta_key' => 'course_id', - 'meta_value' => $course_id, - 'meta_compare' => '=', - 'orderby' => $orderby, - 'order' => $order, - ) - ); - - $quizzes_new = array(); - - foreach ( $quizzes as $k => $quiz ) { - $quiz_lesson = learndash_get_setting( $quiz, 'lesson' ); - if ( empty( $quiz_lesson ) ) { - $quizzes_new[] = $quizzes[ $k ]; - } - } - - LDLMS_Transients::set( $transient_key, $quizzes_new, MINUTE_IN_SECONDS ); - } - return $quizzes_new; - } - } - - return array(); -} - -/** - * LEGACY: Gets the course data for the course builder. - * - * Replaced by `learndash_get_course_data` in 3.4.0. - * - * @since 3.4.0 - * - * @param array $data The data passed down to the front-end. - * - * @return array The data passed down to the front-end. - */ -function learndash_get_course_data_legacy( $data ) { - global $pagenow, $typenow; - - $output_lessons = array(); - $output_quizzes = array(); - $sections = array(); - - if ( ( 'post.php' === $pagenow ) && ( learndash_get_post_type_slug( 'course' ) === $typenow ) ) { - $course_id = isset( $_GET['course_id'] ) ? absint( $_GET['course_id'] ) : get_the_ID(); - if ( ! empty( $course_id ) ) { - // Get a list of lessons to loop. - $lessons = learndash_get_course_lessons_list( $course_id, null, array( 'num' => 0 ) ); - $output_lessons = array(); - $lesson_topics = array(); - - if ( ( is_array( $lessons ) ) && ( ! empty( $lessons ) ) ) { - // Loop course's lessons. - foreach ( $lessons as $lesson ) { - $post = $lesson['post']; - // Get lesson's topics. - $topics = learndash_topic_dots( $post->ID, false, 'array', null, $course_id ); - $output_topics = array(); - - if ( ( is_array( $topics ) ) && ( ! empty( $topics ) ) ) { - // Loop Topics. - foreach ( $topics as $topic ) { - // Get topic's quizzes. - $topic_quizzes = learndash_get_lesson_quiz_list( $topic->ID, null, $course_id ); - $output_topic_quizzes = array(); - - if ( ( is_array( $topic_quizzes ) ) && ( ! empty( $topic_quizzes ) ) ) { - // Loop Topic's Quizzes. - foreach ( $topic_quizzes as $quiz ) { - $quiz_post = $quiz['post']; - - $output_topic_quizzes[] = array( - 'ID' => $quiz_post->ID, - 'expanded' => true, - 'post_title' => $quiz_post->post_title, - 'type' => $quiz_post->post_type, - 'url' => learndash_get_step_permalink( $quiz_post->ID, $course_id ), - 'edit_link' => get_edit_post_link( $quiz_post->ID, '' ), - 'tree' => array(), - ); - } - } - - $output_topics[] = array( - 'ID' => $topic->ID, - 'expanded' => true, - 'post_title' => $topic->post_title, - 'type' => $topic->post_type, - 'url' => learndash_get_step_permalink( $topic->ID, $course_id ), - 'edit_link' => get_edit_post_link( $topic->ID, '' ), - 'tree' => $output_topic_quizzes, - ); - } - } - - // Get lesson's quizzes. - $quizzes = learndash_get_lesson_quiz_list( $post->ID, null, $course_id ); - $output_quizzes = array(); - - if ( ( is_array( $quizzes ) ) && ( ! empty( $quizzes ) ) ) { - // Loop lesson's quizzes. - foreach ( $quizzes as $quiz ) { - $quiz_post = $quiz['post']; - - $output_quizzes[] = array( - 'ID' => $quiz_post->ID, - 'expanded' => true, - 'post_title' => $quiz_post->post_title, - 'type' => $quiz_post->post_type, - 'url' => learndash_get_step_permalink( $quiz_post->ID, $course_id ), - 'edit_link' => get_edit_post_link( $quiz_post->ID, '' ), - 'tree' => array(), - ); - } - } - - // Output lesson with child tree. - $output_lessons[] = array( - 'ID' => $post->ID, - 'expanded' => false, - 'post_title' => $post->post_title, - 'type' => $post->post_type, - 'url' => $lesson['permalink'], - 'edit_link' => get_edit_post_link( $post->ID, '' ), - 'tree' => array_merge( $output_topics, $output_quizzes ), - ); - } - } - - // Get a list of quizzes to loop. - $quizzes = learndash_get_course_quiz_list( $course_id ); - $output_quizzes = array(); - - if ( ( is_array( $quizzes ) ) && ( ! empty( $quizzes ) ) ) { - // Loop course's quizzes. - foreach ( $quizzes as $quiz ) { - $post = $quiz['post']; - - $output_quizzes[] = array( - 'ID' => $post->ID, - 'expanded' => true, - 'post_title' => $post->post_title, - 'type' => $post->post_type, - 'url' => learndash_get_step_permalink( $post->ID, $course_id ), - 'edit_link' => get_edit_post_link( $post->ID, '' ), - 'tree' => array(), - ); - } - } - - // Merge sections at Outline. - $sections_raw = get_post_meta( $course_id, 'course_sections', true ); - $sections = ! empty( $sections_raw ) ? json_decode( $sections_raw ) : array(); - - if ( ( is_array( $sections ) ) && ( ! empty( $sections ) ) ) { - foreach ( $sections as $section ) { - array_splice( $output_lessons, (int) $section->order, 0, array( $section ) ); - } - } - } - } - - // Output data. - $data['outline'] = array( - 'lessons' => $output_lessons, - 'quizzes' => $output_quizzes, - 'sections' => $sections, - ); - - return $data; -} - -/** - * LEGACY: Gets the total count of lessons and topics for a given course ID. - * - * Replaced by `learndash_get_course_steps_count` in 3.4.0. - * - * @since 2.3.0 - * - * @param int $course_id Optional. The ID of the course. Default 0. - * - * @return int The count of the course steps. - */ -function learndash_get_course_steps_count_legacy( $course_id = 0 ) { - static $courses_steps = array(); - - $course_id = absint( $course_id ); - - if ( ! isset( $courses_steps[ $course_id ] ) ) { - $courses_steps[ $course_id ] = 0; - - $course_steps = learndash_get_course_steps( $course_id ); - if ( ! empty( $course_steps ) ) { - $courses_steps[ $course_id ] = count( $course_steps ); - } - - if ( learndash_has_global_quizzes( $course_id ) ) { - $courses_steps[ $course_id ] += 1; - } - } - - return $courses_steps[ $course_id ]; -} - -/** - * LEGACY: Outputs the current status of the course. - * - * Replaced by `learndash_course_status` in 3.4.0. - * - * @since 2.1.0 - * @since 2.5.8 Added $return_slug parameter. - * - * @param int $id Course ID to get status. - * @param int|null $user_id Optional. User ID. Default null. - * @param boolean $return_slug Optional. If false will return translatable string otherwise the status slug. Default false. - * - * @return string The current status of the course. - */ -function learndash_course_status_legacy( $id, $user_id = null, $return_slug = false ) { - $course_status_str = ''; - - if ( empty( $user_id ) ) { - if ( ! is_user_logged_in() ) { - return $course_status_str; - } - - $user_id = get_current_user_id(); - } else { - $user_id = intval( $user_id ); - } - - $completed_on = get_user_meta( $user_id, 'course_completed_' . $id, true ); - if ( ! empty( $completed_on ) ) { - if ( true === $return_slug ) { - $course_status_str = 'completed'; - } else { - $course_status_str = esc_html__( 'Completed', 'learndash' ); - } - } else { - $course_progress = get_user_meta( $user_id, '_sfwd-course_progress', true ); - /** - * We need a better solution for this. A central class to ensure - * correct data compliance and required elements are present. But - * for now adding this here. - * LEARNDASH-4868 - */ - if ( ! is_array( $course_progress ) ) { - $course_progress = array(); - } - if ( ! isset( $course_progress[ $id ] ) ) { - $course_progress[ $id ] = array(); - } - if ( ! isset( $course_progress[ $id ]['completed'] ) ) { - $course_progress[ $id ]['completed'] = 0; - } - if ( ! isset( $course_progress[ $id ]['total'] ) ) { - $course_progress[ $id ]['total'] = 0; - } - - /** - * Filters the recalculation of the course steps. - * - * @since 3.3.0 - * - * @param bool $recalculate_course_total_steps Recalculate course total steps. Default true. - * @param array $course_progress Array of course progress. - * @param int $user_id User ID. - * @param int $course_id Course ID. - */ - if ( apply_filters( 'learndash_course_status_recalc_total_steps', true, $course_progress[ $id ], $user_id, $id ) ) { - $course_steps_count = learndash_get_course_steps_count( $id ); - if ( ( ! empty( $course_steps_count ) ) && ( $course_steps_count < absint( $course_progress[ $id ]['total'] ) ) ) { - $course_progress[ $id ]['total'] = $course_steps_count; - - // We also need to update the user meta since other functions will retrieve this data. - update_user_meta( $user_id, '_sfwd-course_progress', $course_progress ); - } - } - - $has_completed_topic = false; - - if ( ! empty( $course_progress[ $id ] ) && ! empty( $course_progress[ $id ]['topics'] ) && is_array( $course_progress[ $id ]['topics'] ) ) { - foreach ( $course_progress[ $id ]['topics'] as $lesson_topics ) { - if ( ! empty( $lesson_topics ) && is_array( $lesson_topics ) ) { - foreach ( $lesson_topics as $topic ) { - if ( ! empty( $topic ) ) { - $has_completed_topic = true; - break; - } - } - } - - if ( $has_completed_topic ) { - break; - } - } - } - - $quizzes = learndash_get_global_quiz_list( $id ); - if ( ! empty( $quizzes ) ) { - $quizzes_incomplete = array(); - foreach ( $quizzes as $quiz ) { - if ( learndash_is_quiz_notcomplete( $user_id, array( $quiz->ID => 1 ), false, $id ) ) { - $quizzes_incomplete[] = $quiz->ID; - } - } - - if ( ! empty( $quizzes_incomplete ) ) { - $quiz_notstarted = true; - } else { - if ( has_filter( 'learndash_post_args_groups' ) ) { - /** - * Filters whether to autocomplete courses with final quizzes after the first final quiz is completed. - * - * @since 3.2.0 - * - * @param bool false Action to auto complete course step. - * @param int $id Course ID - * @param int $user_id User ID - */ - apply_filters_deprecated( 'learndash_prevent_course_autocompletion_multiple_final_quizzes', array( false, $id, $user_id ), '3.2.3', 'learndash_course_autocompletion_multiple_final_quizzes_step' ); - } - - /** - * Filters to autocomplete course with multiple final (global) quizzes when not all are complete. - * - * @since 3.2.3 - * - * @param bool $autocomplete_course_step Autocomplete course step. Default false. - * @param int $id Course ID - * @param int $user_id User ID - * @param array $quizzes Course Global Quiz Posts. - * @param array $quizzes_incomplete Array of incomplete Quizzes IDs. - * - * @return bool True auto complete step, false do not auto complete step. - */ - $quiz_notstarted = apply_filters( - 'learndash_course_autocompletion_multiple_final_quizzes_step', - false, - $id, - $user_id, - $quizzes, - $quizzes_incomplete - ); - } - - if ( true !== $quiz_notstarted ) { - $course_progress[ $id ]['completed'] += 1; - } - } else { - $quiz_notstarted = true; - } - - if ( ( empty( $course_progress[ $id ] ) || empty( $course_progress[ $id ]['lessons'] ) && ! $has_completed_topic ) && $quiz_notstarted ) { - if ( true === $return_slug ) { - $course_status_str = 'not-started'; - } else { - $course_status_str = esc_html__( 'Not Started', 'learndash' ); - } - } elseif ( - empty( $course_progress[ $id ] ) - || ( - isset( $course_progress[ $id ]['completed'] ) - && isset( $course_progress[ $id ]['total'] ) - && $course_progress[ $id ]['completed'] < $course_progress[ $id ]['total'] - ) - ) { - if ( true === $return_slug ) { - $course_status_str = 'in-progress'; - } else { - $course_status_str = esc_html__( 'In Progress', 'learndash' ); - } - } elseif ( - isset( $course_progress[ $id ]['completed'] ) - && isset( $course_progress[ $id ]['total'] ) - && absint( $course_progress[ $id ]['completed'] ) === absint( $course_progress[ $id ]['total'] ) - ) { - if ( true === $return_slug ) { - $course_status_str = 'completed'; - } else { - $course_status_str = esc_html__( 'Completed', 'learndash' ); - } - - /** - * We call the standard mark complete function so it triggers the notifications etc. - */ - learndash_process_mark_complete( $user_id, $id, false, $id ); - } - } - - if ( true === $return_slug ) { - return $course_status_str; - } else { - /** - * Filters the current status of the course. - * - * @param string $course_status_str The translatable current course status string. - * @param int $course_id Course ID. - * @param int $user_id User ID. - * @param array $name Current course progress. - */ - return apply_filters( - 'learndash_course_status', - $course_status_str, - $id, - $user_id, - isset( $course_progress[ $id ] ) ? $course_progress[ $id ] : array() - ); - } -} - -/** - * LEGACY: Checks if a lesson is not complete. - * - * Replaced by `learndash_is_lesson_notcomplete` in 3.4.0. - * - * @since 2.1.0 - * - * @param int|null $user_id Optional. User ID. Defaults to the current logged-in user. Default null. - * @param array $lessons Optional. An array of lesson IDs. - * @param int $course_id Optional. Course ID. Default 0. - * - * @return boolean Returns true if the lesson is not complete otherwise false. - */ -function learndash_is_lesson_notcomplete_legacy( $user_id = null, $lessons = array(), $course_id = 0 ) { - if ( empty( $user_id ) ) { - $current_user = wp_get_current_user(); - $user_id = $current_user->ID; - } - - $course_id = absint( $course_id ); - if ( empty( $course_id ) ) { - $use_lesson_course = true; - } else { - $use_lesson_course = false; - } - - $course_progress = get_user_meta( $user_id, '_sfwd-course_progress', true ); - - if ( ! empty( $lessons ) ) { - foreach ( $lessons as $lesson => $v ) { - if ( true === $use_lesson_course ) { - $course_id = learndash_get_course_id( $lesson ); - } - - if ( ! empty( $course_progress[ $course_id ] ) && ! empty( $course_progress[ $course_id ]['lessons'] ) && ! empty( $course_progress[ $course_id ]['lessons'][ $lesson ] ) ) { - unset( $lessons[ $lesson ] ); - } - } - } - - if ( empty( $lessons ) ) { - return 0; - } else { - return 1; - } -} - -/** - * LEGACY: Checks if a topic is not complete. - * - * Replaced by `learndash_is_topic_notcomplete` in 3.4.0. - * - * @since 2.3.1 - * @since 3.2.0 Added `$course_id` parameter - * - * @param int|null $user_id Optional. User ID. Defaults to the current logged-in user. Default null. - * @param array $topics Optional. An array of topic IDs. - * @param int $course_id Optional. Course ID. - * - * @return boolean Returns true if the topic is not completed otherwise false. - */ -function learndash_is_topic_notcomplete_legacy( $user_id = null, $topics = array(), $course_id = 0 ) { - if ( empty( $user_id ) ) { - $current_user = wp_get_current_user(); - $user_id = $current_user->ID; - } - $user_id = absint( $user_id ); - $course_id = absint( $course_id ); - if ( empty( $course_id ) ) { - $use_topic_course = true; - } else { - $use_topic_course = false; - } - - $course_progress = get_user_meta( $user_id, '_sfwd-course_progress', true ); - - if ( ! empty( $topics ) ) { - foreach ( $topics as $topic_id => $v ) { - if ( true === $use_topic_course ) { - $course_id = learndash_get_course_id( $topic_id ); - } - $lesson_id = learndash_get_lesson_id( $topic_id ); - - if ( ( isset( $course_progress[ $course_id ] ) ) - && ( ! empty( $course_progress[ $course_id ] ) ) - && ( isset( $course_progress[ $course_id ]['topics'] ) ) - && ( ! empty( $course_progress[ $course_id ]['topics'] ) ) - && ( isset( $course_progress[ $course_id ]['topics'][ $lesson_id ][ $topic_id ] ) ) - && ( ! empty( $course_progress[ $course_id ]['topics'][ $lesson_id ][ $topic_id ] ) ) ) { - unset( $topics[ $topic_id ] ); - } - } - } - - if ( empty( $topics ) ) { - return 0; - } else { - return 1; - } -} - -/** - * Checks if the quiz is accessible to the user (legacy). - * - * Replaced by `learndash_is_quiz_accessable` in 3.4.0. - * - * @since 2.4.0 - * - * @param int|null $user_id Optional. User ID. Default null. - * @param WP_Post|null $post Optional. The `WP_Post` quiz object. Default null. - * @param int $course_id Optional. Course ID. Default 0. - * - * @return int Returns 1 if the quiz is accessible by the user otherwise 0. - */ -function learndash_is_quiz_accessable_legacy( $user_id = null, $post = null, $course_id = 0 ) { - if ( empty( $user_id ) ) { - $current_user = wp_get_current_user(); - - if ( empty( $current_user->ID ) ) { - return 1; - } - - $user_id = $current_user->ID; - } - - if ( ( ! empty( $post ) ) && ( $post instanceof WP_Post ) ) { - if ( empty( $course_id ) ) { - $course_id = learndash_get_course_id( $post ); - } - $course_id = absint( $course_id ); - - if ( learndash_is_course_shared_steps_enabled() ) { - $quiz_lesson = learndash_course_get_single_parent_step( $course_id, $post->ID ); - } else { - $quiz_lesson = learndash_get_setting( $post, 'lesson' ); - } - - if ( ! empty( $quiz_lesson ) ) { - $quiz_lesson_post = get_post( $quiz_lesson ); - if ( ( $quiz_lesson_post instanceof WP_Post ) && ( 'sfwd-topic' === $quiz_lesson_post->post_type ) ) { - return 1; - } elseif ( learndash_lesson_topics_completed( $quiz_lesson ) ) { - return 1; - } else { - return 0; - } - } else { - $course_progress = get_user_meta( $user_id, '_sfwd-course_progress', true ); - - if ( ! empty( $course_progress ) && ! empty( $course_progress[ $course_id ] ) && ! empty( $course_progress[ $course_id ]['total'] ) ) { - $completed = intVal( $course_progress[ $course_id ]['completed'] ); - $total = intVal( $course_progress[ $course_id ]['total'] ); - - if ( $completed >= $total - 1 ) { - return 1; - } - } - - $lessons = learndash_get_lesson_list( $course_id, array( 'num' => 0 ) ); - - if ( empty( $lessons ) ) { - return 1; - } - } - } - return 0; -} - -/** - * LEGACY: Gets the user's current course progress. - * - * Replaced by `learndash_get_course_progress` in 3.4.0. - * - * @since 2.1.0 - * - * @param int|null $user_id Optional. User ID. Default null. - * @param int|null $postid Optional. Post ID. Default null. - * @param int|null $course_id Optional. Course ID. Default null. - * - * @return array An array of user's current course progress. - */ -function learndash_get_course_progress_legacy( $user_id = null, $postid = null, $course_id = null ) { - if ( empty( $user_id ) ) { - $current_user = wp_get_current_user(); - - if ( empty( $current_user->ID ) ) { - return null; - } - - $user_id = $current_user->ID; - } - - $posts = array(); - - $posts = array(); - - if ( is_null( $course_id ) ) { - $course_id = learndash_get_course_id( $postid ); - } - - $course_progress = get_user_meta( $user_id, '_sfwd-course_progress', true ); - $this_post = get_post( $postid ); - - if ( empty( $course_progress ) ) { - $course_progress = array(); - } - - if ( 'sfwd-lessons' === $this_post->post_type ) { - $posts = learndash_get_lesson_list( $postid, array( 'num' => 0 ) ); - - if ( empty( $course_progress ) || empty( $course_progress[ $course_id ]['lessons'] ) ) { - $completed_posts = array(); - } else { - $completed_posts = $course_progress[ $course_id ]['lessons']; - } - } elseif ( 'sfwd-topic' === $this_post->post_type ) { - if ( learndash_is_course_shared_steps_enabled() ) { - $lesson_id = learndash_course_get_single_parent_step( $course_id, $this_post->ID ); - } else { - $lesson_id = learndash_get_setting( $this_post, 'lesson' ); - } - $posts = learndash_get_topic_list( $lesson_id, $course_id ); - - if ( empty( $course_progress ) || empty( $course_progress[ $course_id ]['topics'][ $lesson_id ] ) ) { - $completed_posts = array(); - } else { - $completed_posts = $course_progress[ $course_id ]['topics'][ $lesson_id ]; - } - } - - $temp = ''; - $prev_p = ''; - $next_p = ''; - $this_p = ''; - - if ( ! empty( $posts ) ) { - foreach ( $posts as $k => $post ) { - - if ( $post instanceof WP_Post ) { - - if ( ! empty( $completed_posts[ $post->ID ] ) ) { - $posts[ $k ]->completed = 1; - } else { - $posts[ $k ]->completed = 0; - } - - if ( $post->ID == $postid ) { - $this_p = $post; - $prev_p = $temp; - } - - if ( ! empty( $temp->ID ) && $temp->ID == $postid ) { - $next_p = $post; - } - - $temp = $post; - } - } - } else { - $posts = array(); - } - - return array( - 'posts' => $posts, - 'this' => $this_p, - 'prev' => $prev_p, - 'next' => $next_p, - ); -} - -/** - * LEGACY: Gets all the lessons and topics for a given course ID. - * - * For now excludes quizzes at lesson and topic level. - * - * Replaced by `learndash_get_course_steps` in 3.4.0. - * - * @since 2.3.0 - * - * @param int $course_id Optional. The ID of the course. Default 0. - * @param array $include_post_types Optional. An array of post types to include in course steps. Default array contains 'sfwd-lessons' and 'sfwd-topic'. - * - * @return array An array of all course steps. - */ -function learndash_get_course_steps_legacy( $course_id = 0, $include_post_types = array( 'sfwd-lessons', 'sfwd-topic' ) ) { - - // The steps array will hold all the individual step counts for each post_type. - $steps = array(); - - // This will hold the combined steps post ids once we have run all queries. - $steps_all = array(); - - if ( ! empty( $course_id ) ) { - if ( learndash_is_course_builder_enabled() ) { - foreach ( $include_post_types as $post_type ) { - $steps[ $post_type ] = learndash_course_get_steps_by_type( $course_id, $post_type ); - } - } else { - if ( ( in_array( 'sfwd-lessons', $include_post_types, true ) ) || ( in_array( 'sfwd-topic', $include_post_types, true ) ) ) { - $lesson_steps_query_args = array( - 'post_type' => 'sfwd-lessons', - 'posts_per_page' => -1, - 'post_status' => 'publish', - 'fields' => 'ids', - 'meta_query' => array( - array( - 'key' => 'course_id', - 'value' => intval( $course_id ), - 'compare' => '=', - 'type' => 'NUMERIC', - ), - ), - ); - - $lesson_steps_query = new WP_Query( $lesson_steps_query_args ); - if ( $lesson_steps_query->have_posts() ) { - $steps['sfwd-lessons'] = $lesson_steps_query->posts; - } - } - - // For Topics we still require the parent lessons items. - if ( in_array( 'sfwd-topic', $include_post_types, true ) ) { - - if ( ! empty( $steps['sfwd-lessons'] ) ) { - $topic_steps_query_args = array( - 'post_type' => 'sfwd-topic', - 'posts_per_page' => -1, - 'post_status' => 'publish', - 'fields' => 'ids', - 'meta_query' => array( - array( - 'key' => 'course_id', - 'value' => intval( $course_id ), - 'compare' => '=', - 'type' => 'NUMERIC', - ), - ), - ); - - if ( ( isset( $steps['sfwd-lessons'] ) ) && ( ! empty( $steps['sfwd-lessons'] ) ) ) { - $topic_steps_query_args['meta_query'][] = array( - 'key' => 'lesson_id', - 'value' => $steps['sfwd-lessons'], - 'compare' => 'IN', - 'type' => 'NUMERIC', - ); - } - - $topic_steps_query = new WP_Query( $topic_steps_query_args ); - if ( $topic_steps_query->have_posts() ) { - $steps['sfwd-topic'] = $topic_steps_query->posts; - } - } else { - $steps['sfwd-topic'] = array(); - } - } - } - } - - foreach ( $include_post_types as $post_type ) { - if ( ( isset( $steps[ $post_type ] ) ) && ( ! empty( $steps[ $post_type ] ) ) ) { - $steps_all = array_merge( $steps_all, $steps[ $post_type ] ); - } - } - - return $steps_all; -} - -/** - * LEGACY: Updates the user meta with completion status for any resource. - * - * Replaced by `learndash_process_mark_complete` in 3.4.0. - * - * @since 2.1.0 - * - * @param int|null $user_id Optional. User ID. Default null. - * @param int|null $postid Optional. The ID of the resource like course, lesson, topic, etc. Default null. - * @param boolean $onlycalculate Optional. Whether to mark the resource as complete. Default false. - * @param int $course_id Optional. Course ID. Default 0. - * - * @return boolean Returns true if the meta is updated successfully otherwise false. - */ -function learndash_process_mark_complete_legacy( $user_id = null, $postid = null, $onlycalculate = false, $course_id = 0 ) { - if ( empty( $user_id ) ) { - if ( is_user_logged_in() ) { - $current_user = wp_get_current_user(); - $user_id = $current_user->ID; - } else { - return false; - } - } else { - $current_user = get_user_by( 'id', $user_id ); - } - - $post = get_post( $postid ); - if ( ! ( $post instanceof WP_Post ) ) { - return false; - } - - if ( ! $onlycalculate ) { - - /** - * Filters whether to mark a process complete. - * - * @since 2.1.0 - * - * @param boolean $mark_complete Whether to mark a process complete. - * @param WP_Post $post WP_Post object to be checked. - * @param WP_User $current_user Current logged in WP_User object. - */ - $process_completion = apply_filters( 'learndash_process_mark_complete', true, $post, $current_user ); - - if ( ! $process_completion ) { - return false; - } - } - - if ( 'sfwd-topic' === $post->post_type ) { - if ( learndash_is_course_builder_enabled() ) { - if ( empty( $course_id ) ) { - $course_id = learndash_get_course_id( $post->ID ); - } - $lesson_id = learndash_course_get_single_parent_step( $course_id, $post->ID ); - } else { - $lesson_id = learndash_get_setting( $post, 'lesson' ); - } - } - - if ( empty( $course_id ) ) { - $course_id = learndash_get_course_id( $postid ); - } - - if ( empty( $course_id ) ) { - return false; - } - - $lessons = learndash_get_lesson_list( $course_id, array( 'num' => 0 ) ); - - $course_progress = get_user_meta( $user_id, '_sfwd-course_progress', true ); - - if ( ( empty( $course_progress ) ) || ( ! is_array( $course_progress ) ) ) { - $course_progress = array(); - } - - if ( ( ! isset( $course_progress[ $course_id ] ) ) || ( empty( $course_progress[ $course_id ] ) ) ) { - $course_progress[ $course_id ] = array( - 'lessons' => array(), - 'topics' => array(), - ); - } - - if ( ( ! isset( $course_progress[ $course_id ]['lessons'] ) ) || ( empty( $course_progress[ $course_id ]['lessons'] ) ) ) { - $course_progress[ $course_id ]['lessons'] = array(); - } - - if ( ( ! isset( $course_progress[ $course_id ]['topics'] ) ) || ( empty( $course_progress[ $course_id ]['topics'] ) ) ) { - $course_progress[ $course_id ]['topics'] = array(); - } - - if ( 'sfwd-topic' === $post->post_type && empty( $course_progress[ $course_id ]['topics'][ $lesson_id ] ) ) { - $course_progress[ $course_id ]['topics'][ $lesson_id ] = array(); - } - - $lesson_completed = false; - $topic_completed = false; - - if ( ! $onlycalculate && 'sfwd-lessons' === $post->post_type && empty( $course_progress[ $course_id ]['lessons'][ $postid ] ) ) { - $course_progress[ $course_id ]['lessons'][ $postid ] = 1; - $lesson_completed = true; - } - - if ( ! $onlycalculate && 'sfwd-topic' === $post->post_type && empty( $course_progress[ $course_id ]['topics'][ $lesson_id ][ $postid ] ) ) { - $course_progress[ $course_id ]['topics'][ $lesson_id ][ $postid ] = 1; - $topic_completed = true; - } - - $completed_old = isset( $course_progress[ $course_id ]['completed'] ) ? $course_progress[ $course_id ]['completed'] : 0; - - $completed = learndash_course_get_completed_steps( $user_id, $course_id, $course_progress[ $course_id ] ); - - $course_progress[ $course_id ]['completed'] = $completed; - - // New logic includes lessons and topics. - $course_progress[ $course_id ]['total'] = learndash_get_course_steps_count( $course_id ); - - /** - * Track the last post_id (Lesson, Topic, Quiz) seen by user. - * - * @since 2.1.0 - */ - $course_progress[ $course_id ]['last_id'] = $post->ID; - - $course_completed_time = time(); - // If course is completed. - if ( ( $course_progress[ $course_id ]['completed'] >= $completed_old ) && ( $course_progress[ $course_id ]['completed'] >= $course_progress[ $course_id ]['total'] ) ) { - - /** - * Fires before the course is marked completed. - * - * @since 2.1.0 - * - * @param array $course_data An array of course complete data. - */ - do_action( - 'learndash_before_course_completed', - array( - 'user' => $current_user, - 'course' => get_post( $course_id ), - 'progress' => $course_progress, - 'completed_time' => $course_completed_time, - ) - ); - add_user_meta( $current_user->ID, 'course_completed_' . $course_id, $course_completed_time, true ); - } else { - delete_user_meta( $current_user->ID, 'course_completed_' . $course_id ); - } - - update_user_meta( $user_id, '_sfwd-course_progress', $course_progress ); - - if ( ! empty( $topic_completed ) ) { - - /** - * Fires after the topic is marked completed. - * - * @since 2.1.0 - * - * @param array $topic_data An array of topic complete data. - */ - do_action( - 'learndash_topic_completed', - array( - 'user' => $current_user, - 'course' => get_post( $course_id ), - 'lesson' => get_post( $lesson_id ), - 'topic' => $post, - 'progress' => $course_progress, - ) - ); - - learndash_update_user_activity( - array( - 'course_id' => $course_id, - 'user_id' => $current_user->ID, - 'post_id' => $post->ID, - 'activity_type' => 'topic', - 'activity_status' => true, - 'activity_completed' => time(), - 'activity_meta' => array( - 'steps_total' => $course_progress[ $course_id ]['total'], - 'steps_completed' => $course_progress[ $course_id ]['completed'], - ), - - ) - ); - - $course_args = array( - 'course_id' => $course_id, - 'user_id' => $current_user->ID, - 'post_id' => $course_id, - 'activity_type' => 'course', - ); - $course_activity = learndash_get_user_activity( $course_args ); - if ( ! $course_activity ) { - learndash_update_user_activity( - array( - 'course_id' => $course_id, - 'user_id' => $current_user->ID, - 'post_id' => $course_id, - 'activity_type' => 'course', - 'activity_status' => false, - 'activity_meta' => array( - 'steps_total' => $course_progress[ $course_id ]['total'], - 'steps_completed' => $course_progress[ $course_id ]['completed'], - 'steps_last_id' => $post->ID, - ), - ) - ); - } else { - learndash_update_user_activity_meta( $course_activity->activity_id, 'steps_total', $course_progress[ $course_id ]['total'] ); - learndash_update_user_activity_meta( $course_activity->activity_id, 'steps_completed', $course_progress[ $course_id ]['completed'] ); - learndash_update_user_activity_meta( $course_activity->activity_id, 'steps_last_id', $post->ID ); - } - } - - if ( ! empty( $lesson_completed ) ) { - - /** - * Fires after the lesson is marked completed. - * - * @since 2.1.0 - * - * @param array $lesson_data An array of lesson complete data. - */ - do_action( - 'learndash_lesson_completed', - array( - 'user' => $current_user, - 'course' => get_post( $course_id ), - 'lesson' => $post, - 'progress' => $course_progress, - ) - ); - - learndash_update_user_activity( - array( - 'course_id' => $course_id, - 'user_id' => $current_user->ID, - 'post_id' => $post->ID, - 'activity_type' => 'lesson', - 'activity_status' => true, - 'activity_completed' => time(), - 'activity_meta' => array( - 'steps_total' => $course_progress[ $course_id ]['total'], - 'steps_completed' => $course_progress[ $course_id ]['completed'], - ), - - ) - ); - - $course_args = array( - 'course_id' => $course_id, - 'user_id' => $current_user->ID, - 'post_id' => $course_id, - 'activity_type' => 'course', - ); - $course_activity = learndash_get_user_activity( $course_args ); - if ( ! $course_activity ) { - - learndash_update_user_activity( - array( - 'course_id' => $course_id, - 'user_id' => $current_user->ID, - 'post_id' => $course_id, - 'activity_type' => 'course', - 'activity_status' => false, - 'activity_meta' => array( - 'steps_total' => $course_progress[ $course_id ]['total'], - 'steps_completed' => $course_progress[ $course_id ]['completed'], - 'steps_last_id' => $post->ID, - ), - ) - ); - } else { - learndash_update_user_activity_meta( $course_activity->activity_id, 'steps_total', $course_progress[ $course_id ]['total'] ); - learndash_update_user_activity_meta( $course_activity->activity_id, 'steps_completed', $course_progress[ $course_id ]['completed'] ); - learndash_update_user_activity_meta( $course_activity->activity_id, 'steps_last_id', $post->ID ); - } - } - - if ( $course_progress[ $course_id ]['completed'] >= $completed_old && $course_progress[ $course_id ]['total'] == $course_progress[ $course_id ]['completed'] ) { - $do_course_complete_action = false; - - $course_args = array( - 'course_id' => $course_id, - 'user_id' => $current_user->ID, - 'post_id' => $course_id, - 'activity_type' => 'course', - ); - - $course_activity = learndash_get_user_activity( $course_args ); - if ( ! empty( $course_activity ) ) { - $course_args = json_decode( wp_json_encode( $course_activity ), true ); - - if ( true != $course_activity->activity_status ) { - $course_args['activity_status'] = true; - $course_args['activity_completed'] = time(); - $course_args['activity_updated'] = time(); - - $do_course_complete_action = true; - } - } else { - // If no activity record found. - $course_args['activity_status'] = true; - $course_args['activity_started'] = time(); - $course_args['activity_completed'] = time(); - $course_args['activity_updated'] = time(); - - $do_course_complete_action = true; - } - - $course_args['activity_meta'] = array( - 'steps_total' => $course_progress[ $course_id ]['total'], - 'steps_completed' => $course_progress[ $course_id ]['completed'], - 'steps_last_id' => $post->ID, - ); - - learndash_update_user_activity( $course_args ); - - if ( true == $do_course_complete_action ) { - - /** - * Fires after the course is marked completed. - * - * @since 2.1.0 - * - * @param array $course_data An array of course complete data. - */ - do_action( - 'learndash_course_completed', - array( - 'user' => $current_user, - 'course' => get_post( $course_id ), - 'progress' => $course_progress, - 'course_completed' => $course_completed_time, - ) - ); - } - } else { - - $course_args = array( - 'course_id' => $course_id, - 'user_id' => $current_user->ID, - 'post_id' => $course_id, - 'activity_type' => 'course', - ); - $course_activity = learndash_get_user_activity( $course_args ); - if ( $course_activity ) { - $course_args['activity_completed'] = 0; - $course_args['activity_status'] = false; - - if ( empty( $course_progress[ $course_id ]['completed'] ) ) { - $course_args['activity_updated'] = 0; - } - $course_args['activity_meta'] = array( - 'steps_total' => $course_progress[ $course_id ]['total'], - 'steps_completed' => $course_progress[ $course_id ]['completed'], - 'steps_last_id' => $post->ID, - ); - learndash_update_user_activity( $course_args ); - } - } - - return true; - -} - -/** - * LEGACY: Gets the total completed steps for a given course progress array. - * - * Replaced by `learndash_course_get_completed_steps` in 3.4.0 - * - * @since 2.3.0 - * - * @param int $user_id Optional. The ID of the user. Default 0. - * @param int $course_id Optional. The ID of the course. Default 0. - * @param array $course_progress Optional. An array of course progress data. Default empty array. - * - * @return int The count of completed course steps. - */ -function learndash_course_get_completed_steps_legacy( $user_id = 0, $course_id = 0, $course_progress = array() ) { - $steps_completed_count = 0; - - if ( ( ! empty( $user_id ) ) && ( ! empty( $course_id ) ) ) { - - if ( empty( $course_progress ) ) { - $course_progress_all = get_user_meta( $user_id, '_sfwd-course_progress', true ); - if ( isset( $course_progress_all[ $course_id ] ) ) { - $course_progress = $course_progress_all[ $course_id ]; - } - } - - $course_lessons = learndash_course_get_steps_by_type( $course_id, 'sfwd-lessons' ); - if ( ! empty( $course_lessons ) ) { - if ( isset( $course_progress['lessons'] ) ) { - foreach ( $course_progress['lessons'] as $lesson_id => $lesson_completed ) { - if ( in_array( $lesson_id, $course_lessons, true ) ) { - $steps_completed_count += intval( $lesson_completed ); - } - } - } - } - - $course_topics = learndash_course_get_steps_by_type( $course_id, 'sfwd-topic' ); - if ( isset( $course_progress['topics'] ) ) { - foreach ( $course_progress['topics'] as $lesson_id => $lesson_topics ) { - if ( in_array( $lesson_id, $course_lessons, true ) ) { - if ( ( is_array( $lesson_topics ) ) && ( ! empty( $lesson_topics ) ) ) { - foreach ( $lesson_topics as $topic_id => $topic_completed ) { - if ( in_array( $topic_id, $course_topics, true ) ) { - $steps_completed_count += intval( $topic_completed ); - } - } - } - } - } - } - - if ( learndash_has_global_quizzes( $course_id ) ) { - if ( learndash_is_all_global_quizzes_complete( $user_id, $course_id ) ) { - ++$steps_completed_count; - } - } - } - - return $steps_completed_count; -} diff --git a/web/app/plugins/sfwd-lms/includes/course/ld-course-functions.php b/web/app/plugins/sfwd-lms/includes/course/ld-course-functions.php index 610ec8cac..75c25d640 100644 --- a/web/app/plugins/sfwd-lms/includes/course/ld-course-functions.php +++ b/web/app/plugins/sfwd-lms/includes/course/ld-course-functions.php @@ -7,6 +7,8 @@ * @package LearnDash\Course */ +use LearnDash\Core\Utilities\Cast; + if ( ! defined( 'ABSPATH' ) ) { exit; } @@ -77,16 +79,16 @@ function learndash_get_course_id( $id = null, $bypass_cb = false ) { } if ( ( isset( $_GET['course_id'] ) ) && ( ! empty( $_GET['course_id'] ) ) ) { - return intval( $_GET['course_id'] ); + return absint( $_GET['course_id'] ); } elseif ( ( isset( $_GET['course'] ) ) && ( ! empty( $_GET['course'] ) ) ) { - return intval( $_GET['course'] ); + return absint( $_GET['course'] ); } elseif ( ( isset( $_POST['course_id'] ) ) && ( ! empty( $_POST['course_id'] ) ) ) { - return intval( $_POST['course_id'] ); + return absint( $_POST['course_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- legacy code. } elseif ( ( isset( $_POST['course'] ) ) && ( ! empty( $_POST['course'] ) ) ) { - return intval( $_POST['course'] ); + return absint( $_POST['course'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- legacy code. } elseif ( ( isset( $_GET['post'] ) ) && ( ! empty( $_GET['post'] ) ) ) { - if ( get_post_type( intval( $_GET['post'] ) ) == 'sfwd-courses' ) { - return intval( $_GET['post'] ); + if ( get_post_type( absint( $_GET['post'] ) ) == 'sfwd-courses' ) { + return absint( $_GET['post'] ); } } } @@ -305,77 +307,56 @@ function learndash_get_course_prerequisite( $course_id = 0 ) { } /** - * Sets new prerequisites for a course. + * Checks whether the course prerequisites requirement for enrollment setting is enabled for a course. * - * @since 2.4.4 + * @since 2.4.0 + * @since 4.20.2 Add support for the new requirements_for_enrollment setting key. * - * @param int $course_id Optional. ID of the course. Default 0. - * @param array $course_pre Optional. An array of course prerequisites. Default empty array. + * @param int $course_id The ID of the course. * - * @return boolean Returns true if update was successful otherwise false. + * @return boolean Returns true if the course prerequisites requirement for enrollment setting is enabled, otherwise false. */ -function learndash_set_course_prerequisite( $course_id = 0, $course_pre = array() ) { - if ( ! empty( $course_id ) ) { - if ( ( ! empty( $course_pre ) ) && ( is_array( $course_pre ) ) ) { - $course_pre = array_unique( $course_pre ); - } +function learndash_get_course_prerequisite_enabled( $course_id ) { + if ( empty( $course_id ) ) { + return false; + } - $transient_key = 'learndash_course_pre_' . $course_id; - $course_pre_transient = LDLMS_Transients::delete( $transient_key ); + $course_id = learndash_get_course_id( $course_id ); - return learndash_update_setting( $course_id, 'course_prerequisite', $course_pre ); + if ( ! is_int( $course_id ) ) { + return false; } - return false; -} + /** + * We need to check if the course prerequisites setting is not empty. If the course prerequisite requirement for enrollment + * setting is enabled, we also need to make sure that the courses for prerequisite setting is not empty. + */ -/** - * Checks whether the prerequisites are enabled for a course. - * - * @since 2.4.0 - * - * @param int $course_id The ID of the course. - * - * @return boolean Returns true if the prerequisites are enabled otherwise false. - */ -function learndash_get_course_prerequisite_enabled( $course_id ) { - $course_pre_enabled = false; + $course_pre_courses = learndash_get_setting( $course_id, 'course_prerequisite' ); - $course_id = learndash_get_course_id( $course_id ); - if ( ! empty( $course_id ) ) { - $course_pre_enabled = learndash_get_setting( $course_id, 'course_prerequisite_enabled' ); - if ( 'on' === $course_pre_enabled ) { - $course_pre_courses = learndash_get_setting( $course_id, 'course_prerequisite' ); - if ( ( is_array( $course_pre_courses ) ) && ( ! empty( $course_pre_courses ) ) ) { - $course_pre_enabled = true; - } - } + if ( + ! is_array( $course_pre_courses ) + || empty( $course_pre_courses ) + ) { + return false; } - return $course_pre_enabled; -} + // New setting key to check if the course prerequisites setting is enabled. + $requirements_for_enrollment = learndash_get_setting( $course_id, 'requirements_for_enrollment' ); -/** - * Sets the status of whether the course prerequisite is enabled or disabled. - * - * @since 2.4.4 - * - * @param int $course_id The ID of the course. - * @param boolean $enabled Optional. The value is true to enable course prerequisites. Any other - * value will disable course prerequisites. Default true. - * - * @return boolean Returns true if the status was updated successfully otherwise false. - */ -function learndash_set_course_prerequisite_enabled( $course_id, $enabled = true ) { - if ( true === $enabled ) { - $enabled = 'on'; + if ( $requirements_for_enrollment === 'course_prerequisite_enabled' ) { + return true; } - if ( 'on' !== $enabled ) { - $enabled = ''; + // Legacy setting key to check if the course prerequisites setting is enabled. + $course_pre_enabled = learndash_get_setting( $course_id, 'course_prerequisite_enabled' ); + + // We need to check the legacy key, the old setting key still might being used even after upgrading to LD core v4.20.0+. + if ( $course_pre_enabled === 'on' ) { + return true; } - return learndash_update_setting( $course_id, 'course_prerequisite_enabled', $enabled ); + return false; } /** @@ -385,7 +366,7 @@ function learndash_set_course_prerequisite_enabled( $course_id, $enabled = true * * @param int $post_id The ID of the course. * - * @return string The compare value for the prerequisite. Value can be 'ALL' or 'ANY' by default. + * @return 'ANY'|'ALL' The compare value for the prerequisite. Value can be 'ALL' or 'ANY' by default. */ function learndash_get_course_prerequisite_compare( $post_id ) { @@ -404,84 +385,102 @@ function learndash_get_course_prerequisite_compare( $post_id ) { } /** - * Checks if the course points are enabled for a course. + * Checks if the course points requirement for enrollment setting is enabled for a course. * * @since 2.4.0 + * @since 4.20.2 Add support for the new requirements_for_enrollment setting key. * * @param int $post_id Optional. The course ID. Default 0. * - * @return bool Returns true if the course points are enabled otherwise false. + * @return bool Returns true if the course points requirement for enrollment setting is enabled, otherwise false. */ function learndash_get_course_points_enabled( $post_id = 0 ) { - $course_points_enabled = false; + if ( empty( $post_id ) ) { + return false; + } - if ( ! empty( $post_id ) ) { - $course_id = learndash_get_course_id( $post_id ); - if ( ! empty( $course_id ) ) { - $course_points_enabled = learndash_get_setting( $course_id, 'course_points_enabled' ); - if ( 'on' === $course_points_enabled ) { - $course_points_enabled = true; - } - } + $course_id = learndash_get_course_id( $post_id ); + + if ( ! is_int( $course_id ) ) { + return false; } - return $course_points_enabled; + // New setting key to check if the course points setting is enabled. + $requirements_for_enrollment = learndash_get_setting( $course_id, 'requirements_for_enrollment' ); + + if ( $requirements_for_enrollment === 'course_points_enabled' ) { + return true; + } + + // Legacy setting key to check if the course points setting is enabled. + $course_points_enabled = learndash_get_setting( $course_id, 'course_points_enabled' ); + + // We check the legacy key because the old setting key still might being used even after upgrading to LD core v4.20.0+. + if ( $course_points_enabled === 'on' ) { + return true; + } + + return false; } /** - * Gets the course points for a given course ID. + * Retrieves the course completion points setting of a course. * * @since 2.4.0 + * @since 4.20.2 The value is no longer dependent on the course points requirement for enrollment setting. * * @param int $post_id Optional. Course Step or Course post ID. Default 0. * @param int $decimals Optional. Number of decimal places to round. Default 1. * - * @return int|false Returns false if the course points are disabled otherwise returns course points. + * @return float|false Course completion points of a course if it exists, false otherwise. */ function learndash_get_course_points( $post_id = 0, $decimals = 1 ) { - $course_points = false; + if ( empty( $post_id ) ) { + return false; + } - if ( ! empty( $post_id ) ) { - $course_id = learndash_get_course_id( $post_id ); - if ( ! empty( $course_id ) ) { - if ( learndash_get_course_points_enabled( $course_id ) ) { - $course_points = 0; + $course_id = learndash_get_course_id( $post_id ); - $course_points = learndash_get_setting( $course_id, 'course_points' ); - if ( ! empty( $course_points ) ) { - $course_points = learndash_format_course_points( $course_points, $decimals ); - } - } - } + if ( empty( $course_id ) ) { + return false; + } + + $course_points = learndash_get_setting( $course_id, 'course_points' ); + + if ( empty( $course_points ) ) { + return false; } - return $course_points; + return learndash_format_course_points( $course_points, $decimals ); } /** - * Gets the course points access for a given course ID. + * Retrieves the course points required to access a course. + * + * The value returned from this function is dependent on the course points requirement for enrollment setting. The requirement for enrollment setting must be set to "Course Points". * * @since 2.4.0 * * @param int $post_id Optional. The ID of the course. Default 0. * - * @return int|false Returns false if the course points are disabled otherwise returns course points. + * @return float|false Required course points to access a course, false otherwise. */ function learndash_get_course_points_access( $post_id = 0 ) { - $course_points_access = false; + if ( empty( $post_id ) ) { + return false; + } - if ( ! empty( $post_id ) ) { - $course_id = learndash_get_course_id( $post_id ); - if ( ! empty( $course_id ) ) { - if ( learndash_get_course_points_enabled( $course_id ) ) { - $course_points_access = 0; + $course_id = learndash_get_course_id( $post_id ); - $course_points_access = learndash_format_course_points( learndash_get_setting( $course_id, 'course_points_access' ) ); - } - } + if ( empty( $course_id ) ) { + return false; + } + + if ( ! learndash_get_course_points_enabled( $course_id ) ) { + return false; } - return $course_points_access; + return learndash_format_course_points( learndash_get_setting( $course_id, 'course_points_access' ) ); } /** @@ -628,23 +627,6 @@ function learndash_get_open_courses( $bypass_transient = false ) { return learndash_get_posts_by_price_type( learndash_get_post_type_slug( 'course' ), 'open', $bypass_transient ); } -/** - * Gets all the courses with the price type paynow. - * - * Logic for this query was taken from the `sfwd_lms_has_access_fn()` function. - * - * @global wpdb $wpdb WordPress database abstraction object. - * - * @since 2.3.0 - * - * @param boolean $bypass_transient Optional. Whether to bypass the transient cache. Default false. - * - * @return array An array of course IDs. - */ -function learndash_get_paynow_courses( $bypass_transient = false ) { - return learndash_get_posts_by_price_type( learndash_get_post_type_slug( 'course' ), 'paynow', $bypass_transient ); -} - /** * Gets the list of users with expired course access from the user meta. * @@ -671,7 +653,6 @@ function learndash_get_course_expired_access_from_meta( $course_id = 0 ) { return array_map( 'absint', $expired_user_ids ); } - /** * Gets the course settings from the course meta. * @@ -763,7 +744,7 @@ function( $options, $location ) { function learndash_update_course_users_groups( $user_id, $course_id, $access_list, $remove ) { if ( ( ! empty( $user_id ) ) && ( ! empty( $course_id ) ) && ( true !== (bool) $remove ) ) { - $groups = learndash_get_course_groups( $course_id, true ); + $groups = learndash_get_course_groups( $course_id ); if ( ! empty( $groups ) ) { foreach ( $groups as $group_id ) { $ld_auto_enroll_group_courses = get_post_meta( $group_id, 'ld_auto_enroll_group_courses', true ); @@ -909,12 +890,16 @@ function learndash_get_course_lessons_per_page( $course_id = 0 ) { // From the specific Course Settings > Custom Pagination. if ( ! empty( $course_id ) ) { $course_settings = learndash_get_setting( intval( $course_id ) ); - if ( ( isset( $course_settings['course_lesson_per_page'] ) ) && ( 'CUSTOM' === $course_settings['course_lesson_per_page'] ) && ( isset( $course_settings['course_lesson_per_page_custom'] ) ) ) { + if ( + isset( $course_settings['course_lesson_per_page'] ) + && $course_settings['course_lesson_per_page'] === 'on' + && isset( $course_settings['course_lesson_per_page_custom'] ) + ) { $course_lessons_per_page = $course_settings['course_lesson_per_page_custom']; } } - return absint( $course_lessons_per_page ); + return absint( Cast::to_int( $course_lessons_per_page ) ); } /** @@ -1194,12 +1179,16 @@ function learndash_get_course_topics_per_page( $course_id = 0, $lesson_id = 0 ) // From the specific Course Settings > Custom Pagination. if ( ! empty( $course_id ) ) { $course_settings = learndash_get_setting( intval( $course_id ) ); - if ( ( isset( $course_settings['course_lesson_per_page'] ) ) && ( 'CUSTOM' === $course_settings['course_lesson_per_page'] ) && ( isset( $course_settings['course_topic_per_page_custom'] ) ) ) { - $course_topics_per_page = absint( $course_settings['course_topic_per_page_custom'] ); + if ( + isset( $course_settings['course_lesson_per_page'] ) + && $course_settings['course_lesson_per_page'] === 'on' + && isset( $course_settings['course_topic_per_page_custom'] ) + ) { + $course_topics_per_page = $course_settings['course_topic_per_page_custom']; } } - return $course_topics_per_page; + return absint( Cast::to_int( $course_topics_per_page ) ); } /** @@ -1258,56 +1247,30 @@ function learndash_get_last_active_course( $user_id = 0 ) { return $last_course_id; } - /** - * Gets the user's last active step for a course. + * Checks if a user can bypass certain restrictions based on their role and settings. * - * @since 3.1.4 + * This function determines whether a user can bypass specific actions/restrictions + * (such as course progression, prerequisites, etc.) based on their role and + * corresponding settings. It checks: * - * @param int $user_id Optional. User ID. Default 0. - * @param int $course_id Optional. Course ID. Default 0. + * 1. Admin users - Can bypass if they have admin role AND the setting + * 'bypass_course_limits_admin_users' is enabled in General > Admin User settings. * - * @return int The last active course step ID. - */ -function learndash_user_course_last_step( $user_id = 0, $course_id = 0 ) { - global $wpdb; - - $last_course_step_id = 0; - - if ( empty( $user_id ) ) { - $user_id = get_current_user_id(); - } - - if ( ! empty( $user_id ) ) { - if ( empty( $course_id ) ) { - $course_id = learndash_get_last_active_course( $user_id ); - } - if ( ! empty( $course_id ) ) { - $query_result = $wpdb->get_var( - $wpdb->prepare( - 'SELECT user_activity_meta.activity_meta_value FROM ' . esc_sql( LDLMS_DB::get_table_name( 'user_activity' ) ) . ' as user_activity INNER JOIN ' . esc_sql( LDLMS_DB::get_table_name( 'user_activity_meta' ) ) . " as user_activity_meta ON user_activity.activity_id = user_activity_meta.activity_id WHERE user_activity.user_id=%d AND user_activity.post_id=%d AND user_activity.activity_type='course' AND user_activity_meta.activity_meta_key= 'steps_last_id' ORDER BY activity_updated DESC", - $user_id, - $course_id - ) - ); - $last_course_step_id = absint( $query_result ); - } - } - - return $last_course_step_id; -} - - -/** - * Check if user can bypass action ($context). + * 2. Group Leaders - Can bypass if they have group leader role AND the setting + * 'bypass_course_limits' is enabled in Groups > Group Leader User settings. + * + * The function also provides a filter 'learndash_user_can_bypass' allowing + * custom logic to override the default behavior. * * @since 3.2.0 * - * @param int $user_id User ID. - * @param string $context The specific action to check for. - * @param array $args Optional array of args related to the - * context. Typically starting with an step ID, Course ID, etc. - * @return bool True if user can bypass. Otherwise false. + * @param int $user_id User ID. If 0 or empty, uses the current logged-in user ID. Default 0. + * @param string $context The specific action to check for. Default 'learndash_course_progression'. + * @param array $args Optional array of args related to the context. + * Typically includes step ID, Course ID, etc. Default empty array. + * + * @return bool True if user can bypass the specified context, false otherwise. */ function learndash_can_user_bypass( $user_id = 0, $context = 'learndash_course_progression', $args = array() ) { if ( empty( $user_id ) ) { @@ -1544,37 +1507,70 @@ function learndash_is_course_post( $post ): bool { } /** - * Returns course enrollment url. + * Returns the page url a user is redirected to after completing a course. + * Priority is: Course level setting -> Courses level setting -> Course page url. * - * @param WP_Post|int|null $post Post or Post ID. + * @since 4.11.0 * - * @since 4.1.0 + * @param int $course_id Course ID. * * @return string */ -function learndash_get_course_enrollment_url( $post ): string { - if ( empty( $post ) ) { - return ''; - } - - if ( is_int( $post ) ) { - $post = get_post( $post ); - - if ( is_null( $post ) ) { - return ''; - } +function learndash_course_get_completion_url( int $course_id ): string { + // Get the course completion page. + $page_id = learndash_get_setting( $course_id, 'course_completion_page' ); + + // If the course completion page is not set, then get the default course completion page. + if ( empty( $page_id ) ) { + $page_id = LearnDash_Settings_Section::get_section_setting( + 'LearnDash_Settings_Courses_Management_Display', + 'course_completion_page' + ); } - $url = get_permalink( $post ); + $page_id = Cast::to_int( $page_id ); - $settings = learndash_get_setting( $post ); + /** + * Filters whether to redirect to the course completion page. + * + * @since 4.11.0 + * + * @param bool $redirect_enabled Whether to redirect to the course completion page. Default true. + * @param int $course_id Course ID. + * + * @return bool Whether to redirect to the course completion page. + */ + $course_completion_redirect_enabled = apply_filters( + 'learndash_course_completion_page_redirect_enabled', + true, + $course_id + ); - if ( 'paynow' === $settings['course_price_type'] && ! empty( $settings['course_price_type_paynow_enrollment_url'] ) ) { - $url = $settings['course_price_type_paynow_enrollment_url']; - } elseif ( 'subscribe' === $settings['course_price_type'] && ! empty( $settings['course_price_type_subscribe_enrollment_url'] ) ) { - $url = $settings['course_price_type_subscribe_enrollment_url']; - } + $page_url = get_permalink( + $course_completion_redirect_enabled && $page_id > 0 + ? $page_id + : $course_id + ); + $page_url = Cast::to_string( $page_url ); - /** This filter is documented in includes/course/ld-course-functions.php */ - return apply_filters( 'learndash_course_join_redirect', $url, $post->ID ); + /** + * Filters the course completion URL. + * + * Before version 4.11.0, it was used to filter the ID/URL of the next course quiz which was incorrect. + * + * @since 2.1.0 + * @since 4.11.0 Added the `$page_id` parameter and `$page_url` parameter is always a string. + * + * @param string $page_url The URL of the course completion page. + * @param int $course_id Course ID. + * @param int $page_id The ID of the course completion page. + * + * @return string The URL of the course completion page. + */ + return apply_filters( + 'learndash_course_completion_url', + $page_url, + $course_id, + $page_id + ); } diff --git a/web/app/plugins/sfwd-lms/includes/course/ld-course-navigation.php b/web/app/plugins/sfwd-lms/includes/course/ld-course-navigation.php index 3c81ec515..2b85a0002 100644 --- a/web/app/plugins/sfwd-lms/includes/course/ld-course-navigation.php +++ b/web/app/plugins/sfwd-lms/includes/course/ld-course-navigation.php @@ -7,176 +7,338 @@ * @package LearnDash\Navigation */ +use LearnDash\Core\Utilities\Cast; + if ( ! defined( 'ABSPATH' ) ) { exit; } /** - * Generates the previous post link for lesson or topic. - * - * @since 2.1.0 + * Generates the previous post link/url/ID for a lesson/topic/quiz in a course. * - * @param string $prev_link Default previous post link. - * @param boolean $url Whether to return URL instead of HTML output. - * @param WP_Post|null $post The `WP_Post` object. Defaults to global post object. + * Important note: learndash_clear_prev_next_links() affects it via `learndash_previous_post_link` hook. + * For some historical reason, it affects the link case only, not ID or URL. * - * @return string Previous post link URL or HTML output. + * @since 2.1.0 + * @since 4.11.0 Added support for quizzes. + * + * @param string|null $default_value Default previous post link. Default empty string. + * Null type is added for backward compatibility. + * @param string|bool $url Whether to return URL or ID instead of HTML output. Default false. + * If true, the URL is returned. + * If 'id', ID is returned. + * Otherwise, an HTML link is returned. + * @param WP_Post|null $post Current post. If not passed, the global post object is used. + * + * @return string|int Previous post link URL or HTML link or Post ID depending on the `$url` parameter. + * If a link cannot be generated, the default value will be returned. */ -function learndash_previous_post_link( $prev_link = '', $url = false, $post = null ) { - if ( empty( $post ) ) { +function learndash_previous_post_link( $default_value = '', $url = false, $post = null ) { + // If a post is not passed, use the global post object. + + if ( ! $post instanceof WP_Post ) { global $post; } - if ( empty( $post ) ) { - return $prev_link; + // Prepare arguments. + + /** + * Filters previous step default value for the course. + * + * @since 4.11.0 + * + * @param string $default_value Default previous step value. Always cast to string. + * @param WP_Post|null $post Current post. If not passed, the global post object is used. If not available, null. + * + * @return int Previous step default value. + */ + $default_value = apply_filters( + 'learndash_course_previous_step_default_value', + Cast::to_string( $default_value ), + $post + ); + + // If post is not available, return the default previous post link. + if ( ! $post instanceof WP_Post ) { + return $default_value; } - if ( 'sfwd-lessons' === $post->post_type ) { - $link_name = learndash_get_label_course_step_previous( learndash_get_post_type_slug( 'lesson' ) ); + // If the post is not a lesson/topic/quiz, return the default previous post link. + if ( + ! in_array( + $post->post_type, + [ + LDLMS_Post_Types::get_post_type_slug( LDLMS_Post_Types::LESSON ), + LDLMS_Post_Types::get_post_type_slug( LDLMS_Post_Types::TOPIC ), + LDLMS_Post_Types::get_post_type_slug( LDLMS_Post_Types::QUIZ ), + ], + true + ) + ) { + return $default_value; + } - $course_id = learndash_get_course_id( $post ); - $posts = learndash_course_get_lessons( $course_id, array( 'per_page' => 0 ) ); + $course_id = Cast::to_int( learndash_get_course_id( $post ) ); + $course_step_ids = learndash_course_get_linear_step_ids( $course_id ); + $current_step_position = array_search( $post->ID, $course_step_ids, true ); - } elseif ( 'sfwd-topic' === $post->post_type ) { - $link_name = learndash_get_label_course_step_previous( learndash_get_post_type_slug( 'topic' ) ); + if ( false === $current_step_position ) { + return $default_value; + } - if ( LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Courses_Builder', 'shared_steps' ) == 'yes' ) { - $course_id = learndash_get_course_id( $post ); - $lesson_id = learndash_course_get_single_parent_step( $course_id, $post->ID ); - } else { - $lesson_id = learndash_get_setting( $post, 'lesson' ); - $course_id = learndash_get_setting( $post, 'course' ); - } - $posts = learndash_course_get_topics( $course_id, $lesson_id, array( 'per_page' => 0 ) ); - } else { - return $prev_link; + $previous_step_position = Cast::to_int( $current_step_position ) - 1; + + // If the current step is the first step, return the default previous post link. + if ( ! isset( $course_step_ids[ $previous_step_position ] ) ) { + return $default_value; } - $prev_post = null; - foreach ( $posts as $k => $p ) { - if ( is_a( $p, 'WP_Post' ) ) { - if ( $p->ID == $post->ID ) { - break; - } - $prev_post = $p; - } + $previous_post = get_post( $course_step_ids[ $previous_step_position ] ); + + // If the previous step is not a post for some reason, return the default previous post link. + if ( ! $previous_post instanceof WP_Post ) { + return $default_value; } - if ( ( $prev_post ) && ( is_a( $prev_post, 'WP_Post' ) ) ) { - if ( 'id' === $url ) { - return $prev_post->ID; - } elseif ( $url ) { - return get_permalink( $prev_post->ID ); - } else { - $permalink = get_permalink( $prev_post->ID ); - if ( is_rtl() ) { - $link_name_with_arrow = $link_name; - } else { - $link_name_with_arrow = ' ' . $link_name; - } + // Return the post ID if the ID is requested. + if ( 'id' === $url ) { + /** + * Filters previous step ID for the course. + * + * @since 4.11.0 + * + * @param int $previous_post_id Previous post ID. + * @param WP_Post $post Current post. + * @param WP_Post $previous_post Previous post. + * + * @return int Previous step ID. + */ + return apply_filters( 'learndash_course_previous_step_id', $previous_post->ID, $post, $previous_post ); + } - $link = ''; + $permalink = Cast::to_string( + learndash_get_step_permalink( $previous_post->ID, $course_id ) + ); - /** - * Filters course navigation previous post link output. - * - * @since 2.1.0 - * - * @param string $link Previous post link output. - * @param string $permalink Previous post permalink. - * @param string $link_name Text shown inside previous post link. - * @param WP_Post $post Post object. - */ - return apply_filters( 'learndash_previous_post_link', $link, $permalink, $link_name, $post ); - } - } else { - return $prev_link; + // If $permalink is empty, return the default previous post link. + if ( empty( $permalink ) ) { + return $default_value; } + + // Return the post URL if the URL is requested. + if ( Cast::to_bool( $url ) ) { + /** + * Filters previous step url for the course. + * + * @since 4.11.0 + * + * @param string $permalink Permalink. + * @param WP_Post $post Current post. + * @param WP_Post $previous_post Previous post. + * + * @return string Previous step URL. + */ + return apply_filters( 'learndash_course_previous_step_url', $permalink, $post, $previous_post ); + } + + // Return the HTML output if the URL is not requested. + + $link_label = learndash_get_label_course_step_previous( $previous_post->post_type ); + + $link_name_with_arrow = $link_label; + if ( ! is_rtl() ) { + $link_name_with_arrow = ' ' . $link_label; + } + + $link = sprintf( + '', + esc_url( $permalink ), + $link_name_with_arrow + ); + + /** + * Filters previous post link output for the course. + * + * @since 2.1.0 + * @since 4.11.0 Added `$previous_post` parameter. + * + * @param string $link Link HTML. + * @param string $permalink Permalink. + * @param string $link_label Link label. + * @param WP_Post $post Current post. + * @param WP_Post $previous_post Previous post. + * + * @return string Previous post link output. + */ + return apply_filters( + 'learndash_previous_post_link', + $link, + $permalink, + $link_label, + $post, + $previous_post + ); } /** - * Generates the next post link for lesson or topic. - * - * @since 2.1.0 + * Generates the next post link/url/ID for a lesson/topic/quiz in a course. * - * @param string $prev_link Default next post link. - * @param boolean $url Whether to return URL instead of HTML output. - * @param WP_Post|null $post The `WP_Post` object. Defaults to global post object. + * Important note: learndash_clear_prev_next_links() affects it via `learndash_next_post_link` hook. + * For some historical reason, it affects the link case only, not ID or URL. * - * @return string Next post link URL or HTML output. + * @since 2.1.0 + * @since 4.11.0 Added support for quizzes. + * + * @param string|null $default_value Default next post link. Default empty string. + * Null type is added for backward compatibility. + * @param string|bool $url Whether to return URL or ID instead of HTML output. Default false. + * If true, the URL is returned. + * If 'id', ID is returned. + * Otherwise, an HTML link is returned. + * @param WP_Post|null $post Current post. If not passed, the global post object is used. + * + * @return string|int Next post link URL or HTML link or Post ID depending on the `$url` parameter. + * If a link cannot be generated, the default value will be returned. */ -function learndash_next_post_link( $prev_link = '', $url = false, $post = null ) { - if ( empty( $post ) ) { +function learndash_next_post_link( $default_value = '', $url = false, $post = null ) { + // If a post is not passed, use the global post object. + + if ( ! $post instanceof WP_Post ) { global $post; } - if ( empty( $post ) ) { - return $prev_link; + // Prepare arguments. + + /** + * Filters next step default value for the course. + * + * @since 4.11.0 + * + * @param string $default_value Default step post value. Always cast to string. + * @param WP_Post|null $post Current post. If not passed, the global post object is used. If not available, null. + * + * @return int Next step default value. + */ + $default_value = apply_filters( + 'learndash_course_next_step_default_value', + Cast::to_string( $default_value ), + $post + ); + + // If that is not available, return the default next post link. + + if ( ! $post instanceof WP_Post ) { + return $default_value; } - if ( 'sfwd-lessons' === $post->post_type ) { - $link_name = learndash_get_label_course_step_next( learndash_get_post_type_slug( 'lesson' ) ); - $course_id = learndash_get_course_id( $post ); - $posts = learndash_course_get_lessons( $course_id, array( 'per_page' => 0 ) ); - } elseif ( 'sfwd-topic' === $post->post_type ) { - $link_name = learndash_get_label_course_step_next( learndash_get_post_type_slug( 'topic' ) ); + // If the post is not a lesson/topic/quiz, return the default next post link. + if ( + ! in_array( + $post->post_type, + [ + LDLMS_Post_Types::get_post_type_slug( LDLMS_Post_Types::LESSON ), + LDLMS_Post_Types::get_post_type_slug( LDLMS_Post_Types::TOPIC ), + LDLMS_Post_Types::get_post_type_slug( LDLMS_Post_Types::QUIZ ), + ], + true + ) + ) { + return $default_value; + } - if ( learndash_is_course_builder_enabled() ) { - $course_id = learndash_get_course_id( $post->ID ); - $lesson_id = learndash_course_get_single_parent_step( $course_id, $post->ID ); - } else { - $lesson_id = learndash_get_setting( $post, 'lesson' ); - $course_id = learndash_get_setting( $post, 'course' ); - } - $posts = learndash_course_get_topics( $course_id, $lesson_id, array( 'per_page' => 0 ) ); - } else { - return $prev_link; + $course_id = Cast::to_int( learndash_get_course_id( $post ) ); + $course_step_ids = learndash_course_get_linear_step_ids( $course_id ); + $current_step_position = array_search( $post->ID, $course_step_ids, true ); + + if ( false === $current_step_position ) { + return $default_value; } - $found_at = null; - $next_post = null; - foreach ( $posts as $k => $p ) { + $next_step_position = Cast::to_int( $current_step_position ) + 1; - if ( is_a( $p, 'WP_Post' ) ) { - if ( $p->ID == $post->ID ) { - $found_at = $k; - } elseif ( $found_at ) { - $next_post = $p; - break; - } - } + // If the current step is the last step, return the default next post link. + if ( ! isset( $course_step_ids[ $next_step_position ] ) ) { + return $default_value; } - if ( ( $next_post ) && ( is_a( $next_post, 'WP_Post' ) ) ) { - if ( 'id' === $url ) { - return $next_post->ID; - } elseif ( $url ) { - return get_permalink( $next_post->ID ); - } else { - $permalink = get_permalink( $next_post->ID ); - if ( is_rtl() ) { - $link_name_with_arrow = $link_name; - } else { - $link_name_with_arrow = $link_name . ' '; - } + $next_post = get_post( $course_step_ids[ $next_step_position ] ); - $link = ''; + // If the next step is not a post for some reason, return the default next post link. + if ( ! $next_post instanceof WP_Post ) { + return $default_value; + } - /** - * Filters course navigation next post link output. - * - * @since 2.1.0 - * - * @param string $link Next post link output. - * @param string $permalink Next post permalink. - * @param string $link_name Text shown inside next post link. - * @param WP_Post $post Post object. - */ - return apply_filters( 'learndash_next_post_link', $link, $permalink, $link_name, $next_post ); - } - } else { - return $prev_link; + // Return the post ID if the ID is requested. + if ( 'id' === $url ) { + /** + * Filters next step ID for the course. + * + * @since 4.11.0 + * + * @param int $next_post_id Next post ID. + * @param WP_Post $post Current post. + * @param WP_Post $next_post Next post. + * + * @return int Next step ID. + */ + return apply_filters( 'learndash_course_next_step_id', $next_post->ID, $post, $next_post ); } + + $permalink = Cast::to_string( + learndash_get_step_permalink( $next_post->ID, $course_id ) + ); + + // If $permalink is empty, return the default next post link. + if ( empty( $permalink ) ) { + return $default_value; + } + + // Return the post URL if the URL is requested. + if ( Cast::to_bool( $url ) ) { + /** + * Filters next step url for the course. + * + * @since 4.11.0 + * + * @param string $permalink Permalink. + * @param WP_Post $post Current post. + * @param WP_Post $next_post Next post. + * + * @return string Next step URL. + */ + return apply_filters( 'learndash_course_next_step_url', $permalink, $post, $next_post ); + } + + // Return the HTML output if the URL is not requested. + + $link_label = learndash_get_label_course_step_next( $next_post->post_type ); + + $link_name_with_arrow = $link_label; + if ( ! is_rtl() ) { + $link_name_with_arrow = $link_label . ' '; + } + + $link = sprintf( + '', + esc_url( $permalink ), + $link_name_with_arrow + ); + + /** + * Filters next post link output for the course. + * + * @since 2.1.0 + * @since 4.11.0 Added `$next_post` parameter. + * + * @param string $link Link HTML. + * @param string $permalink Permalink. + * @param string $link_label Link label. + * @param WP_Post $post Current post. + * @param WP_Post $next_post Next post. + * + * @return string Next post link output. + */ + return apply_filters( 'learndash_next_post_link', $link, $permalink, $link_label, $post, $next_post ); } /** @@ -203,103 +365,50 @@ function learndash_clear_prev_next_links( $prev_link = '' ) { add_filter( 'next_post_link', 'learndash_clear_prev_next_links', 1 ); /** - * Outputs the quiz continue link. + * Outputs the continue quiz link. * * @param int $id Quiz ID. * - * @return string The quiz continue link output. + * @return string The continue quiz link HTML. + * Empty string if the quiz is not a part of a course or ID passed is not a quiz. */ function learndash_quiz_continue_link( $id ) { - $course_id = learndash_get_course_id( $id ); - if ( ( ! empty( $course_id ) ) && ( LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Courses_Builder', 'shared_steps' ) == 'yes' ) ) { - $lesson_id = learndash_course_get_single_parent_step( $course_id, $id ); - if ( empty( $lesson_id ) ) { - $url = get_permalink( $course_id ); - $url = add_query_arg( - array( - 'quiz_type' => 'global', - 'quiz_redirect' => 1, - 'course_id' => $course_id, - 'quiz_id' => $id, - 'next_step' => '1', - ), - $url - ); - - } else { - $url = get_permalink( $lesson_id ); - $url = add_query_arg( - array( - 'quiz_type' => 'lesson', - 'quiz_redirect' => 1, - 'lesson_id' => $lesson_id, - 'quiz_id' => $id, - 'next_step' => '1', - ), - $url - ); - } - - if ( ( isset( $url ) ) && ( ! empty( $url ) ) ) { - $return_link = '' . LearnDash_Custom_Label::get_label( 'button_click_here_to_continue' ) . ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Method escapes output - } - } else { - $quizmeta = get_post_meta( $id, '_sfwd-quiz', true ); - - if ( ! empty( $quizmeta['sfwd-quiz_lesson'] ) ) { - $return_id = (int) $quizmeta['sfwd-quiz_lesson']; - $quiz_lesson = (int) $quizmeta['sfwd-quiz_lesson']; - } - - if ( empty( $quiz_lesson ) ) { - $url = add_query_arg( - array( - 'quiz_type' => 'global', - 'quiz_redirect' => 1, - 'course_id' => $course_id, - 'quiz_id' => $id, - 'next_step' => '1', - ), - get_permalink( $course_id ) - ); - $return_link = '' . LearnDash_Custom_Label::get_label( 'button_click_here_to_continue' ) . ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Method escapes output - } else { - $url = add_query_arg( - array( - 'quiz_type' => 'lesson', - 'quiz_redirect' => 1, - 'course_id' => $course_id, - 'lesson_id' => $return_id, - 'quiz_id' => $id, - 'next_step' => '1', - ), - get_permalink( $return_id ) - ); - $return_link = '' . LearnDash_Custom_Label::get_label( 'button_click_here_to_continue' ) . ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Method escapes output - } + $quiz_id = Cast::to_int( $id ); + $course_id = Cast::to_int( learndash_get_course_id( $id ) ); + + if ( + $course_id <= 0 + || $quiz_id <= 0 + || get_post_type( $quiz_id ) !== learndash_get_post_type_slug( LDLMS_Post_Types::QUIZ ) + ) { + return ''; } - // Why are we checking the WordPress version? Shouldn't this be checking the LD version?? - $version = get_bloginfo( 'version' ); - - if ( $version >= '1.5.1' ) { - - /** - * Filters output of quiz continue link. - * - * @since 2.1.0 - * - * @param string $return_link Continue link output. - * @param string $url Continue link url. - */ - return apply_filters( 'learndash_quiz_continue_link', $return_link, $url ); - - } else { - - /** This filter is documented in includes/course/ld-course-navigation.php */ - return apply_filters( 'learndash_quiz_continue_link', $return_link ); - - } + $url = add_query_arg( + [ + 'quiz_redirect' => 1, + 'quiz_id' => $quiz_id, + ], + Cast::to_string( learndash_get_step_permalink( $id, $course_id ) ) + ); + + $link = sprintf( + '%2$s', + esc_url( $url ), + LearnDash_Custom_Label::get_label( 'button_click_here_to_continue' ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Method escapes output. + ); + + /** + * Filters HTML of continue quiz link. + * + * @since 2.1.0 + * + * @param string $link Continue link HTML. + * @param string $url Continue link url. + * + * @return string Continue link HTML. + */ + return apply_filters( 'learndash_quiz_continue_link', $link, $url ); } /** @@ -414,6 +523,7 @@ function learndash_topic_dots( $lesson_id, $show_text = false, $type = 'dots', $ * Gets the topics list for a lesson. * * @since 2.1.0 + * @since 5.0.0 Removed the option to use `learndash_get_topic_list_legacy`. * * @param int|null $lesson_id The ID of the lesson to get topics. * @param int|null $course_id Course ID. @@ -421,10 +531,6 @@ function learndash_topic_dots( $lesson_id, $show_text = false, $type = 'dots', $ * @return array An array of topics list. */ function learndash_get_topic_list( $lesson_id = null, $course_id = null ) { - if ( ( defined( 'LEARNDASH_COURSE_FUNCTIONS_LEGACY' ) ) && ( true === LEARNDASH_COURSE_FUNCTIONS_LEGACY ) ) { - return learndash_get_topic_list_legacy( $lesson_id, $course_id ); - } - $course_topics = array(); if ( empty( $course_id ) ) { @@ -454,6 +560,7 @@ function learndash_get_topic_list( $lesson_id = null, $course_id = null ) { * @global WP_Post $post Global post object. * * @since 2.1.0 + * @since 5.0.0 Removed the option to use `learndash_get_global_quiz_list_legacy`. * * @param int|null $id An ID of the resource. * @@ -464,10 +571,6 @@ function learndash_get_global_quiz_list( $id = null ) { $course_id = learndash_get_course_id( $id ); if ( ! empty( $course_id ) ) { - if ( ( defined( 'LEARNDASH_COURSE_FUNCTIONS_LEGACY' ) ) && ( true === LEARNDASH_COURSE_FUNCTIONS_LEGACY ) ) { - return learndash_get_global_quiz_list_legacy( $id ); - } - $quizzes = learndash_course_get_quizzes( $course_id, $course_id ); } return $quizzes; @@ -477,6 +580,7 @@ function learndash_get_global_quiz_list( $id = null ) { * Gets the lesson list output for a course. * * @since 2.1.0 + * @since 5.0.0 Removed the option to use `learndash_get_course_lessons_list_legacy`. * * @param int|WP_Post|null $course_id Optional. The course ID or `WP_Post` object. Default null. * @param int|null $user_id Optional. User ID. Default null. @@ -485,10 +589,6 @@ function learndash_get_global_quiz_list( $id = null ) { * @return array The lesson list array. */ function learndash_get_course_lessons_list( $course_id = null, $user_id = null, $query_args = array() ) { - if ( ( defined( 'LEARNDASH_COURSE_FUNCTIONS_LEGACY' ) ) && ( true === LEARNDASH_COURSE_FUNCTIONS_LEGACY ) ) { - return learndash_get_course_lessons_list_legacy( $course_id, $user_id, $query_args ); - } - $lessons = array(); if ( empty( $user_id ) ) { @@ -637,17 +737,14 @@ function learndash_get_course_lessons_list( $course_id = null, $user_id = null, * Gets the quiz list output for a course. * * @since 2.1.0 + * @since 5.0.0 Removed the option to use `learndash_get_course_quiz_list_legacy`. * * @param int|WP_Post|null $course Optional. The `WP_Post` course object or course ID. Default null. * @param int|null $user_id Optional. User ID. Default null. * - * @return array|string The quiz list HTML output. + * @return array{sno: int, id: int, post: WP_Post, permalink: string, class: string, status: string, sample: string, sub_title: string, ld_lesson_access_from: string}[] An array of quiz items. */ function learndash_get_course_quiz_list( $course = null, $user_id = null ) { - if ( ( defined( 'LEARNDASH_COURSE_FUNCTIONS_LEGACY' ) ) && ( true === LEARNDASH_COURSE_FUNCTIONS_LEGACY ) ) { - return learndash_get_course_quiz_list_legacy( $course, $user_id ); - } - $quizzes = array(); if ( is_a( $course, 'WP_Post' ) ) { @@ -702,18 +799,15 @@ function learndash_get_course_quiz_list( $course = null, $user_id = null ) { * Gets the quiz list output for a lesson/topic. * * @since 2.1.0 + * @since 5.0.0 Removed the option to use `learndash_get_lesson_quiz_list_legacy`. * * @param int|WP_Post $lesson The `WP_Post` lesson/topic object or ID. * @param int|null $user_id Optional. User ID. Default null. * @param int|null $course_id Optional. Course ID. Default null. * - * @return array|string The lesson quiz list HTML output. + * @return array{sno: int, id: int, post: WP_Post, permalink: string, class: string, status: string, sample: string, sub_title: string, ld_lesson_access_from: string}[] An array of quiz items. */ function learndash_get_lesson_quiz_list( $lesson, $user_id = null, $course_id = null ) { - if ( ( defined( 'LEARNDASH_COURSE_FUNCTIONS_LEGACY' ) ) && ( true === LEARNDASH_COURSE_FUNCTIONS_LEGACY ) ) { - return learndash_get_lesson_quiz_list_legacy( $lesson, $user_id, $course_id ); - } - $quizzes = array(); $lesson_id = 0; diff --git a/web/app/plugins/sfwd-lms/includes/course/ld-course-progress.php b/web/app/plugins/sfwd-lms/includes/course/ld-course-progress.php index dc068a427..fceb1f8ea 100644 --- a/web/app/plugins/sfwd-lms/includes/course/ld-course-progress.php +++ b/web/app/plugins/sfwd-lms/includes/course/ld-course-progress.php @@ -7,6 +7,8 @@ * @package LearnDash\Course */ +use LearnDash\Core\Utilities\Cast; + if ( ! defined( 'ABSPATH' ) ) { exit; } @@ -19,6 +21,7 @@ * Must meet requirements of course to mark the course as complete. * * @since 2.1.0 + * @since 4.24.0 Added support for overriding the form action. * * @param WP_Post $post The `WP_Post` lesson or topic object. * @param array $atts Optional. An array of attributes to mark course complete. Default empty array. @@ -26,7 +29,6 @@ * @return string HTML output to mark course complete */ function learndash_mark_complete( $post, $atts = array() ) { - if ( ! is_user_logged_in() ) { return ''; } @@ -37,7 +39,14 @@ function learndash_mark_complete( $post, $atts = array() ) { return ''; } - $bypass_course_limits_admin_users = learndash_can_user_bypass( $user_id, 'learndash_course_progression', $post->ID, $post ); + $bypass_course_limits_admin_users = learndash_can_user_bypass( + $user_id, + 'learndash_course_progression', + [ + 'step_id' => $post->ID, + 'step' => $post, + ] + ); /** * Bypass prerequisites. @@ -54,7 +63,6 @@ function learndash_mark_complete( $post, $atts = array() ) { $course_id = learndash_get_course_id( $post->ID ); if ( ( learndash_lesson_progression_enabled() ) && ( ! $bypass_course_limits_admin_users ) ) { - if ( ! sfwd_lms_has_access( $course_id, $user_id ) ) { return ''; } @@ -181,6 +189,7 @@ function learndash_mark_complete( $post, $atts = array() ) { $return = ''; $button_disabled = ''; $time = 0; + $time_cookie_key = ''; $time_value = learndash_forced_lesson_time( $post ); if ( ! empty( $time_value ) ) { @@ -188,7 +197,6 @@ function learndash_mark_complete( $post, $atts = array() ) { } if ( ( ! learndash_is_admin_user( $user_id ) ) || ( ! $bypass_course_limits_admin_users ) ) { - if ( ! empty( $time ) ) { $time_cookie_key = learndash_forced_lesson_time_cookie_key( $post ); if ( ! empty( $time_cookie_key ) ) { @@ -229,6 +237,12 @@ function learndash_mark_complete( $post, $atts = array() ) { */ $atts = apply_filters( 'learndash_mark_complete_form_atts', $atts, $post ); + if ( isset( $atts['form']['action'] ) ) { + $form_action = ' action="' . esc_attr( $atts['form']['action'] ) . '" '; + } else { + $form_action = ''; + } + if ( isset( $atts['form']['id'] ) ) { $form_id = ' id="' . esc_attr( $atts['form']['id'] ) . '" '; } else { @@ -253,10 +267,39 @@ function learndash_mark_complete( $post, $atts = array() ) { $button_class = ' class="learndash_mark_complete_button" '; } + $button_label = learndash_course_steps_is_external( $post->ID ) && ! learndash_course_steps_is_external_attendance_required( $post->ID ) + ? LearnDash_Custom_Label::get_label( LearnDash_Custom_Label::$button_skip_event ) + : LearnDash_Custom_Label::get_label( 'button_mark_complete' ); + + /** + * Filters the HTML of the mark complete input button. + * + * @since 4.24.0 + * + * @param string $input_button_html The HTML of the mark complete input button. + * @param WP_Post $post WP_Post object being displayed. + * @param string $button_id The HTML ID attribute of the button. + * @param string $button_class The HTML class attribute of the button. + * @param string $button_disabled The HTML disabled attribute of the button. + * @param string $button_label The label of the button. + * + * @return string Returns the HTML of the mark complete input button. + */ + $input_button_html = apply_filters( + 'learndash_mark_complete_input_button_html', + '', + $post, + $button_id, + $button_class, + $button_disabled, + $button_label + ); + $form_fields = ' - '; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Method escapes output + ' . $input_button_html . ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- It's the button HTML. + /** * Filters form fields to mark a course complete. * @@ -267,7 +310,7 @@ function learndash_mark_complete( $post, $atts = array() ) { */ $form_fields = apply_filters( 'learndash_mark_complete_form_fields', $form_fields, $post ); - $return .= '
' . $form_fields . '
'; + $return .= '
' . $form_fields . '
'; if ( ( ! learndash_is_admin_user( $user_id ) ) || ( ! $bypass_course_limits_admin_users ) ) { if ( ! empty( $time ) ) { @@ -283,7 +326,33 @@ function learndash_mark_complete( $post, $atts = array() ) { } $timer_class .= '" '; - $return .= ''; + $timer_html = ''; + + /** + * Filters the HTML of the timer. + * + * @since 4.24.0 + * + * @param string $timer_html The HTML of the timer. + * @param WP_Post $post WP_Post object being displayed. + * @param string $timer_id The HTML ID attribute of the timer. + * @param string $timer_class The HTML class attribute of the timer. + * @param int $time The time in seconds. + * @param string $time_cookie_key The cookie key for the timer. + * + * @return string Returns the HTML of the timer. + */ + $timer_html = apply_filters( + 'learndash_mark_complete_timer_html', + $timer_html, + $post, + $timer_id, + $timer_class, + $time, + $time_cookie_key + ); + + $return .= $timer_html; } } @@ -298,44 +367,13 @@ function learndash_mark_complete( $post, $atts = array() ) { return apply_filters( 'learndash_mark_complete', $return, $post ); } -/** - * Handles the AJAX output to mark a quiz complete. - * - * @since 2.1.0 - * - * @global WP_Post $post Global post object. - * - * @param int|null $quiz_id Optional. Quiz ID. Default null. - * @param int|null $lesson_id Optional. Lesson ID. Default null. - */ -function learndash_ajax_mark_complete( $quiz_id = null, $lesson_id = null ) { - - if ( empty( $quiz_id ) || empty( $lesson_id ) ) { - return; - } - - global $post; - - $current_user = wp_get_current_user(); - $user_id = $current_user->ID; - - $can_attempt_again = learndash_can_attempt_again( $user_id, $quiz_id ); - - if ( $can_attempt_again ) { - $link = learndash_next_lesson_quiz( false, $user_id, $lesson_id, null ); - } else { - $link = learndash_next_lesson_quiz( false, $user_id, $lesson_id, array( $quiz_id ) ); - } - -} - /** * Checks if the lesson topics are completed. * * @since 2.1.0 * - * @param int $lesson_id Lesson ID. - * @param boolean $mark_lesson_complete Optional. Whether to mark the lesson complete. Default false. + * @param int $lesson_id Lesson ID. + * @param boolean $mark_lesson_complete Optional. Whether to mark the lesson complete. Default false. * * @return boolean Returns true if the lesson is completed otherwise false. */ @@ -367,252 +405,203 @@ function learndash_lesson_topics_completed( $lesson_id, $mark_lesson_complete = } /** - * Processes a request to mark a course complete. - * - * @global WP_Post $post Global post object. + * Processes a request to mark a step/course complete. * * @since 2.1.0 + * @since 4.11.0 Removed the $post argument. + * @since 4.21.5. Updated to use the new 'Automatic Progression' setting. * - * @param WP_Post|null $post Optional. The `WP_Post` object. Defaults to global post object. + * @return void */ -function learndash_mark_complete_process( $post = null ) { - // This is wrong. This function hooks into the 'wp' action. That action doesn't pass a post object or post_id. - // The $post object set were is not even used. We only need the _POST[post] (post_id) variable from the form. - if ( empty( $post ) ) { - global $post; +function learndash_mark_complete_process() { + if ( + ! isset( $_POST['sfwd_mark_complete'] ) + || empty( $_POST['post'] ) + ) { + return; } - if ( ( isset( $_POST['sfwd_mark_complete'] ) ) && ( ! empty( $_POST['sfwd_mark_complete'] ) ) && ( isset( $_POST['post'] ) ) && ( ! empty( $_POST['post'] ) ) ) { - if ( empty( $post ) || empty( $post->ID ) ) { - $post = get_post(); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- I suppose it's what they wanted. - if ( empty( $post ) || empty( $post->ID ) ) { - return; - } - } + $post_id = Cast::to_int( + sanitize_key( $_POST['post'] ) // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Checked below. + ); - $post_id = intval( $_POST['post'] ); + $course_id = isset( $_POST['course_id'] ) + ? sanitize_key( $_POST['course_id'] ) + : learndash_get_course_id( $post_id ); + $course_id = Cast::to_int( $course_id ); - if ( isset( $_POST['course_id'] ) ) { - $course_id = intval( $_POST['course_id'] ); - } else { - $course_id = learndash_get_course_id( $post_id ); - } + $user_id = isset( $_POST['userid'] ) + ? Cast::to_int( sanitize_key( $_POST['userid'] ) ) // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Checked below. + : get_current_user_id(); - if ( isset( $_POST['userid'] ) ) { - $userid = intval( $_POST['userid'] ); - } else { - if ( ! is_user_logged_in() ) { - return; - } + if ( + $post_id <= 0 + || $course_id <= 0 + || $user_id <= 0 + ) { + return; + } - $userid = get_current_user_id(); - } + if ( + ! wp_verify_nonce( + sanitize_key( $_POST['sfwd_mark_complete'] ), + 'sfwd_mark_complete_' . $user_id . '_' . $post_id + ) + ) { + return; + } - /** - * Verify the form is valid - * - * @since 2.2.1.2 - */ - if ( ! wp_verify_nonce( $_POST['sfwd_mark_complete'], 'sfwd_mark_complete_' . $userid . '_' . $post_id ) ) { - return; - } + // Mark the step as completed. - $return = learndash_process_mark_complete( $userid, $post_id, false, $course_id ); + $marked_completed = learndash_process_mark_complete( $user_id, $post_id, false, $course_id ); - if ( $return ) { - // Remove the lesson/topic timer cookie once the step is completed. - $timer_cookie_key = learndash_forced_lesson_time_cookie_key( $post_id ); - if ( ! empty( $timer_cookie_key ) ) { - if ( isset( $_COOKIE[ 'learndash_timer_cookie_' . $timer_cookie_key ] ) ) { - unset( $_COOKIE[ 'learndash_timer_cookie_' . $timer_cookie_key ] ); - } - // empty value and expiration one hour before. - $res = setcookie( 'learndash_timer_cookie_' . $timer_cookie_key, '', time() - 3600 ); - } + if ( ! $marked_completed ) { + return; + } - // Remove the lesson/topic video progress cookie once the step is completed. - learndash_video_delete_cookie_for_step( $post_id, $course_id, $userid ); + // Remove needed cookies. - $next_lesson_redirect = learndash_get_next_lesson_redirect(); - } else { - $next_lesson_redirect = get_permalink(); + // Remove the lesson/topic video progress cookie once the step is completed. + learndash_video_delete_cookie_for_step( $post_id, $course_id, $user_id ); + + // Remove the lesson/topic timer cookie once the step is completed. + $timer_cookie_key = learndash_forced_lesson_time_cookie_key( $post_id ); + + if ( ! empty( $timer_cookie_key ) ) { + if ( isset( $_COOKIE[ 'learndash_timer_cookie_' . $timer_cookie_key ] ) ) { + unset( $_COOKIE[ 'learndash_timer_cookie_' . $timer_cookie_key ] ); } - if ( ! empty( $next_lesson_redirect ) ) { + // empty value and expiration one hour before. + setcookie( 'learndash_timer_cookie_' . $timer_cookie_key, '', time() - 3600 ); + } + + $is_automatic_progression_enabled = LearnDash_Settings_Section::get_section_setting( + 'LearnDash_Settings_Courses_Management_Display', + 'course_automatic_progression' + ) === 'yes'; + + /** + * Filters whether to redirect the user immediately after the step is completed. + * + * @since 4.21.4 + * @since 4.21.5. Changed the default value to true if automatic progression is enabled. + * + * @param boolean $redirect_immediately Whether to redirect the user immediately. True if automatic progression is enabled. + * + * @return boolean Returns true if the user should be redirected immediately, otherwise false. + */ + if ( apply_filters( 'learndash_step_completed_redirect_immediately', $is_automatic_progression_enabled ) ) { + // Redirect immediately to the step completion URL. + + learndash_safe_redirect( + learndash_course_get_step_completion_url( $post_id, $course_id, $user_id ) + ); + } else { + // Set a transient to allow extra processing after the step is completed. + set_transient( + "learndash_step_completed_{$post_id}_{$course_id}_{$user_id}", + true, /** - * Filters URL to redirect to after marking a course complete. + * Filters the transient expiration time for the step completed transient. * - * @param string $redirect_url Next lesson redirect URL. - * @param int $post_id Post ID. + * @since 4.21.4 + * + * @param int $expiration_time The transient expiration time. Default 10 minutes. + * @param int $post_id The post ID. + * @param int $course_id The course ID. + * @param int $user_id The user ID. */ - $next_lesson_redirect = apply_filters( 'learndash_completion_redirect', $next_lesson_redirect, $post_id ); - if ( ! empty( $next_lesson_redirect ) ) { - learndash_safe_redirect( $next_lesson_redirect ); - } - } + apply_filters( + 'learndash_step_completed_transient_expiration_time', + 10 * MINUTE_IN_SECONDS, + $post_id, + $course_id, + $user_id + ) + ); } } + add_action( 'wp', 'learndash_mark_complete_process' ); /** - * Gets the course permalink. + * Returns the step (Lesson or Topic) completed transient data when a step is completed by a user through the `learndash_mark_complete_process` function. * - * @since 2.1.0 + * It's a workaround to allow us to do some extra processing after the step is completed. + * This function only returns the data if the `learndash_step_completed` transient exists. By default, the transient expires in 10 minutes. * - * @param int|null $id Optional. The ID of the resource like course, topic, lesson, quiz, etc. Default null. + * Note this function does not work for quizzes, as they don't use the `learndash_mark_complete_process` function to complete the step. * - * @return string The course permalink. - */ -function learndash_get_course_url( $id = null ) { - - if ( empty( $id ) ) { - $id = learndash_get_course_id(); - } - - return get_permalink( $id ); -} - -/** - * Redirects the user to next lesson. + * If you need the step completion data in another context, you can use the `learndash_course_get_step_completion_data` function. * - * @global WP_Post $post Global post object. - * - * @since 2.1.0 + * @since 4.21.3 * - * @param WP_Post|null $post Optional. The `WP_Post` object. Defaults to global post object. Default null. + * @param int $step_id Step ID. + * @param int $course_id Course ID. + * @param int $user_id User ID. * - * @return string Returns empty string if the next lesson redirect link empty. + * @return array{ + * is_course_completed: bool, + * is_course_completion_url: bool, + * next_step_id: int, + * next_step_url: string, + * }|false Returns the transient data or false if the transient does not exist. */ -function learndash_get_next_lesson_redirect( $post = null ) { - if ( empty( $post->ID ) ) { - global $post; - } +function learndash_get_step_completed_transient_data( $step_id, $course_id, $user_id ) { + $transient_key = "learndash_step_completed_{$step_id}_{$course_id}_{$user_id}"; - $next = learndash_next_post_link( '', true, $post ); + // If the transient does not exist, return false. - if ( ! empty( $next ) ) { - $link = $next; - } else { - if ( 'sfwd-topic' === $post->post_type ) { - if ( LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Courses_Builder', 'shared_steps' ) == 'yes' ) { - $course_id = learndash_get_course_id( $post->ID ); - $lesson_id = learndash_course_get_single_parent_step( $course_id, $post->ID ); - } else { - $lesson_id = learndash_get_setting( $post, 'lesson' ); - } - $link = get_permalink( $lesson_id ); - } else { - $course_id = learndash_get_course_id( $post ); - $link = learndash_next_global_quiz( true, null, $course_id ); - } + if ( false === get_transient( $transient_key ) ) { + return false; } - if ( ! empty( $link ) ) { + // Return the step completion data. - /** This filter is documented in includes/course/ld-course-progress.php */ - $link = apply_filters( 'learndash_completion_redirect', $link, $post->ID ); - if ( ! empty( $link ) ) { - learndash_safe_redirect( $link ); - } - } - - return ''; + return learndash_course_get_step_completion_data( $step_id, $course_id, $user_id ); } /** - * Redirects the user after quiz completion. - * - * Fires on `wp` hook. - * - * @global WP_Post $post Global post object. + * Redirects the user after quiz completion when a user clicks on the "continue" button. + * It redirects to the next step if the quiz is completed otherwise redirects back to the quiz page. * * @since 2.1.0 + * + * @return void */ function learndash_quiz_redirect() { - global $post; - - $current_user = wp_get_current_user(); - $user_id = $current_user->ID; - - if ( ! empty( $_GET['quiz_redirect'] ) && ! empty( $_GET['quiz_id'] ) && ! empty( $_GET['quiz_type'] ) && ! empty( $_GET['course_id'] ) && 'global' == $_GET['quiz_type'] ) { - - $quiz_id = intval( $_GET['quiz_id'] ); - $can_attempt_again = learndash_can_attempt_again( $user_id, $quiz_id ); - - if ( $can_attempt_again ) { - $link = learndash_next_global_quiz(); - } else { - $link = learndash_next_global_quiz( true, null, null, array( $quiz_id ) ); - } - - /** This filter is documented in includes/course/ld-course-progress.php */ - $link = apply_filters( 'learndash_completion_redirect', $link, $quiz_id ); - if ( ! empty( $link ) ) { - learndash_safe_redirect( $link ); - } - } else { - - if ( ! empty( $_GET['quiz_redirect'] ) && ! empty( $_GET['quiz_id'] ) && ! empty( $_GET['quiz_type'] ) && ! empty( $_GET['lesson_id'] ) && 'lesson' == $_GET['quiz_type'] ) { - $quiz_id = intval( $_GET['quiz_id'] ); - $lesson_id = intval( $_GET['lesson_id'] ); - - if ( isset( $_GET['course_id'] ) ) { - $course_id = absint( $_GET['course_id'] ); - } - if ( empty( $course_id ) ) { - $course_id = learndash_get_course_id(); - } + if ( + ! isset( $_GET['quiz_redirect'] ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No nonce here. + || ! isset( $_GET['quiz_id'] ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No nonce here. + ) { + return; + } - $link = ''; + $user_id = get_current_user_id(); + $quiz_id = Cast::to_int( sanitize_key( $_GET['quiz_id'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No nonce here. - $next_step = 0; - if ( isset( $_GET['next_step'] ) ) { - $next_step = absint( $_GET['next_step'] ); - } + if ( + $user_id <= 0 + || $quiz_id <= 0 + ) { + return; + } - if ( ( 1 === $next_step ) && ( ! empty( $user_id ) ) && ( ! empty( $course_id ) ) && ( ! empty( $quiz_id ) ) ) { - $next_incomplete_step_id = learndash_user_progress_get_next_incomplete_step( $user_id, $course_id, $quiz_id ); - if ( ! empty( $next_incomplete_step_id ) ) { - $link = learndash_get_step_permalink( $next_incomplete_step_id, $course_id ); - } + $course_id = Cast::to_int( learndash_get_course_id( $quiz_id ) ); - if ( empty( $link ) ) { - $link = get_permalink( $course_id ); - } - } else { - $link = learndash_next_lesson_quiz( true, $user_id, $lesson_id, null ); - if ( empty( $link ) ) { - $link = learndash_next_post_link( '', true ); - } - - if ( empty( $link ) ) { - $lesson_post = get_post( $lesson_id ); - if ( 'sfwd-topic' === $lesson_post->post_type ) { - if ( LearnDash_Settings_Section::get_section_setting( 'LearnDash_Settings_Courses_Builder', 'shared_steps' ) == 'yes' ) { - $course_id = learndash_get_course_id( $lesson_post->ID ); - $lesson = learndash_course_get_single_parent_step( $course_id, $lesson_post->ID ); - } else { - $lesson = learndash_get_setting( $lesson_post, 'lesson' ); - } - $link = learndash_get_step_permalink( $lesson, $course_id ); - } else { - $link = learndash_next_global_quiz(); - } - } - } + if ( $course_id <= 0 ) { + return; + } - if ( ! empty( $link ) ) { + $redirect_url = learndash_is_quiz_complete( $user_id, $quiz_id, $course_id ) + ? learndash_course_get_step_completion_url( $quiz_id, $course_id, $user_id ) + : Cast::to_string( learndash_get_step_permalink( $quiz_id, $course_id ) ); // Back to the quiz page. - /** This filter is documented in includes/course/ld-course-progress.php */ - $link = apply_filters( 'learndash_completion_redirect', $link, $quiz_id ); - if ( ! empty( $link ) ) { - learndash_safe_redirect( $link ); - } - } - } - } + learndash_safe_redirect( $redirect_url ); } + add_action( 'wp', 'learndash_quiz_redirect' ); /** @@ -654,7 +643,7 @@ function learndash_can_attempt_again( $user_id, $quiz_id ) { if ( ! empty( $quiz_results ) ) { foreach ( $quiz_results as $quiz ) { if ( $quiz['quiz'] == $quiz_id ) { - $count++; + ++$count; } } } @@ -671,7 +660,7 @@ function learndash_can_attempt_again( $user_id, $quiz_id ) { * * @since 3.4.0 * - * @param WP_Post $post The `WP_Post` object of lesson or topic. + * @param WP_Post $post The `WP_Post` object of lesson or topic. * * @return int Returns 1 if the previous lesson or topic is completed otherwise 0. */ @@ -711,19 +700,19 @@ function learndash_get_previous( $post ) { * Updates the user meta with completion status for any resource. * * @since 2.1.0 + * @since 4.11.0 Added the $force parameter. + * @since 5.0.0 Removed the option to use `learndash_process_mark_complete_legacy`. * * @param int|null $user_id Optional. User ID. Default null. * @param int|null $postid Optional. The ID of the resource like course, lesson, topic, etc. Default null. - * @param boolean $onlycalculate Optional. Whether to mark the resource as complete. Default false. + * @param bool $onlycalculate Optional. Whether to mark the resource as complete. Default false. * @param int $course_id Optional. Course ID. Default 0. + * @param bool $force Optional. Whether to force the completion when should not be completed. + * Default false. * - * @return boolean Returns true if the meta is updated successfully otherwise false. + * @return bool Returns true if the meta is updated successfully, otherwise false. */ -function learndash_process_mark_complete( $user_id = null, $postid = null, $onlycalculate = false, $course_id = 0 ) { - if ( ( defined( 'LEARNDASH_COURSE_FUNCTIONS_LEGACY' ) ) && ( true === LEARNDASH_COURSE_FUNCTIONS_LEGACY ) ) { - return learndash_process_mark_complete_legacy( $user_id, $postid, $onlycalculate, $course_id ); - } - +function learndash_process_mark_complete( $user_id = null, $postid = null, $onlycalculate = false, $course_id = 0, $force = false ) { if ( empty( $user_id ) ) { if ( is_user_logged_in() ) { $current_user = wp_get_current_user(); @@ -740,8 +729,36 @@ function learndash_process_mark_complete( $user_id = null, $postid = null, $only return false; } - if ( ! $onlycalculate ) { + // Allow admin users to bypass the validation. + $force = $force || learndash_can_user_bypass( $user_id, 'learndash_course_progression' ); + + // Check if the user can complete the step. + if ( + ! $force && + ! learndash_can_complete_step( $user_id, $post->ID, $course_id ) + ) { + return false; + } + + /** + * In case of video progression, we need to check if the video is completed. + * + * This check should be done in the `learndash_can_complete_step` function, but this function is used in other places with a different purpose. + * We needed to add a new parameter to the function, making it weirder. So, putting the check here for now until we refactor this logic. + */ + + $is_video_enabled = learndash_get_setting( $post->ID, 'lesson_video_enabled' ) === 'on' + && ! empty( learndash_get_setting( $post->ID, 'lesson_video_url' ) ); + if ( + ! $force + && $is_video_enabled + && ! learndash_video_complete_for_step( $post->ID, $course_id, $user_id ) + ) { + return false; + } + + if ( ! $onlycalculate ) { /** * Filters whether to mark a process complete. * @@ -758,25 +775,50 @@ function learndash_process_mark_complete( $user_id = null, $postid = null, $only } } - if ( 'sfwd-topic' === $post->post_type ) { - if ( learndash_is_course_builder_enabled() ) { - if ( empty( $course_id ) ) { - $course_id = learndash_get_course_id( $post->ID ); - } - $lesson_id = learndash_course_get_single_parent_step( $course_id, $post->ID ); - } else { - $lesson_id = learndash_get_setting( $post, 'lesson' ); - } - } - if ( empty( $course_id ) ) { $course_id = learndash_get_course_id( $postid ); } + $course_id = Cast::to_int( $course_id ); + if ( empty( $course_id ) ) { return false; } + // Get the lesson ID. + + $lesson_id = 0; + + if ( LDLMS_Post_Types::get_post_type_slug( LDLMS_Post_Types::TOPIC ) === $post->post_type ) { + $lesson_id = learndash_is_course_builder_enabled() + ? learndash_course_get_single_parent_step( $course_id, $post->ID ) + : learndash_get_setting( $post, 'lesson' ); + } + + // Forcing quiz completion. + + if ( LDLMS_Post_Types::get_post_type_slug( LDLMS_Post_Types::QUIZ ) === $post->post_type ) { + learndash_process_user_course_progress_update( + $user_id, + [ + 'quiz' => [ + $course_id => [ + $postid => 1, + ], + ], + ], + $force + ); + + // We need to force a reload of the quiz progress object. + + $quiz_progress_object = LDLMS_Factory_User::quiz_progress( $user_id ); + + if ( $quiz_progress_object instanceof LDLMS_Model_User_Quiz_Progress ) { + $quiz_progress_object->set_progress_unloaded(); + } + } + $course_progress = learndash_user_get_course_progress( $user_id, $course_id, 'legacy' ); if ( ( empty( $course_progress ) ) || ( ! is_array( $course_progress ) ) ) { $course_progress = array( @@ -832,7 +874,6 @@ function learndash_process_mark_complete( $user_id = null, $postid = null, $only // If course is completed. if ( ( $course_progress['completed'] >= $completed_old ) && ( $course_progress['completed'] >= $course_progress['total'] ) ) { - /** * Fires before the course is marked completed. * @@ -928,7 +969,6 @@ function learndash_process_mark_complete( $user_id = null, $postid = null, $only $return = false; if ( ! empty( $lesson_completed ) ) { - /** * Fires after the lesson is marked completed. * @@ -950,7 +990,6 @@ function learndash_process_mark_complete( $user_id = null, $postid = null, $only } if ( ! empty( $topic_completed ) ) { - /** * Fires after the topic is marked completed. * @@ -973,7 +1012,6 @@ function learndash_process_mark_complete( $user_id = null, $postid = null, $only } if ( true == $do_course_complete_action ) { - /** * Fires after the course is marked completed. * @@ -991,39 +1029,36 @@ function learndash_process_mark_complete( $user_id = null, $postid = null, $only ) ); + set_transient( + 'learndash_course_completed_' . $course_id . '_' . $user_id, + $course_completed_time, + HOUR_IN_SECONDS // We only need this for the redirect. + ); + $return = true; } + /** + * Try to complete the parent step if all the child steps are completed. + * + * The learndash_process_mark_complete validates special cases, for example, if the parent step requires a video to be completed. + */ + + $parent_step_id = learndash_course_get_single_parent_step( $course_id, $post->ID ); + if ( + $parent_step_id > 0 + && empty( learndash_user_progression_get_incomplete_child_steps( $user_id, $course_id, $parent_step_id ) ) + && ! learndash_course_steps_is_external( $parent_step_id ) // Don't auto-complete external steps. + ) { + learndash_process_mark_complete( $user_id, $parent_step_id, false, $course_id ); + } + /** * LEARNDASH-5883 - Always return true if we've made it this far. */ $return = true; return $return; - -} - -/** - * Marks a resource complete. - * - * @todo seems redundant, function already exists - * - * @since 2.1.0 - * - * @param int $user_id Optional. User ID. Default null. - * @param int $postid Optional. The ID of the resource. Default null. - */ -function learndash_update_completion( $user_id = null, $postid = null ) { - if ( empty( $postid ) ) { - global $post; - if ( ( $post ) && ( is_a( $post, 'WP_Post' ) ) ) { - $postid = $post->ID; - } - } - - if ( ! empty( $postid ) ) { - learndash_process_mark_complete( $user_id, $postid, true ); - } } /** @@ -1127,12 +1162,10 @@ function learndash_is_quiz_notcomplete( $user_id = null, $quizzes = null, $retur if ( empty( $quizzes ) ) { return 0; - } else { - if ( true == $return_incomplete_quiz_ids ) { + } elseif ( true == $return_incomplete_quiz_ids ) { return $quizzes; - } else { - return 1; - } + } else { + return 1; } } @@ -1140,6 +1173,7 @@ function learndash_is_quiz_notcomplete( $user_id = null, $quizzes = null, $retur * Gets the user's current course progress. * * @since 2.1.0 + * @since 5.0.0 Removed the option to use `learndash_get_course_progress_legacy`. * * @param int|null $user_id Optional. User ID. Default null. * @param int|null $postid Optional. Post ID. Default null. @@ -1148,10 +1182,6 @@ function learndash_is_quiz_notcomplete( $user_id = null, $quizzes = null, $retur * @return array An array of user's current course progress. */ function learndash_get_course_progress( $user_id = null, $postid = null, $course_id = null ) { - if ( ( defined( 'LEARNDASH_COURSE_FUNCTIONS_LEGACY' ) ) && ( true === LEARNDASH_COURSE_FUNCTIONS_LEGACY ) ) { - return learndash_get_course_progress_legacy( $user_id, $postid, $course_id ); - } - $user_id = absint( $user_id ); $course_id = absint( $course_id ); @@ -1217,9 +1247,7 @@ function learndash_get_course_progress( $user_id = null, $postid = null, $course if ( ! empty( $posts ) ) { foreach ( $posts as $k => $post ) { - if ( $post instanceof WP_Post ) { - if ( ! empty( $completed_posts[ $post->ID ] ) ) { $posts[ $k ]->completed = 1; } else { @@ -1269,6 +1297,7 @@ function learndash_is_lesson_complete( $user_id = null, $lesson_id = 0, $course_ * Checks if a lesson is not complete. * * @since 2.1.0 + * @since 5.0.0 Removed the option to use `learndash_is_lesson_notcomplete_legacy`. * * @param int|null $user_id Optional. User ID. Defaults to the current logged-in user. Default null. * @param array $lessons An array of lesson IDs. @@ -1277,10 +1306,6 @@ function learndash_is_lesson_complete( $user_id = null, $lesson_id = 0, $course_ * @return boolean Returns true if the lesson is not complete otherwise false. */ function learndash_is_lesson_notcomplete( $user_id = null, $lessons = array(), $course_id = 0 ) { - if ( ( defined( 'LEARNDASH_COURSE_FUNCTIONS_LEGACY' ) ) && ( true === LEARNDASH_COURSE_FUNCTIONS_LEGACY ) ) { - return learndash_is_lesson_notcomplete_legacy( $user_id, $lessons, $course_id ); - } - if ( empty( $user_id ) ) { $current_user = wp_get_current_user(); $user_id = $current_user->ID; @@ -1316,6 +1341,7 @@ function learndash_is_lesson_notcomplete( $user_id = null, $lessons = array(), $ * * @since 2.3.1 * @since 3.2.0 Added $course_id + * @since 5.0.0 Removed the option to use `learndash_is_topic_notcomplete_legacy`. * * @param int $user_id Optional. User ID. Defaults to the current logged-in user. Default null. * @param int $topic_id Topic ID. @@ -1340,10 +1366,6 @@ function learndash_is_topic_complete( $user_id = null, $topic_id = 0, $course_id * @return boolean Returns true if the topic is not completed otherwise false. */ function learndash_is_topic_notcomplete( $user_id = null, $topics = array(), $course_id = 0 ) { - if ( ( defined( 'LEARNDASH_COURSE_FUNCTIONS_LEGACY' ) ) && ( true === LEARNDASH_COURSE_FUNCTIONS_LEGACY ) ) { - return learndash_is_topic_notcomplete_legacy( $user_id, $topics, $course_id ); - } - if ( empty( $user_id ) ) { $current_user = wp_get_current_user(); $user_id = $current_user->ID; @@ -1358,12 +1380,10 @@ function learndash_is_topic_notcomplete( $user_id = null, $topics = array(), $co } if ( ! empty( $course_id ) ) { - $course_progress = learndash_user_get_course_progress( $user_id, $course_id, 'legacy' ); $lesson_id = learndash_course_get_single_parent_step( $course_id, $topic_id ); if ( ! empty( $lesson_id ) ) { - if ( ( isset( $course_progress['topics'] ) ) && ( ! empty( $course_progress['topics'] ) ) && ( isset( $course_progress['topics'][ $lesson_id ][ $topic_id ] ) ) @@ -1387,6 +1407,7 @@ function learndash_is_topic_notcomplete( $user_id = null, $topics = array(), $co * * @since 2.1.0 * @since 2.5.8 Added $return_slug parameter. + * @since 5.0.0 Removed the option to use `learndash_course_status_legacy`. * * @param int $course_id Course ID to get status. * @param int|null $user_id Optional. User ID. Default null. @@ -1397,9 +1418,6 @@ function learndash_is_topic_notcomplete( $user_id = null, $topics = array(), $co function learndash_course_status( $course_id, $user_id = null, $return_slug = false ) { global $learndash_course_statuses; - if ( ( defined( 'LEARNDASH_COURSE_FUNCTIONS_LEGACY' ) ) && ( true === LEARNDASH_COURSE_FUNCTIONS_LEGACY ) ) { - return learndash_course_status_legacy( $course_id, $user_id, $return_slug ); - } $course_status_slug = ''; $course_id = absint( $course_id ); @@ -1440,8 +1458,7 @@ function learndash_course_status( $course_id, $user_id = null, $return_slug = fa if ( true === $return_slug ) { return $course_status_slug; - } else { - if ( isset( $learndash_course_statuses[ $course_status_slug ] ) ) { + } elseif ( isset( $learndash_course_statuses[ $course_status_slug ] ) ) { /** * Filters the current status of the course. * @@ -1457,7 +1474,6 @@ function learndash_course_status( $course_id, $user_id = null, $return_slug = fa $user_id, isset( $course_progress ) ? $course_progress : array() ); - } } return $course_status_slug; @@ -1506,6 +1522,7 @@ function learndash_course_status_label( $course_status_slug = '' ) { * Checks if the quiz is accessible to the user. * * @since 3.4.0 + * @since 5.0.0 Removed the option to use `learndash_is_quiz_accessable_legacy`. * * @param int|null $user_id $user_id Optional. The ID of User to check. Defaults to the current logged-in user. Default null. * @param WP_Post|null $post Optional. The `WP_Post` quiz object. Default null. @@ -1516,12 +1533,6 @@ function learndash_course_status_label( $course_status_slug = '' ) { * parameter is set to true it may return `WP_Post` object for incomplete step. */ function learndash_is_quiz_accessable( $user_id = null, $post = null, $return_incomplete = false, $course_id = 0 ) { - - // Allow using the legacy function in case of issues with new logic. - if ( ( defined( 'LEARNDASH_IS_QUIZ_ACCESSABLE_LEGACY' ) && ( LEARNDASH_IS_QUIZ_ACCESSABLE_LEGACY === true ) ) ) { - return learndash_is_quiz_accessable_legacy( $user_id, $post, $course_id ); - } - if ( empty( $user_id ) ) { $current_user = wp_get_current_user(); @@ -1546,7 +1557,16 @@ function learndash_is_quiz_accessable( $user_id = null, $post = null, $return_in return 1; } - $bypass_course_limits_admin_users = learndash_can_user_bypass( $user_id, 'learndash_quiz_accessable', $post, $course_id ); + $bypass_course_limits_admin_users = learndash_can_user_bypass( + $user_id, + 'learndash_quiz_accessable', + [ + 'course_id' => $course_id, + 'step_id' => $post->ID, + 'step' => $post, + ] + ); + if ( true === $bypass_course_limits_admin_users ) { return 1; } @@ -1635,7 +1655,6 @@ function learndash_is_quiz_accessable( $user_id = null, $post = null, $return_in } return 1; - } elseif ( learndash_get_post_type_slug( 'lesson' ) === $quiz_parent_post->post_type ) { $quiz_parent_lesson_post = $quiz_parent_post; $sibling_completed_steps = 0; @@ -1778,124 +1797,6 @@ function learndash_is_all_global_quizzes_complete( $user_id = null, $id = null ) return $return; } -/** - * Gets the next quiz for a course. - * - * @since 2.1.0 - * - * @param boolean $url Optional. Whether to return URL for the next quiz. Default true. - * @param int|null $user_id Optional. User ID. Defaults to the current logged-in user. Default null. - * @param int|null $id Optional. The ID of the resource. Default null. - * @param array $exclude Optional. An array of quiz IDs to exclude. Default empty array. - * - * @return int|string The ID or the URL of the quiz. - */ -function learndash_next_global_quiz( $url = true, $user_id = null, $id = null, $exclude = array() ) { - if ( empty( $id ) ) { - $id = learndash_get_course_id(); - } - - if ( empty( $user_id ) ) { - $current_user = wp_get_current_user(); - $user_id = $current_user->ID; - } - - $quizzes = learndash_get_global_quiz_list( $id ); - $return = get_permalink( $id ); - - if ( ! empty( $quizzes ) ) { - foreach ( $quizzes as $quiz ) { - if ( ! in_array( $quiz->ID, $exclude, true ) && learndash_is_quiz_notcomplete( $user_id, array( $quiz->ID => 1 ), false, $id ) && learndash_can_attempt_again( $user_id, $quiz->ID ) ) { - if ( $url ) { - return get_permalink( $quiz->ID ); - } else { - return $quiz->ID; - } - } - } - } - - /** - * Filters ID or URL of the next quiz of the course. - * - * @todo filter name does not seem correct - * in context of function - * - * @since 2.1.0 - * - * @param int|string $next_quiz ID or URL of next quiz of the course. - * @param int $course_id Course ID. - */ - $return = apply_filters( 'learndash_course_completion_url', $return, $id ); - return $return; -} - -/** - * Gets the next quiz for current lesson for a user. - * - * @global WP_Post $post Global post object. - * - * @since 2.1.0 - * - * @param boolean $url Optional. Whether to return URL for the next quiz. Default true. - * @param int|null $user_id Optional. User ID. Defaults to the current logged-in user. Default null. - * @param int|null $lesson_id Optional. Lesson ID. Default null. - * @param array $exclude Optional. An array of quiz IDs to exclude. Default empty array. - * - * @return int|string The ID or the URL of the quiz. - */ -function learndash_next_lesson_quiz( $url = true, $user_id = null, $lesson_id = null, $exclude = array() ) { - global $post; - - $return = false; - - if ( empty( $lesson_id ) ) { - $lesson_id = $post->ID; - } - - if ( empty( $exclude ) ) { - $exclude = array(); - } - - if ( empty( $user_id ) ) { - $current_user = wp_get_current_user(); - $user_id = $current_user->ID; - } - - $course_id = learndash_get_course_id(); - - // Assumption here is the learndash_get_lesson_quiz_list returns the quizzes in the order they should be taken. - $quizzes = learndash_get_lesson_quiz_list( $lesson_id, $user_id ); - if ( ( ! empty( $quizzes ) ) && ( is_array( $quizzes ) ) ) { - foreach ( $quizzes as $quiz ) { - // The logic here is we need to check all the quizzes in this lesson. If all the quizzes are complete - // (including the current one) then we set the parent (lesson) to complete. - if ( 'completed' == $quiz['status'] ) { - continue; - } - - // If not complete AND the user CAN take the quiz again... - if ( learndash_can_attempt_again( $user_id, $quiz['post']->ID ) ) { - $return = ( $url ) ? get_permalink( $quiz['post']->ID ) : $quiz['post']->ID; - break; - } - - $return = ( $url ) ? get_permalink( $quiz['post']->ID ) : $quiz['post']->ID; - break; - } - } - - if ( empty( $return ) ) { - if ( ( learndash_lesson_progression_enabled( $course_id ) ) && ( ! learndash_can_complete_step( $user_id, $lesson_id, $course_id ) ) ) { - $return = learndash_get_step_permalink( $lesson_id, $course_id ); - } elseif ( learndash_user_is_course_children_progress_complete( $user_id, $course_id, $lesson_id ) ) { - learndash_process_mark_complete( $user_id, $lesson_id, false, $course_id ); - } - } - - return $return; -} - /** * Check if the user can complete the current step. * @@ -1938,14 +1839,13 @@ function learndash_can_complete_step( $user_id = 0, $step_id = 0, $course_id = 0 } if ( in_array( get_post_type( $step_id ), learndash_get_post_type_slug( array( 'lesson', 'topic' ) ), true ) ) { + // Check the lesson/topic timer. - // Check the Lesson Timer... if ( false === $ignore_lesson_timer ) { $step_timer_time = learndash_forced_lesson_time( $step_id ); if ( ! empty( $step_timer_time ) ) { $time_cookie_key = learndash_forced_lesson_time_cookie_key( $step_id ); if ( ! empty( $time_cookie_key ) ) { - /** * Note this is not a 100% check. We are only checking if the cookie * key exists and is zero. But this cookie could have been set from @@ -1959,6 +1859,7 @@ function learndash_can_complete_step( $user_id = 0, $step_id = 0, $course_id = 0 } // Next check the Lesson Assignment. + if ( 'on' === learndash_get_setting( $step_id, 'lesson_assignment_upload' ) ) { $assignments = learndash_get_user_assignments( $step_id, $user_id, $course_id ); if ( empty( $assignments ) ) { @@ -1973,11 +1874,18 @@ function learndash_can_complete_step( $user_id = 0, $step_id = 0, $course_id = 0 } // Next check if all child steps are completed. + if ( ! learndash_user_is_course_children_progress_complete( $user_id, $course_id, $step_id ) ) { return false; } } + // Check external steps. + + if ( learndash_course_steps_is_external_attendance_required( $step_id ) ) { + return false; + } + return true; } @@ -1998,19 +1906,6 @@ function learndash_has_global_quizzes( $id = null ) { return ! empty( $quizzes ); } -/** - * Outputs the course progress HTML for the user. - * - * @todo consider for deprecation, not in use - * - * @since 2.1.0 - * - * @param array $atts An array of course progress attributes. - */ -function learndash_course_progress_widget( $atts ) { - echo learndash_course_progress( $atts ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Need to output HTML -} - /** * Checks whether the lesson progression is enabled or not. * @@ -2056,7 +1951,6 @@ function learndash_lesson_progression_enabled( $course_id = 0 ) { * @return int|string Returns lesson time if it exists otherwise 0. */ function learndash_forced_lesson_time( $lesson_topic_post = '' ) { - if ( empty( $lesson_topic_post ) ) { global $post; $lesson_topic_post = $post; @@ -2110,7 +2004,6 @@ function learndash_forced_lesson_time( $lesson_topic_post = '' ) { * @return string The cookie key value or empty string. */ function learndash_forced_lesson_time_cookie_key( $lesson_topic_post = '' ) { - if ( empty( $lesson_topic_post ) ) { global $post; $lesson_topic_post = $post; @@ -2411,7 +2304,6 @@ function learndash_process_mark_incomplete( $user_id = 0, $course_id = 0, $step_ $topic_id = $course_step_parents[1]; if ( ( isset( $user_course_progress[ $course_id ]['topics'][ $lesson_id ][ $topic_id ] ) ) && ( true == $user_course_progress[ $course_id ]['topics'][ $lesson_id ][ $topic_id ] ) ) { - $user_course_progress[ $course_id ]['topics'][ $lesson_id ][ $topic_id ] = 0; $user_course_progress[ $course_id ]['completed'] -= 1; @@ -2594,8 +2486,11 @@ function learndash_process_mark_incomplete( $user_id = 0, $course_id = 0, $step_ } } - return update_user_meta( $user_id, '_sfwd-course_progress', $user_course_progress ); + // Remove the related transient completion data. + delete_transient( "learndash_step_completed_{$step_id}_{$course_id}_{$user_id}" ); + + return update_user_meta( $user_id, '_sfwd-course_progress', $user_course_progress ); } /** @@ -2639,7 +2534,6 @@ function learndash_get_user_quiz_attempt( $user_id = 0, $args = array() ) { */ function learndash_remove_user_quiz_attempt( $user_id = 0, $args = array() ) { if ( ( ! empty( $user_id ) ) && ( ! empty( $args ) ) ) { - $changes = false; $user_quizzes = get_user_meta( $user_id, '_sfwd-quizzes', true ); @@ -2657,7 +2551,6 @@ function learndash_remove_user_quiz_attempt( $user_id = 0, $args = array() ) { } if ( true === $match_found ) { - /** * Fires before user single quiz attempt has been removed. * @@ -2731,7 +2624,6 @@ function learndash_remove_user_quiz_attempt( $user_id = 0, $args = array() ) { update_user_meta( $user_id, '_sfwd-quizzes', $user_quizzes ); if ( ! empty( $changed_user_quizzes ) ) { - /** * Fires after user all quiz attempts have been removed. * @@ -2743,7 +2635,6 @@ function learndash_remove_user_quiz_attempt( $user_id = 0, $args = array() ) { do_action( 'learndash_user_quiz_delete_all_after', $user_id, $changed_user_quizzes ); foreach ( $changed_user_quizzes as $user_quiz ) { - if ( ! learndash_is_quiz_complete( $user_id, $user_quiz['quiz'], $user_quiz['course'] ) ) { learndash_process_mark_incomplete( $user_id, $user_quiz['course'], $user_quiz['quiz'], false ); } @@ -2902,3 +2793,193 @@ function learndash_mark_incomplete_process() { return false; } add_action( 'wp', 'learndash_mark_incomplete_process' ); + +/** + * Returns the page url a user is redirected to after completing a step. + * + * @since 4.11.0 + * + * @param int $step_id Step post ID. + * @param int $course_id Course ID. + * @param int $user_id User ID. + * + * @return string + */ +function learndash_course_get_step_completion_url( int $step_id, int $course_id, int $user_id ): string { + $step_completion_data = learndash_course_get_step_completion_data( $step_id, $course_id, $user_id ); + $redirect_url = $step_completion_data['next_step_url']; + + /** + * Filters URL to redirect to after marking a step complete. + * + * @deprecated 4.11.0 Use {@see 'learndash_course_step_completion_url'} instead. + * + * @param string $redirect_url Next step redirect URL. Can be empty if post was not found for some reason. + * @param int $step_id Course step post ID. + * + * @return string Next step redirect URL. + */ + $redirect_url = apply_filters_deprecated( + 'learndash_completion_redirect', + [ $redirect_url, $step_id ], + '4.11.0', + 'learndash_course_step_completion_url' + ); + + /** + * Filters URL to redirect to after marking a step complete. + * + * @since 4.11.0 + * + * @param string $redirect_url Next step redirect URL. Can be empty if post was not found for some reason. + * @param int $step_id Course step post ID. + * @param int $course_id Course ID. + * + * @return string Redirect URL. + */ + return apply_filters( 'learndash_course_step_completion_url', $redirect_url, $step_id, $course_id ); +} + +/** + * Returns the step completion data when a step is completed by a user. + * + * @since 4.21.3 + * @since 4.24.0. Added the `$should_preserve_transient` parameter and the `is_course_completion_url` key to the return value. + * + * @param int $step_id Step post ID. + * @param int $course_id Course ID. + * @param int $user_id User ID. + * @param bool $should_preserve_transient If true, it will keep the transient data that affects the result, so it can be reused in the next call. + * + * @return array{ + * is_course_completed: bool, + * is_course_completion_url: bool, + * next_step_id: int, + * next_step_url: string, + * } + */ +function learndash_course_get_step_completion_data( + int $step_id, + int $course_id, + int $user_id, + bool $should_preserve_transient = false +): array { + $step_completion_data = [ + 'is_course_completed' => false, + 'is_course_completion_url' => false, + 'next_step_id' => 0, + 'next_step_url' => '', + ]; + + $course_completion_transient_key = 'learndash_course_completed_' . $course_id . '_' . $user_id; + + if ( false !== get_transient( $course_completion_transient_key ) ) { + /** + * Case 1: + * + * If we have the course completion transient, the course is completed, and we should redirect to the completion page. + */ + + if ( ! $should_preserve_transient ) { + delete_transient( $course_completion_transient_key ); // Delete, as we need to do it once. + } + + $step_completion_data['is_course_completed'] = true; + $step_completion_data['is_course_completion_url'] = true; + $step_completion_data['next_step_url'] = learndash_course_get_completion_url( $course_id ); + } else { + $parent_step_id = learndash_course_get_single_parent_step( $course_id, $step_id ); + $parent_step = get_post( $parent_step_id ); + + $parent_step_is_completed = learndash_user_progress_is_step_complete( $user_id, $course_id, $parent_step_id ); + + // If the parent step is completed, evaluate the grandparent step. + // It happens when we have a quiz inside a topic. The topic (parent step) may not have any special requirements, + // but the lesson (grandparent step) may have. + + if ( $parent_step_is_completed ) { + $parent_step_id = learndash_course_get_single_parent_step( $course_id, $parent_step_id ); + $parent_step = get_post( $parent_step_id ); + } + + /** + * Case 2: + * + * If the parent step is not completed and requires a video, an assignment, or wait for a timer to be completed, and all the child steps are completed, + * redirect back to the parent step. + */ + if ( + $parent_step instanceof WP_Post + && ! learndash_user_progress_is_step_complete( $user_id, $course_id, $parent_step_id ) + && ( + learndash_course_steps_requires_watching_video_after_sub_steps( $parent_step_id ) + || learndash_lesson_hasassignments( $parent_step ) // cspell: disable-line . + || learndash_forced_lesson_time( $parent_step_id ) + || learndash_course_steps_is_external( $parent_step_id ) + ) + && empty( learndash_user_progression_get_incomplete_child_steps( $user_id, $course_id, $parent_step_id ) ) + ) { + // Redirect back to the parent step. + + $step_completion_data['next_step_url'] = learndash_get_step_permalink( $parent_step_id, $course_id ); + $step_completion_data['next_step_id'] = $parent_step_id; + } else { + $step = get_post( $step_id ); + + if ( + $step instanceof WP_Post + && ( + learndash_course_steps_requires_watching_video_after_sub_steps( $step_id ) + || learndash_lesson_hasassignments( $step ) // cspell: disable-line . + || learndash_forced_lesson_time( $step_id ) + || learndash_course_steps_is_external( $step_id ) + ) + ) { + /** + * Case 3: + * + * If the current step: + * - requires watching a video after sub steps, or + * - has assignments, or + * - has a timer, or + * - is external, + * and all child steps are completed, redirect to the next incomplete step. + */ + + // Get the next incomplete step (an incomplete step after the current step). + $next_step_id = learndash_user_progress_get_next_incomplete_step( $user_id, $course_id, $step_id ); + + if ( $next_step_id > 0 ) { + // Redirect to the next incomplete step. + + $step_completion_data['next_step_url'] = learndash_get_step_permalink( $next_step_id, $course_id ); + $step_completion_data['next_step_id'] = $next_step_id; + } + } + } + } + + // If there is no special case, redirect to the next step page or a course page. + + if ( empty( $step_completion_data['next_step_url'] ) ) { + $next_step_id = Cast::to_int( + learndash_next_post_link( + '', + 'id', + get_post( $step_id ) + ) + ); + + if ( $next_step_id > 0 ) { + $step_completion_data['next_step_url'] = learndash_get_step_permalink( $next_step_id, $course_id ); + $step_completion_data['next_step_id'] = $next_step_id; + } else { + $step_completion_data['next_step_url'] = get_permalink( $course_id ); + $step_completion_data['next_step_id'] = $course_id; + } + + $step_completion_data['is_course_completed'] = learndash_course_completed( $user_id, $course_id ); + } + + return $step_completion_data; +} diff --git a/web/app/plugins/sfwd-lms/includes/course/ld-course-steps-functions.php b/web/app/plugins/sfwd-lms/includes/course/ld-course-steps-functions.php index cea1bfa3b..71ba4e63e 100644 --- a/web/app/plugins/sfwd-lms/includes/course/ld-course-steps-functions.php +++ b/web/app/plugins/sfwd-lms/includes/course/ld-course-steps-functions.php @@ -7,6 +7,8 @@ * @package LearnDash\Course_Steps */ +use LearnDash\Core\Utilities\Cast; + if ( ! defined( 'ABSPATH' ) ) { exit; } @@ -17,6 +19,7 @@ * For now excludes quizzes at lesson and topic level. * * @since 2.3.0 + * @since 5.0.0 Removed the option to use `learndash_get_course_steps_legacy`. * * @param int $course_id Optional. The ID of the course. Default 0. * @param array $include_post_types Optional. An array of post types to include in course steps. Default array contains 'sfwd-lessons' and 'sfwd-topic'. @@ -24,11 +27,6 @@ * @return array An array of all course steps. */ function learndash_get_course_steps( $course_id = 0, $include_post_types = array( 'sfwd-lessons', 'sfwd-topic' ) ) { - - if ( ( defined( 'LEARNDASH_COURSE_FUNCTIONS_LEGACY' ) ) && ( true === LEARNDASH_COURSE_FUNCTIONS_LEGACY ) ) { - return learndash_get_course_steps_legacy( $course_id, $include_post_types ); - } - // The steps array will hold all the individual step counts for each post_type. $steps = array(); @@ -49,16 +47,13 @@ function learndash_get_course_steps( $course_id = 0, $include_post_types = array * Gets the total count of lessons and topics for a given course ID. * * @since 2.3.0 + * @since 5.0.0 Removed the option to use `learndash_get_course_steps_count_legacy`. * * @param int $course_id Optional. The ID of the course. Default 0. * * @return int The count of the course steps. */ function learndash_get_course_steps_count( $course_id = 0 ) { - if ( ( defined( 'LEARNDASH_COURSE_FUNCTIONS_LEGACY' ) ) && ( true === LEARNDASH_COURSE_FUNCTIONS_LEGACY ) ) { - return learndash_get_course_steps_count_legacy( $course_id ); - } - return learndash_course_get_steps_count( $course_id ); } @@ -66,6 +61,7 @@ function learndash_get_course_steps_count( $course_id = 0 ) { * Gets the total completed steps for a given course progress array. * * @since 2.3.0 + * @since 5.0.0 Removed the option to use `learndash_course_get_completed_steps_legacy`. * * @param int $user_id Optional. The ID of the user. Default 0. * @param int $course_id Optional. The ID of the course. Default 0. @@ -74,10 +70,6 @@ function learndash_get_course_steps_count( $course_id = 0 ) { * @return int The count of completed course steps. */ function learndash_course_get_completed_steps( $user_id = 0, $course_id = 0, $course_progress = array() ) { - if ( ( defined( 'LEARNDASH_COURSE_FUNCTIONS_LEGACY' ) ) && ( true === LEARNDASH_COURSE_FUNCTIONS_LEGACY ) ) { - return learndash_course_get_completed_steps_legacy( $user_id, $course_id, $course_progress ); - } - $user_id = absint( $user_id ); $course_id = absint( $course_id ); @@ -133,7 +125,7 @@ function learndash_course_get_completed_steps( $user_id = 0, $course_id = 0, $co * @param integer $course_id Course ID. * @param array $query_args Array of query args to filter the query. * - * @return array of Sections. + * @return object{order: int, ID: int, post_title: string, type: string, steps: int[]}[] Sections. */ function learndash_course_get_sections( $course_id = 0, $query_args = array() ) { $sections = array(); @@ -276,6 +268,7 @@ function learndash_course_get_steps_count( $course_id = 0 ) { /** * Gets the parent step IDs for a step in a course. + * It returns the parent steps in the order of the hierarchy: from the top parent to the immediate parent. * * @since 2.5.0 * @@ -326,7 +319,9 @@ function learndash_course_get_all_parent_step_ids( $course_id = 0, $step_id = 0 } /** - * Gets the single parent step ID for a given step ID in a course. + * Returns the parent step ID for a given step ID. 0 if no parent. + * + * Note that a course is not a step, so this function will return 0 for a lesson or a global quiz. * * @since 2.5.0 * @@ -619,6 +614,119 @@ function learndash_set_primary_course_for_step( $step_id = 0, $course_id = 0 ) { } } +/** + * Add a step as child of a parent. + * + * @since 4.8.0 + * + * @param int $course_id Course post ID. + * @param int $child_id Child post ID. + * @param int $parent_id Parent post ID. + * + * @return bool True if successful, false otherwise. + */ +function learndash_course_add_child_to_parent( int $course_id, int $child_id, int $parent_id ): bool { + // Check course. + + $course = get_post( $course_id ); + $course_type = learndash_get_post_type_slug( LDLMS_Post_Types::COURSE ); + + if ( + ! $course + || $course->post_type !== $course_type + ) { + return false; + } + + // Check parent and child possible relationship. + + $parent_type = get_post_type( $parent_id ); + $child_type = get_post_type( $child_id ); + + if ( + ! $parent_type + || ! $child_type + ) { + return false; + } + + $lesson_type = learndash_get_post_type_slug( LDLMS_Post_Types::LESSON ); + $topic_type = learndash_get_post_type_slug( LDLMS_Post_Types::TOPIC ); + $quiz_type = learndash_get_post_type_slug( LDLMS_Post_Types::QUIZ ); + + if ( + ( + $parent_type === $course_type + && ! in_array( + $child_type, + [ + $lesson_type, + $quiz_type, + ], + true + ) + ) + || ( + $parent_type === $lesson_type + && ! in_array( + $child_type, + [ + $topic_type, + $quiz_type, + ], + true + ) + ) + || ( + $parent_type === $topic_type + && ! in_array( + $child_type, + [ + $quiz_type, + ], + true + ) + ) + || ( + $parent_type === $quiz_type + || $child_type === $course_type + ) + ) { + return false; + } + + $course_steps = LDLMS_Factory_Post::course_steps( $course_id ); + + if ( ! $course_steps instanceof LDLMS_Course_Steps ) { + return false; + } + + $steps = $course_steps->get_steps(); + + if ( + $child_type === $lesson_type + && $parent_id === $course_id + ) { + $steps[ $lesson_type ][ $child_id ] = []; + } elseif ( $child_type === $topic_type ) { + $steps[ $lesson_type ][ $parent_id ][ $topic_type ][ $child_id ] = []; + } elseif ( $child_type === $quiz_type ) { + if ( $parent_type === $course_type ) { + $steps[ $quiz_type ][ $child_id ] = []; + } elseif ( $parent_type === $lesson_type ) { + $steps[ $lesson_type ][ $parent_id ][ $quiz_type ][ $child_id ] = []; + } elseif ( $parent_type === $topic_type ) { + $lesson_id = learndash_get_lesson_id( $parent_id, $course_id ); + + $steps[ $lesson_type ][ $lesson_id ][ $topic_type ][ $parent_id ][ $quiz_type ][ $child_id ] = []; + } + } + + $course_steps->set_steps_keeping_sections( $steps ); + + return true; +} + /** * Validates the URL requests when nested URL permalinks are used. * @@ -822,7 +930,7 @@ function learndash_course_set_steps_dirty( $course_id = 0 ) { */ function learndash_get_step_post_statuses() { $ld_post_statuses = array(); - $wp_post_statuses = get_post_stati( array( 'show_in_admin_status_list' => true ), 'object' ); + $wp_post_statuses = get_post_stati( array( 'show_in_admin_status_list' => true ), 'objects' ); if ( ! empty( $wp_post_statuses ) ) { foreach ( $wp_post_statuses as $status_key => $status_object ) { $ld_post_statuses[ $status_key ] = $status_object->label; @@ -860,28 +968,6 @@ function learndash_get_step_post_status_slug( $post ) { return ''; } -/** - * Get single course step post status label. - * - * @since 4.0.0 - * - * @param object $post WP_Post object. - * - * @return string - */ -function learndash_get_step_post_status_label( $post ) { - $post_status_label = ''; - if ( ( $post ) && ( is_a( $post, 'WP_Post' ) ) ) { - $post_status_slug = learndash_get_step_post_status_slug( $post ); - $post_statuses = learndash_get_step_post_statuses(); - if ( isset( $post_statuses[ $post_status_slug ] ) ) { - $post_status_label = $post_statuses[ $post_status_slug ]; - } - } - - return $post_status_label; -} - /** * Get the post title formatted with post status label. * @@ -1169,3 +1255,146 @@ function learndash_course_steps_add_post_meta( $object_id, $meta_key, $meta_valu } } add_action( 'add_post_meta', 'learndash_course_steps_add_post_meta', 20, 3 ); + +/** + * Returns all step ids for a course in a linear (flattened) array. + * + * @since 4.11.0 + * + * @param int $course_id Course post ID. + * + * @return int[] Array of step IDs. + */ +function learndash_course_get_linear_step_ids( int $course_id ): array { + if ( $course_id <= 0 ) { + return []; + } + + $course_steps_handler = LDLMS_Factory_Post::course_steps( $course_id ); + + if ( ! $course_steps_handler instanceof LDLMS_Course_Steps ) { + return []; + } + + $flattened_steps_with_post_type_prefix = $course_steps_handler->get_steps( 'l' ); + + if ( empty( $flattened_steps_with_post_type_prefix ) ) { + return []; + } + + $step_ids = []; + + // Extracting post ids from strings like "sfwd-lessons:272". + foreach ( $flattened_steps_with_post_type_prefix as $step_with_post_type_prefix ) { + [ , $step_id ] = explode( + ':', + Cast::to_string( $step_with_post_type_prefix ) // Casting to be safe. + ); + + $step_id = Cast::to_int( $step_id ); + + if ( $step_id > 0 ) { + $step_ids[] = $step_id; + } + } + + /** + * Filters the flattened step ids for a course. + * + * @since 4.11.0 + * + * @param int[] $step_ids Step IDs. + * @param int $course_id Course ID. + */ + return apply_filters( 'learndash_course_linear_step_ids', $step_ids, $course_id ); +} + +/** + * Returns whether the video progression is enabled for the current step after the user has completed sub-steps. + * + * @since 4.11.0 + * + * @param int $step_id Step ID. + * + * @return bool + */ +function learndash_course_steps_requires_watching_video_after_sub_steps( int $step_id ): bool { + $step_settings = learndash_get_setting( $step_id ); + + return is_array( $step_settings ) + && isset( $step_settings['lesson_video_enabled'] ) + && 'on' === $step_settings['lesson_video_enabled'] + && isset( $step_settings['lesson_video_url'] ) + && ! empty( $step_settings['lesson_video_url'] ) + && isset( $step_settings['lesson_video_shown'] ) + && 'AFTER' === $step_settings['lesson_video_shown']; +} + +/** + * Returns whether the step is external. + * + * @since 4.12.0 + * + * @param int $step_id Step ID. + * + * @return bool + */ +function learndash_course_steps_is_external( int $step_id ): bool { + return 'on' === learndash_get_setting( $step_id, 'external' ); +} + +/** + * Returns the external type of the step if it is external. Empty string otherwise. + * + * @since 4.12.0 + * + * @param int $step_id Step ID. + * + * @return string + */ +function learndash_course_steps_get_external_type( int $step_id ): string { + if ( ! learndash_course_steps_is_external( $step_id ) ) { + return ''; + } + + return Cast::to_string( learndash_get_setting( $step_id, 'external_type' ) ); +} + +/** + * Returns whether the step is external and requires attendance. False if not external. + * + * @since 4.12.0 + * + * @param int $step_id Step ID. + * + * @return bool + */ +function learndash_course_steps_is_external_attendance_required( int $step_id ): bool { + if ( ! learndash_course_steps_is_external( $step_id ) ) { + return false; + } + + return 'yes' === learndash_get_setting( $step_id, 'external_require_attendance' ); +} + +/** + * Returns the step's external type label. + * + * @since 4.12.0 + * + * @param string $external_type External type. + * + * @return string External type label. Empty string if external type is invalid. + */ +function learndash_course_steps_map_external_type_to_label( string $external_type ): string { + $external_type = strtolower( $external_type ); + + switch ( $external_type ) { + case 'virtual': + return esc_html__( 'Virtual', 'learndash' ); + case 'in-person': + return esc_html__( 'In-Person', 'learndash' ); + default: + return ''; + } +} diff --git a/web/app/plugins/sfwd-lms/includes/course/ld-course-user-functions.php b/web/app/plugins/sfwd-lms/includes/course/ld-course-user-functions.php index 5989bc39c..1a954cbc4 100644 --- a/web/app/plugins/sfwd-lms/includes/course/ld-course-user-functions.php +++ b/web/app/plugins/sfwd-lms/includes/course/ld-course-user-functions.php @@ -7,31 +7,16 @@ * @package LearnDash\User */ +use LearnDash\Core\Models\Product; +use LearnDash\Core\Utilities\Cast; +use StellarWP\Learndash\StellarWP\DB\DB; + if ( ! defined( 'ABSPATH' ) ) { exit; } -use LearnDash\Core\Models\Product; - // cspell:ignore childen . -/** - * Checks if the user has access to a course. - * - * @todo duplicate function, exists in other places - * check it's use and consolidate - * - * @since 2.1.0 - * - * @param int $course_id Course ID. - * @param int|null $user_id Optional. User ID. Default null. - * - * @return boolean Returns true if the user has access otherwise false. - */ -function ld_course_check_user_access( $course_id, $user_id = null ) { - return sfwd_lms_has_access( $course_id, $user_id ); -} - /** * Gets the array of courses that can be accessed by the user. * @@ -49,7 +34,6 @@ function ld_course_check_user_access( $course_id, $user_id = null ) { * @return array An array of courses accessible to user. */ function ld_get_mycourses( $user_id = null, $atts = array() ) { - $defaults = array( 'order' => 'DESC', 'orderby' => 'ID', @@ -75,7 +59,6 @@ function ld_get_mycourses( $user_id = null, $atts = array() ) { * @return bool Returns true if the user has access. */ function sfwd_lms_has_access( $post_id, $user_id = null ) { - /** * Filters whether a user has access to the course. * @@ -90,6 +73,7 @@ function sfwd_lms_has_access( $post_id, $user_id = null ) { /** * Checks whether a user has access to a course. + * Use sfwd_lms_has_access instead. * * @since 2.1.0 * @@ -124,24 +108,24 @@ function sfwd_lms_has_access_fn( $post_id, $user_id = null ) { } /** - * Post meta of the course. + * Settings of the course. * - * @var array $meta Post meta of the course. + * @var array $course_settings */ - $meta = learndash_get_setting( $course_id ); + $course_settings = learndash_get_setting( $course_id ); - if ( ( isset( $meta['course_price_type'] ) ) && ( $meta['course_price_type'] === 'open' ) ) { + if ( ( isset( $course_settings['course_price_type'] ) ) && ( $course_settings['course_price_type'] === 'open' ) ) { return true; } - if ( ( isset( $meta['course_price_type'] ) ) && ( $meta['course_price_type'] === 'paynow' ) ) { + if ( ( isset( $course_settings['course_price_type'] ) ) && ( $course_settings['course_price_type'] === 'paynow' ) ) { // Allow for the course price field to be empty or not present. - if ( ! isset( $meta['course_price'] ) || ( empty( $meta['course_price'] ) ) ) { + if ( ! isset( $course_settings['course_price'] ) || ( empty( $course_settings['course_price'] ) ) ) { return true; } } - if ( ( isset( $meta['course_join'] ) ) && ( empty( $meta['course_join'] ) ) ) { + if ( ( isset( $course_settings['course_join'] ) ) && ( empty( $course_settings['course_join'] ) ) ) { return true; } @@ -150,8 +134,8 @@ function sfwd_lms_has_access_fn( $post_id, $user_id = null ) { } if ( true === learndash_use_legacy_course_access_list() ) { - if ( ! empty( $meta['course_access_list'] ) ) { - $course_access_list = learndash_convert_course_access_list( $meta['course_access_list'], true ); + if ( ! empty( $course_settings['course_access_list'] ) ) { + $course_access_list = learndash_convert_course_access_list( $course_settings['course_access_list'], true ); } else { $course_access_list = array(); } @@ -185,7 +169,7 @@ function sfwd_lms_has_access_fn( $post_id, $user_id = null ) { $product && ( ! $product->has_started() - || $product->has_ended() + || $product->has_ended( $user_id ) ) ) { return false; @@ -193,8 +177,8 @@ function sfwd_lms_has_access_fn( $post_id, $user_id = null ) { } // Check access expiration. - $expired = ld_course_access_expired( $course_id, $user_id ); + return ! $expired; // True if not expired. } } @@ -242,9 +226,7 @@ function ld_course_access_expired( $course_id, $user_id ) { if ( empty( $course_access_upto ) ) { return false; - } else { - - if ( time() >= $course_access_upto ) { + } elseif ( time() >= $course_access_upto ) { /** * Filters whether the course is expired for a user or not. * @@ -255,35 +237,33 @@ function ld_course_access_expired( $course_id, $user_id ) { * @param int $course_id Course ID. * @param int $course_access_upto Course expiration timestamp. */ - if ( apply_filters( 'learndash_process_user_course_access_expire', true, $user_id, $course_id, $course_access_upto ) ) { - - /** - * As of LearnDash 2.3.0.3 we store the GMT timestamp as the meta value. In prior versions we stored 1 - */ - update_user_meta( $user_id, 'learndash_course_expired_' . $course_id, time() ); - ld_update_course_access( $user_id, $course_id, true ); + if ( apply_filters( 'learndash_process_user_course_access_expire', true, $user_id, $course_id, $course_access_upto ) ) { + /** + * As of LearnDash 2.3.0.3 we store the GMT timestamp as the meta value. In prior versions we stored 1 + */ + update_user_meta( $user_id, 'learndash_course_expired_' . $course_id, time() ); + ld_update_course_access( $user_id, $course_id, true ); - /** - * Fires when the user course access is expired. - * - * @since 2.6.2 - * - * @param int $user_id User ID. - * @param int $course_id Course ID. - */ - do_action( 'learndash_user_course_access_expired', $user_id, $course_id ); + /** + * Fires when the user course access is expired. + * + * @since 2.6.2 + * + * @param int $user_id User ID. + * @param int $course_id Course ID. + */ + do_action( 'learndash_user_course_access_expired', $user_id, $course_id ); - $delete_course_progress = learndash_get_setting( $course_id, 'expire_access_delete_progress' ); - if ( ! empty( $delete_course_progress ) ) { - learndash_delete_course_progress( $course_id, $user_id ); - } - return true; - } else { - return false; + $delete_course_progress = learndash_get_setting( $course_id, 'expire_access_delete_progress' ); + if ( ! empty( $delete_course_progress ) ) { + learndash_delete_course_progress( $course_id, $user_id ); } + return true; } else { return false; } + } else { + return false; } } @@ -343,8 +323,8 @@ function ld_course_access_expired_alert() { * * @since 2.1.0 * - * @param int $course_id Course ID. - * @param int $user_id User ID. + * @param int $course_id The course ID. + * @param int $user_id The user ID. * * @return int The timestamp for course access expiration. */ @@ -362,7 +342,6 @@ function ld_course_access_expires_on( $course_id, $user_id ) { // If we have a non-empty access from... if ( abs( intval( $courses_access_from ) ) ) { - // Check the course is using expire access. $expire_access = learndash_get_setting( $course_id, 'expire_access' ); // The value stored in the post meta for 'expire_access' is 'on' not true/false 1 or 0. The string 'on'. @@ -374,6 +353,19 @@ function ld_course_access_expires_on( $course_id, $user_id ) { } } + // Check if the user has an access extension. + + if ( ! empty( $course_access_upto ) ) { + $extended_access = learndash_course_get_extended_access_timestamp( $course_id, $user_id ); + + if ( + ! empty( $extended_access ) + && $extended_access > $course_access_upto + ) { + $course_access_upto = $extended_access; + } + } + /** * Filters the amount of time until the user's course access expires. * @@ -387,19 +379,19 @@ function ld_course_access_expires_on( $course_id, $user_id ) { } /** - * Returns the course enrollment date for a regular user in no-open courses. + * Returns the date when a course becomes available for a user (does not work for open courses). * * It can return a future date if the course has not started yet (course with a start date). * Admin users don't have an enrollment date even if they have access to the course. * - * Open courses don't have an enrollment date too unless the user is enrolled in a group. In that case, the enrollment date is the group enrollment date. + * Open courses don't have an access date too unless the user is enrolled in a group. In that case, the access date is the group access date. * * @since 2.1.0 * * @param int $course_id Optional. Course ID to check. Default 0. * @param int $user_id Optional. User ID to check. Default 0. * - * @return int|bool The timestamp of when the course can be accessed from or false if the meta value does not exist. + * @return int|bool The date when a course becomes available for a user or false if the meta value does not exist. */ function ld_course_access_from( $course_id = 0, $user_id = 0 ) { static $courses = array(); @@ -454,7 +446,7 @@ function ld_course_access_from( $course_id = 0, $user_id = 0 ) { } /** - * Filters the amount of time when a lesson becomes available to the user. + * Filters the date when a course becomes available for a user. * * @since 3.0.7 * @@ -466,7 +458,7 @@ function ld_course_access_from( $course_id = 0, $user_id = 0 ) { } /** - * Updates the course access time for a user. + * Updated the date when a course becomes available for a user. * * @since 3.0.0 * @@ -479,7 +471,6 @@ function ld_course_access_from( $course_id = 0, $user_id = 0 ) { */ function ld_course_access_from_update( $course_id, $user_id, $access = '', $is_gmt = false ) { if ( ( ! empty( $course_id ) ) && ( ! empty( $user_id ) ) && ( ! empty( $access ) ) ) { - if ( ! is_numeric( $access ) ) { // If we a non-numeric value like a date stamp Y-m-d hh:mm:ss we want to convert it to a GMT timestamp. $access_time = learndash_get_timestamp_from_date_string( $access, ! $is_gmt ); @@ -519,9 +510,9 @@ function ld_course_access_from_update( $course_id, $user_id, $access = '', $is_g * * @since 2.1.0 * - * @param int $user_id User ID. - * @param int $course_id Course ID. - * @param boolean $remove Optional. Whether to remove course access for the user. Default false. + * @param int $user_id User ID. + * @param int $course_id Course ID. + * @param boolean $remove Optional. Whether to remove course access for the user. Default false. * * @return bool Returns true if the user course access update was successful otherwise false. */ @@ -562,18 +553,24 @@ function ld_update_course_access( $user_id, $course_id, $remove = false ): bool $user_course_access_time = 0; if ( empty( $remove ) ) { $user_course_access_time = get_user_meta( $user_id, 'course_' . $course_id . '_access_from', true ); + if ( empty( $user_course_access_time ) ) { // set the course access time to the course start date if it exists to avoid issues with content dripping. $start_date = $product ? $product->get_start_date() : null; $user_course_access_time = ! is_null( $start_date ) ? $start_date : time(); update_user_meta( $user_id, 'course_' . $course_id . '_access_from', $user_course_access_time ); + update_user_meta( $user_id, 'learndash_course_' . $course_id . '_enrolled_at', time() ); + $action_success = true; } } else { $user_course_access_time = get_user_meta( $user_id, 'course_' . $course_id . '_access_from', true ); + if ( ! empty( $user_course_access_time ) ) { delete_user_meta( $user_id, 'course_' . $course_id . '_access_from' ); + // we don't delete the course enrollment date because it is used in reports. + $action_success = true; } } @@ -645,7 +642,7 @@ function ld_update_course_access( $user_id, $course_id, $remove = false ): bool } /** - * Gets the timestamp of when a user can access the lesson. + * Returns the date when a lesson becomes available for a user. * * @since 2.1.0 * @@ -670,7 +667,6 @@ function ld_lesson_access_from( $lesson_id, $user_id, $course_id = null, $bypass $visible_after = learndash_get_setting( $lesson_id, 'visible_after' ); if ( $visible_after > 0 ) { - // Adjust the Course access from by the number of days. Use abs() to ensure no negative days. $lesson_access_from = intval( $courses_access_from ) + abs( $visible_after ) * 24 * 60 * 60; /** @@ -710,7 +706,7 @@ function ld_lesson_access_from( $lesson_id, $user_id, $course_id = null, $bypass } /** - * Filters the timestamp of when the user will have access to the lesson. + * Filters the date when a lesson becomes available for a user. * * @param int $timestamp The timestamp of when the lesson can be accessed. * @param int $lesson_id Lesson ID. @@ -719,21 +715,6 @@ function ld_lesson_access_from( $lesson_id, $user_id, $course_id = null, $bypass return apply_filters( 'ld_lesson_access_from', $return, $lesson_id, $user_id ); } -/** - * Gets when the lesson will be available. - * - * Fires on `learndash_content` hook. - * - * This function is not reentrant. If called using a Topic post it will recursively - * call itself for the parent Lesson post. - * - * @since 2.1.0 - * - * @param string $content The content of lesson. - * @param WP_Post $post The `WP_Post` object. - * - * @return string The output of when the lesson will be available. - */ /** * Gets when the lesson will be available. * @@ -767,7 +748,14 @@ function lesson_visible_after( string $content = '', $post = null ) { return $content; } - $bypass_course_limits_admin_users = learndash_can_user_bypass( $user_id, 'learndash_course_lesson_not_available', $post->ID, $post ); + $bypass_course_limits_admin_users = learndash_can_user_bypass( + $user_id, + 'learndash_course_lesson_not_available', + [ + 'step_id' => $post->ID, + 'step' => $post, + ] + ); // For logged in users to allow an override filter. /** This filter is documented in includes/course/ld-course-progress.php */ @@ -850,12 +838,9 @@ function learndash_get_users_for_course( $course_id = 0, $query_args = array(), $course_price_type = learndash_get_course_meta_setting( $course_id, 'course_price_type' ); if ( 'open' === $course_price_type ) { - $user_query = new WP_User_Query( $query_args ); return $user_query; - } else { - if ( true === learndash_use_legacy_course_access_list() ) { $course_access_list = learndash_get_course_meta_setting( $course_id, 'course_access_list' ); $course_user_ids = array_merge( $course_user_ids, $course_access_list ); @@ -897,9 +882,7 @@ function learndash_get_users_for_course( $course_id = 0, $query_args = array(), * @param array $course_users_new Optional. An array of user IDs to set course access. Default empty array. */ function learndash_set_users_for_course( $course_id = 0, $course_users_new = array() ) { - if ( ! empty( $course_id ) ) { - if ( ! empty( $course_users_new ) ) { $course_users_new = learndash_convert_course_access_list( $course_users_new, true ); } else { @@ -1027,6 +1010,9 @@ function learndash_user_is_course_children_progress_complete( $user_id = 0, $cou /** * Gets the course step available date. * + * It's used in the LD30 legacy templates only. + * For new code, please use the `Step::get_available_on_date()` method instead. + * * @since 4.2.0 * * @param int $step_id The Course step post ID Lesson, Topic, or Quiz. @@ -1066,7 +1052,16 @@ function learndash_course_step_available_date( int $step_id = 0, int $course_id } } - if ( learndash_can_user_bypass( $user_id, 'learndash_course_lesson_not_available', $step_post->ID, $step_post ) ) { + if ( + learndash_can_user_bypass( + $user_id, + 'learndash_course_lesson_not_available', + [ + 'step_id' => $step_post->ID, + 'step' => $step_post, + ] + ) + ) { return $available_timestamp; } @@ -1090,3 +1085,99 @@ function learndash_course_step_available_date( int $step_id = 0, int $course_id return $available_timestamp; } + +/** + * Extend the user's access to a course to a new expiration date. + * + * @since 4.8.0 + * + * @param int $course_id The course ID. + * @param array $user_ids Array of user IDs. + * @param int $new_expiration_date New expiration date timestamp. + * @param ?int $access_by_group_id The group ID if the user has access by group. Default null. + * + * @return void + */ +function learndash_course_extend_user_access( + int $course_id, + array $user_ids, + int $new_expiration_date, + int $access_by_group_id = null +): void { + if ( + empty( $course_id ) + || empty( $user_ids ) + || empty( $new_expiration_date ) + ) { + return; + } + + $product = Product::find( $course_id ); + + if ( ! $product ) { + return; + } + + foreach ( $user_ids as $user_id ) { + // Revert the course expiration if it was expired. + + delete_user_meta( $user_id, 'learndash_course_expired_' . $course_id ); + + // Update the extended access meta. + + update_user_meta( + $user_id, + 'learndash_course_' . $course_id . '_access_extended_until', + $new_expiration_date + ); + + /** + * If the user has access by group, we don't need to update the access_from meta. + * This meta is only used for direct access and is deleted when it expires. + * + * In the case of access by group, the related meta is not deleted when the access expires. + * So we don't need to update anything. + */ + + if ( empty( $access_by_group_id ) ) { + update_user_meta( + $user_id, + 'course_' . $course_id . '_access_from', + $product->get_enrollment_date( $user_id ) ?? time() + ); + } + } +} + +/** + * Returns the extended access for a user. + * + * @since 4.8.0 + * + * @param int $course_id The course ID. + * @param int $user_id The user ID. + * + * @return ?int The extended access timestamp. Null if the user has not an extended access for the course. + */ +function learndash_course_get_extended_access_timestamp( int $course_id, $user_id ): ?int { + $extended_access_timestamp = Cast::to_int( + get_user_meta( $user_id, 'learndash_course_' . $course_id . '_access_extended_until', true ) + ); + + // Normalize the value. + + $extended_access_timestamp = empty( $extended_access_timestamp ) ? null : $extended_access_timestamp; + + /** + * Filters the extended access for a user. + * + * @since 4.8.0 + * + * @param ?int $extended_access Course extended access for a user. + * @param int $course_id The course ID. + * @param int $user_id The user ID. + * + * @return ?int The extended access timestamp. Null if the user has not an extended access for the course. + */ + return apply_filters( 'learndash_course_get_extended_access_timestamp', $extended_access_timestamp, $course_id, $user_id ); +} diff --git a/web/app/plugins/sfwd-lms/includes/course/ld-course-video.php b/web/app/plugins/sfwd-lms/includes/course/ld-course-video.php index 4d1d7b27b..91c0bb572 100644 --- a/web/app/plugins/sfwd-lms/includes/course/ld-course-video.php +++ b/web/app/plugins/sfwd-lms/includes/course/ld-course-video.php @@ -2,10 +2,14 @@ /** * Handles Video Progression logic and setup. * + * @since 2.4.0 + * @package LearnDash\Video_Progression - * @since 2.4.0 */ +use LearnDash\Core\Utilities\Cast; +use LearnDash\Core\Utilities\Str; + if ( ! defined( 'ABSPATH' ) ) { exit; } @@ -17,20 +21,19 @@ * @since 2.4.0 */ class Learndash_Course_Video { - /** * Static instance of class. * - * @var array $instance; + * @var self $instance */ private static $instance; /** * Array of video progress data options and default values. * - * @var array $video_data; + * @var array $video_data */ - private $video_data = array( + private $video_data = [ 'videos_found_provider' => false, 'videos_found_type' => false, 'videos_auto_start' => false, @@ -45,45 +48,48 @@ class Learndash_Course_Video { 'video_cookie_key' => false, 'video_focus_pause' => false, 'video_track_time' => false, - 'video_track_expires' => 30, // Cookie Expire Days the cookie expires. Can be partial 0.5, 1.25, etc. - 'video_track_domain' => '', // Cookie Domain. Default set to WP COOKIE_DOMAIN. - 'video_track_path' => '', // Cookie Path. Default set to COOKIEPATH or if Multisite SITECOOKIEPATH. + 'video_track_expires' => 30, + // Cookie Expire Days the cookie expires. Can be partial 0.5, 1.25, etc. + 'video_track_domain' => '', + // Cookie Domain. Default set to WP COOKIE_DOMAIN. + 'video_track_path' => '', + // Cookie Path. Default set to COOKIEPATH or if Multisite SITECOOKIEPATH. 'course_id' => 0, 'step_id' => 0, - ); + ]; /** * User ID. * - * @var int $user_id. + * @var int $user_id */ private $user_id; /** * Course ID. * - * @var int $course_id. + * @var int $course_id */ private $course_id; /** * Course Step ID. * - * @var int $step_id. + * @var int $step_id */ private $step_id; /** * Course Step Settings array. * - * @var array $step_settings. + * @var array $step_settings */ - private $step_settings = array(); + private $step_settings = []; /** * Variable to contain the final rendered video HTML element. * - * @var string $video_content; + * @var string $video_content */ private $video_content = ''; @@ -93,14 +99,15 @@ class Learndash_Course_Video { * @since 2.4.0 */ public function __construct() { - add_action( 'wp_footer', array( $this, 'action_wp_footer' ), 1 ); - add_filter( 'learndash_process_mark_complete', array( $this, 'process_mark_complete' ), 99, 3 ); + add_action( 'wp_footer', [ $this, 'action_wp_footer' ], 1 ); } /** * Get instance. * * @since 2.4.0 + * + * @return self */ final public static function get_instance() { if ( null === self::$instance ) { @@ -118,15 +125,11 @@ final public static function get_instance() { * @param string $content HTML content to be output to browser. * @param Object $post WP_Post instance for Lesson or Topic. * @param array $settings Current setting values for Post. - * @return string $content. + * + * @return string Content with Video Progression HTML. */ - public function add_video_to_content( $content, $post, $settings = array() ) { - if ( is_user_logged_in() ) { - $this->user_id = (int) get_current_user_id(); - } else { - $this->user_id = 0; - } - + public function add_video_to_content( $content, $post, $settings = [] ) { + $this->user_id = get_current_user_id(); $this->step_id = (int) $post->ID; $this->course_id = (int) learndash_get_course_id( $post->ID ); $this->step_settings = $settings; @@ -260,6 +263,8 @@ public function add_video_to_content( $content, $post, $settings = array() ) { $this->video_data['videos_found_provider'] = 'vooplayer'; } elseif ( strpos( $this->step_settings['lesson_video_url'], trailingslashit( get_home_url() ) ) !== false ) { $this->video_data['videos_found_provider'] = 'local'; + } elseif ( strpos( $this->step_settings['lesson_video_url'], 'b-cdn.net' ) !== false ) { + $this->video_data['videos_found_provider'] = 'bunny'; } if ( empty( $this->video_data['videos_found_provider'] ) ) { @@ -288,11 +293,12 @@ public function add_video_to_content( $content, $post, $settings = array() ) { if ( 'local' === $this->video_data['videos_found_provider'] ) { $this->video_data['videos_found_type'] = 'video_shortcode'; $this->step_settings['lesson_video_url'] = '[video src="' . $this->step_settings['lesson_video_url'] . '"][/video]'; - - } elseif ( ( 'youtube' === $this->video_data['videos_found_provider'] ) || ( 'vimeo' === $this->video_data['videos_found_provider'] ) ) { - $this->video_data['videos_found_type'] = 'embed_shortcode'; - $this->step_settings['lesson_video_url'] = '[embed]' . $this->step_settings['lesson_video_url'] . '[/embed]'; - } elseif ( 'wistia' === $this->video_data['videos_found_provider'] ) { + } elseif ( + 'youtube' === $this->video_data['videos_found_provider'] + || 'vimeo' === $this->video_data['videos_found_provider'] + || 'wistia' === $this->video_data['videos_found_provider'] + || 'bunny' === $this->video_data['videos_found_provider'] + ) { $this->video_data['videos_found_type'] = 'embed_shortcode'; $this->step_settings['lesson_video_url'] = '[embed]' . $this->step_settings['lesson_video_url'] . '[/embed]'; } @@ -324,7 +330,11 @@ public function add_video_to_content( $content, $post, $settings = array() ) { } elseif ( 'iframe' === $this->video_data['videos_found_type'] ) { $this->video_content = $this->step_settings['lesson_video_url']; } - } elseif ( ( 'youtube' === $this->video_data['videos_found_provider'] ) || ( 'vimeo' === $this->video_data['videos_found_provider'] ) || ( 'wistia' === $this->video_data['videos_found_provider'] ) ) { + } elseif ( + 'youtube' === $this->video_data['videos_found_provider'] + || 'vimeo' === $this->video_data['videos_found_provider'] + || 'wistia' === $this->video_data['videos_found_provider'] + ) { if ( 'embed_shortcode' === $this->video_data['videos_found_type'] ) { global $wp_embed; $this->video_content = $wp_embed->run_shortcode( $this->step_settings['lesson_video_url'] ); @@ -339,6 +349,60 @@ public function add_video_to_content( $content, $post, $settings = array() ) { } elseif ( 'iframe' === $this->video_data['videos_found_type'] ) { $this->video_content = $this->step_settings['lesson_video_url']; } + } elseif ( 'bunny' === $this->video_data['videos_found_provider'] ) { + /** This filter is documented in includes/course/ld-course-video.php */ + $bunny_video_params = apply_filters( + 'ld_video_params', + [ + 'mp4_quality' => 720, + ], + $this->video_data['videos_found_provider'], + $this->video_content, + $post, + $this->step_settings + ); + + if ( 'embed_shortcode' === $this->video_data['videos_found_type'] ) { + // Get the Bunny embed URL. + + preg_match( + '/' . get_shortcode_regex( [ 'embed' ] ) . '/s', + $this->step_settings['lesson_video_url'], + $bunny_video_shortcode_parts + ); + $bunny_video_playlist_url = $bunny_video_shortcode_parts[5] ?? ''; + + $this->replace_bunny_playlist_url_with_mp4_url( + Cast::to_string( $bunny_video_playlist_url ), + Cast::to_int( $bunny_video_params['mp4_quality'] ?? 720 ) + ); + + global $wp_embed; + $this->video_content = do_shortcode( + $wp_embed->run_shortcode( $this->step_settings['lesson_video_url'] ) + ); + } elseif ( 'video_shortcode' === $this->video_data['videos_found_type'] ) { + // Get the Bunny video URL from the shortcode. + + preg_match( + '/' . get_shortcode_regex( [ 'video' ] ) . '/s', + $this->step_settings['lesson_video_url'], + $bunny_video_shortcode_parts + ); + $bunny_video_shortcode_parsed = shortcode_parse_atts( $bunny_video_shortcode_parts[3] ?? '' ); + $bunny_video_playlist_url = is_array( $bunny_video_shortcode_parsed ) + ? $bunny_video_shortcode_parsed['src'] ?? '' + : ''; + + $this->replace_bunny_playlist_url_with_mp4_url( + Cast::to_string( $bunny_video_playlist_url ), + Cast::to_int( $bunny_video_params['mp4_quality'] ?? 720 ) + ); + + $this->video_content = do_shortcode( + Cast::to_string( $this->step_settings['lesson_video_url'] ) + ); + } } if ( ! empty( $this->video_content ) ) { @@ -372,7 +436,6 @@ public function add_video_to_content( $content, $post, $settings = array() ) { if ( ! empty( $video_preg_pattern ) ) { preg_match( $video_preg_pattern, $this->video_content, $matches ); if ( ( is_array( $matches ) ) && ( isset( $matches[1] ) ) && ( ! empty( $matches[1] ) ) ) { - // Next we need to check if the video is YouTube, Vimeo, etc. so we check the matches[1]. if ( 'youtube' === $this->video_data['videos_found_provider'] ) { /** @@ -386,13 +449,13 @@ public function add_video_to_content( $content, $post, $settings = array() ) { */ $ld_video_params = apply_filters( 'ld_video_params', - array( - 'controls' => $this->video_data['videos_show_controls'], - 'autoplay' => $this->video_data['videos_auto_start'], + [ + 'controls' => $this->video_data['videos_show_controls'], + 'autoplay' => $this->video_data['videos_auto_start'], 'modestbranding' => 1, - 'showinfo' => 0, - 'rel' => 0, - ), + 'showinfo' => 0, + 'rel' => 0, + ], $this->video_data['videos_found_provider'], $this->video_content, $post, @@ -417,10 +480,10 @@ public function add_video_to_content( $content, $post, $settings = array() ) { /** This filter is documented in includes/course/ld-course-video.php */ $ld_video_params = apply_filters( 'ld_video_params', - array( + [ 'controls' => $this->video_data['videos_show_controls'], 'autoplay' => $this->video_data['videos_auto_start'], - ), + ], $this->video_data['videos_found_provider'], $this->video_content, $post, @@ -445,7 +508,7 @@ public function add_video_to_content( $content, $post, $settings = array() ) { /** This filter is documented in includes/course/ld-course-video.php */ $ld_video_params = apply_filters( 'ld_video_params', - array(), + [], $this->video_data['videos_found_provider'], $this->video_content, $post, @@ -461,12 +524,29 @@ public function add_video_to_content( $content, $post, $settings = array() ) { $url_path = wp_parse_url( $matches_1_new, PHP_URL_PATH ); $url_path_parts = explode( '/', $url_path ); $video_id = $url_path_parts[ count( $url_path_parts ) - 1 ]; - $this->video_content = str_replace( '