Quiz And Survey Master (Formerly Quiz Master Next) - Version 5.2.0

Version Description

(February 25, 2018) = * Closed Enhancement: Make Quiz Results Extendable/Filterable - (Issue #622) * Closed Enhancement: New Question Editor - (Issue #568) * Closed Bug: Pagination Bug - (Issue #477) * Closed Bug: Questions shift - (Issue #467) * Closed User Request: Remove duplicate question popup confirmation - (Issue #396) * Closed User Request: Question Grouping - (Issue #356) * Closed User Request: Ability To Move Submit Button To Last Question Page - (Issue #321)

(Read Full Changelog)

=

Download this release

Release Info

Developer fpcorso
Plugin Icon 128x128 Quiz And Survey Master (Formerly Quiz Master Next)
Version 5.2.0
Comparing to
See all releases

Code changes from version 5.1.7 to 5.2.0

Files changed (59) hide show
  1. CHANGELOG.md +18 -0
  2. CONTRIBUTING.md +15 -15
  3. license.md → LICENSE.md +0 -0
  4. README.md +17 -5
  5. css/qsm-admin-contact.css +10 -4
  6. css/qsm-admin-question.css +223 -70
  7. css/qsm-admin.css +13 -6
  8. js/micromodal.min.js +30 -0
  9. js/qmn_quiz.js +149 -19
  10. js/qsm-admin-contact.js +4 -3
  11. js/qsm-admin-question.js +420 -309
  12. mlw_quizmaster2.php +105 -98
  13. php/{about-page.php → admin/about-page.php} +11 -22
  14. php/{addons-page.php → admin/addons-page.php} +1 -1
  15. php/{admin-results-details-page.php → admin/admin-results-details-page.php} +0 -0
  16. php/{admin-results-page.php → admin/admin-results-page.php} +1 -1
  17. php/{dashboard-widgets.php → admin/dashboard-widgets.php} +8 -8
  18. php/{help-page.php → admin/help-page.php} +1 -1
  19. php/admin/index.php +4 -0
  20. php/{options-page-contact-tab.php → admin/options-page-contact-tab.php} +2 -2
  21. php/{options-page-email-tab.php → admin/options-page-email-tab.php} +1 -1
  22. php/{options-page-leaderboard-tab.php → admin/options-page-leaderboard-tab.php} +0 -0
  23. php/{options-page-option-tab.php → admin/options-page-option-tab.php} +0 -0
  24. php/{options-page-preview-tab.php → admin/options-page-preview-tab.php} +0 -0
  25. php/admin/options-page-questions-tab.php +299 -0
  26. php/{options-page-results-page-tab.php → admin/options-page-results-page-tab.php} +1 -1
  27. php/{options-page-style-tab.php → admin/options-page-style-tab.php} +0 -0
  28. php/{options-page-text-tab.php → admin/options-page-text-tab.php} +1 -1
  29. php/{options-page-tools-tab.php → admin/options-page-tools-tab.php} +0 -0
  30. php/{quiz-options-page.php → admin/quiz-options-page.php} +4 -3
  31. php/{quizzes-page.php → admin/quizzes-page.php} +3 -3
  32. php/{settings-page.php → admin/settings-page.php} +0 -0
  33. php/{stats-page.php → admin/stats-page.php} +1 -1
  34. php/{tools-page.php → admin/tools-page.php} +0 -0
  35. php/{class-qmn-alert-manager.php → classes/class-qmn-alert-manager.php} +0 -0
  36. php/{class-qmn-log-manager.php → classes/class-qmn-log-manager.php} +0 -0
  37. php/{class-qmn-plugin-helper.php → classes/class-qmn-plugin-helper.php} +0 -0
  38. php/{class-qmn-quiz-creator.php → classes/class-qmn-quiz-creator.php} +0 -0
  39. php/{class-qmn-quiz-manager.php → classes/class-qmn-quiz-manager.php} +394 -185
  40. php/{class-qmn-review-message.php → classes/class-qmn-review-message.php} +0 -0
  41. php/{class-qmn-tracking.php → classes/class-qmn-tracking.php} +0 -0
  42. php/{class-qsm-audit.php → classes/class-qsm-audit.php} +0 -0
  43. php/{class-qsm-changelog-generator.php → classes/class-qsm-changelog-generator.php} +53 -45
  44. php/{class-qsm-contact-manager.php → classes/class-qsm-contact-manager.php} +79 -54
  45. php/{class-qsm-fields.php → classes/class-qsm-fields.php} +0 -0
  46. php/{class-qsm-install.php → classes/class-qsm-install.php} +5 -1
  47. php/classes/class-qsm-questions.php +316 -0
  48. php/{class-qsm-settings.php → classes/class-qsm-settings.php} +0 -0
  49. php/classes/index.php +4 -0
  50. php/options-page-questions-tab.php +0 -705
  51. php/rest-api.php +220 -0
  52. php/template-variables.php +2 -2
  53. readme.txt +12 -34
  54. templates/qmn_amethyst.css +14 -16
  55. templates/qmn_base.css +14 -16
  56. templates/qmn_emerald.css +14 -16
  57. templates/qmn_gray.css +13 -15
  58. templates/qmn_primary.css +9 -11
  59. templates/qmn_turquoise.css +14 -16
CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  = 5.1.2 (October 17, 2017) =
2
  * Closed Bug: Special characters fail the uppercase validation in open answer/fill in the blank questions - ([Issue #580](https://github.com/fpcorso/quiz_master_next/issues/580))
3
 
1
+ = 5.1.7 (January 2, 2018) =
2
+ * Closed Bug: Quizzes/Surveys table not working on certain installs - ([Issue #598](https://github.com/fpcorso/quiz_master_next/issues/598))
3
+
4
+ = 5.1.6 (December 25, 2017) =
5
+ * Closed Bug: Timezone ID '' is invalid - ([Issue #606](https://github.com/fpcorso/quiz_master_next/issues/606))
6
+ * Closed Bug: Required contact fields not working correctly when the loggedin_user_contact option is set to no - ([Issue #603](https://github.com/fpcorso/quiz_master_next/issues/603))
7
+
8
+ = 5.1.5 (November 27, 2017) =
9
+ * IMPORTANT FIX: 5.1.4 had a fatal error for sites using out of date PHP versions. Please update to this!
10
+
11
+ = 5.1.4 (November 27, 2017) =
12
+ * Closed Bug: Headers already sent message - ([Issue #596](https://github.com/fpcorso/quiz_master_next/issues/596))
13
+ * Closed Bug: Styling for hints is missing causing them to be hard to read - ([Issue #587](https://github.com/fpcorso/quiz_master_next/issues/587))
14
+
15
+ = 5.1.3 (November 18, 2017) =
16
+ * Closed Bug: MathJax library not loading - ([Issue #590](https://github.com/fpcorso/quiz_master_next/issues/590))
17
+ * Closed Bug: Fatal error: Call to a member function register_question_type - ([Issue #509](https://github.com/fpcorso/quiz_master_next/issues/509))
18
+
19
  = 5.1.2 (October 17, 2017) =
20
  * Closed Bug: Special characters fail the uppercase validation in open answer/fill in the blank questions - ([Issue #580](https://github.com/fpcorso/quiz_master_next/issues/580))
21
 
CONTRIBUTING.md CHANGED
@@ -1,25 +1,25 @@
1
- #Contribute To Quiz And Survey Master
2
 
3
  Community made feature requests, patches, localisations, bug reports and contributions are always welcome and are crucial to ensure Quiz and Survey Master continues to grow to become the #1 quiz and survey platform for on WordPress.
4
 
5
  When contributing please ensure you follow the guidelines below so that we can keep on top of things.
6
 
7
- __Please Note:__ GitHub is not intended for support based questions. For those, please use the [Support Forums](https://wordpress.org/support/plugin/quiz-master-next) or [Our Contact Form](http://quizandsurveymaster.com/contact-us/)
8
 
9
  ## Getting Started
10
  * Make sure you have a free [GitHub Account](https://github.com/signup/free)
11
 
12
  ## Creating Issues
13
  * If you have a bug report or feature request, please [create an issue](https://github.com/fpcorso/quiz_master_next/issues).
14
- * For bug reports:
15
- * Please follow the debug guidlines below and report findings
16
- * Include what version of WordPress and what version of Quiz And Survey Master you are using
17
- * Include what operating system and browser you are using if applicable
18
- * If possible include link to quiz url or screenshot of issue
19
- * Clearly describe the bug/issue and include steps on how to reproduce it
20
- * For feature requests:
21
- * Please clearly describe what you would like and how it would be used
22
- * If possible, include a link or screenshot of an example
23
 
24
  ## Debug Guidelines
25
 
@@ -33,17 +33,17 @@ If you are reporting a bug, please follow these guidlines first to see if any of
33
 
34
  * Fork the repository on GitHub
35
  * Make the changes to your forked repository
36
- * Ensure you stick to the [WordPress Coding Standards](https://codex.wordpress.org/WordPress_Coding_Standards)
37
  * When committing, reference your issue (if present) and include a note about the fix
38
  * Push the changes to your fork and submit a pull request to the 'master' branch of the QMN repository
39
 
40
  ## Code Documentation
41
 
42
- * We are trying to ensure that every QMN function is documented well and follows the standards set by phpDoc going forward
43
  * An example function can be found [here](https://gist.github.com/sunnyratilal/5308969)
44
  * Please make sure that every function is documented so that when we update our API Documentation things don't go awry!
45
- * If you're adding/editing a function in a class, make sure to add `@access {private|public|protected}`
46
- * Finally, please use tabs and not spaces. The tab indent size should be 4 for all QMN code.
47
 
48
  At this point you're waiting on us to merge your pull request. We'll review all pull requests, and make suggestions and changes if necessary.
49
 
1
+ # Contribute To Quiz And Survey Master
2
 
3
  Community made feature requests, patches, localisations, bug reports and contributions are always welcome and are crucial to ensure Quiz and Survey Master continues to grow to become the #1 quiz and survey platform for on WordPress.
4
 
5
  When contributing please ensure you follow the guidelines below so that we can keep on top of things.
6
 
7
+ __Please Note:__ GitHub is not intended for support based questions. For those, please use [Our Contact Form](http://quizandsurveymaster.com/contact-us/)
8
 
9
  ## Getting Started
10
  * Make sure you have a free [GitHub Account](https://github.com/signup/free)
11
 
12
  ## Creating Issues
13
  * If you have a bug report or feature request, please [create an issue](https://github.com/fpcorso/quiz_master_next/issues).
14
+ * For bug reports:
15
+ * Please follow the debug guidlines below and report findings
16
+ * Include what version of WordPress and what version of Quiz And Survey Master you are using
17
+ * Include what operating system and browser you are using if applicable
18
+ * If possible include link to quiz url or screenshot of issue
19
+ * Clearly describe the bug/issue and include steps on how to reproduce it
20
+ * For feature requests:
21
+ * Please clearly describe what you would like and how it would be used
22
+ * If possible, include a link or screenshot of an example
23
 
24
  ## Debug Guidelines
25
 
33
 
34
  * Fork the repository on GitHub
35
  * Make the changes to your forked repository
36
+ * Ensure you stick to the [WordPress Coding Standards](https://codex.wordpress.org/WordPress_Coding_Standards)
37
  * When committing, reference your issue (if present) and include a note about the fix
38
  * Push the changes to your fork and submit a pull request to the 'master' branch of the QMN repository
39
 
40
  ## Code Documentation
41
 
42
+ * We are trying to ensure that every QSM function is documented well and follows the standards set by phpDoc going forward
43
  * An example function can be found [here](https://gist.github.com/sunnyratilal/5308969)
44
  * Please make sure that every function is documented so that when we update our API Documentation things don't go awry!
45
+ * If you're adding/editing a function in a class, make sure to add `@access {private|public|protected}`
46
+ * Finally, please use tabs and not spaces. The tab indent size should be 4 for all QSM code.
47
 
48
  At this point you're waiting on us to merge your pull request. We'll review all pull requests, and make suggestions and changes if necessary.
49
 
license.md → LICENSE.md RENAMED
File without changes
README.md CHANGED
@@ -1,12 +1,24 @@
1
- Quiz And Survey Master (Formerly Quiz Master Next)
2
- ================
3
 
4
  Easily and quickly add quizzes, tests, and surveys to your WordPress site.
5
 
6
- Feel free to browse the code and make suggestions/requests. Thanks!
7
 
8
- ## Bugs ##
9
- If you find an issue, let us know [here](https://github.com/fpcorso/quiz_master_next/issues?q=is%3Aopen)!
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
  ## Support ##
12
  This is a developer's portal for Quiz And Survey Master and should _not_ be used for support. Please create a support ticket [here](http://quizandsurveymaster.com/contact-us/).
1
+ # Quiz And Survey Master (Formerly Quiz Master Next)
 
2
 
3
  Easily and quickly add quizzes, tests, and surveys to your WordPress site.
4
 
5
+ ## Getting Started
6
 
7
+ This repo is for the core plugin for Quiz And Survey Master. This can be downloaded as a zip and installed as-is with no build script needing to be run.
8
+
9
+ ## Contributing
10
+ Please read [CONTRIBUTING.md](https://github.com/fpcorso/quiz_master_next/blob/master/CONTRIBUTING.md) for the process for submitting pull requests or issues to us.
11
+
12
+ ## Versioning
13
+ We use [SemVer](http://semver.org/) for versioning. For the versions available, see [the releases in this repository](https://github.com/fpcorso/quiz_master_next/releases).
14
+
15
+ ## Developers
16
+ * Frank Corso - Lead Developer
17
+
18
+ See also [the list of contributors](https://github.com/fpcorso/quiz_master_next/graphs/contributors) who participated in this project.
19
+
20
+ ## License
21
+ This project is licensed under the GPLv2 License - see the [LICENSE.md file](https://github.com/fpcorso/quiz_master_next/blob/master/LICENSE.md) for details.
22
 
23
  ## Support ##
24
  This is a developer's portal for Quiz And Survey Master and should _not_ be used for support. Please create a support ticket [here](http://quizandsurveymaster.com/contact-us/).
css/qsm-admin-contact.css CHANGED
@@ -1,7 +1,15 @@
 
 
 
 
 
 
 
1
  .contact-form-field {
2
  padding: 25px 10px 10px;
3
- margin: 15px 0;
4
  background: #fff;
 
5
  }
6
 
7
  .contact-form-field.new {
@@ -19,6 +27,7 @@
19
  .contact-form-label {
20
  font-weight: bold;
21
  margin-right: 10px;
 
22
  }
23
 
24
  .contact-form-control {
@@ -26,8 +35,5 @@
26
  padding: 6px 12px;
27
  font-size: 14px;
28
  line-height: 1.4;
29
- }
30
-
31
- .contact-form-control.wide {
32
  width: 100%;
33
  }
1
+ .contact-form {
2
+ background-color: #0d97d8;
3
+ box-sizing: border-box;
4
+ margin: 20px 0;
5
+ overflow: hidden;
6
+ }
7
+
8
  .contact-form-field {
9
  padding: 25px 10px 10px;
10
+ margin: 15px 10px;
11
  background: #fff;
12
+ border: 5px solid #1DD969;
13
  }
14
 
15
  .contact-form-field.new {
27
  .contact-form-label {
28
  font-weight: bold;
29
  margin-right: 10px;
30
+ display: block;
31
  }
32
 
33
  .contact-form-control {
35
  padding: 6px 12px;
36
  font-size: 14px;
37
  line-height: 1.4;
 
 
 
38
  width: 100%;
39
  }
css/qsm-admin-question.css CHANGED
@@ -1,95 +1,248 @@
1
- .edit_link,
2
- .duplicate_link {
3
- color: #0074a2 !important;
4
- font-size: 14px !important;
5
- }
6
- .delete_link {
7
- color: red !important;
8
- font-size: 14px !important;
9
- }
10
- .edit_link:hover,
11
- .duplicate_link:hover,
12
- .delete_link:hover {
13
- background-color: black;
14
- }
15
-
16
- .row:after,
17
- .answers:after,
18
- .answers_single:after {
19
- clear:both;
20
- display:table;
21
- content: " ";
22
- }
23
- .row {
24
- margin-bottom: 15px;
25
- }
26
- .row .option_label {
27
- width:15%;
28
- float:left;
29
- font-weight: bold;
30
  }
31
- .row .option_input {
32
- width:84%;
33
- float:left;
 
 
 
 
 
34
  }
35
 
36
- .row textarea.option_input {
37
- min-height: 50px;
38
  }
39
 
40
- .question_form {
 
 
41
 
 
 
 
 
 
42
  }
43
- .question_form fieldset {
44
- margin: 20px 0px;
45
- background: #fff;
46
- padding: 5px;
47
  }
48
- .question_form legend {
49
- font-size: 16px;
50
- font-weight: bold;
51
- background: #f1f1f1;
52
- padding: 5px;
53
  }
54
- .answer_number,
55
- .answer_text,
56
- .answer_points,
57
- .answer_correct {
58
- font-weight: bold;
59
- float:left;
60
- margin: 1%;
61
  }
62
- .answer_number {
63
- width:10%;
 
64
  }
65
- .answer_text {
66
- width:60%;
 
 
 
67
  }
68
- .answer_points {
69
- width:10%;
 
70
  }
71
- .answer_correct {
72
- width:10%;
 
73
  }
74
- .answer_input {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  width: 100%;
76
  }
77
- .question_area_header_text {
78
- padding: 40px 0 0 !important;
 
 
 
 
79
  }
80
 
81
- .other_quiz_question {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  display: flex;
83
- flex-direction: row;
84
  justify-content: space-between;
85
  align-items: center;
86
- margin: 10px 0;
87
- border: 1px solid #ccc;
88
  }
89
 
90
- .import_question_button,
91
- .other_quiz_question_text {
92
- margin-right: 15px !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  }
94
 
95
  @-moz-keyframes qsm-spinner-loader {
@@ -146,4 +299,4 @@
146
  margin: 1.5em;
147
  overflow: hidden;
148
  text-indent: 100%;
149
- }
1
+ .page {
2
+ width: 100%;
3
+ background-color: #0d97d8;
4
+ margin: 20px 0;
5
+ padding-bottom: 15px;
6
+ box-shadow: 0px 0px 5px 2px rgba(0,0,0,0.4)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  }
8
+
9
+ .page-header {
10
+ display: flex;
11
+ align-items: center;
12
+ justify-content: space-between;
13
+ background-color: #fff;
14
+ padding: 10px 35px;
15
+ border-bottom: 5px solid #1DD969;
16
  }
17
 
18
+ .page-header a {
19
+ text-decoration: none;
20
  }
21
 
22
+ .page-header-buttons {
23
+ text-align: center;
24
+ }
25
 
26
+ .question, .question-bank-question {
27
+ padding: 10px;
28
+ background-color: #fff;
29
+ border: 5px solid #1DD969;
30
+ margin: 15px 10px 0;
31
  }
32
+
33
+ .question a {
34
+ text-decoration: none;
 
35
  }
36
+
37
+ .question-content {
38
+ display: flex;
39
+ align-items: center;
40
+ justify-content: space-between;
41
  }
42
+
43
+ .question-content > div {
44
+ margin: 0 10px;
 
 
 
 
45
  }
46
+
47
+ .question-content-text {
48
+ flex-grow: 1;
49
  }
50
+
51
+ .question-bank-question {
52
+ display: flex;
53
+ align-items: center;
54
+ justify-content: space-between;
55
  }
56
+
57
+ .question-bank-question div {
58
+ margin: 0 10px;
59
  }
60
+
61
+ .page-new, .question-new {
62
+ background-color: yellow !important;
63
  }
64
+
65
+ .correct-header {
66
+ text-align: right;
67
+ }
68
+
69
+ .answers-single {
70
+ display: flex;
71
+ justify-content: space-between;
72
+ margin-bottom: 5px;
73
+ }
74
+
75
+ .answers-single div {
76
+ margin-left: 5px;
77
+ }
78
+
79
+ .answer-text-div {
80
  width: 100%;
81
  }
82
+
83
+ .qsm-row {
84
+ display: block;
85
+ width: 100%;
86
+ margin-bottom: 10px;
87
+ font-size: 16px;
88
  }
89
 
90
+ .qsm-row > label {
91
+ font-weight: bold;
92
+ display: block;
93
+ }
94
+
95
+ .qsm-row select, .qsm-row input[type=text], .qsm-row textarea {
96
+ width: 100%;
97
+ }
98
+
99
+ .qsm-popup {
100
+ font-family: -apple-system,BlinkMacSystemFont,avenir next,avenir,helvetica neue,helvetica,ubuntu,roboto,noto,segoe ui,arial,sans-serif;
101
+ }
102
+
103
+ .qsm-popup__overlay {
104
+ position: fixed;
105
+ top: 0;
106
+ left: 0;
107
+ right: 0;
108
+ bottom: 0;
109
+ background: rgba(0,0,0,0.6);
110
+ display: flex;
111
+ justify-content: center;
112
+ align-items: center;
113
+ z-index: 9999;
114
+ }
115
+
116
+ .qsm-popup__container {
117
+ background-color: #fff;
118
+ padding: 30px;
119
+ min-width: 500px;
120
+ max-width: 700px;
121
+ max-height: 95vh;
122
+ border-radius: 4px;
123
+ overflow-y: auto;
124
+ box-sizing: border-box;
125
+ }
126
+
127
+ .qsm-popup__header {
128
  display: flex;
 
129
  justify-content: space-between;
130
  align-items: center;
 
 
131
  }
132
 
133
+ .qsm-popup__title {
134
+ margin-top: 0;
135
+ margin-bottom: 0;
136
+ font-weight: 600;
137
+ font-size: 1.25rem;
138
+ line-height: 1.25;
139
+ color: #00449e;
140
+ box-sizing: border-box;
141
+ }
142
+
143
+ .qsm-popup__close {
144
+ background: transparent;
145
+ border: 0;
146
+ color: #00449e;
147
+ text-decoration: none;
148
+ }
149
+
150
+ .qsm-popup__header .qsm-popup__close:before {
151
+ content: "\2715";
152
+ }
153
+
154
+ .qsm-popup__content {
155
+ margin-top: 2rem;
156
+ margin-bottom: 2rem;
157
+ line-height: 1.5;
158
+ color: rgba(0,0,0,.8);
159
+ }
160
+
161
+ .qsm-popup__btn {
162
+ font-size: .875rem;
163
+ padding-left: 1rem;
164
+ padding-right: 1rem;
165
+ padding-top: .5rem;
166
+ padding-bottom: .5rem;
167
+ background-color: #e6e6e6;
168
+ color: rgba(0,0,0,.8);
169
+ border-radius: .25rem;
170
+ border-style: none;
171
+ border-width: 0;
172
+ cursor: pointer;
173
+ -webkit-appearance: button;
174
+ text-transform: none;
175
+ overflow: visible;
176
+ line-height: 1.15;
177
+ margin: 0;
178
+ will-change: transform;
179
+ -moz-osx-font-smoothing: grayscale;
180
+ -webkit-backface-visibility: hidden;
181
+ backface-visibility: hidden;
182
+ -webkit-transform: translateZ(0);
183
+ transform: translateZ(0);
184
+ transition: -webkit-transform .25s ease-out;
185
+ transition: transform .25s ease-out;
186
+ transition: transform .25s ease-out,-webkit-transform .25s ease-out;
187
+ }
188
+
189
+ .qsm-popup__btn:focus, .qsm-popup__btn:hover {
190
+ -webkit-transform: scale(1.05);
191
+ transform: scale(1.05);
192
+ }
193
+
194
+ .qsm-popup__btn-primary {
195
+ background-color: #00449e;
196
+ color: #fff;
197
+ }
198
+
199
+ @keyframes mmfadeIn {
200
+ from { opacity: 0; }
201
+ to { opacity: 1; }
202
+ }
203
+
204
+ @keyframes mmfadeOut {
205
+ from { opacity: 1; }
206
+ to { opacity: 0; }
207
+ }
208
+
209
+ @keyframes mmslideIn {
210
+ from { transform: translateY(15%); }
211
+ to { transform: translateY(0); }
212
+ }
213
+
214
+ @keyframes mmslideOut {
215
+ from { transform: translateY(0); }
216
+ to { transform: translateY(-10%); }
217
+ }
218
+
219
+ .qsm-popup-slide {
220
+ display: none;
221
+ }
222
+
223
+ .qsm-popup-slide.is-open {
224
+ display: block;
225
+ }
226
+
227
+ .qsm-popup-slide[aria-hidden="false"] .qsm-popup__overlay {
228
+ animation: mmfadeIn .3s cubic-bezier(0.0, 0.0, 0.2, 1);
229
+ }
230
+
231
+ .qsm-popup-slide[aria-hidden="false"] .qsm-popup__container {
232
+ animation: mmslideIn .3s cubic-bezier(0, 0, .2, 1);
233
+ }
234
+
235
+ .qsm-popup-slide[aria-hidden="true"] .qsm-popup__overlay {
236
+ animation: mmfadeOut .3s cubic-bezier(0.0, 0.0, 0.2, 1);
237
+ }
238
+
239
+ .qsm-popup-slide[aria-hidden="true"] .qsm-popup__container {
240
+ animation: mmslideOut .3s cubic-bezier(0, 0, .2, 1);
241
+ }
242
+
243
+ .qsm-popup-slide .qsm-popup__container,
244
+ .qsm-popup-slide .qsm-popup__overlay {
245
+ will-change: transform;
246
  }
247
 
248
  @-moz-keyframes qsm-spinner-loader {
299
  margin: 1.5em;
300
  overflow: hidden;
301
  text-indent: 100%;
302
+ }
css/qsm-admin.css CHANGED
@@ -21,21 +21,28 @@ Quizzes/Surveys Page
21
  }
22
 
23
  .qsm-news-ads {
24
- background-color: white;
25
  }
26
 
27
  .qsm-news-ads-title {
28
  text-align: center;
29
- border-bottom: 1px solid black;
 
 
 
30
  }
31
 
32
  .qsm-news-ads-widget {
33
  text-align: center;
34
- border-top: 2px solid black;
35
- border-bottom: 5px solid black;
36
- margin: 10px 0;
37
- background: #ddd;
38
  padding: 10px 5px;
 
 
 
 
 
39
  }
40
 
41
  .qsm-edit-name {
21
  }
22
 
23
  .qsm-news-ads {
24
+ background-color: #0d97d8;
25
  }
26
 
27
  .qsm-news-ads-title {
28
  text-align: center;
29
+ border-bottom: 5px solid #1DD969;
30
+ margin: 0;
31
+ padding: 10px 0;
32
+ background-color: #fff;
33
  }
34
 
35
  .qsm-news-ads-widget {
36
  text-align: center;
37
+ border: 5px solid #1DD969;
38
+ margin: 10px 5px;
39
+ background: #fff;
 
40
  padding: 10px 5px;
41
+ transition-duration: 0.5s;
42
+ }
43
+
44
+ .qsm-news-ads-widget:hover {
45
+ transform: scale(1.1);
46
  }
47
 
48
  .qsm-edit-name {
js/micromodal.min.js ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.MicroModal=t()}(this,function(){"use strict"
2
+ var e=(function(){function e(e){this.value=e}function t(t){function o(e,t){return new Promise(function(o,i){var l={key:e,arg:t,resolve:o,reject:i,next:null}
3
+ a?a=a.next=l:(r=a=l,n(e,t))})}function n(o,r){try{var a=t[o](r),l=a.value
4
+ l instanceof e?Promise.resolve(l.value).then(function(e){n("next",e)},function(e){n("throw",e)}):i(a.done?"return":"normal",a.value)}catch(e){i("throw",e)}}function i(e,t){switch(e){case"return":r.resolve({value:t,done:!0})
5
+ break
6
+ case"throw":r.reject(t)
7
+ break
8
+ default:r.resolve({value:t,done:!1})}r=r.next,r?n(r.key,r.arg):a=null}var r,a
9
+ this._invoke=o,"function"!=typeof t.return&&(this.return=void 0)}"function"==typeof Symbol&&Symbol.asyncIterator&&(t.prototype[Symbol.asyncIterator]=function(){return this}),t.prototype.next=function(e){return this._invoke("next",e)},t.prototype.throw=function(e){return this._invoke("throw",e)},t.prototype.return=function(e){return this._invoke("return",e)}}(),function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}),t=function(){function e(e,t){for(var o=0;o<t.length;o++){var n=t[o]
10
+ n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(t,o,n){return o&&e(t.prototype,o),n&&e(t,n),t}}(),o=function(e){if(Array.isArray(e)){for(var t=0,o=Array(e.length);t<e.length;t++)o[t]=e[t]
11
+ return o}return Array.from(e)}
12
+ return function(){var n=["a[href]","area[href]",'input:not([disabled]):not([type="hidden"])',"select:not([disabled])","textarea:not([disabled])","button:not([disabled])","iframe","object","embed","[contenteditable]",'[tabindex]:not([tabindex^="-"])'],i=function(){function i(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t.targetModal,r=t.triggers,a=void 0===r?[]:r,l=t.disableScroll,s=void 0!==l&&l,c=(t.debugMode,t.onShow),u=void 0===c?function(){}:c,d=t.onClose,f=void 0===d?function(){}:d
13
+ e(this,i),this.modal=document.getElementById(n),a.length>0&&this.registerTriggers.apply(this,o(a)),this.disableScroll=s,this.callbacks={onShow:u,onClose:f},this.onClick=this.onClick.bind(this),this.onKeydown=this.onKeydown.bind(this)}return t(i,[{key:"registerTriggers",value:function(){for(var e=this,t=arguments.length,o=Array(t),n=0;n<t;n++)o[n]=arguments[n]
14
+ o.forEach(function(t){t.addEventListener("click",function(){return e.showModal()})})}},{key:"showModal",value:function(){var e=this
15
+ this.activeElement=document.activeElement,this.modal.setAttribute("aria-hidden","false"),window.requestAnimationFrame(function(){e.modal.classList.add("is-open"),e.setFocusToFirstNode()}),this.scrollBehaviour("disable"),this.addEventListeners(),this.callbacks.onShow(this.modal)}},{key:"closeModal",value:function(){var e=this.modal
16
+ this.modal.addEventListener("animationend",function t(){window.requestAnimationFrame(function(){return e.classList.remove("is-open")}),e.removeEventListener("animationend",t,!1)},!1),this.modal.setAttribute("aria-hidden","true"),this.removeEventListeners(),this.scrollBehaviour("enable"),this.activeElement.focus(),this.callbacks.onClose(this.modal)}},{key:"scrollBehaviour",value:function(e){if(!1!==this.disableScroll){var t=document.querySelector("body")
17
+ switch(e){case"enable":Object.assign(t.style,{overflow:"initial",height:"initial"})
18
+ break
19
+ case"disable":Object.assign(t.style,{overflow:"hidden",height:"100vh"})}}}},{key:"addEventListeners",value:function(){this.modal.addEventListener("touchstart",this.onClick),this.modal.addEventListener("click",this.onClick),document.addEventListener("keydown",this.onKeydown)}},{key:"removeEventListeners",value:function(){this.modal.removeEventListener("touchstart",this.onClick),this.modal.removeEventListener("click",this.onClick),document.removeEventListener("keydown",this.onKeydown)}},{key:"onClick",value:function(e){e.target.hasAttribute("data-micromodal-close")&&(this.closeModal(),e.preventDefault())}},{key:"onKeydown",value:function(e){27===e.keyCode&&this.closeModal(e),9===e.keyCode&&this.maintainFocus(e)}},{key:"getFocusableNodes",value:function(){var e=this.modal.querySelectorAll(n)
20
+ return Object.keys(e).map(function(t){return e[t]})}},{key:"setFocusToFirstNode",value:function(){var e=this.getFocusableNodes()
21
+ e.length&&e[0].focus()}},{key:"maintainFocus",value:function(e){var t=this.getFocusableNodes(),o=t.indexOf(document.activeElement)
22
+ e.shiftKey&&0===o&&(t[t.length-1].focus(),e.preventDefault()),e.shiftKey||o!==t.length-1||(t[0].focus(),e.preventDefault())}}]),i}(),r=function(e){var t=[]
23
+ return e.forEach(function(e){var o=e.dataset.micromodalTrigger
24
+ void 0===t[o]&&(t[o]=[]),t[o].push(e)}),t},a=function(e){if(!document.getElementById(e))return console.warn("MicroModal v0.2.0: ❗Seems like you have missed %c'"+e+"'","background-color: #f8f9fa;color: #50596c;font-weight: bold;","ID somewhere in your code. Refer example below to resolve it."),console.warn("%cExample:","background-color: #f8f9fa;color: #50596c;font-weight: bold;",'<div class="modal" id="'+e+'"></div>'),!1},l=function(e){if(e.length<=0)return console.warn("MicroModal v0.2.0: ❗Please specify at least one %c'micromodal-trigger'","background-color: #f8f9fa;color: #50596c;font-weight: bold;","data attribute."),console.warn("%cExample:","background-color: #f8f9fa;color: #50596c;font-weight: bold;",'<a href="#" data-micromodal-trigger="my-modal"></a>'),!1},s=function(e,t){if(l(e),!t)return!0
25
+ for(var o in t)a(o)
26
+ return!0},c=function(e){var t=e||{},n=[].concat(o(document.querySelectorAll("[data-micromodal-trigger]"))),a=r(n)
27
+ if(!0!==t.debugMode||!1!==s(n,a))for(var l in a){var c=a[l]
28
+ t.targetModal=l,t.triggers=[].concat(o(c)),new i(t)}},u=null
29
+ return{init:c,show:function(e,t){var o=t||{}
30
+ o.targetModal=e,!0===o.debugMode&&!1===a(e)||(u=new i(o),u.showModal())},close:function(){u.closeModal()}}}()})
js/qmn_quiz.js CHANGED
@@ -2,6 +2,154 @@
2
  * Quiz And Survey Master
3
  *************************/
4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  // Global Variables
6
  var qmn_timer_activated = false;
7
  var qsmTitleText = window.document.title;
@@ -185,10 +333,6 @@ function qmnInit() {
185
  if ( qmn_quiz_data[key].hasOwnProperty('pagination') ) {
186
  qmnInitPagination( qmn_quiz_data[key].quiz_id );
187
  }
188
-
189
- if ( qmn_quiz_data[key].hasOwnProperty('timer_limit') ) {
190
- qmnInitTimer( qmn_quiz_data[key].quiz_id );
191
- }
192
  }
193
  }
194
 
@@ -240,19 +384,6 @@ function qmnEndTimer( quiz_id ) {
240
  }
241
  }
242
 
243
- function qmnInitTimer( quiz_id ) {
244
- if ( qmn_quiz_data[quiz_id].hasOwnProperty('pagination') && qmn_quiz_data[quiz_id].first_page ) {
245
- jQuery( '#quizForm' + quiz_id ).closest( '.qmn_quiz_container' ).find( '.mlw_next' ).on( 'click', function(event) {
246
- event.preventDefault();
247
- if ( !qmn_timer_activated && qmnValidatePage( 'quizForm' + quiz_id ) ) {
248
- qmnActivateTimer( quiz_id );
249
- }
250
- });
251
- } else {
252
- qmnActivateTimer( quiz_id );
253
- }
254
- }
255
-
256
  function qmnMinToSec( amount ) {
257
  var timer_display = '';
258
  var hours = Math.floor(amount/3600);
@@ -403,7 +534,7 @@ function qmnUpdatePageNumber( amount, quiz_form_id ) {
403
  var current_page = +jQuery( quiz_form_id ).closest( '.qmn_quiz_container' ).find( '.current_page_hidden' ).val();
404
  var total_pages = jQuery( quiz_form_id ).closest( '.qmn_quiz_container' ).find( '.total_pages_hidden' ).val();
405
  current_page += amount;
406
- jQuery( quiz_form_id + " .qmn_page_counter_message" ).text( current_page + "/" + total_pages );
407
  }
408
 
409
  function qmnInitPagination( quiz_id ) {
@@ -457,7 +588,6 @@ function qmnSocialShare( network, mlw_qmn_social_text, mlw_qmn_title, facebook_i
457
  return false;
458
  }
459
 
460
-
461
  qmnInit();
462
 
463
  jQuery(".mlw_next").click(function(event) {
2
  * Quiz And Survey Master
3
  *************************/
4
 
5
+ /**************************
6
+ * This object is the newer functions. All global functions under are slowing
7
+ * being deprecated and replaced with rewritten newer functions
8
+ **************************/
9
+ var QSM;
10
+ (function ($) {
11
+ QSM = {
12
+ init: function() {
13
+ _.each( qmn_quiz_data, function( quiz ) {
14
+ quizID = parseInt( quiz.quiz_id );
15
+ QSM.initPagination( quizID );
16
+ if ( quiz.hasOwnProperty( 'timer_limit' ) && 0 != quiz.timer_limit ) {
17
+ QSM.initTimer( quizID );
18
+ }
19
+ });
20
+ },
21
+
22
+ /**
23
+ * Sets up timer for a quiz
24
+ *
25
+ * @param int quizID The ID of the quiz
26
+ */
27
+ initTimer: function( quizID ) {
28
+ $quizForm = QSM.getQuizForm( quizID );
29
+ if ( 0 < $quizForm.children( '.qsm-page' ).length ) {
30
+ if ( qmn_quiz_data[quizID].hasOwnProperty('first_page') && qmn_quiz_data[quizID].first_page ) {
31
+ jQuery( '#quizForm' + quizID ).closest( '.qmn_quiz_container' ).find( '.mlw_next' ).on( 'click', function(event) {
32
+ event.preventDefault();
33
+ if ( !qmn_timer_activated && qmnValidatePage( 'quizForm' + quizID ) ) {
34
+ qmnActivateTimer( quizID );
35
+ }
36
+ });
37
+ } else {
38
+ qmnActivateTimer( quizID );
39
+ }
40
+ } else {
41
+ if ( qmn_quiz_data[quizID].hasOwnProperty('pagination') && qmn_quiz_data[quizID].first_page ) {
42
+ jQuery( '#quizForm' + quizID ).closest( '.qmn_quiz_container' ).find( '.mlw_next' ).on( 'click', function(event) {
43
+ event.preventDefault();
44
+ if ( !qmn_timer_activated && ( 0 == $( '.quiz_begin:visible' ).length || ( 1 == $( '.quiz_begin:visible' ).length && qmnValidatePage( 'quizForm' + quizID ) ) ) ) {
45
+ qmnActivateTimer( quizID );
46
+ }
47
+ });
48
+ } else {
49
+ qmnActivateTimer( quizID );
50
+ }
51
+ }
52
+ },
53
+ /**
54
+ * Sets up pagination for a quiz
55
+ *
56
+ * @param int quizID The ID of the quiz.
57
+ */
58
+ initPagination: function( quizID ) {
59
+ $quizForm = QSM.getQuizForm( quizID );
60
+ if ( 0 < $quizForm.children( '.qsm-page' ).length ) {
61
+ $quizForm.children( '.qsm-page' ).hide();
62
+ template = wp.template( 'qsm-pagination' );
63
+ $quizForm.append( template() );
64
+ QSM.goToPage( quizID, 1 );
65
+ $quizForm.find( '.qsm-pagination .qsm-next' ).on( 'click', function( event ) {
66
+ event.preventDefault();
67
+ QSM.nextPage( quizID );
68
+ });
69
+ $quizForm.find( '.qsm-pagination .qsm-previous' ).on( 'click', function( event ) {
70
+ event.preventDefault();
71
+ QSM.prevPage( quizID );
72
+ });
73
+ }
74
+ },
75
+ /**
76
+ * Navigates quiz to specific page
77
+ *
78
+ * @param int pageNumber The number of the page
79
+ */
80
+ goToPage: function( quizID, pageNumber ) {
81
+ var $quizForm = QSM.getQuizForm( quizID );
82
+ var $pages = $quizForm.children( '.qsm-page' );
83
+ $pages.hide();
84
+ $quizForm.children( '.qsm-page:nth-of-type(' + pageNumber + ')' ).show();
85
+ $quizForm.find( '.qsm-previous' ).hide();
86
+ $quizForm.find( '.qsm-next' ).hide();
87
+ $quizForm.find( '.qsm-submit-btn' ).hide();
88
+ if ( pageNumber < $pages.length ) {
89
+ $quizForm.find( '.qsm-next' ).show();
90
+ } else {
91
+ $quizForm.find( '.qsm-submit-btn' ).show();
92
+ }
93
+ if ( 1 < pageNumber ) {
94
+ $quizForm.find( '.qsm-previous' ).show();
95
+ }
96
+ QSM.savePage( quizID, pageNumber );
97
+ },
98
+ /**
99
+ * Moves forward or backwards through the pages
100
+ *
101
+ * @param int quizID The ID of the quiz
102
+ * @param int difference The number of pages to forward or back
103
+ */
104
+ changePage: function( quizID, difference ) {
105
+ var page = QSM.getPage( quizID );
106
+ page += difference;
107
+ QSM.goToPage( quizID, page );
108
+ },
109
+ nextPage: function( quizID ) {
110
+ if ( qmnValidatePage( 'quizForm' + quizID ) ) {
111
+ QSM.changePage( quizID, 1 );
112
+ }
113
+ },
114
+ prevPage: function( quizID ) {
115
+ QSM.changePage( quizID, -1 );
116
+ },
117
+ savePage: function( quizID, pageNumber ) {
118
+ sessionStorage.setItem( 'quiz' + quizID + 'page', pageNumber );
119
+ },
120
+ getPage: function( quizID ) {
121
+ pageNumber = parseInt( sessionStorage.getItem( 'quiz' + quizID + 'page' ) );
122
+ if ( isNaN( pageNumber ) || null == pageNumber ) {
123
+ pageNumber = 1;
124
+ }
125
+ return pageNumber;
126
+ },
127
+ /**
128
+ * Scrolls to the top of supplied element
129
+ *
130
+ * @param jQueryObject The jQuery version of an element. i.e. $('#quizForm3')
131
+ */
132
+ scrollTo: function( $element ) {
133
+ jQuery( 'html, body' ).animate(
134
+ {
135
+ scrollTop: $element.offset().top - 150
136
+ },
137
+ 1000 );
138
+ },
139
+ /**
140
+ * Gets the jQuery object of the quiz form
141
+ */
142
+ getQuizForm: function( quizID ) {
143
+ return $( '#quizForm' + quizID );
144
+ }
145
+ };
146
+
147
+ // On load code
148
+ $(function() {
149
+ QSM.init();
150
+ });
151
+ }(jQuery));
152
+
153
  // Global Variables
154
  var qmn_timer_activated = false;
155
  var qsmTitleText = window.document.title;
333
  if ( qmn_quiz_data[key].hasOwnProperty('pagination') ) {
334
  qmnInitPagination( qmn_quiz_data[key].quiz_id );
335
  }
 
 
 
 
336
  }
337
  }
338
 
384
  }
385
  }
386
 
 
 
 
 
 
 
 
 
 
 
 
 
 
387
  function qmnMinToSec( amount ) {
388
  var timer_display = '';
389
  var hours = Math.floor(amount/3600);
534
  var current_page = +jQuery( quiz_form_id ).closest( '.qmn_quiz_container' ).find( '.current_page_hidden' ).val();
535
  var total_pages = jQuery( quiz_form_id ).closest( '.qmn_quiz_container' ).find( '.total_pages_hidden' ).val();
536
  current_page += amount;
537
+ //jQuery( quiz_form_id ).siblings( '.qmn_pagination' ).find( " .qmn_page_counter_message" ).text( current_page + "/" + total_pages );
538
  }
539
 
540
  function qmnInitPagination( quiz_id ) {
588
  return false;
589
  }
590
 
 
591
  qmnInit();
592
 
593
  jQuery(".mlw_next").click(function(event) {
js/qsm-admin-contact.js CHANGED
@@ -12,7 +12,8 @@ var QSMContact;
12
  },
13
  addField : function( fieldArray ) {
14
  var contactField = $( '<div class="contact-form-field new">' +
15
- '<div class="contact-form-group">' +
 
16
  '<select class="contact-form-control wide type-control">' +
17
  '<option value="none">Select a type...</option>' +
18
  '<option value="text">Small Open Answer</option>' +
@@ -178,9 +179,9 @@ var QSMContact;
178
  QSMContact.duplicateField( $( this ) );
179
  });
180
  $( '.contact-form' ).sortable({
181
- containment: "parent",
182
  cursor: 'move',
183
- opacity: 0.6
 
184
  });
185
  });
186
  }(jQuery));
12
  },
13
  addField : function( fieldArray ) {
14
  var contactField = $( '<div class="contact-form-field new">' +
15
+ '<div class="contact-form-group">' +
16
+ '<label class="contact-form-label">Field Type</label>' +
17
  '<select class="contact-form-control wide type-control">' +
18
  '<option value="none">Select a type...</option>' +
19
  '<option value="text">Small Open Answer</option>' +
179
  QSMContact.duplicateField( $( this ) );
180
  });
181
  $( '.contact-form' ).sortable({
 
182
  cursor: 'move',
183
+ opacity: 60,
184
+ placeholder: "ui-state-highlight"
185
  });
186
  });
187
  }(jQuery));
js/qsm-admin-question.js CHANGED
@@ -4,323 +4,434 @@
4
 
5
  var QSMQuestion;
6
  (function ($) {
7
- QSMQuestion = {
8
- addQuestionFromQuiz: function() {
9
- jQuery( "#from_other_quiz_dialog" ).dialog({
10
- autoOpen: false,
11
- width: 550,
12
- height: 400,
13
- buttons: {
14
- Cancel: function() {
15
- jQuery( this ).dialog( 'close' );
16
- }
17
- }
18
- });
19
- QSMQuestion.loadSpinner( '.other_quiz_questions', true );
20
- jQuery( "#from_other_quiz_dialog" ).dialog( 'open' );
21
- QSMQuestion.loadQuestionBank();
22
- },
23
- loadQuestionBank: function() {
24
- var data = {
25
- action: 'qsm_load_all_quiz_questions'
26
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
- jQuery.post( ajaxurl, data, function( response ) {
29
- QSMQuestion.displayQuestionBank( JSON.parse( response ) );
30
- });
31
- },
32
- displayQuestionBank: function( questions ) {
33
- QSMQuestion.removeSpinner( '.other_quiz_questions' );
34
- $.each( questions, function( i, val ) {
35
- $( '.other_quiz_questions' ).append(
36
- '<div class="other_quiz_question">' +
37
- '<input type="hidden" class="hidden_question_id" value="' + val.id + '">' +
38
- '<button class="import_question_button button">Import Question</button>' +
39
- '<span class="other_quiz_question_text">' + val.question + '</span> <span class="other_quiz_question_quiz_text"> ' + val.quiz + '</span>' +
40
- '</div>'
41
- );
42
- });
43
- },
44
- importQuestion: function( id ) {
45
- $( '#copy_question_id' ).val( id );
46
- $( '#copy_question_form' ).submit();
47
- },
48
- searchQuestionBank: function( query ) {
49
- jQuery( ".other_quiz_question" ).each(function() {
50
- if ( -1 === jQuery( this ).children( '.other_quiz_question_text' ).text().toLowerCase().indexOf( query.toLowerCase() ) ) {
51
- jQuery( this ).hide();
52
- } else {
53
- jQuery( this ).show();
54
- }
55
- });
56
- },
57
- loadSpinner: function( container, empty ) {
58
- if ( empty ) {
59
- $( container ).empty();
60
- }
61
- $( container ).append( '<div class="qsm-spinner-loader"></div>' );
62
- },
63
- removeSpinner: function( container ) {
64
- $( container + ' .qsm-spinner-loader' ).remove();
65
- }
66
- };
67
 
68
- // Code to run after DOM is loaded
69
- $(function() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
 
71
- // Adds event handler for adding question from other quizzes dialog
72
- $( '#from_other_quiz_button' ).on( 'click', function( event ) {
73
- event.preventDefault();
74
- QSMQuestion.addQuestionFromQuiz();
75
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
 
77
- // Adds event handler to import button in other quizzes dialog
78
- $( '.other_quiz_questions' ).on( 'click', '.import_question_button', function( event ) {
79
- event.preventDefault();
80
- QSMQuestion.importQuestion( $( this ).prev().val() );
81
- });
 
 
 
 
 
82
 
83
- // Adds event handlers for searching question bank
84
- $( "#dialog_question_search" ).keyup(function() {
85
- QSMQuestion.searchQuestionBank( $( this ).val() );
86
- });
87
- $( '#dialog_question_search_button' ).on( 'click', function( event ) {
88
- event.preventDefault();
89
- var query = $( "#dialog_question_search" ).val();
90
- QSMQuestion.searchQuestionBank( query );
91
- });
92
- });
93
- }(jQuery));
94
-
95
- function add_answer(answer, points, correct)
96
- {
97
- if (!answer) {
98
- answer = '';
99
- }
100
- if (!points) {
101
- points = 0;
102
- }
103
- if (!correct) {
104
- correct = 0;
105
- }
106
- var correct_text = '';
107
- if (correct === 1) {
108
- correct_text = ' checked="checked"';
109
- }
110
- var total_answers = parseInt(jQuery("#new_question_answer_total").val());
111
- total_answers += 1;
112
- jQuery("#new_question_answer_total").val(total_answers);
113
- var $answer_single = jQuery('<div class="answers_single">'+
114
- '<div class="answer_number"><button class="button delete_answer">Delete</button> '+answer_text+'</div>'+
115
- '<div class="answer_text"><input type="text" class="answer_input" name="answer_'+total_answers+'" id="answer_'+total_answers+'" value="'+answer+'" /></div>'+
116
- '<div class="answer_points"><input type="text" class="answer_input" name="answer_'+total_answers+'_points" id="answer_'+total_answers+'_points" value="'+points+'" /></div>'+
117
- '<div class="answer_correct"><input type="checkbox" id="answer_'+total_answers+'_correct" name="answer_'+total_answers+'_correct"'+correct_text+' value=1 /></div>'+
118
- '</div>');
119
- jQuery("#answers").append($answer_single);
120
- }
121
-
122
- function deleteQuestion( id ) {
123
- jQuery("#delete_dialog").dialog({
124
- autoOpen: false,
125
- show: 'blind',
126
- hide: 'explode',
127
- buttons: {
128
- Cancel: function() {
129
- jQuery(this).dialog('close');
130
- }
131
- }
132
- });
133
- jQuery("#delete_dialog").dialog('open');
134
- var idHidden = document.getElementById("delete_question_id");
135
- idHidden.value = id;
136
- }
137
- function duplicateQuestion( id ) {
138
- jQuery("#duplicate_dialog").dialog({
139
- autoOpen: false,
140
- show: 'blind',
141
- hide: 'explode',
142
- buttons: {
143
- Cancel: function() {
144
- jQuery(this).dialog('close');
145
- }
146
- }
147
- });
148
- jQuery("#duplicate_dialog").dialog('open');
149
- var idHidden = document.getElementById("duplicate_question_id");
150
- idHidden.value = id;
151
- }
152
-
153
- jQuery("#new_answer_button").click(function(event) {
154
- event.preventDefault();
155
- add_answer();
156
- });
157
-
158
- jQuery(".answers").on('click', '.delete_answer', function(event) {
159
- event.preventDefault();
160
- jQuery(this).parent().parent().detach();
161
- });
162
 
163
- jQuery("#question_type").on('change', function(event) {
164
- var new_value = jQuery("#question_type").val();
165
- qmn_hide_show_correct_fields( new_value );
166
- });
167
 
168
- function qmn_hide_show_correct_fields( question_type ) {
169
- var type_fields = qmn_question_type_fields[question_type];
170
- if ( type_fields.information ) {
171
- jQuery("#question_type_info").text(type_fields.information);
172
- jQuery("#question_type_info").show();
173
- } else {
174
- jQuery("#question_type_info").hide();
175
- }
176
- if ( type_fields.inputs.indexOf( "question") !== -1 ) {
177
- jQuery("#question_name").show();
178
- } else {
179
- jQuery("#question_name").hide();
180
- }
181
- if ( type_fields.inputs.indexOf( "answer") !== -1 ) {
182
- jQuery("#answer_area").show();
183
- } else {
184
- jQuery("#answer_area").hide();
185
- }
186
- if ( type_fields.inputs.indexOf( "correct_info") !== -1 ) {
187
- jQuery("#correct_answer_area").show();
188
- } else {
189
- jQuery("#correct_answer_area").hide();
190
- }
191
- if ( type_fields.inputs.indexOf( "hint") !== -1 ) {
192
- jQuery("#hint_area").show();
193
- } else {
194
- jQuery("#hint_area").hide();
195
- }
196
- if ( type_fields.inputs.indexOf( "comments") !== -1 ) {
197
- jQuery("#comment_area").show();
198
- } else {
199
- jQuery("#comment_area").hide();
200
- }
201
- if ( type_fields.inputs.indexOf( "category") !== -1 ) {
202
- jQuery("#category_area").show();
203
- } else {
204
- jQuery("#category_area").hide();
205
- }
206
- if ( type_fields.inputs.indexOf( "required") !== -1 ) {
207
- jQuery("#required_area").show();
208
- } else {
209
- jQuery("#required_area").hide();
210
- }
211
- }
212
 
213
- jQuery("#the-list").on('click', '.edit_link', function(event) {
214
- event.preventDefault();
215
- var question_array_id = jQuery(this).attr('data-question-id');
216
- var question = jQuery('<textarea/>').html(questions_list[question_array_id].question).text();
217
- if ( 'undefined' === typeof tinyMCE || null === tinyMCE ) {
218
- jQuery( "#question_name" ).val( question );
219
- } else {
220
- var question_editor = tinyMCE.get( 'question_name' );
221
- if ( question_editor ) {
222
- tinyMCE.get( 'question_name' ).setContent( question );
223
- } else {
224
- jQuery( "#question_name" ).val( question );
225
- }
226
- }
227
- jQuery(".question_area_header_text").text('Edit Question');
228
- jQuery(".question_area .button-primary").val("Save Question");
229
- jQuery("#correct_answer_info").val(jQuery('<textarea/>').html(questions_list[question_array_id].correct_info).text());
230
- jQuery("#hint").val(jQuery('<textarea/>').html(questions_list[question_array_id].hint).text());
231
- jQuery("#new_question_order").val(questions_list[question_array_id].order);
232
- jQuery("#question_type").val(questions_list[question_array_id].type);
233
- jQuery(".comments_radio").val([questions_list[question_array_id].comment]);
234
- jQuery("#required").val(questions_list[question_array_id].required);
235
- jQuery(".category_radio").removeAttr('checked');
236
- if ( questions_list[question_array_id].category !== '' ) {
237
- jQuery(".category_radio").val([questions_list[question_array_id].category]);
238
- }
239
- jQuery("#question_submission").val('edit_question');
240
- jQuery("#question_id").val(questions_list[question_array_id].id);
241
- jQuery("#answers").empty();
242
- jQuery("#new_question_answer_total").val(0);
243
- for (var i = 0; i < questions_list[question_array_id].answers.length; i++) {
244
- add_answer(questions_list[question_array_id].answers[i].answer,questions_list[question_array_id].answers[i].points,questions_list[question_array_id].answers[i].correct);
245
- }
246
- qmn_hide_show_correct_fields(questions_list[question_array_id].type);
247
- location.hash = '';
248
- location.hash = '#question_area';
249
- });
250
 
251
- jQuery("#new_question_button").click(function() {
252
- jQuery(".question_area_header_text").text('Add New Question');
253
- jQuery(".question_area .button-primary").val("Create Question");
254
- var question_editor = tinyMCE.get('question_name');
255
- if (question_editor)
256
- {
257
- tinyMCE.get('question_name').setContent('');
258
- }
259
- else
260
- {
261
- jQuery("#question_name").val('');
262
- }
263
- jQuery("#correct_answer_info").val('');
264
- jQuery("#hint").val('');
265
- jQuery("#new_question_order").val(questions_list.length+1);
266
- jQuery("#question_type").val(0);
267
- jQuery(".comments_radio").val([1]);
268
- jQuery("#required").val(1);
269
- jQuery("#question_submission").val('new_question');
270
- jQuery("#question_id").val(0);
271
- jQuery(".category_radio").removeAttr('checked');
272
- jQuery("#answers").empty();
273
- jQuery("#new_question_answer_total").val(0);
274
- location.hash = '';
275
- location.hash = '#question_area';
276
- });
277
 
278
- jQuery("#question_search").keyup(function() {
279
- jQuery(".question_row").each(function() {
280
- if ( jQuery(this).text().toLowerCase().indexOf(jQuery("#question_search").val().toLowerCase()) === -1 ) {
281
- jQuery(this).hide();
282
- } else {
283
- jQuery(this).show();
284
- }
285
- });
286
- });
 
 
 
 
 
 
 
 
 
 
 
 
287
 
288
- jQuery('.button-primary').on('click',function() {
289
- location.hash = '';
290
- });
291
-
292
- jQuery("#the-list").text('');
293
- var alternate = false;
294
- var alternate_css = '';
295
- for (var i = 0; i < questions_list.length; i++) {
296
- alternate_css = '';
297
- if (alternate) {
298
- alternate_css = ' alternate';
299
- }
300
- var $question_row = jQuery('<tr id="question_'+questions_list[i].id+'" class="question_row'+alternate_css+'">'+
301
- '<td>'+questions_list[i].order+'</td>'+
302
- '<td>'+questions_list[i].type_name+'</td>'+
303
- '<td>'+questions_list[i].category+'</td>'+
304
- '<td>'+
305
- jQuery('<textarea/>').html(questions_list[i].question.replace(/\\"/g, '"').replace(/\\'/g, "'")).text()+
306
- '<div class="row-actions">'+
307
- '<a class="edit_link" data-question-id="'+i+'" href="#">Edit</a> | '+
308
- '<a class="duplicate_link" onclick="duplicateQuestion('+questions_list[i].id+')" href="#">Duplicate</a>| '+
309
- '<a class="delete_link" onclick="deleteQuestion('+questions_list[i].id+')" href="#">Delete</a>'+
310
- '</div>'+
311
- '</td>'+
312
- '</tr>');
313
- jQuery("#the-list").append($question_row);
314
- alternate = !alternate;
315
- }
316
-
317
- jQuery( '.widefat tbody' ).sortable({
318
- containment: "parent",
319
- cursor: 'move',
320
- opacity: 0.7
321
- });
322
-
323
- jQuery( '#save_question_order' ).click(function() {
324
- jQuery( '#save_question_order_input' ).val( jQuery( '.widefat tbody' ).sortable("toArray") );
325
- jQuery( '#save_question_order_form' ).submit();
326
- });
4
 
5
  var QSMQuestion;
6
  (function ($) {
7
+ QSMQuestion = {
8
+ question: Backbone.Model.extend({
9
+ defaults: {
10
+ id: null,
11
+ quizID: 1,
12
+ type: '0',
13
+ name: 'Your new question!',
14
+ answerInfo: '',
15
+ comments: '1',
16
+ hint: '',
17
+ category: '',
18
+ required: 1,
19
+ answers: [],
20
+ page: 0
21
+ }
22
+ }),
23
+ questions: null,
24
+ questionCollection: null,
25
+ categories: [],
26
+ openQuestionBank: function( pageID ) {
27
+ QSMQuestion.loadQuestionBank();
28
+ $( '#add-question-bank-page' ).val( pageID );
29
+ MicroModal.show( 'modal-2' );
30
+ },
31
+ loadQuestionBank: function() {
32
+ $( '#question-bank' ).empty();
33
+ $( '#question-bank' ).append( '<div class="qsm-spinner-loader"></div>' );
34
+ $.ajax( {
35
+ url: wpApiSettings.root + 'quiz-survey-master/v1/questions',
36
+ method: 'GET',
37
+ beforeSend: function ( xhr ) {
38
+ xhr.setRequestHeader( 'X-WP-Nonce', qsmQuestionSettings.nonce );
39
+ },
40
+ data: {
41
+ 'quizID' : 0
42
+ },
43
+ success: QSMQuestion.questionBankLoadSuccess
44
+ });
45
+ },
46
+ questionBankLoadSuccess: function( questions ) {
47
+ $( '#question-bank' ).empty();
48
+ for ( var i = 0; i < questions.length; i++) {
49
+ QSMQuestion.addQuestionToQuestionBank( questions[i] );
50
+ }
51
+ },
52
+ addQuestionToQuestionBank: function( question ) {
53
+ var questionText = QSMQuestion.prepareQuestionText( question.name );
54
+ var template = wp.template( 'single-question-bank-question' );
55
+ $( '#question-bank' ).append( template( { id: question.id, question: questionText } ) );
56
+ },
57
+ addQuestionFromQuestionBank: function( questionID ) {
58
+ MicroModal.close( 'modal-2' );
59
+ QSMQuestion.displayAlert( 'Adding question...', 'info' );
60
+ var model = new QSMQuestion.question( { id: questionID } );
61
+ model.fetch({
62
+ headers: { 'X-WP-Nonce': qsmQuestionSettings.nonce },
63
+ url: wpApiSettings.root + 'quiz-survey-master/v1/questions/' + questionID,
64
+ success: QSMQuestion.questionBankSuccess,
65
+ error: QSMQuestion.displayError
66
+ });
67
+ },
68
+ questionBankSuccess: function( model ) {
69
+ var page = parseInt( $( '#add-question-bank-page' ).val(), 10 );
70
+ model.set( 'page', page );
71
+ QSMQuestion.displayAlert( 'Question added!', 'success' );
72
+ QSMQuestion.questions.add( model );
73
+ QSMQuestion.addQuestionToPage( model );
74
+ },
75
+ prepareCategories: function() {
76
+ QSMQuestion.categories = [];
77
+ QSMQuestion.questions.each(function( question ) {
78
+ var category = question.get( 'category' );
79
+ if ( 0 !== category.length && ! _.contains( QSMQuestion.categories, category ) ) {
80
+ QSMQuestion.categories.push( category );
81
+ }
82
+ });
83
+ },
84
+ processCategories: function() {
85
+ $( '.category' ).remove();
86
+ _.each( QSMQuestion.categories, function( category ) {
87
+ QSMQuestion.addCategory( category );
88
+ });
89
+ },
90
+ addCategory: function( category ) {
91
+ var template = wp.template( 'single-category' );
92
+ $( '#categories' ).prepend( template( { category: category } ) );
93
+ },
94
+ loadQuestions: function() {
95
+ QSMQuestion.displayAlert( 'Loading questions...', 'info' );
96
+ QSMQuestion.questions.fetch({
97
+ headers: { 'X-WP-Nonce': qsmQuestionSettings.nonce },
98
+ data: { quizID: qsmQuestionSettings.quizID },
99
+ success: QSMQuestion.loadSuccess,
100
+ error: QSMQuestion.displayError
101
+ });
102
+ },
103
+ loadSuccess: function() {
104
+ QSMQuestion.clearAlerts();
105
+ var question;
106
+ if ( qsmQuestionSettings.pages.length > 0 ) {
107
+ for ( var i = 0; i < qsmQuestionSettings.pages.length; i++ ) {
108
+ for ( var j = 0; j < qsmQuestionSettings.pages[ i ].length; j++ ) {
109
+ question = QSMQuestion.questions.get( qsmQuestionSettings.pages[ i ][ j ] );
110
+ QSMQuestion.addQuestionToPage( question );
111
+ }
112
+ }
113
+ } else {
114
+ QSMQuestion.questions.each( QSMQuestion.addQuestionToPage );
115
+ }
116
+ },
117
+ savePages: function() {
118
+ QSMQuestion.displayAlert( 'Saving pages and questions...', 'info' );
119
+ var pages = [];
120
 
121
+ // Cycles through each page and add page + questions to pages variable
122
+ _.each( jQuery( '.page' ), function( page ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
 
124
+ // If page is empty, do not add it.
125
+ if( 0 == jQuery( page ).children( '.question' ).length ) {
126
+ return;
127
+ }
128
+ var singlePage = [];
129
+ // Cycle through each question and add to the page.
130
+ _.each( jQuery( page ).children( '.question' ), function( question ){
131
+ singlePage.push( jQuery( question ).data( 'question-id' ) )
132
+ });
133
+ pages.push( singlePage );
134
+ });
135
+ var data = {
136
+ action: 'qsm_save_pages',
137
+ pages: pages,
138
+ quiz_id : qsmQuestionSettings.quizID
139
+ };
140
+
141
+ jQuery.ajax( ajaxurl, {
142
+ data: data,
143
+ method: 'POST',
144
+ success: QSMQuestion.savePagesSuccess,
145
+ error: QSMQuestion.displayjQueryError
146
+ });
147
+ },
148
+ savePagesSuccess: function() {
149
+ QSMQuestion.displayAlert( 'Questions and pages were saved!', 'success' );
150
+ },
151
+ addNewPage: function() {
152
+ var template = wp.template( 'page' );
153
+ $( '.questions' ).append( template() );
154
+ $( '.page' ).sortable({
155
+ items: '.question',
156
+ opacity: 70,
157
+ cursor: 'move',
158
+ placeholder: "ui-state-highlight",
159
+ connectWith: '.page'
160
+ });
161
+ setTimeout( QSMQuestion.removeNew, 250 );
162
+ },
163
+ addNewQuestion: function( model ) {
164
+ QSMQuestion.displayAlert( 'Question created!', 'success' );
165
+ QSMQuestion.addQuestionToPage( model );
166
+ QSMQuestion.openEditPopup( model.id );
167
+ },
168
+ addQuestionToPage: function( model ) {
169
+ var page = model.get( 'page' ) + 1;
170
+ var template = wp.template( 'question' );
171
+ var page_exists = $( '.page:nth-child(' + page + ')' ).length;
172
+ var count = 0;
173
+ while ( ! page_exists ) {
174
+ QSMQuestion.addNewPage();
175
+ page_exists = $( '.page:nth-child(' + page + ')' ).length;
176
+ count++;
177
+ if ( count > 5 ) {
178
+ page_exists = true;
179
+ console.log( 'count reached' );
180
+ }
181
+ }
182
+ var questionName = QSMQuestion.prepareQuestionText( model.get( 'name' ) );
183
+ $( '.page:nth-child(' + page + ')' ).append( template( { id: model.id, category : model.get('category'), question: questionName } ) );
184
+ setTimeout( QSMQuestion.removeNew, 250 );
185
+ },
186
+ createQuestion: function( page ) {
187
+ QSMQuestion.displayAlert( 'Creating question...', 'info' );
188
+ QSMQuestion.questions.create(
189
+ {
190
+ quizID: qsmQuestionSettings.quizID,
191
+ page: page
192
+ },
193
+ {
194
+ headers: { 'X-WP-Nonce': qsmQuestionSettings.nonce },
195
+ success: QSMQuestion.addNewQuestion,
196
+ error: QSMQuestion.displayError
197
+ }
198
+ );
199
+ },
200
+ duplicateQuestion: function( questionID ) {
201
+ QSMQuestion.displayAlert( 'Duplicating question...', 'info' );
202
+ var model = QSMQuestion.questions.get( questionID );
203
+ var newModel = _.clone(model.attributes);
204
+ newModel.id = null;
205
+ QSMQuestion.questions.create(
206
+ newModel,
207
+ {
208
+ headers: { 'X-WP-Nonce': qsmQuestionSettings.nonce },
209
+ success: QSMQuestion.addNewQuestion,
210
+ error: QSMQuestion.displayError
211
+ }
212
+ );
213
+ },
214
+ saveQuestion: function( questionID ) {
215
+ QSMQuestion.displayAlert( 'Saving question...', 'info' );
216
+ var model = QSMQuestion.questions.get( questionID );
217
+ var hint = $( '#hint' ).val();
218
+ var name = wp.editor.getContent( 'question-text' );
219
+ var answerInfo = $( '#correct_answer_info' ).val();
220
+ var type = $( "#question_type" ).val();
221
+ var comments = $( "#comments" ).val();
222
+ var required = $( "#required" ).val();
223
+ var category = $( ".category-radio:checked" ).val();
224
+ if ( 'new_category' == category ) {
225
+ category = $( '#new_category' ).val();
226
+ }
227
+ if ( ! category ) {
228
+ category = '';
229
+ }
230
+ var answers = [];
231
+ var $answers = jQuery( '.answers-single');
232
+ _.each( $answers, function( answer ) {
233
+ var $answer = jQuery( answer );
234
+ var answer = $answer.find( '.answer-text' ).val();
235
+ var points = $answer.find( '.answer-points' ).val();
236
+ var correct = 0;
237
+ if ( $answer.find( '.answer-correct' ).prop( 'checked' ) ) {
238
+ correct = 1;
239
+ }
240
+ answers.push( [ answer, points, correct ] );
241
+ });
242
+ model.save(
243
+ {
244
+ type: type,
245
+ name: name,
246
+ answerInfo: answerInfo,
247
+ comments: comments,
248
+ hint: hint,
249
+ category: category,
250
+ required: required,
251
+ answers: answers,
252
+ },
253
+ {
254
+ headers: { 'X-WP-Nonce': qsmQuestionSettings.nonce },
255
+ success: QSMQuestion.saveSuccess,
256
+ error: QSMQuestion.displayError
257
+ }
258
+ );
259
+ MicroModal.close('modal-1');
260
+ },
261
+ saveSuccess: function( model ) {
262
+ QSMQuestion.displayAlert( 'Question was saved!', 'success' );
263
+ var template = wp.template( 'question' );
264
+ var page = model.get( 'page' ) + 1;
265
+ $( '.question[data-question-id=' + model.id + ']' ).replaceWith( template( { id: model.id, type : model.get('type'), category : model.get('category'), question: model.get('name') } ) );
266
+ setTimeout( QSMQuestion.removeNew, 250 );
267
+ },
268
+ addNewAnswer: function( answer ) {
269
+ var answerTemplate = wp.template( 'single-answer' );
270
+ $( '#answers' ).append( answerTemplate( { answer: answer[0], points: answer[1], correct: answer[2] } ) );
271
+ },
272
+ openEditPopup: function( questionID ) {
273
+ QSMQuestion.prepareCategories();
274
+ QSMQuestion.processCategories();
275
+ var question = QSMQuestion.questions.get( questionID );
276
+ var questionText = QSMQuestion.prepareQuestionText( question.get( 'name' ) );
277
+ $( '#edit_question_id' ).val( questionID );
278
+ var question_editor = tinyMCE.get( 'question-text' );
279
+ if ( question_editor ) {
280
+ tinyMCE.get( 'question-text' ).setContent( questionText );
281
+ } else {
282
+ jQuery( "#question-text" ).val( questionText );
283
+ }
284
 
285
+ $( '#answers' ).empty();
286
+ var answers = question.get( 'answers' );
287
+ _.each( answers, function( answer ) {
288
+ QSMQuestion.addNewAnswer( answer );
289
+ });
290
+ $( '#hint' ).val( question.get( 'hint' ) );
291
+ $( '#correct_answer_info' ).val( question.get( 'answerInfo' ) );
292
+ $( "#question_type" ).val( question.get( 'type' ) );
293
+ $( "#comments" ).val( question.get( 'comments' ) );
294
+ $( "#required" ).val( question.get( 'required' ) );
295
+ $( ".category-radio" ).removeAttr( 'checked' );
296
+ if ( 0 !== question.get( 'category' ).length ) {
297
+ $( ".category-radio" ).val( [question.get( 'category' )] );
298
+ }
299
+ MicroModal.show( 'modal-1' );
300
+ },
301
+ displayjQueryError: function( jqXHR, textStatus, errorThrown ) {
302
+ QSMQuestion.displayAlert( 'Error: ' + errorThrown + '! Please try again.', 'error' );
303
+ },
304
+ displayError: function( jqXHR, textStatus, errorThrown ) {
305
+ QSMQuestion.displayAlert( 'Error: ' + errorThrown.errorThrown + '! Please try again.', 'error' );
306
+ },
307
+ displayAlert: function( message, type ) {
308
+ QSMQuestion.clearAlerts();
309
+ var template = wp.template( 'notice' );
310
+ var data = {
311
+ message: message,
312
+ type: type
313
+ };
314
+ $( '.questions-messages' ).append( template( data ) );
315
+ },
316
+ clearAlerts: function() {
317
+ $( '.questions-messages' ).empty();
318
+ },
319
+ removeNew: function() {
320
+ $( '.page-new' ).removeClass( 'page-new' );
321
+ $( '.question-new' ).removeClass( 'question-new' );
322
+ },
323
+ prepareQuestionText: function( question ) {
324
+ return jQuery('<textarea />').html( question ).text();
325
+ },
326
+ prepareEditor: function() {
327
+ var settings = {
328
+ mediaButtons: true,
329
+ tinymce: {
330
+ toolbar1: 'formatselect,bold,italic,bullist,numlist,link,blockquote,alignleft,aligncenter,alignright,strikethrough,hr,forecolor,pastetext,removeformat,codeformat,undo,redo'
331
+ },
332
+ quicktags: true,
333
+ };
334
+ wp.editor.initialize( 'question-text', settings );
335
+ }
336
+ };
337
 
338
+ $(function() {
339
+ QSMQuestion.questionCollection = Backbone.Collection.extend({
340
+ url: wpApiSettings.root + 'quiz-survey-master/v1/questions',
341
+ model: QSMQuestion.question
342
+ });
343
+ QSMQuestion.questions = new QSMQuestion.questionCollection();
344
+ $( '.new-page-button' ).on( 'click', function( event ) {
345
+ event.preventDefault();
346
+ QSMQuestion.addNewPage();
347
+ });
348
 
349
+ $( '.questions' ).on( 'click', '.new-question-button', function( event ) {
350
+ event.preventDefault();
351
+ QSMQuestion.createQuestion( $( this ).parents( '.page' ).index() );
352
+ });
353
+
354
+ $( '.questions' ).on( 'click', '.add-question-bank-button', function( event ) {
355
+ event.preventDefault();
356
+ QSMQuestion.openQuestionBank( $( this ).parents( '.page' ).index() );
357
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
358
 
359
+ $( '.questions' ).on( 'click', '.edit-question-button', function( event ) {
360
+ event.preventDefault();
361
+ QSMQuestion.openEditPopup( $( this ).parents( '.question' ).data( 'question-id' ) );
362
+ });
363
 
364
+ $( '.questions' ).on( 'click', '.duplicate-question-button', function( event ) {
365
+ event.preventDefault();
366
+ QSMQuestion.duplicateQuestion( $( this ).parents( '.question' ).data( 'question-id' ) );
367
+ });
368
+ $( '.questions' ).on( 'click', '.delete-question-button', function( event ) {
369
+ event.preventDefault();
370
+ $( this ).parents( '.question' ).remove();
371
+ });
372
+ $( '.questions' ).on( 'click', '.delete-page-button', function( event ) {
373
+ event.preventDefault();
374
+ $( this ).parents( '.page' ).remove();
375
+ });
376
+ $( '#answers' ).on( 'click', '.delete-answer-button', function( event ) {
377
+ event.preventDefault();
378
+ $( this ).parents( '.answers-single' ).remove();
379
+ });
380
+ $( '#save-popup-button' ).on( 'click', function( event ) {
381
+ event.preventDefault();
382
+ QSMQuestion.saveQuestion( $( this ).parent().siblings( 'main' ).children( '#edit_question_id' ).val() );
383
+ });
384
+ $( '#new-answer-button' ).on( 'click', function( event ) {
385
+ event.preventDefault();
386
+ var answer = [ '', '', 0 ];
387
+ QSMQuestion.addNewAnswer( answer );
388
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
389
 
390
+ $( '.qsm-popup-bank' ).on( 'click', '.import-button', function( event) {
391
+ event.preventDefault();
392
+ QSMQuestion.addQuestionFromQuestionBank( $( this ).parents( '.question-bank-question' ).data( 'question-id' ) );
393
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
394
 
395
+ $( '.save-page-button' ).on( 'click', function( event ) {
396
+ event.preventDefault();
397
+ QSMQuestion.savePages();
398
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399
 
400
+ // Adds event handlers for searching questions
401
+ $( '#question_search' ).on( 'keyup', function() {
402
+ $( '.question' ).each(function() {
403
+ if ( $(this).text().toLowerCase().indexOf( $( '#question_search' ).val().toLowerCase()) === -1 ) {
404
+ $(this).hide();
405
+ } else {
406
+ $(this).show();
407
+ }
408
+ });
409
+ $( '.page' ).each(function() {
410
+ if ( 0 === $(this).children( '.question:visible' ).length ) {
411
+ $(this).hide();
412
+ } else {
413
+ $(this).show();
414
+ }
415
+ });
416
+ if ( 0 === $( '#question_search' ).val().length ) {
417
+ $( '.page' ).show();
418
+ $( '.question' ).show();
419
+ }
420
+ });
421
 
422
+ $( '.questions' ).sortable({
423
+ opacity: 70,
424
+ cursor: 'move',
425
+ placeholder: "ui-state-highlight"
426
+ });
427
+ $( '.page' ).sortable({
428
+ items: '.question',
429
+ opacity: 70,
430
+ cursor: 'move',
431
+ placeholder: "ui-state-highlight",
432
+ connectWith: '.page'
433
+ });
434
+ QSMQuestion.prepareEditor();
435
+ QSMQuestion.loadQuestions();
436
+ });
437
+ }(jQuery));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
mlw_quizmaster2.php CHANGED
@@ -2,17 +2,20 @@
2
  /**
3
  * Plugin Name: Quiz And Survey Master
4
  * Description: Easily and quickly add quizzes and surveys to your website.
5
- * Version: 5.1.7
6
  * Author: Frank Corso
7
  * Author URI: https://www.quizandsurveymaster.com/
8
  * Plugin URI: https://www.quizandsurveymaster.com/
9
  * Text Domain: quiz-master-next
10
  *
11
  * @author Frank Corso
12
- * @version 5.1.7
 
13
  */
14
 
15
- if ( ! defined( 'ABSPATH' ) ) exit;
 
 
16
 
17
  define( 'QSM_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
18
  /**
@@ -30,7 +33,7 @@ class MLWQuizMasterNext {
30
  * @var string
31
  * @since 4.0.0
32
  */
33
- public $version = '5.1.7';
34
 
35
  /**
36
  * QSM Alert Manager Object
@@ -81,95 +84,98 @@ class MLWQuizMasterNext {
81
  public $quiz_settings;
82
 
83
  /**
84
- * Main Construct Function
85
- *
86
- * Call functions within class
87
- *
88
- * @since 3.6.1
89
- * @uses MLWQuizMasterNext::load_dependencies() Loads required filed
90
- * @uses MLWQuizMasterNext::add_hooks() Adds actions to hooks and filters
91
- * @return void
92
- */
93
  public function __construct() {
94
  $this->load_dependencies();
95
  $this->add_hooks();
96
  }
97
 
98
  /**
99
- * Load File Dependencies
100
- *
101
- * @since 3.6.1
102
- * @return void
103
- */
104
  private function load_dependencies() {
105
 
106
- include( "php/class-qsm-install.php" );
107
- include( "php/class-qsm-fields.php" );
108
 
109
- include( "php/class-qmn-log-manager.php" );
110
- $this->log_manager = new QMN_Log_Manager;
111
 
112
- include( "php/class-qsm-audit.php" );
113
  $this->audit_manager = new QSM_Audit();
114
 
115
  if ( is_admin() ) {
116
- include( "php/stats-page.php" );
117
- include( "php/quizzes-page.php" );
118
- include( "php/quiz-options-page.php" );
119
- include( "php/admin-results-page.php" );
120
- include( "php/admin-results-details-page.php" );
121
- include( "php/tools-page.php" );
122
- include( "php/class-qsm-changelog-generator.php" );
123
- include( "php/about-page.php" );
124
- include( "php/help-page.php" );
125
- include( "php/dashboard-widgets.php" );
126
- include( "php/options-page-questions-tab.php" );
127
- include("php/options-page-contact-tab.php");
128
- include( "php/options-page-text-tab.php" );
129
- include( "php/options-page-option-tab.php" );
130
- include( "php/options-page-leaderboard-tab.php" );
131
- include( "php/options-page-email-tab.php" );
132
- include( "php/options-page-results-page-tab.php" );
133
- include( "php/options-page-style-tab.php" );
134
- include( "php/options-page-tools-tab.php" );
135
- include( "php/options-page-preview-tab.php" );
136
- include( "php/addons-page.php" );
137
- include( "php/settings-page.php" );
138
- include( "php/class-qmn-tracking.php" );
139
- include( "php/class-qmn-review-message.php" );
140
  }
141
- include( "php/class-qsm-contact-manager.php" );
142
- include( "php/class-qmn-quiz-manager.php" );
143
-
144
- include( "php/leaderboard-shortcode.php" );
145
- include( "php/widgets.php" );
146
- include( "php/template-variables.php" );
147
- include( "php/adverts-generate.php" );
148
- include( "php/question-types.php" );
149
- include( "php/default-templates.php" );
150
- include( "php/shortcodes.php" );
151
-
152
- include( "php/class-qmn-alert-manager.php" );
 
153
  $this->alertManager = new MlwQmnAlertManager();
154
 
155
- include( "php/class-qmn-quiz-creator.php" );
156
  $this->quizCreator = new QMNQuizCreator();
157
 
158
- include( "php/class-qmn-plugin-helper.php" );
159
  $this->pluginHelper = new QMNPluginHelper();
160
 
161
- include( "php/class-qsm-settings.php" );
162
  $this->quiz_settings = new QSM_Quiz_Settings();
 
 
163
  }
164
 
165
  /**
166
- * Add Hooks
167
- *
168
- * Adds functions to relavent hooks and filters
169
- *
170
- * @since 3.6.1
171
- * @return void
172
- */
173
  private function add_hooks() {
174
  add_action( 'admin_menu', array( $this, 'setup_admin_menu' ) );
175
  add_action( 'admin_head', array( $this, 'admin_head' ), 900 );
@@ -186,9 +192,9 @@ class MLWQuizMasterNext {
186
  */
187
  public function register_quiz_post_types() {
188
 
189
- // Prepares labels
190
  $quiz_labels = array(
191
- 'name' => 'Quizzes',
192
  'singular_name' => 'Quiz',
193
  'menu_name' => 'Quiz',
194
  'name_admin_bar' => 'Quiz',
@@ -201,56 +207,57 @@ class MLWQuizMasterNext {
201
  'search_items' => 'Search Quizzes',
202
  'parent_item_colon' => 'Parent Quiz:',
203
  'not_found' => 'No Quiz Found',
204
- 'not_found_in_trash' => 'No Quiz Found In Trash'
205
  );
206
 
207
- // Checks settings to see if we need to alter the defaults
208
- $has_archive = true;
209
  $exclude_search = false;
210
- $cpt_slug = 'quiz';
211
- $settings = (array) get_option( 'qmn-settings' );
212
 
213
- // Checks if admin turned off archive
214
  if ( isset( $settings['cpt_archive'] ) && '1' == $settings['cpt_archive'] ) {
215
  $has_archive = false;
216
  }
217
 
218
- // Checks if admin turned off search
219
  if ( isset( $settings['cpt_search'] ) && '1' == $settings['cpt_search'] ) {
220
  $exclude_search = true;
221
  }
222
 
223
- // Checks if admin changed slug
224
  if ( isset( $settings['cpt_slug'] ) ) {
225
- $cpt_slug = trim( strtolower( str_replace( " ", "-", $settings['cpt_slug'] ) ) );
226
  }
227
 
228
- // Prepares post type array
229
  $quiz_args = array(
230
- 'show_ui' => true,
231
- 'show_in_menu' => false,
232
- 'show_in_nav_menus' => true,
233
- 'labels' => $quiz_labels,
234
- 'publicly_queryable' => true,
 
235
  'exclude_from_search' => $exclude_search,
236
- 'label' => __( 'Quizzes', 'quiz-master-next' ),
237
- 'rewrite' => array( 'slug' => $cpt_slug ),
238
- 'has_archive' => $has_archive,
239
- 'supports' => array( 'title', 'author', 'comments' )
240
  );
241
 
242
- // Registers post type
243
  register_post_type( 'quiz', $quiz_args );
244
  }
245
 
246
  /**
247
- * Setup Admin Menu
248
- *
249
- * Creates the admin menu and pages for the plugin and attaches functions to them
250
- *
251
- * @since 3.6.1
252
- * @return void
253
- */
254
  public function setup_admin_menu() {
255
  if ( function_exists( 'add_menu_page' ) ) {
256
  add_menu_page( 'Quiz And Survey Master', __( 'Quizzes/Surveys', 'quiz-master-next' ), 'moderate_comments', __FILE__, 'qsm_generate_quizzes_surveys_page', 'dashicons-feedback' );
2
  /**
3
  * Plugin Name: Quiz And Survey Master
4
  * Description: Easily and quickly add quizzes and surveys to your website.
5
+ * Version: 5.2.0
6
  * Author: Frank Corso
7
  * Author URI: https://www.quizandsurveymaster.com/
8
  * Plugin URI: https://www.quizandsurveymaster.com/
9
  * Text Domain: quiz-master-next
10
  *
11
  * @author Frank Corso
12
+ * @version 5.2.0
13
+ * @package QSM
14
  */
15
 
16
+ if ( ! defined( 'ABSPATH' ) ) {
17
+ exit;
18
+ }
19
 
20
  define( 'QSM_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
21
  /**
33
  * @var string
34
  * @since 4.0.0
35
  */
36
+ public $version = '5.2.0';
37
 
38
  /**
39
  * QSM Alert Manager Object
84
  public $quiz_settings;
85
 
86
  /**
87
+ * Main Construct Function
88
+ *
89
+ * Call functions within class
90
+ *
91
+ * @since 3.6.1
92
+ * @uses MLWQuizMasterNext::load_dependencies() Loads required filed
93
+ * @uses MLWQuizMasterNext::add_hooks() Adds actions to hooks and filters
94
+ * @return void
95
+ */
96
  public function __construct() {
97
  $this->load_dependencies();
98
  $this->add_hooks();
99
  }
100
 
101
  /**
102
+ * Load File Dependencies
103
+ *
104
+ * @since 3.6.1
105
+ * @return void
106
+ */
107
  private function load_dependencies() {
108
 
109
+ include 'php/classes/class-qsm-install.php';
110
+ include 'php/classes/class-qsm-fields.php';
111
 
112
+ include 'php/classes/class-qmn-log-manager.php';
113
+ $this->log_manager = new QMN_Log_Manager();
114
 
115
+ include 'php/classes/class-qsm-audit.php';
116
  $this->audit_manager = new QSM_Audit();
117
 
118
  if ( is_admin() ) {
119
+ include 'php/admin/stats-page.php';
120
+ include 'php/admin/quizzes-page.php';
121
+ include 'php/admin/quiz-options-page.php';
122
+ include 'php/admin/admin-results-page.php';
123
+ include 'php/admin/admin-results-details-page.php';
124
+ include 'php/admin/tools-page.php';
125
+ include 'php/classes/class-qsm-changelog-generator.php';
126
+ include 'php/admin/about-page.php';
127
+ include 'php/admin/help-page.php';
128
+ include 'php/admin/dashboard-widgets.php';
129
+ include 'php/admin/options-page-questions-tab.php';
130
+ include 'php/admin/options-page-contact-tab.php';
131
+ include 'php/admin/options-page-text-tab.php';
132
+ include 'php/admin/options-page-option-tab.php';
133
+ include 'php/admin/options-page-leaderboard-tab.php';
134
+ include 'php/admin/options-page-email-tab.php';
135
+ include 'php/admin/options-page-results-page-tab.php';
136
+ include 'php/admin/options-page-style-tab.php';
137
+ include 'php/admin/options-page-tools-tab.php';
138
+ include 'php/admin/options-page-preview-tab.php';
139
+ include 'php/admin/addons-page.php';
140
+ include 'php/admin/settings-page.php';
141
+ include 'php/classes/class-qmn-tracking.php';
142
+ include 'php/classes/class-qmn-review-message.php';
143
  }
144
+ include 'php/classes/class-qsm-questions.php';
145
+ include 'php/classes/class-qsm-contact-manager.php';
146
+ include 'php/classes/class-qmn-quiz-manager.php';
147
+
148
+ include 'php/leaderboard-shortcode.php';
149
+ include 'php/widgets.php';
150
+ include 'php/template-variables.php';
151
+ include 'php/adverts-generate.php';
152
+ include 'php/question-types.php';
153
+ include 'php/default-templates.php';
154
+ include 'php/shortcodes.php';
155
+
156
+ include 'php/classes/class-qmn-alert-manager.php';
157
  $this->alertManager = new MlwQmnAlertManager();
158
 
159
+ include 'php/classes/class-qmn-quiz-creator.php';
160
  $this->quizCreator = new QMNQuizCreator();
161
 
162
+ include 'php/classes/class-qmn-plugin-helper.php';
163
  $this->pluginHelper = new QMNPluginHelper();
164
 
165
+ include 'php/classes/class-qsm-settings.php';
166
  $this->quiz_settings = new QSM_Quiz_Settings();
167
+
168
+ include 'php/rest-api.php';
169
  }
170
 
171
  /**
172
+ * Add Hooks
173
+ *
174
+ * Adds functions to relavent hooks and filters
175
+ *
176
+ * @since 3.6.1
177
+ * @return void
178
+ */
179
  private function add_hooks() {
180
  add_action( 'admin_menu', array( $this, 'setup_admin_menu' ) );
181
  add_action( 'admin_head', array( $this, 'admin_head' ), 900 );
192
  */
193
  public function register_quiz_post_types() {
194
 
195
+ // Prepares labels.
196
  $quiz_labels = array(
197
+ 'name' => 'Quizzes & Surveys',
198
  'singular_name' => 'Quiz',
199
  'menu_name' => 'Quiz',
200
  'name_admin_bar' => 'Quiz',
207
  'search_items' => 'Search Quizzes',
208
  'parent_item_colon' => 'Parent Quiz:',
209
  'not_found' => 'No Quiz Found',
210
+ 'not_found_in_trash' => 'No Quiz Found In Trash',
211
  );
212
 
213
+ // Checks settings to see if we need to alter the defaults.
214
+ $has_archive = true;
215
  $exclude_search = false;
216
+ $cpt_slug = 'quiz';
217
+ $settings = (array) get_option( 'qmn-settings' );
218
 
219
+ // Checks if admin turned off archive.
220
  if ( isset( $settings['cpt_archive'] ) && '1' == $settings['cpt_archive'] ) {
221
  $has_archive = false;
222
  }
223
 
224
+ // Checks if admin turned off search.
225
  if ( isset( $settings['cpt_search'] ) && '1' == $settings['cpt_search'] ) {
226
  $exclude_search = true;
227
  }
228
 
229
+ // Checks if admin changed slug.
230
  if ( isset( $settings['cpt_slug'] ) ) {
231
+ $cpt_slug = trim( strtolower( str_replace( ' ', '-', $settings['cpt_slug'] ) ) );
232
  }
233
 
234
+ // Prepares post type array.
235
  $quiz_args = array(
236
+ 'public' => true,
237
+ 'show_ui' => true,
238
+ 'show_in_menu' => false,
239
+ 'show_in_nav_menus' => true,
240
+ 'labels' => $quiz_labels,
241
+ 'publicly_queryable' => true,
242
  'exclude_from_search' => $exclude_search,
243
+ 'label' => __( 'Quizzes', 'quiz-master-next' ),
244
+ 'rewrite' => array( 'slug' => $cpt_slug ),
245
+ 'has_archive' => $has_archive,
246
+ 'supports' => array( 'title', 'author', 'comments' )
247
  );
248
 
249
+ // Registers post type.
250
  register_post_type( 'quiz', $quiz_args );
251
  }
252
 
253
  /**
254
+ * Setup Admin Menu
255
+ *
256
+ * Creates the admin menu and pages for the plugin and attaches functions to them
257
+ *
258
+ * @since 3.6.1
259
+ * @return void
260
+ */
261
  public function setup_admin_menu() {
262
  if ( function_exists( 'add_menu_page' ) ) {
263
  add_menu_page( 'Quiz And Survey Master', __( 'Quizzes/Surveys', 'quiz-master-next' ), 'moderate_comments', __FILE__, 'qsm_generate_quizzes_surveys_page', 'dashicons-feedback' );
php/{about-page.php → admin/about-page.php} RENAMED
@@ -11,12 +11,12 @@ function mlw_generate_about_page() {
11
 
12
  global $mlwQuizMasterNext;
13
  $version = $mlwQuizMasterNext->version;
14
- wp_enqueue_style( 'qsm_admin_style', plugins_url( '../css/qsm-admin.css' , __FILE__ ), array(), '5.1.0' );
15
- wp_enqueue_script( 'qsm_admin_js', plugins_url( '../js/admin.js' , __FILE__ ), array( 'jquery' ), '5.1.0' );
16
  ?>
17
  <style>
18
  div.qsm_icon_wrap {
19
- background: <?php echo 'url("' . plugins_url( '../assets/icon-128x128.png', __FILE__ ) . '" )'; ?> no-repeat;
20
  }
21
  </style>
22
  <div class="wrap about-wrap">
@@ -33,34 +33,23 @@ function mlw_generate_about_page() {
33
  </h2>
34
  <div class="qsm-tab-content tab-1">
35
  <div class="feature">
36
- <h2 class="feature-headline">Welcome to QSM 5.1!</h2>
37
  </div>
38
  <div class="feature">
39
- <h2 class="feature-headline">New Shortcode For Quiz/Survey Link</h2>
40
- <p class="feature-text">There has always been a shortcode for displaying your quizzes and surveys. However, adding a link directly to the quiz or survey has been difficult.</p>
41
- <p class="feature-text">Before, if you place a direct link and the permalink changed, your link would break.</p>
42
- <p class="feature-text">Now, you can use the new "qsm_link" shortcode for creating links. The shortcode has been added to the "Quizzes/Surveys" page so it can easily be copied to be pasted anywhere on your site!</p>
43
- </div>
44
- <div class="feature">
45
- <h2 class="feature-headline">Dates Are Now Localized</h2>
46
- <p class="feature-text">You may have noticed that the dates in your results as well as variables such as %DATE_TAKEN% and %CURRENT_DATE% never followed the format you set your WordPress to.</p>
47
- <p class="feature-text">With this update, all dates will follow the format set on the "General" page of the "Settings" menu in your WordPress dashboard.</p>
48
  </div>
49
  <hr />
50
  <div class="feature">
51
- <h2 class="feature-headline">For Developers: New All Quizzes Function</h2>
52
- <p class="feature-text">There is a new function "get_quizzes" in the plugin helper API that returns all quizzes. With the functions parameters, you can get the quizzes ordered by a certain field and include deleted quizzes if needed.</p>
 
53
  </div>
54
  </div>
55
  <div class="qsm-tab-content tab-2" style="display: none;">
56
  <h2>Changelog</h2>
57
- <?php QSM_Changelog_Generator::get_changelog_list( 'fpcorso/quiz_master_next', 47 ); ?>
58
- <?php QSM_Changelog_Generator::get_changelog_list( 'fpcorso/quiz_master_next', 45 ); ?>
59
- <?php QSM_Changelog_Generator::get_changelog_list( 'fpcorso/quiz_master_next', 44 ); ?>
60
- <?php QSM_Changelog_Generator::get_changelog_list( 'fpcorso/quiz_master_next', 43 ); ?>
61
- <?php QSM_Changelog_Generator::get_changelog_list( 'fpcorso/quiz_master_next', 41 ); ?>
62
- <?php QSM_Changelog_Generator::get_changelog_list( 'fpcorso/quiz_master_next', 40 ); ?>
63
- <?php QSM_Changelog_Generator::get_changelog_list( 'fpcorso/quiz_master_next', 25 ); ?>
64
  </div>
65
  <div class="qsm-tab-content tab-3" style="display:none;">
66
  <h2>GitHub Contributors</h2>
11
 
12
  global $mlwQuizMasterNext;
13
  $version = $mlwQuizMasterNext->version;
14
+ wp_enqueue_style( 'qsm_admin_style', plugins_url( '../../css/qsm-admin.css' , __FILE__ ), array(), $version );
15
+ wp_enqueue_script( 'qsm_admin_js', plugins_url( '../../js/admin.js' , __FILE__ ), array( 'jquery' ), $version );
16
  ?>
17
  <style>
18
  div.qsm_icon_wrap {
19
+ background: <?php echo 'url("' . plugins_url( '../../assets/icon-128x128.png', __FILE__ ) . '" )'; ?> no-repeat;
20
  }
21
  </style>
22
  <div class="wrap about-wrap">
33
  </h2>
34
  <div class="qsm-tab-content tab-1">
35
  <div class="feature">
36
+ <h2 class="feature-headline">Welcome to QSM 5.2!</h2>
37
  </div>
38
  <div class="feature">
39
+ <h2 class="feature-headline">New Question Editor!</h2>
40
+ <p class="feature-text">The "Questions" tab has had a major new redesign. Now, it is much easier to drag-and-drop to reorder all of your questions.</p>
41
+ <p class="feature-text">Even better, with this new editor, you can create pages for your quiz or survey and drag questions between pages as well as reorder the pages!</p>
 
 
 
 
 
 
42
  </div>
43
  <hr />
44
  <div class="feature">
45
+ <h2 class="feature-headline">For Developers: Results Now Extendable</h2>
46
+ <p class="feature-text">There have been ways to add extra data to quizzes/surveys and questions for a while. However, there hasn't been an easy way for developers to add additional data to the results prior to them being stored in the database.</p>
47
+ <p class="feature-text">Now, the results array is passed through a new "qsm_results_array" filter so developers can add data to the results. Then, using the template variable system, a developer can have this data shown in the admin details as well.</p>
48
  </div>
49
  </div>
50
  <div class="qsm-tab-content tab-2" style="display: none;">
51
  <h2>Changelog</h2>
52
+ <?php QSM_Changelog_Generator::get_changelog_list( 'fpcorso/quiz_master_next', 32 ); ?>
 
 
 
 
 
 
53
  </div>
54
  <div class="qsm-tab-content tab-3" style="display:none;">
55
  <h2>GitHub Contributors</h2>
php/{addons-page.php → admin/addons-page.php} RENAMED
@@ -50,7 +50,7 @@ function qmn_addons_page() {
50
  * @since 4.4.0
51
  */
52
  function qsm_generate_featured_addons() {
53
- wp_enqueue_style( 'qsm_addons_style', plugins_url( '../css/qmn_addons_page.css' , __FILE__ ) );
54
  ?>
55
  <p><?php _e('These addons extend the functionality of Quiz And Survey Master', 'quiz-master-next'); ?></p>
56
  <a href="http://quizandsurveymaster.com/addons/?utm_source=qsm-addons-page&utm_medium=plugin&utm_content=all-addons-top&utm_campaign=qsm_plugin" target="_blank" class="button-primary"><?php _e('Browse All Addons', 'quiz-master-next'); ?></a>
50
  * @since 4.4.0
51
  */
52
  function qsm_generate_featured_addons() {
53
+ wp_enqueue_style( 'qsm_addons_style', plugins_url( '../../css/qmn_addons_page.css' , __FILE__ ) );
54
  ?>
55
  <p><?php _e('These addons extend the functionality of Quiz And Survey Master', 'quiz-master-next'); ?></p>
56
  <a href="http://quizandsurveymaster.com/addons/?utm_source=qsm-addons-page&utm_medium=plugin&utm_content=all-addons-top&utm_campaign=qsm_plugin" target="_blank" class="button-primary"><?php _e('Browse All Addons', 'quiz-master-next'); ?></a>
php/{admin-results-details-page.php → admin/admin-results-details-page.php} RENAMED
File without changes
php/{admin-results-page.php → admin/admin-results-page.php} RENAMED
@@ -187,7 +187,7 @@ function qsm_results_overview_tab_content() {
187
  wp_enqueue_script( 'jquery-ui-button' );
188
  wp_enqueue_script( 'jquery-effects-blind' );
189
  wp_enqueue_script( 'jquery-effects-explode' );
190
- wp_enqueue_script('qmn_admin_js', plugins_url( '../js/admin.js' , __FILE__ ));
191
  wp_enqueue_style( 'qmn_jquery_redmond_theme', '//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/themes/redmond/jquery-ui.css' );
192
  ?>
193
  <script type="text/javascript">
187
  wp_enqueue_script( 'jquery-ui-button' );
188
  wp_enqueue_script( 'jquery-effects-blind' );
189
  wp_enqueue_script( 'jquery-effects-explode' );
190
+ wp_enqueue_script('qmn_admin_js', plugins_url( '../../js/admin.js' , __FILE__ ));
191
  wp_enqueue_style( 'qmn_jquery_redmond_theme', '//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/themes/redmond/jquery-ui.css' );
192
  ?>
193
  <script type="text/javascript">
php/{dashboard-widgets.php → admin/dashboard-widgets.php} RENAMED
@@ -183,11 +183,11 @@ function qmn_snapshot_dashboard_widget()
183
  echo $mlw_qmn_analyze_today."% ";
184
  if ($mlw_qmn_analyze_today >= 0)
185
  {
186
- echo "<img src='".plugin_dir_url( __FILE__ )."images/green_triangle.png'/>";
187
  }
188
  else
189
  {
190
- echo "<img src='".plugin_dir_url( __FILE__ )."images/red_triangle.png'/>";
191
  }
192
  ?>
193
  </span>
@@ -202,11 +202,11 @@ function qmn_snapshot_dashboard_widget()
202
  echo $mlw_qmn_analyze_week."% ";
203
  if ($mlw_qmn_analyze_week >= 0)
204
  {
205
- echo "<img src='".plugin_dir_url( __FILE__ )."images/green_triangle.png'/>";
206
  }
207
  else
208
  {
209
- echo "<img src='".plugin_dir_url( __FILE__ )."images/red_triangle.png'/>";
210
  }
211
  ?>
212
  </span>
@@ -221,11 +221,11 @@ function qmn_snapshot_dashboard_widget()
221
  echo $mlw_qmn_analyze_month."% ";
222
  if ($mlw_qmn_analyze_month >= 0)
223
  {
224
- echo "<img src='".plugin_dir_url( __FILE__ )."images/green_triangle.png'/>";
225
  }
226
  else
227
  {
228
- echo "<img src='".plugin_dir_url( __FILE__ )."images/red_triangle.png'/>";
229
  }
230
  ?>
231
  </span>
@@ -240,11 +240,11 @@ function qmn_snapshot_dashboard_widget()
240
  echo $mlw_qmn_analyze_quater."% ";
241
  if ($mlw_qmn_analyze_quater >= 0)
242
  {
243
- echo "<img src='".plugin_dir_url( __FILE__ )."images/green_triangle.png'/>";
244
  }
245
  else
246
  {
247
- echo "<img src='".plugin_dir_url( __FILE__ )."images/red_triangle.png'/>";
248
  }
249
  ?>
250
  </span>
183
  echo $mlw_qmn_analyze_today."% ";
184
  if ($mlw_qmn_analyze_today >= 0)
185
  {
186
+ echo "<img src='".plugin_dir_url( __FILE__ )."../images/green_triangle.png'/>";
187
  }
188
  else
189
  {
190
+ echo "<img src='".plugin_dir_url( __FILE__ )."../images/red_triangle.png'/>";
191
  }
192
  ?>
193
  </span>
202
  echo $mlw_qmn_analyze_week."% ";
203
  if ($mlw_qmn_analyze_week >= 0)
204
  {
205
+ echo "<img src='".plugin_dir_url( __FILE__ )."../images/green_triangle.png'/>";
206
  }
207
  else
208
  {
209
+ echo "<img src='".plugin_dir_url( __FILE__ )."../images/red_triangle.png'/>";
210
  }
211
  ?>
212
  </span>
221
  echo $mlw_qmn_analyze_month."% ";
222
  if ($mlw_qmn_analyze_month >= 0)
223
  {
224
+ echo "<img src='".plugin_dir_url( __FILE__ )."../images/green_triangle.png'/>";
225
  }
226
  else
227
  {
228
+ echo "<img src='".plugin_dir_url( __FILE__ )."../images/red_triangle.png'/>";
229
  }
230
  ?>
231
  </span>
240
  echo $mlw_qmn_analyze_quater."% ";
241
  if ($mlw_qmn_analyze_quater >= 0)
242
  {
243
+ echo "<img src='".plugin_dir_url( __FILE__ )."../images/green_triangle.png'/>";
244
  }
245
  else
246
  {
247
+ echo "<img src='".plugin_dir_url( __FILE__ )."../images/red_triangle.png'/>";
248
  }
249
  ?>
250
  </span>
php/{help-page.php → admin/help-page.php} RENAMED
@@ -12,7 +12,7 @@ function mlw_generate_help_page() {
12
  return;
13
  }
14
 
15
- wp_enqueue_style( 'qsm_admin_style', plugins_url( '../css/qsm-admin.css' , __FILE__ ) );
16
 
17
  ///Creates the widgets
18
  add_meta_box("wpss_mrts", __('Need Help?', 'quiz-master-next'), "qsm_documentation_meta_box_content", "meta_box_help");
12
  return;
13
  }
14
 
15
+ wp_enqueue_style( 'qsm_admin_style', plugins_url( '../../css/qsm-admin.css' , __FILE__ ) );
16
 
17
  ///Creates the widgets
18
  add_meta_box("wpss_mrts", __('Need Help?', 'quiz-master-next'), "qsm_documentation_meta_box_content", "meta_box_help");
php/admin/index.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+
3
+ die("Error: Unauthorized Access");
4
+ ?>
php/{options-page-contact-tab.php → admin/options-page-contact-tab.php} RENAMED
@@ -28,9 +28,9 @@ function qsm_options_contact_tab_content() {
28
 
29
  $contact_form = QSM_Contact_Manager::load_fields();
30
 
31
- wp_enqueue_script( 'qsm_contact_admin_script', plugins_url( '../js/qsm-admin-contact.js' , __FILE__ ), array( 'jquery-ui-sortable' ) );
32
  wp_localize_script( 'qsm_contact_admin_script', 'qsmContactObject', array( 'contactForm' => $contact_form, 'quizID' => $quiz_id ) );
33
- wp_enqueue_style( 'qsm_contact_admin_style', plugins_url( '../css/qsm-admin-contact.css' , __FILE__ ) );
34
 
35
  /**
36
  * Example contact form array
28
 
29
  $contact_form = QSM_Contact_Manager::load_fields();
30
 
31
+ wp_enqueue_script( 'qsm_contact_admin_script', plugins_url( '../../js/qsm-admin-contact.js' , __FILE__ ), array( 'jquery-ui-sortable' ) );
32
  wp_localize_script( 'qsm_contact_admin_script', 'qsmContactObject', array( 'contactForm' => $contact_form, 'quizID' => $quiz_id ) );
33
+ wp_enqueue_style( 'qsm_contact_admin_style', plugins_url( '../../css/qsm-admin-contact.css' , __FILE__ ) );
34
 
35
  /**
36
  * Example contact form array
php/{options-page-email-tab.php → admin/options-page-email-tab.php} RENAMED
@@ -236,7 +236,7 @@ function mlw_options_emails_tab_content()
236
  "subject" => 'Quiz Results For %QUIZ_NAME%'
237
  ));
238
  }
239
- wp_enqueue_style( 'qmn_admin_style', plugins_url( '../css/qsm-admin.css' , __FILE__ ) );
240
  ?>
241
  <script type="text/javascript">
242
  var $j = jQuery.noConflict();
236
  "subject" => 'Quiz Results For %QUIZ_NAME%'
237
  ));
238
  }
239
+ wp_enqueue_style( 'qmn_admin_style', plugins_url( '../../css/qsm-admin.css' , __FILE__ ) );
240
  ?>
241
  <script type="text/javascript">
242
  var $j = jQuery.noConflict();
php/{options-page-leaderboard-tab.php → admin/options-page-leaderboard-tab.php} RENAMED
File without changes
php/{options-page-option-tab.php → admin/options-page-option-tab.php} RENAMED
File without changes
php/{options-page-preview-tab.php → admin/options-page-preview-tab.php} RENAMED
File without changes
php/admin/options-page-questions-tab.php ADDED
@@ -0,0 +1,299 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This file handles the "Questions" tab when editing a quiz/survey
4
+ */
5
+
6
+ if ( ! defined( 'ABSPATH' ) ) exit;
7
+
8
+ /**
9
+ * Adds the settings for questions tab to the Quiz Settings page.
10
+ *
11
+ * @return void
12
+ * @since 4.4.0
13
+ */
14
+ function qsm_settings_questions_tab() {
15
+ global $mlwQuizMasterNext;
16
+ $mlwQuizMasterNext->pluginHelper->register_quiz_settings_tabs( __( 'Questions', 'quiz-master-next' ), 'qsm_options_questions_tab_content' );
17
+ }
18
+ add_action( "plugins_loaded", 'qsm_settings_questions_tab', 5 );
19
+
20
+
21
+ /**
22
+ * Adds the content for the options for questions tab.
23
+ *
24
+ * @return void
25
+ * @since 4.4.0
26
+ */
27
+ function qsm_options_questions_tab_content() {
28
+
29
+ global $wpdb;
30
+ global $mlwQuizMasterNext;
31
+ $quiz_id = intval( $_GET['quiz_id'] );
32
+
33
+ $json_data = array(
34
+ 'quizID' => $quiz_id,
35
+ 'answerText' => __( 'Answer', 'quiz-master-next' ),
36
+ 'nonce' => wp_create_nonce( 'wp_rest' ),
37
+ 'pages' => $mlwQuizMasterNext->pluginHelper->get_quiz_setting( 'pages', array() ),
38
+ );
39
+
40
+ // Scripts and styles.
41
+ wp_enqueue_script( 'micromodal_script', plugins_url( '../../js/micromodal.min.js', __FILE__ ) );
42
+ wp_enqueue_script( 'qsm_admin_question_js', plugins_url( '../../js/qsm-admin-question.js', __FILE__ ), array( 'backbone', 'underscore', 'jquery-ui-sortable', 'wp-util', 'micromodal_script' ), $mlwQuizMasterNext->version, true );
43
+ wp_localize_script( 'qsm_admin_question_js', 'qsmQuestionSettings', $json_data );
44
+ wp_enqueue_style( 'qsm_admin_question_css', plugins_url( '../../css/qsm-admin-question.css', __FILE__ ) );
45
+ wp_enqueue_script( 'math_jax', '//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML' );
46
+ wp_enqueue_editor();
47
+ wp_enqueue_media();
48
+
49
+ // Load Question Types.
50
+ $question_types = $mlwQuizMasterNext->pluginHelper->get_question_type_options();
51
+
52
+ // Display warning if using competing options.
53
+ $pagination = $mlwQuizMasterNext->pluginHelper->get_section_setting( 'quiz_options', 'pagination' );
54
+ if ( 0 != $pagination ) {
55
+ ?>
56
+ <div class="notice notice-warning">
57
+ <p>This quiz has the "How many questions per page would you like?" option enabled. The pages below will not be used while that option is enabled. To turn off, go to the "Options" tab and set that option to 0.</p>
58
+ </div>
59
+ <?php
60
+ }
61
+ $from_total = $mlwQuizMasterNext->pluginHelper->get_section_setting( 'quiz_options', 'question_from_total' );
62
+ if ( 0 != $from_total ) {
63
+ ?>
64
+ <div class="notice notice-warning">
65
+ <p>This quiz has the "How many questions should be loaded for quiz?" option enabled. The pages below will not be used while that option is enabled. To turn off, go to the "Options" tab and set that option to 0.</p>
66
+ </div>
67
+ <?php
68
+ }
69
+ $randomness = $mlwQuizMasterNext->pluginHelper->get_section_setting( 'quiz_options', 'randomness_order' );
70
+ if ( 0 != $randomness ) {
71
+ ?>
72
+ <div class="notice notice-warning">
73
+ <p>This quiz has the "Are the questions random?" option enabled. The pages below will not be used while that option is enabled. To turn off, go to the "Options" tab and set that option to "No".</p>
74
+ </div>
75
+ <?php
76
+ }
77
+ ?>
78
+ <h3>Questions</h3>
79
+ <p>Use this tab to create and modify the different pages of your quiz or survey as well as the questions on each page. Click "Create New Page" to get started! Need more information? Check out the <a href="http://bit.ly/2FkR9Wd" target="_blank">documentation for this tab!</a></p>
80
+ <div class="questions-messages"></div>
81
+ <a href="#" class="new-page-button button">Create New Page</a>
82
+ <a href="#" class="save-page-button button-primary">Save Questions</a>
83
+ <p class="search-box">
84
+ <label class="screen-reader-text" for="question_search">Search Questions:</label>
85
+ <input type="search" id="question_search" name="question_search" value="">
86
+ <a href="#" class="button">Search Questions</a>
87
+ </p>
88
+ <div class="questions"></div>
89
+
90
+ <!-- Popup for question bank -->
91
+ <div class="qsm-popup qsm-popup-slide qsm-popup-bank" id="modal-2" aria-hidden="true">
92
+ <div class="qsm-popup__overlay" tabindex="-1" data-micromodal-close>
93
+ <div class="qsm-popup__container" role="dialog" aria-modal="true" aria-labelledby="modal-1-title">
94
+ <header class="qsm-popup__header">
95
+ <h2 class="qsm-popup__title" id="modal-2-title">Add Question From Question Bank</h2>
96
+ <a class="qsm-popup__close" aria-label="Close modal" data-micromodal-close></a>
97
+ </header>
98
+ <main class="qsm-popup__content" id="modal-2-content">
99
+ <input type="hidden" name="add-question-bank-page" id="add-question-bank-page" value="">
100
+ <div id="question-bank"></div>
101
+ </main>
102
+ <footer class="qsm-popup__footer">
103
+ <button class="qsm-popup__btn" data-micromodal-close aria-label="Close this dialog window">Cancel</button>
104
+ </footer>
105
+ </div>
106
+ </div>
107
+ </div>
108
+
109
+
110
+ <!-- Popup for editing question -->
111
+ <div class="qsm-popup qsm-popup-slide" id="modal-1" aria-hidden="true">
112
+ <div class="qsm-popup__overlay" tabindex="-1" data-micromodal-close>
113
+ <div class="qsm-popup__container" role="dialog" aria-modal="true" aria-labelledby="modal-1-title">
114
+ <header class="qsm-popup__header">
115
+ <h2 class="qsm-popup__title" id="modal-1-title">Edit Question</h2>
116
+ <a class="qsm-popup__close" aria-label="Close modal" data-micromodal-close></a>
117
+ </header>
118
+ <main class="qsm-popup__content" id="modal-1-content">
119
+ <input type="hidden" name="edit_question_id" id="edit_question_id" value="">
120
+ <div class="qsm-row">
121
+ <label><?php _e( 'Question Type', 'quiz-master-next' ); ?></label>
122
+ <select name="question_type" id="question_type">
123
+ <?php
124
+ foreach ( $question_types as $type ) {
125
+ echo "<option value='{$type['slug']}'>{$type['name']}</option>";
126
+ }
127
+ ?>
128
+ </select>
129
+ </div>
130
+ <p id="question_type_info"></p>
131
+ <div class="qsm-row">
132
+ <textarea id="question-text"></textarea>
133
+ </div>
134
+ <div class="qsm-row">
135
+ <label><?php _e( 'Answers', 'quiz-master-next' ); ?></label>
136
+ <div class="correct-header"><?php _e( 'Correct', 'quiz-master-next' ); ?></div>
137
+ <div class="answers" id="answers">
138
+
139
+ </div>
140
+ <a href="#" class="button" id="new-answer-button"><?php _e( 'Add New Answer!', 'quiz-master-next'); ?></a>
141
+ </div>
142
+ <div id="correct_answer_area" class="qsm-row">
143
+ <label><?php _e( 'Correct Answer Info', 'quiz-master-next' ); ?></label>
144
+ <input type="text" name="correct_answer_info" value="" id="correct_answer_info" />
145
+ </div>
146
+ <div id="hint_area" class="qsm-row">
147
+ <label><?php _e( 'Hint', 'quiz-master-next' ); ?></label>
148
+ <input type="text" name="hint" value="" id="hint"/>
149
+ </div>
150
+ <div id="comment_area" class="qsm-row">
151
+ <label><?php _e( 'Comment Field', 'quiz-master-next' ); ?></label>
152
+ <select name="comments" id="comments">
153
+ <option value="0"><?php _e('Small Text Field', 'quiz-master-next'); ?></option>
154
+ <option value="2"><?php _e('Large Text Field', 'quiz-master-next'); ?></option>
155
+ <option value="1" selected="selected"><?php _e('None', 'quiz-master-next'); ?></option>
156
+ <select>
157
+ </div>
158
+ <div id="required_area" class="qsm-row">
159
+ <label><?php _e( 'Required?', 'quiz-master-next' ); ?></label>
160
+ <select name="required" id="required">
161
+ <option value="0" selected="selected"><?php _e( 'Yes', 'quiz-master-next' ); ?></option>
162
+ <option value="1"><?php _e( 'No', 'quiz-master-next' ); ?></option>
163
+ </select>
164
+ </div>
165
+ <div id="category_area" class="qsm-row">
166
+ <label><?php _e( 'Category', 'quiz-master-next' ); ?></label>
167
+ <div id="categories">
168
+ <input type="radio" name="category" class="category-radio" id="new_category_new" value="new_category"><label for="new_category_new">New: <input type='text' id='new_category' value='' /></label>
169
+ </div>
170
+ </div>
171
+ </main>
172
+ <footer class="qsm-popup__footer">
173
+ <button id="save-popup-button" class="qsm-popup__btn qsm-popup__btn-primary">Save Question</button>
174
+ <button class="qsm-popup__btn" data-micromodal-close aria-label="Close this dialog window">Cancel</button>
175
+ </footer>
176
+ </div>
177
+ </div>
178
+ </div>
179
+
180
+ <!--Views-->
181
+
182
+ <!-- View for Notices -->
183
+ <script type="text/template" id="tmpl-notice">
184
+ <div class="notice notice-{{data.type}}">
185
+ <p>{{data.message}}</p>
186
+ </div>
187
+ </script>
188
+
189
+ <!-- View for Page -->
190
+ <script type="text/template" id="tmpl-page">
191
+ <div class="page page-new">
192
+ <div class="page-header">
193
+ <div><span class="dashicons dashicons-move"></span></div>
194
+ <div class="page-header-buttons">
195
+ <a href="#" class="new-question-button button">Create New Question</a>
196
+ <a href="#" class="add-question-bank-button button">Add Question From Question Bank</a>
197
+ </div>
198
+ <div><a href="#" class="delete-page-button"><span class="dashicons dashicons-trash"></span></a></div>
199
+ </div>
200
+ </div>
201
+ </script>
202
+
203
+ <!-- View for Question -->
204
+ <script type="text/template" id="tmpl-question">
205
+ <div class="question question-new" data-question-id="{{data.id }}">
206
+ <div class="question-content">
207
+ <div><span class="dashicons dashicons-move"></span></div>
208
+ <div><a href="#" class="edit-question-button"><span class="dashicons dashicons-edit"></span></a></div>
209
+ <div><a href="#" class="duplicate-question-button"><span class="dashicons dashicons-controls-repeat"></span></a></div>
210
+ <div class="question-content-text">{{{data.question}}}</div>
211
+ <div><# if ( 0 !== data.category.length ) { #> Category: {{data.category}} <# } #></div>
212
+ <div><a href="#" class="delete-question-button"><span class="dashicons dashicons-trash"></span></a><div>
213
+ </div>
214
+ </div>
215
+ </script>
216
+
217
+ <!-- View for question in question bank -->
218
+ <script type="text/template" id="tmpl-single-question-bank-question">
219
+ <div class="question-bank-question" data-question-id="{{data.id}}">
220
+ <div><a href="#" class="import-button button">Add This Question</a></div>
221
+ <div><p>{{{data.question}}}</p></div>
222
+ </div>
223
+ </script>
224
+
225
+ <!-- View for single category -->
226
+ <script type="text/template" id="tmpl-single-category">
227
+ <div class="category">
228
+ <input type="radio" name="category" class="category-radio" value="{{data.category}}"><label>{{data.category}}</label>
229
+ </div>
230
+ </script>
231
+
232
+ <!-- View for single answer -->
233
+ <script type="text/template" id="tmpl-single-answer">
234
+ <div class="answers-single">
235
+ <div><a href="#" class="delete-answer-button"><span class="dashicons dashicons-trash"></span></a></div>
236
+ <div class="answer-text-div"><input type="text" class="answer-text" value="{{data.answer}}" placeholder="Your answer"/></div>
237
+ <div><input type="text" class="answer-points" value="{{data.points}}" placeholder="Points"/></div>
238
+ <div><input type="checkbox" class="answer-correct" value="1" <# if ( 1 == data.correct ) { #> checked="checked"/> <# } #></div>
239
+ </div>
240
+ </script>
241
+ <?php
242
+ }
243
+
244
+
245
+ add_action( 'wp_ajax_qsm_save_pages', 'qsm_ajax_save_pages' );
246
+ add_action( 'wp_ajax_nopriv_qsm_save_pages', 'qsm_ajax_save_pages' );
247
+
248
+
249
+ /**
250
+ * Saves the pages and order from the Questions tab
251
+ *
252
+ * @since 5.2.0
253
+ */
254
+ function qsm_ajax_save_pages() {
255
+ global $mlwQuizMasterNext;
256
+ $json = array(
257
+ 'status' => 'error',
258
+ );
259
+ $quiz_id = intval( $_POST['quiz_id'] );
260
+ $mlwQuizMasterNext->pluginHelper->prepare_quiz( $quiz_id );
261
+ $response = $mlwQuizMasterNext->pluginHelper->update_quiz_setting( 'pages', $_POST['pages'] );
262
+ if ( $response ) {
263
+ $json['status'] = 'success';
264
+ }
265
+ echo wp_json_encode( $json );
266
+ wp_die();
267
+ }
268
+
269
+ add_action( 'wp_ajax_qsm_load_all_quiz_questions', 'qsm_load_all_quiz_questions_ajax' );
270
+ add_action( 'wp_ajax_nopriv_qsm_load_all_quiz_questions', 'qsm_load_all_quiz_questions_ajax' );
271
+
272
+ /**
273
+ * Loads all the questions and echos out JSON
274
+ *
275
+ * @since 0.1.0
276
+ * @return void
277
+ */
278
+ function qsm_load_all_quiz_questions_ajax() {
279
+ global $wpdb;
280
+ global $mlwQuizMasterNext;
281
+
282
+ // Loads questions.
283
+ $questions = $wpdb->get_results( "SELECT question_id, question_name FROM {$wpdb->prefix}mlw_questions WHERE deleted = '0' ORDER BY question_id DESC" );
284
+
285
+ // Creates question array.
286
+ $question_json = array();
287
+ foreach ( $questions as $question ) {
288
+ $question_json[] = array(
289
+ 'id' => $question->question_id,
290
+ 'question' => $question->question_name,
291
+ );
292
+ }
293
+
294
+ // Echos JSON and dies.
295
+ echo wp_json_encode( $question_json );
296
+ wp_die();
297
+ }
298
+
299
+ ?>
php/{options-page-results-page-tab.php → admin/options-page-results-page-tab.php} RENAMED
@@ -104,7 +104,7 @@ function mlw_options_results_tab_content()
104
  {
105
  $mlw_message_after_array = array(array(0, 0, $mlw_quiz_options->message_after, "redirect_url" => ''));
106
  }
107
- wp_enqueue_style( 'qmn_admin_style', plugins_url( '../css/qsm-admin.css' , __FILE__ ) );
108
  ?>
109
  <div id="tabs-6" class="mlw_tab_content">
110
  <script>
104
  {
105
  $mlw_message_after_array = array(array(0, 0, $mlw_quiz_options->message_after, "redirect_url" => ''));
106
  }
107
+ wp_enqueue_style( 'qmn_admin_style', plugins_url( '../../css/qsm-admin.css' , __FILE__ ) );
108
  ?>
109
  <div id="tabs-6" class="mlw_tab_content">
110
  <script>
php/{options-page-style-tab.php → admin/options-page-style-tab.php} RENAMED
File without changes
php/{options-page-text-tab.php → admin/options-page-text-tab.php} RENAMED
@@ -22,7 +22,7 @@ add_action( "plugins_loaded", 'qmn_settings_text_tab', 5 );
22
  function mlw_options_text_tab_content() {
23
  global $wpdb;
24
  global $mlwQuizMasterNext;
25
- wp_enqueue_style( 'qmn_admin_style', plugins_url( '../css/qsm-admin.css' , __FILE__ ) );
26
  ?>
27
  <h3 style="text-align: center;"><?php _e("Template Variables", 'quiz-master-next'); ?></h3>
28
  <div class="template_list_holder">
22
  function mlw_options_text_tab_content() {
23
  global $wpdb;
24
  global $mlwQuizMasterNext;
25
+ wp_enqueue_style( 'qmn_admin_style', plugins_url( '../../css/qsm-admin.css' , __FILE__ ) );
26
  ?>
27
  <h3 style="text-align: center;"><?php _e("Template Variables", 'quiz-master-next'); ?></h3>
28
  <div class="template_list_holder">
php/{options-page-tools-tab.php → admin/options-page-tools-tab.php} RENAMED
File without changes
php/{quiz-options-page.php → admin/quiz-options-page.php} RENAMED
@@ -17,16 +17,17 @@ function qsm_generate_quiz_options() {
17
 
18
  global $wpdb;
19
  global $mlwQuizMasterNext;
 
20
 
21
  // Get registered tabs for the options page and set current tab
22
  $tab_array = $mlwQuizMasterNext->pluginHelper->get_settings_tabs();
23
  $active_tab = isset( $_GET[ 'tab' ] ) ? stripslashes( $_GET[ 'tab' ] ) : 'questions';
24
 
25
- // Prepare quiz
26
- $quiz_id = intval( $_GET["quiz_id"] );
27
  if ( isset( $_GET["quiz_id"] ) ) {
28
  $quiz_name = $wpdb->get_var( $wpdb->prepare( "SELECT quiz_name FROM {$wpdb->prefix}mlw_quizzes WHERE quiz_id=%d LIMIT 1", $quiz_id ) );
29
- $mlwQuizMasterNext->quiz_settings->prepare_quiz( $_GET["quiz_id"] );
30
  }
31
 
32
  wp_enqueue_script( 'jquery' );
17
 
18
  global $wpdb;
19
  global $mlwQuizMasterNext;
20
+ $quiz_name = '';
21
 
22
  // Get registered tabs for the options page and set current tab
23
  $tab_array = $mlwQuizMasterNext->pluginHelper->get_settings_tabs();
24
  $active_tab = isset( $_GET[ 'tab' ] ) ? stripslashes( $_GET[ 'tab' ] ) : 'questions';
25
 
26
+ // Prepares quiz.
27
+ $quiz_id = isset( $_GET['quiz_id'] ) ? intval( $_GET['quiz_id'] ) : 0;
28
  if ( isset( $_GET["quiz_id"] ) ) {
29
  $quiz_name = $wpdb->get_var( $wpdb->prepare( "SELECT quiz_name FROM {$wpdb->prefix}mlw_quizzes WHERE quiz_id=%d LIMIT 1", $quiz_id ) );
30
+ $mlwQuizMasterNext->pluginHelper->prepare_quiz( $_GET["quiz_id"] );
31
  }
32
 
33
  wp_enqueue_script( 'jquery' );
php/{quizzes-page.php → admin/quizzes-page.php} RENAMED
@@ -24,8 +24,8 @@ function qsm_generate_quizzes_surveys_page() {
24
  global $mlwQuizMasterNext;
25
 
26
  // Enqueue our styles and scripts.
27
- wp_enqueue_style( 'qsm_admin_style', plugins_url( '../css/qsm-admin.css', __FILE__ ) );
28
- wp_enqueue_script( 'qsm_admin_script', plugins_url( '../js/qsm-admin.js', __FILE__ ), array( 'wp-util', 'underscore', 'jquery-ui-core', 'jquery-ui-dialog', 'jquery-ui-button' ), $mlwQuizMasterNext->version );
29
  wp_enqueue_style( 'qsm_jquery_redmond_theme', '//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/themes/redmond/jquery-ui.css' );
30
 
31
  // Create new quiz.
@@ -196,7 +196,7 @@ function qsm_generate_quizzes_surveys_page() {
196
  <div>
197
  <?php echo esc_html( $item['description'] ); ?>
198
  </div>
199
- <a target='_blank' href="<?php echo esc_attr( $item['link'] ); ?>" class="button-primary"><?php _e( 'Read More', 'quiz-master-next' ); ?></a>
200
  </div>
201
  <?php
202
  }
24
  global $mlwQuizMasterNext;
25
 
26
  // Enqueue our styles and scripts.
27
+ wp_enqueue_style( 'qsm_admin_style', plugins_url( '../../css/qsm-admin.css', __FILE__ ) );
28
+ wp_enqueue_script( 'qsm_admin_script', plugins_url( '../../js/qsm-admin.js', __FILE__ ), array( 'wp-util', 'underscore', 'jquery-ui-core', 'jquery-ui-dialog', 'jquery-ui-button' ), $mlwQuizMasterNext->version );
29
  wp_enqueue_style( 'qsm_jquery_redmond_theme', '//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/themes/redmond/jquery-ui.css' );
30
 
31
  // Create new quiz.
196
  <div>
197
  <?php echo esc_html( $item['description'] ); ?>
198
  </div>
199
+ <a target='_blank' href="<?php echo esc_attr( $item['link'] ); ?>?utm_source=qsm-quizzes-page&utm_medium=plugin&utm_campaign=qsm_plugin" class="button-primary"><?php _e( 'Read More', 'quiz-master-next' ); ?></a>
200
  </div>
201
  <?php
202
  }
php/{settings-page.php → admin/settings-page.php} RENAMED
File without changes
php/{stats-page.php → admin/stats-page.php} RENAMED
@@ -77,7 +77,7 @@ add_action("plugins_loaded", 'qmn_stats_overview_tab');
77
  */
78
  function qmn_stats_overview_content()
79
  {
80
- wp_enqueue_script('ChartJS', plugins_url( '../js/Chart.min.js' , __FILE__ ));
81
  $range = "daily";
82
  if (isset($_POST["range"])) {
83
  $range = sanitize_text_field( $_POST["range"] );
77
  */
78
  function qmn_stats_overview_content()
79
  {
80
+ wp_enqueue_script('ChartJS', plugins_url( '../../js/Chart.min.js' , __FILE__ ));
81
  $range = "daily";
82
  if (isset($_POST["range"])) {
83
  $range = sanitize_text_field( $_POST["range"] );
php/{tools-page.php → admin/tools-page.php} RENAMED
File without changes
php/{class-qmn-alert-manager.php → classes/class-qmn-alert-manager.php} RENAMED
File without changes
php/{class-qmn-log-manager.php → classes/class-qmn-log-manager.php} RENAMED
File without changes
php/{class-qmn-plugin-helper.php → classes/class-qmn-plugin-helper.php} RENAMED
File without changes
php/{class-qmn-quiz-creator.php → classes/class-qmn-quiz-creator.php} RENAMED
File without changes
php/{class-qmn-quiz-manager.php → classes/class-qmn-quiz-manager.php} RENAMED
@@ -1,9 +1,13 @@
1
  <?php
2
  /**
3
  * File for the QMNQuizManager class
 
 
4
  */
5
 
6
- if ( ! defined( 'ABSPATH' ) ) exit;
 
 
7
 
8
  /**
9
  * This class generates the contents of the quiz shortcode
@@ -46,7 +50,7 @@ class QMNQuizManager {
46
  * Generates the content for the [mlw_quizmaster] shortcode
47
  *
48
  * @since 4.0.0
49
- * @param array $atts The attributes passed from the shortcode
50
  * @uses QMNQuizManager:load_questions() Loads questions
51
  * @uses QMNQuizManager:create_answer_array() Prepares answers
52
  * @uses QMNQuizManager:display_quiz() Generates and prepares quiz page
@@ -55,8 +59,8 @@ class QMNQuizManager {
55
  */
56
  public function display_shortcode( $atts ) {
57
  extract(shortcode_atts(array(
58
- 'quiz' => 0,
59
- 'question_amount' => 0
60
  ), $atts));
61
 
62
  ob_start();
@@ -84,34 +88,34 @@ class QMNQuizManager {
84
 
85
  // Loads Quiz Template.
86
  if ( 'default' == $qmn_quiz_options->theme_selected ) {
87
- $return_display .= '<style type="text/css">' . $qmn_quiz_options->quiz_stye . '</style>';
88
- wp_enqueue_style( 'qmn_quiz_style', plugins_url( '../css/qmn_quiz.css', __FILE__ ) );
89
  } else {
90
  $registered_template = $mlwQuizMasterNext->pluginHelper->get_quiz_templates( $qmn_quiz_options->theme_selected );
91
  // Check direct file first, then check templates folder in plugin, then check templates file in theme.
92
  // If all fails, then load custom styling instead.
93
- if ( $registered_template && file_exists( $registered_template["path"] ) ) {
94
- wp_enqueue_style( 'qmn_quiz_template', $registered_template["path"], array(), $mlwQuizMasterNext->version );
95
- } elseif ( $registered_template && file_exists( plugin_dir_path( __FILE__ ).'../templates/'.$registered_template["path"] ) ) {
96
- wp_enqueue_style( 'qmn_quiz_template', plugins_url( '../templates/'.$registered_template["path"], __FILE__ ), array(), $mlwQuizMasterNext->version );
97
- } elseif ( $registered_template && file_exists( get_stylesheet_directory_uri().'/templates/'.$registered_template["path"] ) ) {
98
- wp_enqueue_style( 'qmn_quiz_template', get_stylesheet_directory_uri().'/templates/'.$registered_template["path"], array(), $mlwQuizMasterNext->version );
99
  } else {
100
- echo "<style type='text/css'>" . $qmn_quiz_options->quiz_stye . "</style>";
101
  }
102
  }
103
 
104
  // Start to prepare variable array for filters.
105
  $qmn_array_for_variables = array(
106
- 'quiz_id' => $qmn_quiz_options->quiz_id,
107
- 'quiz_name' => $qmn_quiz_options->quiz_name,
108
- 'quiz_system' => $qmn_quiz_options->system
109
  );
110
 
111
- if ( $_SERVER["REMOTE_ADDR"] ) {
112
- $qmn_array_for_variables['user_ip'] = $_SERVER["REMOTE_ADDR"];
113
  } else {
114
- $qmn_array_for_variables['user_ip'] = "Unknown";
115
  }
116
 
117
  $return_display .= "<script>
@@ -120,25 +124,21 @@ class QMNQuizManager {
120
  }
121
  </script>";
122
  $qmn_json_data = array(
123
- 'quiz_id' => $qmn_array_for_variables['quiz_id'],
124
- 'quiz_name' => $qmn_array_for_variables['quiz_name'],
125
- 'disable_answer' => $qmn_quiz_options->disable_answer_onselect,
126
- 'ajax_show_correct' => $qmn_quiz_options->ajax_show_correct
127
  );
128
 
129
  $return_display = apply_filters( 'qmn_begin_shortcode', $return_display, $qmn_quiz_options, $qmn_array_for_variables );
130
 
131
  // Check if we should be showing quiz or results page.
132
  if ( $qmn_allowed_visit && ! isset( $_POST["complete_quiz"] ) && ! empty( $qmn_quiz_options->quiz_name ) ) {
133
- $qmn_quiz_questions = $this->load_questions( $quiz, $qmn_quiz_options, true, $question_amount );
134
- $qmn_quiz_answers = $this->create_answer_array( $qmn_quiz_questions );
135
- $return_display .= $this->display_quiz( $qmn_quiz_options, $qmn_quiz_questions, $qmn_quiz_answers, $qmn_array_for_variables );
136
  } elseif ( isset( $_POST["complete_quiz"] ) && 'confirmation' == $_POST["complete_quiz"] && $_POST["qmn_quiz_id"] == $qmn_array_for_variables["quiz_id"] ) {
137
  $qmn_quiz_questions = $this->load_questions( $quiz, $qmn_quiz_options, false );
138
  $qmn_quiz_answers = $this->create_answer_array( $qmn_quiz_questions );
139
  $return_display .= $this->display_results( $qmn_quiz_options, $qmn_quiz_questions, $qmn_quiz_answers, $qmn_array_for_variables );
140
- } else {
141
- // @todo Do something else here
142
  }
143
 
144
  $qmn_filtered_json = apply_filters( 'qmn_json_data', $qmn_json_data, $qmn_quiz_options, $qmn_array_for_variables );
@@ -163,11 +163,14 @@ class QMNQuizManager {
163
  * @param bool $is_quiz_page If the page being loaded is the quiz page or not.
164
  * @param int $question_amount The amount of questions entered using the shortcode attribute.
165
  * @return array The questions for the quiz
 
166
  */
167
  public function load_questions( $quiz_id, $quiz_options, $is_quiz_page, $question_amount = 0 ) {
168
 
169
  // Prepare variables.
170
  global $wpdb;
 
 
171
  $order_by_sql = 'ORDER BY question_order ASC';
172
  $limit_sql = '';
173
 
@@ -185,8 +188,24 @@ class QMNQuizManager {
185
  }
186
  }
187
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  // Returns an array of all the loaded questions.
189
- return $wpdb->get_results( $wpdb->prepare( "SELECT * FROM " . $wpdb->prefix . "mlw_questions WHERE quiz_id=%d AND deleted=0 " . $order_by_sql . $limit_sql, $quiz_id ) );
190
  }
191
 
192
  /**
@@ -198,6 +217,7 @@ class QMNQuizManager {
198
  * @param array $questions The questions for the quiz.
199
  * @param bool $is_ajax Pass true if this is an ajax call.
200
  * @return array The answers for the quiz
 
201
  */
202
  public function create_answer_array( $questions, $is_ajax = false ) {
203
 
@@ -236,22 +256,21 @@ class QMNQuizManager {
236
  * Generates the content for the quiz page part of the shortcode
237
  *
238
  * @since 4.0.0
239
- * @param array $qmn_quiz_options The database row of the quiz.
240
- * @param array $qmn_quiz_questions The questions of the quiz.
241
- * @param array $qmn_quiz_answers The answers of the quiz.
242
- * @param array $qmn_array_for_variables The array of results for the quiz.
243
  * @uses QMNQuizManager:display_begin_section() Creates display for beginning section
244
  * @uses QMNQuizManager:display_questions() Creates display for questions
245
  * @uses QMNQuizManager:display_comment_section() Creates display for comment section
246
  * @uses QMNQuizManager:display_end_section() Creates display for end section
247
  * @return string The content for the quiz page section
248
  */
249
- public function display_quiz( $qmn_quiz_options, $qmn_quiz_questions, $qmn_quiz_answers, $qmn_array_for_variables ) {
250
 
251
  global $qmn_allowed_visit;
252
  global $mlwQuizMasterNext;
253
  $quiz_display = '';
254
- $quiz_display = apply_filters( 'qmn_begin_quiz', $quiz_display, $qmn_quiz_options, $qmn_array_for_variables );
255
  if ( ! $qmn_allowed_visit ) {
256
  return $quiz_display;
257
  }
@@ -262,14 +281,14 @@ class QMNQuizManager {
262
  wp_enqueue_style( 'jquery-redmond-theme', '//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/themes/redmond/jquery-ui.css' );
263
 
264
  global $qmn_json_data;
265
- $qmn_json_data["error_messages"] = array(
266
- 'email' => $qmn_quiz_options->email_error_text,
267
- 'number' => $qmn_quiz_options->number_error_text,
268
- 'incorrect' => $qmn_quiz_options->incorrect_error_text,
269
- 'empty' => $qmn_quiz_options->empty_error_text
270
  );
271
 
272
- wp_enqueue_script( 'qmn_quiz', plugins_url( '../js/qmn_quiz.js', __FILE__ ), array( 'jquery', 'jquery-ui-tooltip' ), $mlwQuizMasterNext->version );
273
  wp_localize_script( 'qmn_quiz', 'qmn_ajax_object', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) ); // setting ajaxurl
274
  wp_enqueue_script( 'math_jax', '//cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-MML-AM_CHTML' );
275
 
@@ -279,105 +298,294 @@ class QMNQuizManager {
279
  $mlw_qmn_section_count = 0;
280
 
281
  $quiz_display .= "<div class='qmn_quiz_container mlw_qmn_quiz'>";
282
- $quiz_display .= "<form name='quizForm".$qmn_array_for_variables["quiz_id"]."' id='quizForm".$qmn_array_for_variables["quiz_id"]."' action='' method='post' class='qmn_quiz_form mlw_quiz_form' novalidate >";
283
- $quiz_display .= "<div name='mlw_error_message' id='mlw_error_message' class='qmn_error_message_section'></div>";
284
  $quiz_display .= "<span id='mlw_top_of_quiz'></span>";
285
- $quiz_display = apply_filters('qmn_begin_quiz_form', $quiz_display, $qmn_quiz_options, $qmn_array_for_variables);
286
- $quiz_display .= $this->display_begin_section($qmn_quiz_options, $qmn_array_for_variables);
287
- $quiz_display = apply_filters('qmn_begin_quiz_questions', $quiz_display, $qmn_quiz_options, $qmn_array_for_variables);
288
- $quiz_display .= $this->display_questions($qmn_quiz_options, $qmn_quiz_questions, $qmn_quiz_answers);
289
- $quiz_display = apply_filters('qmn_before_comment_section', $quiz_display, $qmn_quiz_options, $qmn_array_for_variables);
290
- $quiz_display .= $this->display_comment_section($qmn_quiz_options, $qmn_array_for_variables);
291
- $quiz_display = apply_filters('qmn_after_comment_section', $quiz_display, $qmn_quiz_options, $qmn_array_for_variables);
292
- $quiz_display .= $this->display_end_section($qmn_quiz_options, $qmn_array_for_variables);
 
 
 
 
 
 
 
 
 
 
 
293
  $quiz_display .= "<div name='mlw_error_message_bottom' id='mlw_error_message_bottom' class='qmn_error_message_section'></div>";
294
- $quiz_display .= "<input type='hidden' name='total_questions' id='total_questions' value='".$qmn_total_questions."'/>";
295
  $quiz_display .= "<input type='hidden' name='timer' id='timer' value='0'/>";
296
- $quiz_display .= "<input type='hidden' class='qmn_quiz_id' name='qmn_quiz_id' id='qmn_quiz_id' value='".$qmn_array_for_variables["quiz_id"]."'/>";
297
  $quiz_display .= "<input type='hidden' name='complete_quiz' value='confirmation' />";
298
- $quiz_display = apply_filters('qmn_end_quiz_form', $quiz_display, $qmn_quiz_options, $qmn_array_for_variables);
299
- $quiz_display .= "</form>";
300
- $quiz_display .= "</div>";
301
 
302
- $quiz_display = apply_filters('qmn_end_quiz', $quiz_display, $qmn_quiz_options, $qmn_array_for_variables);
303
  return $quiz_display;
304
  }
305
 
306
  /**
307
- * Creates Display For Beginning Section
308
- *
309
- * Generates the content for the beginning section of the quiz page
310
- *
311
- * @since 4.0.0
312
- * @param array $qmn_quiz_options The database row of the quiz
313
- * @param array $qmn_array_for_variables The array of results for the quiz
314
- * @return string The content for the beginning section
315
- */
316
- public function display_begin_section($qmn_quiz_options, $qmn_array_for_variables)
317
- {
318
- $section_display = "";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
319
  global $qmn_json_data;
320
- if ( !empty( $qmn_quiz_options->message_before ) OR $qmn_quiz_options->contact_info_location == 0) {
321
  $qmn_json_data["first_page"] = true;
322
- global $mlw_qmn_section_count;
323
- $mlw_qmn_section_count +=1;
324
- $section_display .= "<div class='quiz_section quiz_begin slide$mlw_qmn_section_count'>";
325
 
326
- $message_before = wpautop(htmlspecialchars_decode($qmn_quiz_options->message_before, ENT_QUOTES));
327
- $message_before = apply_filters( 'mlw_qmn_template_variable_quiz_page', $message_before, $qmn_array_for_variables);
328
 
329
- $section_display .= "<div class='mlw_qmn_message_before'>$message_before</div>";
330
- if ( 0 == $qmn_quiz_options->contact_info_location ) {
331
  $section_display .= QSM_Contact_Manager::display_fields( $qmn_quiz_options );
332
- }
333
- $section_display .= "</div>";
334
- } else {
335
- $qmn_json_data["first_page"] = false;
336
- }
337
  return $section_display;
338
  }
339
 
340
  /**
341
- * Creates Display For Questions
342
- *
343
- * Generates the content for the questions part of the quiz page
344
- *
345
- * @since 4.0.0
346
- * @param array $qmn_quiz_options The database row of the quiz
347
- * @param array $qmn_quiz_questions The questions of the quiz
348
- * @param array $qmn_quiz_answers The answers of the quiz
349
- * @uses QMNPluginHelper:display_question() Displays a question
350
- * @return string The content for the questions section
351
- */
352
- public function display_questions($qmn_quiz_options, $qmn_quiz_questions, $qmn_quiz_answers)
353
- {
354
  $question_display = '';
355
  global $mlwQuizMasterNext;
356
  global $qmn_total_questions;
357
  global $mlw_qmn_section_count;
358
  $question_id_list = '';
359
- foreach($qmn_quiz_questions as $mlw_question)
360
- {
361
  $question_id_list .= $mlw_question->question_id."Q";
362
  $mlw_qmn_section_count = $mlw_qmn_section_count + 1;
363
  $question_display .= "<div class='quiz_section question-section-id-{$mlw_question->question_id} slide{$mlw_qmn_section_count}'>";
364
 
365
- $question_display .= $mlwQuizMasterNext->pluginHelper->display_question($mlw_question->question_type_new, $mlw_question->question_id, $qmn_quiz_options);
366
 
367
- if ($mlw_question->comments == 0)
368
- {
369
  $question_display .= "<input type='text' class='mlw_qmn_question_comment' x-webkit-speech id='mlwComment".$mlw_question->question_id."' name='mlwComment".$mlw_question->question_id."' value='".esc_attr(htmlspecialchars_decode($qmn_quiz_options->comment_field_text, ENT_QUOTES))."' onclick='qmnClearField(this)'/>";
370
  $question_display .= "<br />";
371
  }
372
- if ($mlw_question->comments == 2)
373
- {
374
  $question_display .= "<textarea cols='70' rows='5' class='mlw_qmn_question_comment' id='mlwComment".$mlw_question->question_id."' name='mlwComment".$mlw_question->question_id."' onclick='qmnClearField(this)'>".htmlspecialchars_decode($qmn_quiz_options->comment_field_text, ENT_QUOTES)."</textarea>";
375
  $question_display .= "<br />";
376
  }
377
 
378
- // Checks if a hint is entered
379
  if ( ! empty( $mlw_question->hints ) ) {
380
- $question_display .= "<span title=\"" . esc_attr( htmlspecialchars_decode( $mlw_question->hints, ENT_QUOTES ) ) . "\" class='qsm_hint mlw_qmn_hint_link'>{$qmn_quiz_options->hint_text}</span>";
381
  $question_display .= "<br /><br />";
382
  }
383
  $question_display .= "</div>";
@@ -387,20 +595,20 @@ class QMNQuizManager {
387
  }
388
 
389
  /**
390
- * Creates Display For Comment Section
391
- *
392
- * Generates the content for the comment section part of the quiz page
393
- *
394
- * @since 4.0.0
395
- * @param array $qmn_quiz_options The database row of the quiz
396
- * @param array $qmn_array_for_variables The array of results for the quiz
397
- * @return string The content for the comment section
398
- */
 
399
  public function display_comment_section( $qmn_quiz_options, $qmn_array_for_variables ) {
400
  global $mlw_qmn_section_count;
401
  $comment_display = '';
402
- if ($qmn_quiz_options->comment_section == 0)
403
- {
404
  $mlw_qmn_section_count = $mlw_qmn_section_count + 1;
405
  $comment_display .= "<div class='quiz_section slide".$mlw_qmn_section_count."'>";
406
  $message_comments = wpautop(htmlspecialchars_decode($qmn_quiz_options->message_comment, ENT_QUOTES));
@@ -413,25 +621,24 @@ class QMNQuizManager {
413
  }
414
 
415
  /**
416
- * Creates Display For End Section Of Quiz Page
417
- *
418
- * Generates the content for the end section of the quiz page
419
- *
420
- * @since 4.0.0
421
- * @param array $qmn_quiz_options The database row of the quiz
422
- * @param array $qmn_array_for_variables The array of results for the quiz
423
- * @return string The content for the end section
424
- */
425
- public function display_end_section($qmn_quiz_options, $qmn_array_for_variables)
426
- {
427
  global $mlw_qmn_section_count;
428
  $section_display = '';
429
  $section_display .= "<br />";
430
  $mlw_qmn_section_count = $mlw_qmn_section_count + 1;
431
  $section_display .= "<div class='quiz_section slide$mlw_qmn_section_count quiz_end'>";
432
- if ($qmn_quiz_options->message_end_template != '')
433
- {
434
- $message_end = wpautop(htmlspecialchars_decode($qmn_quiz_options->message_end_template, ENT_QUOTES));
435
  $message_end = apply_filters( 'mlw_qmn_template_variable_quiz_page', $message_end, $qmn_array_for_variables);
436
  $section_display .= "<span class='mlw_qmn_message_end'>$message_end</span>";
437
  $section_display .= "<br /><br />";
@@ -442,9 +649,9 @@ class QMNQuizManager {
442
 
443
  //Legacy Code
444
  ob_start();
445
- do_action('mlw_qmn_end_quiz_section');
446
- $section_display .= ob_get_contents();
447
- ob_end_clean();
448
 
449
  $section_display .= "<input type='submit' class='qsm-btn qsm-submit-btn qmn_btn' value='".esc_attr(htmlspecialchars_decode($qmn_quiz_options->submit_button_text, ENT_QUOTES))."' />";
450
  $section_display .= "</div>";
@@ -453,31 +660,31 @@ class QMNQuizManager {
453
  }
454
 
455
  /**
456
- * Generates Content Results Page
457
- *
458
- * Generates the content for the results page part of the shortcode
459
- *
460
- * @since 4.0.0
461
- * @param array $qmn_quiz_options The database row of the quiz
462
- * @param array $qmn_quiz_questions The questions of the quiz
463
- * @param array $qmn_quiz_answers The answers of the quiz
464
- * @param array $qmn_array_for_variables The array of results for the quiz
465
- * @uses QMNQuizManager:submit_results() Perform The Quiz/Survey Submission
466
- * @return string The content for the results page section
467
- */
468
- public function display_results($qmn_quiz_options, $qmn_quiz_questions, $qmn_quiz_answers, $qmn_array_for_variables) {
469
- $result = $this->submit_results($qmn_quiz_options, $qmn_quiz_questions, $qmn_quiz_answers, $qmn_array_for_variables);
470
  $results_array = $result;
471
  return $results_array['display'];
472
  }
473
 
474
  /**
475
- * Calls the results page from ajax
476
- *
477
- * @since 4.6.0
478
- * @uses QMNQuizManager:submit_results() Perform The Quiz/Survey Submission
479
- * @return string The content for the results page section
480
- */
481
  public function ajax_submit_results() {
482
  global $qmn_allowed_visit;
483
  global $mlwQuizMasterNext;
@@ -491,30 +698,30 @@ class QMNQuizManager {
491
  $qmn_array_for_variables = array(
492
  'quiz_id' => $qmn_quiz_options->quiz_id,
493
  'quiz_name' => $qmn_quiz_options->quiz_name,
494
- 'quiz_system' => $qmn_quiz_options->system
495
  );
496
- echo json_encode( $this->submit_results($qmn_quiz_options, $qmn_quiz_questions, $qmn_quiz_answers, $qmn_array_for_variables) );
497
  die();
498
  }
499
 
500
  /**
501
- * Perform The Quiz/Survey Submission
502
- *
503
- * Perpares and save the results, prepares and send emails, prepare results page
504
- *
505
- * @since 4.6.0
506
- * @param array $qmn_quiz_options The database row of the quiz
507
- * @param array $qmn_quiz_questions The questions of the quiz
508
- * @param array $qmn_quiz_answers The answers of the quiz
509
- * @param array $qmn_array_for_variables The array of results for the quiz
510
- * @uses QMNQuizManager:check_answers() Creates display for beginning section
511
- * @uses QMNQuizManager:check_comment_section() Creates display for questions
512
- * @uses QMNQuizManager:display_results_text() Creates display for end section
513
- * @uses QMNQuizManager:display_social() Creates display for comment section
514
- * @uses QMNQuizManager:send_user_email() Creates display for end section
515
- * @uses QMNQuizManager:send_admin_email() Creates display for end section
516
- * @return string The content for the results page section
517
- */
518
  public function submit_results( $qmn_quiz_options, $qmn_quiz_questions, $qmn_quiz_answers, $qmn_array_for_variables ) {
519
  global $qmn_allowed_visit;
520
  $result_display = '';
@@ -570,27 +777,28 @@ class QMNQuizManager {
570
  $result_display .= $this->display_social($qmn_quiz_options, $qmn_array_for_variables);
571
  $result_display = apply_filters('qmn_after_social_media', $result_display, $qmn_quiz_options, $qmn_array_for_variables);
572
 
573
- // Save the results into database
574
- $mlw_quiz_results_array = array(
575
- intval($qmn_array_for_variables['timer']),
576
  $qmn_array_for_variables['question_answers_array'],
577
- htmlspecialchars(stripslashes($qmn_array_for_variables['comments']), ENT_QUOTES),
578
- 'contact' => $contact_responses
579
  );
580
- $mlw_quiz_results = serialize($mlw_quiz_results_array);
 
581
 
582
  global $wpdb;
583
  $table_name = $wpdb->prefix . "mlw_results";
584
  $results_insert = $wpdb->insert(
585
  $table_name,
586
  array(
587
- 'quiz_id' => $qmn_array_for_variables['quiz_id'],
588
- 'quiz_name' => $qmn_array_for_variables['quiz_name'],
589
- 'quiz_system' => $qmn_array_for_variables['quiz_system'],
590
- 'point_score' => $qmn_array_for_variables['total_points'],
591
  'correct_score' => $qmn_array_for_variables['total_score'],
592
- 'correct' => $qmn_array_for_variables['total_correct'],
593
- 'total' => $qmn_array_for_variables['total_questions'],
594
  'name' => $qmn_array_for_variables['user_name'],
595
  'business' => $qmn_array_for_variables['user_business'],
596
  'email' => $qmn_array_for_variables['user_email'],
@@ -599,7 +807,7 @@ class QMNQuizManager {
599
  'user_ip' => $qmn_array_for_variables['user_ip'],
600
  'time_taken' => $qmn_array_for_variables['time_taken'],
601
  'time_taken_real' => date( "Y-m-d H:i:s", strtotime( $qmn_array_for_variables['time_taken'] ) ),
602
- 'quiz_results' => $mlw_quiz_results,
603
  'deleted' => 0
604
  ),
605
  array(
@@ -1240,7 +1448,8 @@ function qmn_pagination_check( $display, $qmn_quiz_options, $qmn_array_for_varia
1240
  if ( $qmn_quiz_options->question_from_total != 0 ) {
1241
  $total_questions = $qmn_quiz_options->question_from_total;
1242
  } else {
1243
- $total_questions = $wpdb->get_var($wpdb->prepare("SELECT COUNT(quiz_id) FROM ".$wpdb->prefix."mlw_questions WHERE deleted=0 AND quiz_id=%d", $qmn_array_for_variables["quiz_id"]));
 
1244
  }
1245
  $display .= "<style>.quiz_section { display: none; }</style>";
1246
 
1
  <?php
2
  /**
3
  * File for the QMNQuizManager class
4
+ *
5
+ * @package QSM
6
  */
7
 
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
10
+ }
11
 
12
  /**
13
  * This class generates the contents of the quiz shortcode
50
  * Generates the content for the [mlw_quizmaster] shortcode
51
  *
52
  * @since 4.0.0
53
+ * @param array $atts The attributes passed from the shortcode.
54
  * @uses QMNQuizManager:load_questions() Loads questions
55
  * @uses QMNQuizManager:create_answer_array() Prepares answers
56
  * @uses QMNQuizManager:display_quiz() Generates and prepares quiz page
59
  */
60
  public function display_shortcode( $atts ) {
61
  extract(shortcode_atts(array(
62
+ 'quiz' => 0,
63
+ 'question_amount' => 0,
64
  ), $atts));
65
 
66
  ob_start();
88
 
89
  // Loads Quiz Template.
90
  if ( 'default' == $qmn_quiz_options->theme_selected ) {
91
+ $return_display .= '<style type="text/css">' . $qmn_quiz_options->quiz_style . '</style>';
92
+ wp_enqueue_style( 'qmn_quiz_style', plugins_url( '../../css/qmn_quiz.css', __FILE__ ) );
93
  } else {
94
  $registered_template = $mlwQuizMasterNext->pluginHelper->get_quiz_templates( $qmn_quiz_options->theme_selected );
95
  // Check direct file first, then check templates folder in plugin, then check templates file in theme.
96
  // If all fails, then load custom styling instead.
97
+ if ( $registered_template && file_exists( $registered_template['path'] ) ) {
98
+ wp_enqueue_style( 'qmn_quiz_template', $registered_template['path'], array(), $mlwQuizMasterNext->version );
99
+ } elseif ( $registered_template && file_exists( plugin_dir_path( __FILE__ ) . '../../templates/' . $registered_template['path'] ) ) {
100
+ wp_enqueue_style( 'qmn_quiz_template', plugins_url( '../../templates/' . $registered_template['path'], __FILE__ ), array(), $mlwQuizMasterNext->version );
101
+ } elseif ( $registered_template && file_exists( get_stylesheet_directory_uri() . '/templates/' . $registered_template['path'] ) ) {
102
+ wp_enqueue_style( 'qmn_quiz_template', get_stylesheet_directory_uri() . '/templates/' . $registered_template['path'], array(), $mlwQuizMasterNext->version );
103
  } else {
104
+ echo "<style type='text/css'>{$qmn_quiz_options->quiz_style}</style>";
105
  }
106
  }
107
 
108
  // Start to prepare variable array for filters.
109
  $qmn_array_for_variables = array(
110
+ 'quiz_id' => $qmn_quiz_options->quiz_id,
111
+ 'quiz_name' => $qmn_quiz_options->quiz_name,
112
+ 'quiz_system' => $qmn_quiz_options->system,
113
  );
114
 
115
+ if ( $_SERVER['REMOTE_ADDR'] ) {
116
+ $qmn_array_for_variables['user_ip'] = $_SERVER['REMOTE_ADDR'];
117
  } else {
118
+ $qmn_array_for_variables['user_ip'] = 'Unknown';
119
  }
120
 
121
  $return_display .= "<script>
124
  }
125
  </script>";
126
  $qmn_json_data = array(
127
+ 'quiz_id' => $qmn_array_for_variables['quiz_id'],
128
+ 'quiz_name' => $qmn_array_for_variables['quiz_name'],
129
+ 'disable_answer' => $qmn_quiz_options->disable_answer_onselect,
130
+ 'ajax_show_correct' => $qmn_quiz_options->ajax_show_correct,
131
  );
132
 
133
  $return_display = apply_filters( 'qmn_begin_shortcode', $return_display, $qmn_quiz_options, $qmn_array_for_variables );
134
 
135
  // Check if we should be showing quiz or results page.
136
  if ( $qmn_allowed_visit && ! isset( $_POST["complete_quiz"] ) && ! empty( $qmn_quiz_options->quiz_name ) ) {
137
+ $return_display .= $this->display_quiz( $qmn_quiz_options, $qmn_array_for_variables, $question_amount );
 
 
138
  } elseif ( isset( $_POST["complete_quiz"] ) && 'confirmation' == $_POST["complete_quiz"] && $_POST["qmn_quiz_id"] == $qmn_array_for_variables["quiz_id"] ) {
139
  $qmn_quiz_questions = $this->load_questions( $quiz, $qmn_quiz_options, false );
140
  $qmn_quiz_answers = $this->create_answer_array( $qmn_quiz_questions );
141
  $return_display .= $this->display_results( $qmn_quiz_options, $qmn_quiz_questions, $qmn_quiz_answers, $qmn_array_for_variables );
 
 
142
  }
143
 
144
  $qmn_filtered_json = apply_filters( 'qmn_json_data', $qmn_json_data, $qmn_quiz_options, $qmn_array_for_variables );
163
  * @param bool $is_quiz_page If the page being loaded is the quiz page or not.
164
  * @param int $question_amount The amount of questions entered using the shortcode attribute.
165
  * @return array The questions for the quiz
166
+ * @deprecated 5.2.0 Use new class: QSM_Questions instead
167
  */
168
  public function load_questions( $quiz_id, $quiz_options, $is_quiz_page, $question_amount = 0 ) {
169
 
170
  // Prepare variables.
171
  global $wpdb;
172
+ global $mlwQuizMasterNext;
173
+ $questions = array();
174
  $order_by_sql = 'ORDER BY question_order ASC';
175
  $limit_sql = '';
176
 
188
  }
189
  }
190
 
191
+ // If using newer pages system from 5.2.
192
+ $pages = $mlwQuizMasterNext->pluginHelper->get_quiz_setting( 'pages', array() );
193
+ // Get all question IDs needed.
194
+ $total_pages = count( $pages );
195
+ if ( $total_pages > 0 ) {
196
+ for ( $i = 0; $i < $total_pages; $i++ ) {
197
+ foreach ( $pages[ $i ] as $question ) {
198
+ $question_ids[] = intval( $question );
199
+ }
200
+ }
201
+ $question_sql = implode( ', ', $question_ids );
202
+ $questions = $wpdb->get_results( "SELECT * FROM " . $wpdb->prefix . "mlw_questions WHERE question_id IN ($question_sql) " . $order_by_sql . $limit_sql );
203
+ } else {
204
+ $questions = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM " . $wpdb->prefix . "mlw_questions WHERE quiz_id=%d AND deleted=0 " . $order_by_sql . $limit_sql, $quiz_id ) );
205
+ }
206
+
207
  // Returns an array of all the loaded questions.
208
+ return $questions;
209
  }
210
 
211
  /**
217
  * @param array $questions The questions for the quiz.
218
  * @param bool $is_ajax Pass true if this is an ajax call.
219
  * @return array The answers for the quiz
220
+ * @deprecated 5.2.0 Use new class: QSM_Questions instead
221
  */
222
  public function create_answer_array( $questions, $is_ajax = false ) {
223
 
256
  * Generates the content for the quiz page part of the shortcode
257
  *
258
  * @since 4.0.0
259
+ * @param array $options The database row of the quiz.
260
+ * @param array $quiz_data The array of results for the quiz.
261
+ * @param int $question_amount The number of questions to load for quiz.
 
262
  * @uses QMNQuizManager:display_begin_section() Creates display for beginning section
263
  * @uses QMNQuizManager:display_questions() Creates display for questions
264
  * @uses QMNQuizManager:display_comment_section() Creates display for comment section
265
  * @uses QMNQuizManager:display_end_section() Creates display for end section
266
  * @return string The content for the quiz page section
267
  */
268
+ public function display_quiz( $options, $quiz_data, $question_amount ) {
269
 
270
  global $qmn_allowed_visit;
271
  global $mlwQuizMasterNext;
272
  $quiz_display = '';
273
+ $quiz_display = apply_filters( 'qmn_begin_quiz', $quiz_display, $options, $quiz_data );
274
  if ( ! $qmn_allowed_visit ) {
275
  return $quiz_display;
276
  }
281
  wp_enqueue_style( 'jquery-redmond-theme', '//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/themes/redmond/jquery-ui.css' );
282
 
283
  global $qmn_json_data;
284
+ $qmn_json_data['error_messages'] = array(
285
+ 'email' => $options->email_error_text,
286
+ 'number' => $options->number_error_text,
287
+ 'incorrect' => $options->incorrect_error_text,
288
+ 'empty' => $options->empty_error_text,
289
  );
290
 
291
+ wp_enqueue_script( 'qmn_quiz', plugins_url( '../../js/qmn_quiz.js', __FILE__ ), array( 'wp-util', 'underscore', 'jquery', 'jquery-ui-tooltip' ), $mlwQuizMasterNext->version );
292
  wp_localize_script( 'qmn_quiz', 'qmn_ajax_object', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) ); // setting ajaxurl
293
  wp_enqueue_script( 'math_jax', '//cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-MML-AM_CHTML' );
294
 
298
  $mlw_qmn_section_count = 0;
299
 
300
  $quiz_display .= "<div class='qmn_quiz_container mlw_qmn_quiz'>";
301
+ $quiz_display .= "<form name='quizForm{$quiz_data['quiz_id']}' id='quizForm{$quiz_data['quiz_id']}' action='' method='post' class='qsm-quiz-form qmn_quiz_form mlw_quiz_form' novalidate >";
302
+ $quiz_display .= "<div name='mlw_error_message' id='mlw_error_message' class='qsm-error-message qmn_error_message_section'></div>";
303
  $quiz_display .= "<span id='mlw_top_of_quiz'></span>";
304
+ $quiz_display = apply_filters( 'qmn_begin_quiz_form', $quiz_display, $options, $quiz_data );
305
+
306
+ // If deprecated pagination setting is not used, use new system...
307
+ $pages = $mlwQuizMasterNext->pluginHelper->get_quiz_setting( 'pages', array() );
308
+ if ( 0 == $options->randomness_order && 0 == $options->question_from_total && 0 == $options->pagination && 0 !== count( $pages ) ) {
309
+ $quiz_display .= $this->display_pages( $options, $quiz_data );
310
+ } else {
311
+ // ... else, use older system.
312
+ $questions = $this->load_questions( $quiz_data['quiz_id'], $options, true, $question_amount );
313
+ $answers = $this->create_answer_array( $questions );
314
+ $quiz_display .= $this->display_begin_section( $options, $quiz_data );
315
+ $quiz_display = apply_filters( 'qmn_begin_quiz_questions', $quiz_display, $options, $quiz_data );
316
+ $quiz_display .= $this->display_questions( $options, $questions, $answers );
317
+ $quiz_display = apply_filters( 'qmn_before_comment_section', $quiz_display, $options, $quiz_data );
318
+ $quiz_display .= $this->display_comment_section( $options, $quiz_data );
319
+ $quiz_display = apply_filters( 'qmn_after_comment_section', $quiz_display, $options, $quiz_data );
320
+ $quiz_display .= $this->display_end_section( $options, $quiz_data );
321
+ }
322
+
323
  $quiz_display .= "<div name='mlw_error_message_bottom' id='mlw_error_message_bottom' class='qmn_error_message_section'></div>";
324
+ $quiz_display .= "<input type='hidden' name='total_questions' id='total_questions' value='$qmn_total_questions'/>";
325
  $quiz_display .= "<input type='hidden' name='timer' id='timer' value='0'/>";
326
+ $quiz_display .= "<input type='hidden' class='qmn_quiz_id' name='qmn_quiz_id' id='qmn_quiz_id' value='{$quiz_data['quiz_id']}'/>";
327
  $quiz_display .= "<input type='hidden' name='complete_quiz' value='confirmation' />";
328
+ $quiz_display = apply_filters( 'qmn_end_quiz_form', $quiz_display, $options, $quiz_data );
329
+ $quiz_display .= '</form>';
330
+ $quiz_display .= '</div>';
331
 
332
+ $quiz_display = apply_filters( 'qmn_end_quiz', $quiz_display, $options, $quiz_data );
333
  return $quiz_display;
334
  }
335
 
336
  /**
337
+ * Creates the pages of content for the quiz/survey
338
+ *
339
+ * @since 5.2.0
340
+ * @param array $options The settings for the quiz.
341
+ * @param array $quiz_data The array of quiz data.
342
+ * @return string The HTML for the pages
343
+ */
344
+ public function display_pages( $options, $quiz_data ) {
345
+ global $mlwQuizMasterNext;
346
+ global $qmn_json_data;
347
+ ob_start();
348
+ $pages = $mlwQuizMasterNext->pluginHelper->get_quiz_setting( 'pages', array() );
349
+ $questions = QSM_Questions::load_questions_by_pages( $options->quiz_id );
350
+ $question_list = '';
351
+ if ( count( $pages ) > 1 && ( ! empty( $options->message_before ) || 0 == $options->contact_info_location ) ) {
352
+ $qmn_json_data['first_page'] = true;
353
+ $message_before = wpautop( htmlspecialchars_decode( $options->message_before, ENT_QUOTES ) );
354
+ $message_before = apply_filters( 'mlw_qmn_template_variable_quiz_page', $message_before, $quiz_data );
355
+ ?>
356
+ <section class="qsm-page">
357
+ <div class="quiz_section quiz_begin">
358
+ <div class='qsm-before-message mlw_qmn_message_before'><?php echo $message_before; ?></div>
359
+ <?php
360
+ if ( 0 == $options->contact_info_location ) {
361
+ echo QSM_Contact_Manager::display_fields( $options );
362
+ }
363
+ ?>
364
+ </div>
365
+ </section>
366
+ <?php
367
+ }
368
+
369
+ // If there is only one page.
370
+ if ( 1 == count( $pages ) ) {
371
+ ?>
372
+ <section class="qsm-page">
373
+ <?php
374
+ if ( ! empty( $options->message_before ) || 0 == $options->contact_info_location ) {
375
+ $qmn_json_data['first_page'] = false;
376
+ $message_before = wpautop( htmlspecialchars_decode( $options->message_before, ENT_QUOTES ) );
377
+ $message_before = apply_filters( 'mlw_qmn_template_variable_quiz_page', $message_before, $quiz_data );
378
+ ?>
379
+ <div class="quiz_section quiz_begin">
380
+ <div class='qsm-before-message mlw_qmn_message_before'><?php echo $message_before; ?></div>
381
+ <?php
382
+ if ( 0 == $options->contact_info_location ) {
383
+ echo QSM_Contact_Manager::display_fields( $options );
384
+ }
385
+ ?>
386
+ </div>
387
+ <?php
388
+ }
389
+ foreach ( $pages[0] as $question_id ) {
390
+ $question_list .= $question_id . 'Q';
391
+ $question = $questions[ $question_id ];
392
+ ?>
393
+ <div class='quiz_section question-section-id-<?php echo esc_attr( $question_id ); ?>'>
394
+ <?php
395
+ echo $mlwQuizMasterNext->pluginHelper->display_question( $question['question_type_new'], $question_id, $options );
396
+ if ( 0 == $question['comments'] ) {
397
+ echo "<input type='text' class='qsm-question-comment qsm-question-comment-small mlw_qmn_question_comment' x-webkit-speech id='mlwComment$question_id' name='mlwComment$question_id' value='" . esc_attr( htmlspecialchars_decode( $options->comment_field_text, ENT_QUOTES ) ) . "' onclick='qmnClearField(this)'/>";
398
+ }
399
+ if ( 2 == $question['comments'] ) {
400
+ echo "<textarea class='qsm-question-comment qsm-question-comment-large mlw_qmn_question_comment' id='mlwComment$question_id' name='mlwComment$question_id' onclick='qmnClearField(this)'>" . htmlspecialchars_decode( $options->comment_field_text, ENT_QUOTES ) . "</textarea>";
401
+ }
402
+ // Checks if a hint is entered.
403
+ if ( ! empty( $question['hints'] ) ) {
404
+ echo '<div title="' . esc_attr( htmlspecialchars_decode( $question['hints'], ENT_QUOTES ) ) . '" class="qsm-hint qsm_hint mlw_qmn_hint_link">' . $options->hint_text . '</div>';
405
+ }
406
+ ?>
407
+ </div>
408
+ <?php
409
+ }
410
+ if ( 0 == $options->comment_section ) {
411
+ $message_comments = wpautop( htmlspecialchars_decode( $options->message_comment, ENT_QUOTES ) );
412
+ $message_comments = apply_filters( 'mlw_qmn_template_variable_quiz_page', $message_comments, $quiz_data );
413
+ ?>
414
+ <div class="quiz_section quiz_begin">
415
+ <label for='mlwQuizComments' class='qsm-comments-label mlw_qmn_comment_section_text'><?php echo esc_html( $message_comments ); ?></label>
416
+ <textarea id='mlwQuizComments' name='mlwQuizComments' class='qsm-comments qmn_comment_section'></textarea>
417
+ </div>
418
+ <?php
419
+ }
420
+ if ( ! empty( $options->message_end_template ) || 1 == $options->contact_info_location ) {
421
+ $message_after = wpautop( htmlspecialchars_decode( $options->message_end_template, ENT_QUOTES ) );
422
+ $message_after = apply_filters( 'mlw_qmn_template_variable_quiz_page', $message_after, $quiz_data );
423
+ ?>
424
+ <div class="quiz_section">
425
+ <div class='qsm-after-message mlw_qmn_message_end'><?php echo $message_after; ?></div>
426
+ <?php
427
+ if ( 1 == $options->contact_info_location ) {
428
+ echo QSM_Contact_Manager::display_fields( $options );
429
+ }
430
+ ?>
431
+ </div>
432
+ <?php
433
+ }
434
+ ?>
435
+ </section>
436
+ <?php
437
+ } else {
438
+ foreach ( $pages as $page ) {
439
+ ?>
440
+ <section class="qsm-page">
441
+ <?php
442
+ foreach ( $page as $question_id ) {
443
+ $question_list .= $question_id . 'Q';
444
+ $question = $questions[ $question_id ];
445
+ ?>
446
+ <div class='quiz_section question-section-id-<?php echo esc_attr( $question_id ); ?>'>
447
+ <?php
448
+ echo $mlwQuizMasterNext->pluginHelper->display_question( $question['question_type_new'], $question_id, $options );
449
+ if ( 0 == $question['comments'] ) {
450
+ echo "<input type='text' class='qsm-question-comment qsm-question-comment-small mlw_qmn_question_comment' x-webkit-speech id='mlwComment$question_id' name='mlwComment$question_id' value='" . esc_attr( htmlspecialchars_decode( $options->comment_field_text, ENT_QUOTES ) ) . "' onclick='qmnClearField(this)'/>";
451
+ }
452
+ if ( 2 == $question['comments'] ) {
453
+ echo "<textarea class='qsm-question-comment qsm-question-comment-large mlw_qmn_question_comment' id='mlwComment$question_id' name='mlwComment$question_id' onclick='qmnClearField(this)'>" . htmlspecialchars_decode( $options->comment_field_text, ENT_QUOTES ) . "</textarea>";
454
+ }
455
+ // Checks if a hint is entered.
456
+ if ( ! empty( $question['hints'] ) ) {
457
+ echo '<div title="' . esc_attr( htmlspecialchars_decode( $question['hints'], ENT_QUOTES ) ) . '" class="qsm-hint qsm_hint mlw_qmn_hint_link">' . $options->hint_text . '</div>';
458
+ }
459
+ ?>
460
+ </div>
461
+ <?php
462
+ }
463
+ ?>
464
+ </section>
465
+ <?php
466
+ }
467
+ }
468
+
469
+ if ( count( $pages ) > 1 && 0 == $options->comment_section ) {
470
+ $message_comments = wpautop( htmlspecialchars_decode( $options->message_comment, ENT_QUOTES ) );
471
+ $message_comments = apply_filters( 'mlw_qmn_template_variable_quiz_page', $message_comments, $quiz_data );
472
+ ?>
473
+ <section class="qsm-page">
474
+ <div class="quiz_section quiz_begin">
475
+ <label for='mlwQuizComments' class='qsm-comments-label mlw_qmn_comment_section_text'><?php echo $message_comments; ?></label>
476
+ <textarea id='mlwQuizComments' name='mlwQuizComments' class='qsm-comments qmn_comment_section'></textarea>
477
+ </div>
478
+ </section>
479
+ <?php
480
+ }
481
+ if ( count( $pages ) > 1 && ( ! empty( $options->message_end_template ) || 1 == $options->contact_info_location ) ) {
482
+ $message_after = wpautop( htmlspecialchars_decode( $options->message_end_template, ENT_QUOTES ) );
483
+ $message_after = apply_filters( 'mlw_qmn_template_variable_quiz_page', $message_after, $quiz_data );
484
+ ?>
485
+ <section class="qsm-page">
486
+ <div class="quiz_section">
487
+ <div class='qsm-after-message mlw_qmn_message_end'><?php echo $message_after; ?></div>
488
+ <?php
489
+ if ( 1 == $options->contact_info_location ) {
490
+ echo QSM_Contact_Manager::display_fields( $options );
491
+ }
492
+ ?>
493
+ </div>
494
+ <?php
495
+ // Legacy code.
496
+ do_action( 'mlw_qmn_end_quiz_section' );
497
+ ?>
498
+ </section>
499
+ <?php
500
+ }
501
+ ?>
502
+ <!-- View for pagination -->
503
+ <script type="text/template" id="tmpl-qsm-pagination">
504
+ <div class="qsm-pagination qmn_pagination border margin-bottom">
505
+ <a class="qsm-btn qsm-previous qmn_btn mlw_qmn_quiz_link mlw_previous" href="#"><?php echo esc_html( $options->previous_button_text ); ?></a>
506
+ <span class="qmn_page_message"></span>
507
+ <div class="qmn_page_counter_message"></div>
508
+ <a class="qsm-btn qsm-next qmn_btn mlw_qmn_quiz_link mlw_next" href="#"><?php echo esc_html( $options->next_button_text ); ?></a>
509
+ <input type='submit' class='qsm-btn qsm-submit-btn qmn_btn' value='<?php echo esc_attr( htmlspecialchars_decode( $options->submit_button_text, ENT_QUOTES ) ); ?>' />
510
+ </div>
511
+ </script>
512
+ <input type='hidden' name='qmn_question_list' value='<?php echo esc_attr( $question_list ); ?>' />
513
+ <?php
514
+ return ob_get_clean();
515
+ }
516
+
517
+ /**
518
+ * Creates Display For Beginning Section
519
+ *
520
+ * Generates the content for the beginning section of the quiz page
521
+ *
522
+ * @since 4.0.0
523
+ * @param array $qmn_quiz_options The database row of the quiz.
524
+ * @param array $qmn_array_for_variables The array of results for the quiz.
525
+ * @return string The content for the beginning section
526
+ * @deprecated 5.2.0 Use new page system instead
527
+ */
528
+ public function display_begin_section( $qmn_quiz_options, $qmn_array_for_variables ) {
529
+ $section_display = '';
530
  global $qmn_json_data;
531
+ if ( ! empty( $qmn_quiz_options->message_before ) || $qmn_quiz_options->contact_info_location == 0) {
532
  $qmn_json_data["first_page"] = true;
533
+ global $mlw_qmn_section_count;
534
+ $mlw_qmn_section_count +=1;
535
+ $section_display .= "<div class='quiz_section quiz_begin slide$mlw_qmn_section_count'>";
536
 
537
+ $message_before = wpautop(htmlspecialchars_decode($qmn_quiz_options->message_before, ENT_QUOTES));
538
+ $message_before = apply_filters( 'mlw_qmn_template_variable_quiz_page', $message_before, $qmn_array_for_variables);
539
 
540
+ $section_display .= "<div class='mlw_qmn_message_before'>$message_before</div>";
541
+ if ( 0 == $qmn_quiz_options->contact_info_location ) {
542
  $section_display .= QSM_Contact_Manager::display_fields( $qmn_quiz_options );
543
+ }
544
+ $section_display .= "</div>";
545
+ } else {
546
+ $qmn_json_data["first_page"] = false;
547
+ }
548
  return $section_display;
549
  }
550
 
551
  /**
552
+ * Creates Display For Questions
553
+ *
554
+ * Generates the content for the questions part of the quiz page
555
+ *
556
+ * @since 4.0.0
557
+ * @param array $qmn_quiz_options The database row of the quiz.
558
+ * @param array $qmn_quiz_questions The questions of the quiz.
559
+ * @param array $qmn_quiz_answers The answers of the quiz.
560
+ * @uses QMNPluginHelper:display_question() Displays a question
561
+ * @return string The content for the questions section
562
+ * @deprecated 5.2.0 Use new page system instead
563
+ */
564
+ public function display_questions( $qmn_quiz_options, $qmn_quiz_questions, $qmn_quiz_answers ) {
565
  $question_display = '';
566
  global $mlwQuizMasterNext;
567
  global $qmn_total_questions;
568
  global $mlw_qmn_section_count;
569
  $question_id_list = '';
570
+ foreach ( $qmn_quiz_questions as $mlw_question ) {
 
571
  $question_id_list .= $mlw_question->question_id."Q";
572
  $mlw_qmn_section_count = $mlw_qmn_section_count + 1;
573
  $question_display .= "<div class='quiz_section question-section-id-{$mlw_question->question_id} slide{$mlw_qmn_section_count}'>";
574
 
575
+ $question_display .= $mlwQuizMasterNext->pluginHelper->display_question( $mlw_question->question_type_new, $mlw_question->question_id, $qmn_quiz_options );
576
 
577
+ if ( 0 == $mlw_question->comments ) {
 
578
  $question_display .= "<input type='text' class='mlw_qmn_question_comment' x-webkit-speech id='mlwComment".$mlw_question->question_id."' name='mlwComment".$mlw_question->question_id."' value='".esc_attr(htmlspecialchars_decode($qmn_quiz_options->comment_field_text, ENT_QUOTES))."' onclick='qmnClearField(this)'/>";
579
  $question_display .= "<br />";
580
  }
581
+ if ( 2 == $mlw_question->comments ) {
 
582
  $question_display .= "<textarea cols='70' rows='5' class='mlw_qmn_question_comment' id='mlwComment".$mlw_question->question_id."' name='mlwComment".$mlw_question->question_id."' onclick='qmnClearField(this)'>".htmlspecialchars_decode($qmn_quiz_options->comment_field_text, ENT_QUOTES)."</textarea>";
583
  $question_display .= "<br />";
584
  }
585
 
586
+ // Checks if a hint is entered.
587
  if ( ! empty( $mlw_question->hints ) ) {
588
+ $question_display .= "<div title=\"" . esc_attr( htmlspecialchars_decode( $mlw_question->hints, ENT_QUOTES ) ) . "\" class='qsm_hint mlw_qmn_hint_link'>{$qmn_quiz_options->hint_text}</div>";
589
  $question_display .= "<br /><br />";
590
  }
591
  $question_display .= "</div>";
595
  }
596
 
597
  /**
598
+ * Creates Display For Comment Section
599
+ *
600
+ * Generates the content for the comment section part of the quiz page
601
+ *
602
+ * @since 4.0.0
603
+ * @param array $qmn_quiz_options The database row of the quiz.
604
+ * @param array $qmn_array_for_variables The array of results for the quiz.
605
+ * @return string The content for the comment section
606
+ * @deprecated 5.2.0 Use new page system instead
607
+ */
608
  public function display_comment_section( $qmn_quiz_options, $qmn_array_for_variables ) {
609
  global $mlw_qmn_section_count;
610
  $comment_display = '';
611
+ if ( 0 == $qmn_quiz_options->comment_section ) {
 
612
  $mlw_qmn_section_count = $mlw_qmn_section_count + 1;
613
  $comment_display .= "<div class='quiz_section slide".$mlw_qmn_section_count."'>";
614
  $message_comments = wpautop(htmlspecialchars_decode($qmn_quiz_options->message_comment, ENT_QUOTES));
621
  }
622
 
623
  /**
624
+ * Creates Display For End Section Of Quiz Page
625
+ *
626
+ * Generates the content for the end section of the quiz page
627
+ *
628
+ * @since 4.0.0
629
+ * @param array $qmn_quiz_options The database row of the quiz.
630
+ * @param array $qmn_array_for_variables The array of results for the quiz.
631
+ * @return string The content for the end section
632
+ * @deprecated 5.2.0 Use new page system instead
633
+ */
634
+ public function display_end_section( $qmn_quiz_options, $qmn_array_for_variables ) {
635
  global $mlw_qmn_section_count;
636
  $section_display = '';
637
  $section_display .= "<br />";
638
  $mlw_qmn_section_count = $mlw_qmn_section_count + 1;
639
  $section_display .= "<div class='quiz_section slide$mlw_qmn_section_count quiz_end'>";
640
+ if (! empty( $qmn_quiz_options->message_end_template ) ) {
641
+ $message_end = wpautop( htmlspecialchars_decode( $qmn_quiz_options->message_end_template, ENT_QUOTES));
 
642
  $message_end = apply_filters( 'mlw_qmn_template_variable_quiz_page', $message_end, $qmn_array_for_variables);
643
  $section_display .= "<span class='mlw_qmn_message_end'>$message_end</span>";
644
  $section_display .= "<br /><br />";
649
 
650
  //Legacy Code
651
  ob_start();
652
+ do_action( 'mlw_qmn_end_quiz_section' );
653
+ $section_display .= ob_get_contents();
654
+ ob_end_clean();
655
 
656
  $section_display .= "<input type='submit' class='qsm-btn qsm-submit-btn qmn_btn' value='".esc_attr(htmlspecialchars_decode($qmn_quiz_options->submit_button_text, ENT_QUOTES))."' />";
657
  $section_display .= "</div>";
660
  }
661
 
662
  /**
663
+ * Generates Content Results Page
664
+ *
665
+ * Generates the content for the results page part of the shortcode
666
+ *
667
+ * @since 4.0.0
668
+ * @param array $qmn_quiz_options The database row of the quiz.
669
+ * @param array $qmn_quiz_questions The questions of the quiz.
670
+ * @param array $qmn_quiz_answers The answers of the quiz.
671
+ * @param array $qmn_array_for_variables The array of results for the quiz.
672
+ * @uses QMNQuizManager:submit_results() Perform The Quiz/Survey Submission
673
+ * @return string The content for the results page section
674
+ */
675
+ public function display_results( $qmn_quiz_options, $qmn_quiz_questions, $qmn_quiz_answers, $qmn_array_for_variables ) {
676
+ $result = $this->submit_results( $qmn_quiz_options, $qmn_quiz_questions, $qmn_quiz_answers, $qmn_array_for_variables );
677
  $results_array = $result;
678
  return $results_array['display'];
679
  }
680
 
681
  /**
682
+ * Calls the results page from ajax
683
+ *
684
+ * @since 4.6.0
685
+ * @uses QMNQuizManager:submit_results() Perform The Quiz/Survey Submission
686
+ * @return string The content for the results page section
687
+ */
688
  public function ajax_submit_results() {
689
  global $qmn_allowed_visit;
690
  global $mlwQuizMasterNext;
698
  $qmn_array_for_variables = array(
699
  'quiz_id' => $qmn_quiz_options->quiz_id,
700
  'quiz_name' => $qmn_quiz_options->quiz_name,
701
+ 'quiz_system' => $qmn_quiz_options->system,
702
  );
703
+ echo json_encode( $this->submit_results( $qmn_quiz_options, $qmn_quiz_questions, $qmn_quiz_answers, $qmn_array_for_variables) );
704
  die();
705
  }
706
 
707
  /**
708
+ * Perform The Quiz/Survey Submission
709
+ *
710
+ * Prepares and save the results, prepares and send emails, prepare results page
711
+ *
712
+ * @since 4.6.0
713
+ * @param array $qmn_quiz_options The database row of the quiz.
714
+ * @param array $qmn_quiz_questions The questions of the quiz.
715
+ * @param array $qmn_quiz_answers The answers of the quiz.
716
+ * @param array $qmn_array_for_variables The array of results for the quiz.
717
+ * @uses QMNQuizManager:check_answers() Creates display for beginning section
718
+ * @uses QMNQuizManager:check_comment_section() Creates display for questions
719
+ * @uses QMNQuizManager:display_results_text() Creates display for end section
720
+ * @uses QMNQuizManager:display_social() Creates display for comment section
721
+ * @uses QMNQuizManager:send_user_email() Creates display for end section
722
+ * @uses QMNQuizManager:send_admin_email() Creates display for end section
723
+ * @return string The content for the results page section
724
+ */
725
  public function submit_results( $qmn_quiz_options, $qmn_quiz_questions, $qmn_quiz_answers, $qmn_array_for_variables ) {
726
  global $qmn_allowed_visit;
727
  $result_display = '';
777
  $result_display .= $this->display_social($qmn_quiz_options, $qmn_array_for_variables);
778
  $result_display = apply_filters('qmn_after_social_media', $result_display, $qmn_quiz_options, $qmn_array_for_variables);
779
 
780
+ // Creates our results array.
781
+ $results_array = array(
782
+ intval( $qmn_array_for_variables['timer'] ),
783
  $qmn_array_for_variables['question_answers_array'],
784
+ htmlspecialchars( stripslashes( $qmn_array_for_variables['comments'] ), ENT_QUOTES ),
785
+ 'contact' => $contact_responses,
786
  );
787
+ $results_array = apply_filters( 'qsm_results_array', $results_array, $qmn_array_for_variables );
788
+ $serialized_results = serialize( $results_array );
789
 
790
  global $wpdb;
791
  $table_name = $wpdb->prefix . "mlw_results";
792
  $results_insert = $wpdb->insert(
793
  $table_name,
794
  array(
795
+ 'quiz_id' => $qmn_array_for_variables['quiz_id'],
796
+ 'quiz_name' => $qmn_array_for_variables['quiz_name'],
797
+ 'quiz_system' => $qmn_array_for_variables['quiz_system'],
798
+ 'point_score' => $qmn_array_for_variables['total_points'],
799
  'correct_score' => $qmn_array_for_variables['total_score'],
800
+ 'correct' => $qmn_array_for_variables['total_correct'],
801
+ 'total' => $qmn_array_for_variables['total_questions'],
802
  'name' => $qmn_array_for_variables['user_name'],
803
  'business' => $qmn_array_for_variables['user_business'],
804
  'email' => $qmn_array_for_variables['user_email'],
807
  'user_ip' => $qmn_array_for_variables['user_ip'],
808
  'time_taken' => $qmn_array_for_variables['time_taken'],
809
  'time_taken_real' => date( "Y-m-d H:i:s", strtotime( $qmn_array_for_variables['time_taken'] ) ),
810
+ 'quiz_results' => $serialized_results,
811
  'deleted' => 0
812
  ),
813
  array(
1448
  if ( $qmn_quiz_options->question_from_total != 0 ) {
1449
  $total_questions = $qmn_quiz_options->question_from_total;
1450
  } else {
1451
+ $questions = QSM_Questions::load_questions_by_pages( $qmn_quiz_options->quiz_id );
1452
+ $total_questions = count( $questions );
1453
  }
1454
  $display .= "<style>.quiz_section { display: none; }</style>";
1455
 
php/{class-qmn-review-message.php → classes/class-qmn-review-message.php} RENAMED
File without changes
php/{class-qmn-tracking.php → classes/class-qmn-tracking.php} RENAMED
File without changes
php/{class-qsm-audit.php → classes/class-qsm-audit.php} RENAMED
File without changes
php/{class-qsm-changelog-generator.php → classes/class-qsm-changelog-generator.php} RENAMED
@@ -1,5 +1,13 @@
1
  <?php
2
- if ( ! defined( 'ABSPATH' ) ) exit;
 
 
 
 
 
 
 
 
3
 
4
  /**
5
  * This class pings the GitHub API to load in the changelog for a particular milestone
@@ -8,50 +16,50 @@ if ( ! defined( 'ABSPATH' ) ) exit;
8
  */
9
  class QSM_Changelog_Generator {
10
 
11
- /**
12
- * Gets the changelog as an HTML list. Either echos or returns the list
13
- *
14
- * @since 4.7.0
15
- * @uses QSM_Changelog_Generator::get_changelog Used to retrieve the changelog from GitHub
16
- * @param string $repo The name of the GitHub repo. Should be similar to 'fpcorso/quiz_master_next'
17
- * @param int $milestone The number of the milestone in your GitHub repo
18
- * @param bool $echo Whether to echo or return the HTML list. Defaults to true
19
- * @return string The HTML list is returned if $echo is set to false
20
- */
21
- public static function get_changelog_list( $repo, $milestone, $echo = true ) {
22
-
23
- // Gets the changelog array
24
- $changelog = QSM_Changelog_Generator::get_changelog( $repo, $milestone );
25
-
26
- if ( $changelog && is_array( $changelog ) ) {
27
-
28
- // Creates header for milestone
29
- $display = "<h3>{$changelog["milestone"]["title"]}</h3>";
30
-
31
- // Creates paragraph for description
32
- if ( ! empty( $changelog["milestone"]["description"] ) ) {
33
- $display .= "<p>{$changelog["milestone"]["description"]}</p>";
34
- }
35
-
36
- // Creates paragraph for closed date
37
- $display .= "<p>Closed on {$changelog["milestone"]["closed_date"]}</p>";
38
-
39
- // Converts the issues array into HTML list
40
- $display .= '<ul class="changelog">';
41
- foreach ( $changelog["issues"] as $change ) {
42
- $label_type = $change["labels"][0]["name"];
43
- $display .= "<li class='fixed'><div class='two'>Closed</div>$label_type: {$change['title']} - <a target='_blank' href='{$change['url']}'>Issue #{$change['issue']}</a></li>";
44
- }
45
- $display .= '</ul>';
46
-
47
- // Echos or returns HTML list based on $echo parameter
48
- if ( true === $echo ) {
49
- echo $display;
50
- } else {
51
- return $display;
52
- }
53
- }
54
- }
55
 
56
  /**
57
  * Gets the changelog from GitHub and returns as an array
1
  <?php
2
+ /**
3
+ * Changelog class
4
+ *
5
+ * @package QSM
6
+ */
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
10
+ }
11
 
12
  /**
13
  * This class pings the GitHub API to load in the changelog for a particular milestone
16
  */
17
  class QSM_Changelog_Generator {
18
 
19
+ /**
20
+ * Gets the changelog as an HTML list. Either echos or returns the list
21
+ *
22
+ * @since 4.7.0
23
+ * @uses QSM_Changelog_Generator::get_changelog Used to retrieve the changelog from GitHub
24
+ * @param string $repo The name of the GitHub repo. Should be similar to 'fpcorso/quiz_master_next'
25
+ * @param int $milestone The number of the milestone in your GitHub repo
26
+ * @param bool $echo Whether to echo or return the HTML list. Defaults to true
27
+ * @return string The HTML list is returned if $echo is set to false
28
+ */
29
+ public static function get_changelog_list( $repo, $milestone, $echo = true ) {
30
+
31
+ // Gets the changelog array
32
+ $changelog = QSM_Changelog_Generator::get_changelog( $repo, $milestone );
33
+
34
+ if ( $changelog && is_array( $changelog ) ) {
35
+
36
+ // Creates header for milestone
37
+ $display = "<h3>{$changelog["milestone"]["title"]}</h3>";
38
+
39
+ // Creates paragraph for description
40
+ if ( ! empty( $changelog["milestone"]["description"] ) ) {
41
+ $display .= "<p>{$changelog["milestone"]["description"]}</p>";
42
+ }
43
+
44
+ // Creates paragraph for closed date
45
+ $display .= "<p>Closed on {$changelog["milestone"]["closed_date"]}</p>";
46
+
47
+ // Converts the issues array into HTML list
48
+ $display .= '<ul class="changelog">';
49
+ foreach ( $changelog["issues"] as $change ) {
50
+ $label_type = $change["labels"][0]["name"];
51
+ $display .= "<li class='fixed'><div class='two'>Closed</div>$label_type: {$change['title']} - <a target='_blank' href='{$change['url']}'>Issue #{$change['issue']}</a></li>";
52
+ }
53
+ $display .= '</ul>';
54
+
55
+ // Echos or returns HTML list based on $echo parameter
56
+ if ( true === $echo ) {
57
+ echo $display;
58
+ } else {
59
+ return $display;
60
+ }
61
+ }
62
+ }
63
 
64
  /**
65
  * Gets the changelog from GitHub and returns as an array
php/{class-qsm-contact-manager.php → classes/class-qsm-contact-manager.php} RENAMED
@@ -23,23 +23,26 @@ class QSM_Contact_Manager {
23
  */
24
  public static function display_fields( $options ) {
25
 
26
- $return = '';
27
  $fields_hidden = false;
 
 
28
 
29
- // Prepare name and email values from profile if logged in.
30
- $name = '';
31
- $email = '';
32
  if ( is_user_logged_in() ) {
33
  $current_user = wp_get_current_user();
34
- $name = $current_user->display_name;
35
- $email = $current_user->user_email;
36
  }
37
 
38
  // If user is logged in and the option to allow users to edit is set to no...
39
  if ( is_user_logged_in() && 1 == $options->loggedin_user_contact ) {
40
  // ..then, hide the fields.
41
  $fields_hidden = true;
42
- $return = '<div style="display:none;">';
 
 
43
  }
44
 
45
  // Loads fields.
@@ -54,8 +57,10 @@ class QSM_Contact_Manager {
54
  if ( 1 == $options->user_name && ! $fields_hidden ) {
55
  $class = 'mlwRequiredText qsm_required_text';
56
  }
57
- $return .= "<span class='mlw_qmn_question qsm_question'>" . htmlspecialchars_decode( $options->name_field_text, ENT_QUOTES ) . "</span>";
58
- $return .= "<input type='text' class='$class' x-webkit-speech name='mlwUserName' value='$name' />";
 
 
59
  }
60
 
61
  // Check for comp field.
@@ -64,8 +69,10 @@ class QSM_Contact_Manager {
64
  if ( 1 == $options->user_comp && ! $fields_hidden ) {
65
  $class = 'mlwRequiredText qsm_required_text';
66
  }
67
- $return .= "<span class='mlw_qmn_question qsm_question'>" . htmlspecialchars_decode( $options->business_field_text, ENT_QUOTES ) . "</span>";
68
- $return .= "<input type='text' class='$class' x-webkit-speech name='mlwUserComp' value='' />";
 
 
69
  }
70
 
71
  // Check for email field.
@@ -74,8 +81,10 @@ class QSM_Contact_Manager {
74
  if ( 1 == $options->user_email && ! $fields_hidden ) {
75
  $class = 'mlwRequiredText qsm_required_text';
76
  }
77
- $return .= "<span class='mlw_qmn_question qsm_question'>" . htmlspecialchars_decode( $options->email_field_text, ENT_QUOTES ) . "</span>";
78
- $return .= "<input type='email' class='mlwEmail $class' x-webkit-speech name='mlwUserEmail' value='$email' />";
 
 
79
  }
80
 
81
  // Check for phone field.
@@ -84,8 +93,10 @@ class QSM_Contact_Manager {
84
  if ( 1 == $options->user_phone && ! $fields_hidden ) {
85
  $class = 'mlwRequiredText qsm_required_text';
86
  }
87
- $return .= "<span class='mlw_qmn_question qsm_question'>" . htmlspecialchars_decode( $options->phone_field_text, ENT_QUOTES ) . "</span>";
88
- $return .= "<input type='text' class='$class' x-webkit-speech name='mlwUserPhone' value='' />";
 
 
89
  }
90
  } elseif ( ! empty( $fields ) && is_array( $fields ) ) {
91
 
@@ -93,55 +104,69 @@ class QSM_Contact_Manager {
93
  $total_fields = count( $fields );
94
  for ( $i = 0; $i < $total_fields; $i++ ) {
95
 
96
- $return .= '<div class="qsm_contact_div">';
97
  $class = '';
98
- $return .= "<span class='mlw_qmn_question qsm_question'>{$fields[ $i ]['label']}</span>";
99
  $value = '';
100
- if ( 'name' == $fields[ $i ]['use'] ) {
101
- $value = $name;
102
- }
103
- if ( 'email' == $fields[ $i ]['use'] ) {
104
- $value = $email;
105
- }
106
-
107
- // Switch for contact field type.
108
- switch ( $fields[ $i ]['type'] ) {
109
- case 'text':
110
- if ( ( 'true' === $fields[ $i ]["required"] || true === $fields[ $i ]["required"] ) && ! $fields_hidden ) {
111
- $class = 'mlwRequiredText qsm_required_text';
112
- }
113
- $return .= "<input type='text' class='$class' x-webkit-speech name='contact_field_$i' value='$value' />";
114
- break;
115
-
116
- case 'email':
117
- if ( ( 'true' === $fields[ $i ]["required"] || true === $fields[ $i ]["required"] ) && ! $fields_hidden ) {
118
- $class = 'mlwRequiredText qsm_required_text';
119
- }
120
- $return .= "<input type='text' class='mlwEmail $class' x-webkit-speech name='contact_field_$i' value='$value' />";
121
- break;
122
-
123
- case 'checkbox':
124
- if ( ( 'true' === $fields[ $i ]["required"] || true === $fields[ $i ]["required"] ) && ! $fields_hidden ) {
125
- $class = 'mlwRequiredAccept qsm_required_accept';
126
- }
127
- $return .= "<input type='checkbox' class='$class' x-webkit-speech name='contact_field_$i' value='checked' />";
128
- break;
129
-
130
- default:
131
- break;
132
- }
133
-
134
- $return .= '</div>';
 
 
 
 
 
 
 
 
 
 
 
135
  }
136
  }
137
 
 
 
 
138
  // If logged in user should see fields.
139
  if ( is_user_logged_in() && 1 == $options->loggedin_user_contact ) {
140
- $return .= '</div>';
 
 
141
  }
142
 
143
  // Return contact field HTML.
144
- return $return;
145
  }
146
 
147
  /**
23
  */
24
  public static function display_fields( $options ) {
25
 
 
26
  $fields_hidden = false;
27
+ $name = '';
28
+ $email = '';
29
 
30
+ ob_start();
31
+
32
+ // Prepares name and email if user is logged in.
33
  if ( is_user_logged_in() ) {
34
  $current_user = wp_get_current_user();
35
+ $name = $current_user->display_name;
36
+ $email = $current_user->user_email;
37
  }
38
 
39
  // If user is logged in and the option to allow users to edit is set to no...
40
  if ( is_user_logged_in() && 1 == $options->loggedin_user_contact ) {
41
  // ..then, hide the fields.
42
  $fields_hidden = true;
43
+ ?>
44
+ <div style="display:none;">
45
+ <?php
46
  }
47
 
48
  // Loads fields.
57
  if ( 1 == $options->user_name && ! $fields_hidden ) {
58
  $class = 'mlwRequiredText qsm_required_text';
59
  }
60
+ ?>
61
+ <span class='mlw_qmn_question qsm_question'><?php echo htmlspecialchars_decode( $options->name_field_text, ENT_QUOTES ); ?></span>
62
+ <input type='text' class='<?php echo esc_attr( $class ); ?>' x-webkit-speech name='mlwUserName' value='<?php echo esc_attr( $name ); ?>' />
63
+ <?php
64
  }
65
 
66
  // Check for comp field.
69
  if ( 1 == $options->user_comp && ! $fields_hidden ) {
70
  $class = 'mlwRequiredText qsm_required_text';
71
  }
72
+ ?>
73
+ <span class='mlw_qmn_question qsm_question'><?php echo htmlspecialchars_decode( $options->business_field_text, ENT_QUOTES ); ?></span>
74
+ <input type='text' class='<?php echo esc_attr( $class ); ?>' x-webkit-speech name='mlwUserComp' value='' />
75
+ <?php
76
  }
77
 
78
  // Check for email field.
81
  if ( 1 == $options->user_email && ! $fields_hidden ) {
82
  $class = 'mlwRequiredText qsm_required_text';
83
  }
84
+ ?>
85
+ <span class='mlw_qmn_question qsm_question'><?php echo htmlspecialchars_decode( $options->email_field_text, ENT_QUOTES ); ?></span>
86
+ <input type='email' class='mlwEmail <?php echo esc_attr( $class ); ?>' x-webkit-speech name='mlwUserEmail' value='<?php echo esc_attr( $email ); ?>' />
87
+ <?php
88
  }
89
 
90
  // Check for phone field.
93
  if ( 1 == $options->user_phone && ! $fields_hidden ) {
94
  $class = 'mlwRequiredText qsm_required_text';
95
  }
96
+ ?>
97
+ <span class='mlw_qmn_question qsm_question'><?php echo htmlspecialchars_decode( $options->phone_field_text, ENT_QUOTES ); ?></span>
98
+ <input type='text' class='<?php echo esc_attr( $class ); ?>' x-webkit-speech name='mlwUserPhone' value='' />
99
+ <?php
100
  }
101
  } elseif ( ! empty( $fields ) && is_array( $fields ) ) {
102
 
104
  $total_fields = count( $fields );
105
  for ( $i = 0; $i < $total_fields; $i++ ) {
106
 
 
107
  $class = '';
 
108
  $value = '';
109
+ ?>
110
+ <div class="qsm_contact_div">
111
+ <span class='mlw_qmn_question qsm_question'><?php echo $fields[ $i ]['label']; ?></span>
112
+ <?php
113
+ if ( 'name' == $fields[ $i ]['use'] ) {
114
+ $value = $name;
115
+ }
116
+ if ( 'email' == $fields[ $i ]['use'] ) {
117
+ $value = $email;
118
+ }
119
+
120
+ // Switch for contact field type.
121
+ switch ( $fields[ $i ]['type'] ) {
122
+ case 'text':
123
+ if ( ( 'true' === $fields[ $i ]["required"] || true === $fields[ $i ]["required"] ) && ! $fields_hidden ) {
124
+ $class = 'mlwRequiredText qsm_required_text';
125
+ }
126
+ ?>
127
+ <input type='text' class='<?php echo esc_attr( $class ); ?>' x-webkit-speech name='contact_field_<?php echo $i; ?>' value='<?php echo esc_attr( $value ); ?>' />
128
+ <?php
129
+ break;
130
+
131
+ case 'email':
132
+ if ( ( 'true' === $fields[ $i ]["required"] || true === $fields[ $i ]["required"] ) && ! $fields_hidden ) {
133
+ $class = 'mlwRequiredText qsm_required_text';
134
+ }
135
+ ?>
136
+ <input type='text' class='mlwEmail <?php echo esc_attr( $class ); ?>' x-webkit-speech name='contact_field_<?php echo $i; ?>' value='<?php echo esc_attr( $value ); ?>' />
137
+ <?php
138
+ break;
139
+
140
+ case 'checkbox':
141
+ if ( ( 'true' === $fields[ $i ]["required"] || true === $fields[ $i ]["required"] ) && ! $fields_hidden ) {
142
+ $class = 'mlwRequiredAccept qsm_required_accept';
143
+ }
144
+ ?>
145
+ <input type='checkbox' class='<?php echo esc_attr( $class ); ?>' x-webkit-speech name='contact_field_<?php echo $i; ?>' value='checked' />
146
+ <?php
147
+ break;
148
+
149
+ default:
150
+ break;
151
+ }
152
+ ?>
153
+ </div>
154
+ <?php
155
  }
156
  }
157
 
158
+ // Extend contact fields section.
159
+ do_action( 'qsm_contact_fields_end' );
160
+
161
  // If logged in user should see fields.
162
  if ( is_user_logged_in() && 1 == $options->loggedin_user_contact ) {
163
+ ?>
164
+ </div>
165
+ <?php
166
  }
167
 
168
  // Return contact field HTML.
169
+ return ob_get_clean();
170
  }
171
 
172
  /**
php/{class-qsm-fields.php → classes/class-qsm-fields.php} RENAMED
File without changes
php/{class-qsm-install.php → classes/class-qsm-install.php} RENAMED
@@ -855,7 +855,11 @@ class QSM_Install {
855
 
856
  require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
857
  dbDelta( $sql );
858
- }
 
 
 
 
859
  }
860
 
861
  /**
855
 
856
  require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
857
  dbDelta( $sql );
858
+ }
859
+
860
+ global $mlwQuizMasterNext;
861
+ $mlwQuizMasterNext->register_quiz_post_types();
862
+ flush_rewrite_rules();
863
  }
864
 
865
  /**
php/classes/class-qsm-questions.php ADDED
@@ -0,0 +1,316 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * File that contains class for questions.
4
+ *
5
+ * @package QSM
6
+ */
7
+
8
+ /**
9
+ * Class that handles all creating, saving, and deleting of questions.
10
+ *
11
+ * @since 5.2.0
12
+ */
13
+ class QSM_Questions {
14
+
15
+ /**
16
+ * Loads single question using question ID
17
+ *
18
+ * @since 5.2.0
19
+ * @param int $question_id The ID of the question.
20
+ * @return array The data for the question.
21
+ */
22
+ public static function load_question( $question_id ) {
23
+ global $wpdb;
24
+ $question_id = intval( $question_id );
25
+ $question = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}mlw_questions WHERE question_id = %d LIMIT 1", $question_id ), 'ARRAY_A' );
26
+ if ( ! is_null( $question ) ) {
27
+ // Prepare answers.
28
+ $answers = maybe_unserialize( $question['answer_array'] );
29
+ if ( ! is_array( $answers ) ) {
30
+ $answers = array();
31
+ }
32
+ $question['answers'] = $answers;
33
+
34
+ $settings = maybe_unserialize( $question['question_settings'] );
35
+ if ( ! is_array( $settings ) ) {
36
+ $settings = array( 'required' => 1 );
37
+ }
38
+ $question['settings'] = $settings;
39
+
40
+ return $question;
41
+ }
42
+ return array();
43
+ }
44
+
45
+ /**
46
+ * Loads questions for a quiz using the new page system
47
+ *
48
+ * @since 5.2.0
49
+ * @param int $quiz_id The ID of the quiz.
50
+ * @return array The array of questions.
51
+ */
52
+ public static function load_questions_by_pages( $quiz_id ) {
53
+
54
+ // Prepares our variables.
55
+ global $wpdb;
56
+ global $mlwQuizMasterNext;
57
+ $quiz_id = intval( $quiz_id );
58
+ $question_ids = array();
59
+ $questions = array();
60
+ $page_for_ids = array();
61
+
62
+ // Gets the pages for the quiz.
63
+ $mlwQuizMasterNext->pluginHelper->prepare_quiz( $quiz_id );
64
+ $pages = $mlwQuizMasterNext->pluginHelper->get_quiz_setting( 'pages', array() );
65
+
66
+ // Get all question IDs needed.
67
+ $total_pages = count( $pages );
68
+ for ( $i = 0; $i < $total_pages; $i++ ) {
69
+ foreach ( $pages[ $i ] as $question ) {
70
+ $question_id = intval( $question );
71
+ $question_ids[] = $question_id;
72
+ $page_for_ids[ $question_id ] = $i;
73
+ }
74
+ }
75
+
76
+ // If we have any question IDs, get the questions.
77
+ if ( count( $question_ids ) > 0 ) {
78
+
79
+ $question_sql = implode( ', ', $question_ids );
80
+
81
+ // Get all questions.
82
+ $question_array = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}mlw_questions WHERE question_id IN ($question_sql)", 'ARRAY_A' );
83
+
84
+ // Loop through questions and prepare serialized data.
85
+ foreach ( $question_array as $question ) {
86
+
87
+ // Prepare answers.
88
+ $answers = maybe_unserialize( $question['answer_array'] );
89
+ if ( ! is_array( $answers ) ) {
90
+ $answers = array();
91
+ }
92
+ $question['answers'] = $answers;
93
+
94
+ // Prepares settings.
95
+ $settings = maybe_unserialize( $question['question_settings'] );
96
+ if ( ! is_array( $settings ) ) {
97
+ $settings = array( 'required' => 1 );
98
+ }
99
+ $question['settings'] = $settings;
100
+
101
+ // Get the page.
102
+ $question_id = intval( $question['question_id'] );
103
+ $question['page'] = intval( $page_for_ids[ $question_id ] );
104
+
105
+ $questions[ $question_id ] = $question;
106
+ }
107
+ } else {
108
+ // If we do not have pages on this quiz yet, use older load_questions and add page to them.
109
+ $questions = self::load_questions( $quiz_id );
110
+ foreach ( $questions as $key => $question ) {
111
+ $questions[ $key ]['page'] = isset( $question['page'] ) ? $question['page'] : 0;
112
+ }
113
+ }
114
+ return $questions;
115
+ }
116
+
117
+ /**
118
+ * Loads questions for a quiz
119
+ *
120
+ * @since 5.2.0
121
+ * @param int $quiz_id The ID of the quiz.
122
+ * @return array The array of questions.
123
+ */
124
+ public static function load_questions( $quiz_id ) {
125
+
126
+ global $wpdb;
127
+ $question_array = array();
128
+
129
+ // Get all questions.
130
+ if ( 0 !== $quiz_id ) {
131
+ $quiz_id = intval( $quiz_id );
132
+ $questions = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}mlw_questions WHERE quiz_id=%d AND deleted='0' ORDER BY question_order ASC", $quiz_id ), 'ARRAY_A' );
133
+ } else {
134
+ $questions = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}mlw_questions WHERE deleted='0' ORDER BY question_order ASC", 'ARRAY_A' );
135
+ }
136
+
137
+ // Loop through questions and prepare serialized data.
138
+ foreach ( $questions as $question ) {
139
+
140
+ // Prepare answers.
141
+ $answers = maybe_unserialize( $question['answer_array'] );
142
+ if ( ! is_array( $answers ) ) {
143
+ $answers = array();
144
+ }
145
+ $question['answers'] = $answers;
146
+
147
+ $settings = maybe_unserialize( $question['question_settings'] );
148
+ if ( ! is_array( $settings ) ) {
149
+ $settings = array( 'required' => 1 );
150
+ }
151
+ $question['settings'] = $settings;
152
+
153
+ $question_array[ $question['question_id'] ] = $question;
154
+ }
155
+ return $question_array;
156
+ }
157
+
158
+ /**
159
+ * Creates a new question
160
+ *
161
+ * @since 5.2.0
162
+ * @param array $data The question data.
163
+ * @param array $answers The answers for the question.
164
+ * @param array $settings Any settings for the question.
165
+ * @throws Exception Throws exception if wpdb query results in error.
166
+ * @return int The ID of the question that was created.
167
+ */
168
+ public static function create_question( $data, $answers = array(), $settings = array() ) {
169
+ return self::create_save_question( $data, $answers, $settings );
170
+ }
171
+
172
+ /**
173
+ * Saves a question
174
+ *
175
+ * @since 5.2.0
176
+ * @param int $question_id The ID of the question to be saved.
177
+ * @param array $data The question data.
178
+ * @param array $answers The answers for the question.
179
+ * @param array $settings Any settings for the question.
180
+ * @throws Exception Throws exception if wpdb query results in error.
181
+ * @return int The ID of the question that was saved.
182
+ */
183
+ public static function save_question( $question_id, $data, $answers = array(), $settings = array() ) {
184
+ $data['ID'] = intval( $question_id );
185
+ return self::create_save_question( $data, $answers, $settings, false );
186
+ }
187
+
188
+ /**
189
+ * Deletes a question
190
+ *
191
+ * @since 5.2.0
192
+ * @param int $question_id The ID for the question.
193
+ * @throws Exception Throws exception if wpdb query results in error.
194
+ * @return bool True if successful
195
+ */
196
+ public static function delete_question( $question_id ) {
197
+ $results = $wpdb->update(
198
+ $wpdb->prefix . 'mlw_questions',
199
+ array(
200
+ 'deleted' => 1,
201
+ ),
202
+ array( 'question_id' => intval( $question_id ) ),
203
+ array(
204
+ '%d',
205
+ ),
206
+ array( '%d' )
207
+ );
208
+
209
+ if ( false === $results ) {
210
+ $msg = $wpdb->last_error . ' from ' . $wpdb->last_query;
211
+ $mlwQuizMasterNext->log_manager->add( 'Error when deleting question', $msg, 0, 'error' );
212
+ throw new Exception( $msg );
213
+ }
214
+
215
+ return true;
216
+ }
217
+
218
+ /**
219
+ * Creates or saves a question
220
+ *
221
+ * This is used internally. Use create_question or save_question instead.
222
+ *
223
+ * @since 5.2.0
224
+ * @param array $data The question data.
225
+ * @param array $answers The answers for the question.
226
+ * @param array $settings Any settings for the question.
227
+ * @param bool $is_creating True if question is being created, false if being saved.
228
+ * @throws Exception Throws exception if wpdb query results in error.
229
+ * @return int The ID of the question that was created/saved.
230
+ */
231
+ private static function create_save_question( $data, $answers, $settings, $is_creating = true ) {
232
+ global $wpdb;
233
+
234
+ // Prepare defaults and parse.
235
+ $defaults = array(
236
+ 'quiz_id' => 0,
237
+ 'type' => '0',
238
+ 'name' => '',
239
+ 'answer_info' => '',
240
+ 'comments' => '1',
241
+ 'hint' => '',
242
+ 'order' => 1,
243
+ 'category' => '',
244
+ );
245
+ $data = wp_parse_args( $data, $defaults );
246
+
247
+ $defaults = array(
248
+ 'required' => 1,
249
+ );
250
+ $settings = wp_parse_args( $settings, $defaults );
251
+
252
+ foreach ( $answers as $key => $answer ) {
253
+ $answers[ $key ] = array(
254
+ htmlspecialchars( stripslashes( $answer[0] ), ENT_QUOTES ),
255
+ floatval( $answer[1] ),
256
+ intval( $answer[2] ),
257
+ );
258
+ }
259
+
260
+ $values = array(
261
+ 'quiz_id' => intval( $data['quiz_id'] ),
262
+ 'question_name' => trim( preg_replace( '/\s+/', ' ', htmlspecialchars( nl2br( wp_kses_post( stripslashes( $data['name'] ) ) ), ENT_QUOTES ) ) ),
263
+ 'answer_array' => serialize( $answers ),
264
+ 'question_answer_info' => htmlspecialchars( stripslashes( $data['answer_info'] ), ENT_QUOTES ),
265
+ 'comments' => htmlspecialchars( stripslashes( $data['comments'] ), ENT_QUOTES ),
266
+ 'hints' => htmlspecialchars( stripslashes( $data['hint'] ), ENT_QUOTES ),
267
+ 'question_order' => intval( $data['order'] ),
268
+ 'question_type_new' => sanitize_text_field( $data['type'] ),
269
+ 'question_settings' => serialize( $settings ),
270
+ 'category' => sanitize_text_field( $data['category'] ),
271
+ 'deleted' => 0,
272
+ );
273
+
274
+ $types = array(
275
+ '%d',
276
+ '%s',
277
+ '%s',
278
+ '%s',
279
+ '%d',
280
+ '%s',
281
+ '%d',
282
+ '%s',
283
+ '%s',
284
+ '%s',
285
+ '%d',
286
+ );
287
+
288
+ if ( $is_creating ) {
289
+ $results = $wpdb->insert(
290
+ $wpdb->prefix . 'mlw_questions',
291
+ $values,
292
+ $types
293
+ );
294
+ } else {
295
+ $results = $wpdb->update(
296
+ $wpdb->prefix . 'mlw_questions',
297
+ $values,
298
+ array( 'question_id' => intval( $data['ID'] ) ),
299
+ $types,
300
+ array( '%d' )
301
+ );
302
+ }
303
+
304
+ if ( false === $results ) {
305
+ $msg = $wpdb->last_error . ' from ' . $wpdb->last_query;
306
+ $mlwQuizMasterNext->log_manager->add( 'Error when creating/saving question', $msg, 0, 'error' );
307
+ throw new Exception( $msg );
308
+ }
309
+
310
+ if ( $is_creating ) {
311
+ return $wpdb->insert_id;
312
+ } else {
313
+ return $data['ID'];
314
+ }
315
+ }
316
+ }
php/{class-qsm-settings.php → classes/class-qsm-settings.php} RENAMED
File without changes
php/classes/index.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+
3
+ die("Error: Unauthorized Access");
4
+ ?>
php/options-page-questions-tab.php DELETED
@@ -1,705 +0,0 @@
1
- <?php
2
- if ( ! defined( 'ABSPATH' ) ) exit;
3
-
4
- /**
5
- * Adds the settings for questions tab to the Quiz Settings page.
6
- *
7
- * @return void
8
- * @since 4.4.0
9
- */
10
- function qsm_settings_questions_tab() {
11
- global $mlwQuizMasterNext;
12
- $mlwQuizMasterNext->pluginHelper->register_quiz_settings_tabs( __( "Questions", 'quiz-master-next' ), 'qsm_options_questions_tab_content' );
13
- }
14
- add_action( "plugins_loaded", 'qsm_settings_questions_tab', 5 );
15
-
16
-
17
- /**
18
- * Adds the content for the options for questions tab.
19
- *
20
- * @return void
21
- * @since 4.4.0
22
- */
23
- function qsm_options_questions_tab_content() {
24
- ?>
25
-
26
- <script>
27
- var answer_text = '<?php _e('Answer', 'quiz-master-next'); ?>';
28
- </script>
29
- <?php
30
- wp_enqueue_script('qmn_admin_question_js', plugins_url( '../js/qsm-admin-question.js' , __FILE__ ), array( 'jquery-ui-sortable' ) );
31
- wp_enqueue_style('qmn_admin_question_css', plugins_url( '../css/qsm-admin-question.css' , __FILE__ ) );
32
- wp_enqueue_script( 'math_jax', '//cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-MML-AM_CHTML' );
33
-
34
- global $wpdb;
35
- global $mlwQuizMasterNext;
36
- $quiz_id = $_GET["quiz_id"];
37
-
38
- //Re-ordering questions
39
- if ( isset( $_POST['qmn_question_order_nonce'] ) && wp_verify_nonce( $_POST['qmn_question_order_nonce'], 'qmn_question_order' ) ) {
40
- $list_of_questions = explode( ',', $_POST["save_question_order_input"] );
41
- $question_order = 0;
42
- $success = true;
43
- foreach( $list_of_questions as $id ) {
44
- $question_order++;
45
- $update_question_id = explode( '_', $id );
46
- $results = $wpdb->update(
47
- $wpdb->prefix . "mlw_questions",
48
- array(
49
- 'question_order' => $question_order
50
- ),
51
- array( 'question_id' => $update_question_id[1] ),
52
- array(
53
- '%d'
54
- ),
55
- array( '%d' )
56
- );
57
- if ( $results ) {
58
- $success = false;
59
- }
60
- }
61
- if ( ! $success ) {
62
- $mlwQuizMasterNext->alertManager->newAlert(__('The question order has been updated successfully.', 'quiz-master-next'), 'success');
63
- $mlwQuizMasterNext->audit_manager->new_audit( "Question Order Has Been Updated On Quiz: $quiz_id" );
64
- }
65
- }
66
-
67
- // Edit question
68
- if ( isset( $_POST['qsm_question_save_nonce'] ) && wp_verify_nonce( $_POST['qsm_question_save_nonce'], 'qsm_question_save' ) && isset( $_POST["question_submission"] ) && "edit_question" == $_POST["question_submission"] ) {
69
-
70
- // Variables from edit question form
71
- $edit_question_name = trim( preg_replace( '/\s+/',' ', htmlspecialchars( nl2br( wp_kses_post( stripslashes( $_POST["question_name"] ) ) ), ENT_QUOTES ) ) );
72
- $edit_question_answer_info = htmlspecialchars( stripslashes( $_POST["correct_answer_info"] ), ENT_QUOTES );
73
- $edit_question_id = intval( $_POST["question_id"] );
74
- $edit_question_type = sanitize_text_field( $_POST["question_type"] );
75
- $edit_comments = htmlspecialchars( $_POST["comments"], ENT_QUOTES );
76
- $edit_hint = htmlspecialchars( stripslashes( $_POST["hint"] ), ENT_QUOTES );
77
- $edit_question_order = intval( $_POST["new_question_order"] );
78
- $total_answers = intval( $_POST["new_question_answer_total"] );
79
-
80
- // Checks if a category was selected or entered
81
- if ( isset( $_POST["new_category"] ) ) {
82
-
83
- $edit_category = sanitize_text_field( $_POST["new_category"] );
84
-
85
- // Checks if the new category radio was selected
86
- if ( 'new_category' == $edit_category ) {
87
- $edit_category = sanitize_text_field( stripslashes( $_POST["new_new_category"] ) );
88
- }
89
- } else {
90
- $edit_category = '';
91
- }
92
-
93
- // Retrieves question settings and sets required field
94
- $row_settings = $wpdb->get_row( $wpdb->prepare( "SELECT question_settings FROM {$wpdb->prefix}mlw_questions WHERE question_id=%d", $edit_question_id ) );
95
- if ( is_serialized( $row_settings->question_settings ) && is_array( @unserialize( $row_settings->question_settings ) ) ) {
96
- $question_settings = @unserialize( $row_settings->question_settings );
97
- } else {
98
- $question_settings = array();
99
- $question_settings['required'] = intval( $_POST["required"] );
100
- }
101
- if ( ! isset( $question_settings['required'] ) ) {
102
- $question_settings['required'] = intval( $_POST["required"] );
103
- }
104
- $question_settings['required'] = intval( $_POST["required"] );
105
- $question_settings = serialize( $question_settings );
106
-
107
- // Cycles through answers
108
- $i = 1;
109
- $answer_array = array();
110
- while ( $i <= $total_answers ) {
111
-
112
- // Checks if that answer exists and it's not empty
113
- if ( isset( $_POST["answer_$i"] ) && ( '0' == $_POST["answer_$i"] || ! empty( $_POST["answer_$i"] ) ) ) {
114
-
115
- // Checks if the answer was marked as correct
116
- $correct = 0;
117
- if ( isset( $_POST["answer_$i"."_correct"] ) && 1 == $_POST["answer_$i"."_correct"] ) {
118
- $correct = 1;
119
- }
120
-
121
- // Prepares this answer array
122
- $answer_array[] = array(
123
- htmlspecialchars( stripslashes( $_POST["answer_$i"] ), ENT_QUOTES ),
124
- floatval( $_POST["answer_".$i."_points"] ),
125
- $correct
126
- );
127
- }
128
- $i++;
129
- }
130
-
131
- $answer_array = serialize( $answer_array );
132
- $quiz_id = intval( $_POST["quiz_id"] );
133
-
134
- // Updates question row in table
135
- $results = $wpdb->update(
136
- $wpdb->prefix . "mlw_questions",
137
- array(
138
- 'question_name' => $edit_question_name,
139
- 'answer_array' => $answer_array,
140
- 'question_answer_info' => $edit_question_answer_info,
141
- 'comments' => $edit_comments,
142
- 'hints' => $edit_hint,
143
- 'question_order' => $edit_question_order,
144
- 'question_type_new' => $edit_question_type,
145
- 'question_settings' => $question_settings,
146
- 'category' => $edit_category
147
- ),
148
- array( 'question_id' => $edit_question_id ),
149
- array(
150
- '%s',
151
- '%s',
152
- '%s',
153
- '%d',
154
- '%s',
155
- '%d',
156
- '%s',
157
- '%s',
158
- '%s'
159
- ),
160
- array( '%d' )
161
- );
162
- if ( false !== $results ) {
163
- $mlwQuizMasterNext->alertManager->newAlert(__('The question has been updated successfully.', 'quiz-master-next'), 'success');
164
- $mlwQuizMasterNext->audit_manager->new_audit( "Question Has Been Edited: $edit_question_name" );
165
- } else {
166
- $mlwQuizMasterNext->alertManager->newAlert(sprintf(__('There has been an error in this action. Please share this with the developer. Error Code: %s', 'quiz-master-next'), '0004'), 'error');
167
- $mlwQuizMasterNext->log_manager->add("Error 0004", $wpdb->last_error.' from '.$wpdb->last_query, 0, 'error');
168
- }
169
- }
170
-
171
- // Delete question from quiz
172
- if ( isset( $_POST['qsm_delete_question_nonce'] ) && wp_verify_nonce( $_POST['qsm_delete_question_nonce'], 'qsm_delete_question' ) ) {
173
-
174
- // Variables from delete question form
175
- $mlw_question_id = intval( $_POST["delete_question_id"] );
176
- $quiz_id = intval( $_POST["quiz_id"] );
177
-
178
- $results = $wpdb->update(
179
- $wpdb->prefix . "mlw_questions",
180
- array(
181
- 'deleted' => 1
182
- ),
183
- array( 'question_id' => $mlw_question_id ),
184
- array(
185
- '%d'
186
- ),
187
- array( '%d' )
188
- );
189
- if ( false !== $results ) {
190
- $mlwQuizMasterNext->alertManager->newAlert(__('The question has been deleted successfully.', 'quiz-master-next'), 'success');
191
- $mlwQuizMasterNext->audit_manager->new_audit( "Question Has Been Deleted: $mlw_question_id" );
192
- } else {
193
- $mlwQuizMasterNext->alertManager->newAlert(sprintf(__('There has been an error in this action. Please share this with the developer. Error Code: %s', 'quiz-master-next'), '0005'), 'error');
194
- $mlwQuizMasterNext->log_manager->add("Error 0005", $wpdb->last_error.' from '.$wpdb->last_query, 0, 'error');
195
- }
196
- }
197
-
198
- // Duplicate Questions
199
- if ( isset( $_POST['qsm_duplicate_question_nonce'] ) && wp_verify_nonce( $_POST['qsm_duplicate_question_nonce'], 'qsm_duplicate_question' ) ) {
200
-
201
- // Variables from delete question form
202
- $mlw_question_id = intval( $_POST["duplicate_question_id"] );
203
- $quiz_id = intval( $_POST["quiz_id"] );
204
-
205
- $mlw_original = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}mlw_questions WHERE question_id=%d", $mlw_question_id ), ARRAY_A );
206
-
207
- $results = $wpdb->insert(
208
- $wpdb->prefix."mlw_questions",
209
- array(
210
- 'quiz_id' => $mlw_original['quiz_id'],
211
- 'question_name' => $mlw_original['question_name'],
212
- 'answer_array' => $mlw_original['answer_array'],
213
- 'answer_one' => $mlw_original['answer_one'],
214
- 'answer_one_points' => $mlw_original['answer_one_points'],
215
- 'answer_two' => $mlw_original['answer_two'],
216
- 'answer_two_points' => $mlw_original['answer_two_points'],
217
- 'answer_three' => $mlw_original['answer_three'],
218
- 'answer_three_points' => $mlw_original['answer_three_points'],
219
- 'answer_four' => $mlw_original['answer_four'],
220
- 'answer_four_points' => $mlw_original['answer_four_points'],
221
- 'answer_five' => $mlw_original['answer_five'],
222
- 'answer_five_points' => $mlw_original['answer_five_points'],
223
- 'answer_six' => $mlw_original['answer_six'],
224
- 'answer_six_points' => $mlw_original['answer_six_points'],
225
- 'correct_answer' => $mlw_original['correct_answer'],
226
- 'question_answer_info' => $mlw_original['question_answer_info'],
227
- 'comments' => $mlw_original['comments'],
228
- 'hints' => $mlw_original['hints'],
229
- 'question_order' => $mlw_original['question_order'],
230
- 'question_type_new' => $mlw_original['question_type_new'],
231
- 'question_settings' => $mlw_original['question_settings'],
232
- 'category' => $mlw_original['category'],
233
- 'deleted' => $mlw_original['deleted']
234
- ),
235
- array(
236
- '%d',
237
- '%s',
238
- '%s',
239
- '%s',
240
- '%d',
241
- '%s',
242
- '%d',
243
- '%s',
244
- '%d',
245
- '%s',
246
- '%d',
247
- '%s',
248
- '%d',
249
- '%s',
250
- '%d',
251
- '%d',
252
- '%s',
253
- '%d',
254
- '%s',
255
- '%d',
256
- '%s',
257
- '%s',
258
- '%s',
259
- '%d'
260
- )
261
- );
262
-
263
- if ( false !== $results ) {
264
- $mlwQuizMasterNext->alertManager->newAlert(__('The question has been duplicated successfully.', 'quiz-master-next'), 'success');
265
- $mlwQuizMasterNext->audit_manager->new_audit( "Question Has Been Duplicated: $mlw_question_id" );
266
- } else {
267
- $mlwQuizMasterNext->alertManager->newAlert(sprintf(__('There has been an error in this action. Please share this with the developer. Error Code: %s', 'quiz-master-next'), '0019'), 'error');
268
- $mlwQuizMasterNext->log_manager->add("Error 00019", $wpdb->last_error.' from '.$wpdb->last_query, 0, 'error');
269
- }
270
- }
271
-
272
- // Submit new question into database
273
- if ( isset( $_POST['qsm_question_save_nonce'] ) && wp_verify_nonce( $_POST['qsm_question_save_nonce'], 'qsm_question_save' ) && isset( $_POST["question_submission"] ) && "new_question" == $_POST["question_submission"] ) {
274
-
275
- // Variables from new question form
276
- $question_name = trim( preg_replace( '/\s+/',' ', htmlspecialchars( nl2br( wp_kses_post( stripslashes( $_POST["question_name"] ) ) ), ENT_QUOTES ) ) );
277
- $question_answer_info = htmlspecialchars( stripslashes( $_POST["correct_answer_info"] ), ENT_QUOTES );
278
- $question_type = sanitize_text_field( $_POST["question_type"] );
279
- $comments = htmlspecialchars( $_POST["comments"], ENT_QUOTES );
280
- $hint = htmlspecialchars( stripslashes( $_POST["hint"] ), ENT_QUOTES );
281
- $new_question_order = intval( $_POST["new_question_order"] );
282
- $total_answers = intval( $_POST["new_question_answer_total"] );
283
-
284
- // Checks if a category was selected or entered
285
- if ( isset( $_POST['new_category'] ) ) {
286
-
287
- $qmn_category = sanitize_text_field( $_POST["new_category"] );
288
-
289
- // Checks if the new category radio was selected
290
- if ( 'new_category' == $qmn_category ) {
291
- $qmn_category = sanitize_text_field( stripslashes( $_POST["new_new_category"] ) );
292
- }
293
- } else {
294
- $qmn_category = '';
295
- }
296
-
297
- // Creates question settings array
298
- $question_settings = array();
299
- $question_settings['required'] = intval($_POST["required"]);
300
- $question_settings = serialize($question_settings);
301
-
302
- // Cycles through answers
303
- $i = 1;
304
- $answer_array = array();
305
- while ( $i <= $total_answers ) {
306
-
307
- // Checks if that answer exists and it's not empty
308
- if ( isset( $_POST["answer_$i"] ) && ( '0' == $_POST["answer_$i"] || ! empty( $_POST["answer_$i"] ) ) ) {
309
-
310
- // Checks if the answer was marked as correct
311
- $correct = 0;
312
- if ( isset( $_POST["answer_".$i."_correct"] ) && 1 == $_POST["answer_".$i."_correct"] ) {
313
- $correct = 1;
314
- }
315
-
316
- // Prepares answer array
317
- $answer_array[] = array(
318
- htmlspecialchars( stripslashes( $_POST["answer_".$i] ), ENT_QUOTES ),
319
- floatval( $_POST["answer_".$i."_points"] ),
320
- $correct
321
- );
322
- }
323
- $i++;
324
- }
325
-
326
- $answer_array = serialize( $answer_array );
327
- $quiz_id = intval( $_POST["quiz_id"] );
328
-
329
- // Inserts new question into table
330
- $results = $wpdb->insert(
331
- $wpdb->prefix."mlw_questions",
332
- array(
333
- 'quiz_id' => $quiz_id,
334
- 'question_name' => $question_name,
335
- 'answer_array' => $answer_array,
336
- 'question_answer_info' => $question_answer_info,
337
- 'comments' => $comments,
338
- 'hints' => $hint,
339
- 'question_order' => $new_question_order,
340
- 'question_type_new' => $question_type,
341
- 'question_settings' => $question_settings,
342
- 'category' => $qmn_category,
343
- 'deleted' => 0
344
- ),
345
- array(
346
- '%d',
347
- '%s',
348
- '%s',
349
- '%s',
350
- '%d',
351
- '%s',
352
- '%d',
353
- '%s',
354
- '%s',
355
- '%s',
356
- '%d'
357
- )
358
- );
359
-
360
- // Checks if insert was successful or not
361
- if ( false !== $results ) {
362
- $mlwQuizMasterNext->alertManager->newAlert(__('The question has been created successfully.', 'quiz-master-next'), 'success');
363
- $mlwQuizMasterNext->audit_manager->new_audit( "Question Has Been Added: $question_name" );
364
- } else {
365
- $mlwQuizMasterNext->alertManager->newAlert(sprintf(__('There has been an error in this action. Please share this with the developer. Error Code: %s', 'quiz-master-next'), '0006'), 'error');
366
- $mlwQuizMasterNext->log_manager->add("Error 0006", $wpdb->last_error.' from '.$wpdb->last_query, 0, 'error');
367
- }
368
- }
369
-
370
- // Import question from another quiz
371
- if ( isset( $_POST["add_question_from_quiz_nonce"] ) && wp_verify_nonce( $_POST['add_question_from_quiz_nonce'], 'add_question_from_quiz') ) {
372
-
373
- // Load question from question bank
374
- $question_id = intval( $_POST["copy_question_id"] );
375
- $quiz_id = intval( $_POST["quiz_id"] );
376
- $importing_question = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}mlw_questions WHERE question_id=%d", $question_id ) );
377
-
378
- // Save question into question bank for this quiz
379
- $results = $wpdb->insert(
380
- $wpdb->prefix."mlw_questions",
381
- array(
382
- 'quiz_id' => $quiz_id,
383
- 'question_name' => $importing_question->question_name,
384
- 'answer_array' => $importing_question->answer_array,
385
- 'question_answer_info' => $importing_question->question_answer_info,
386
- 'comments' => $importing_question->comments,
387
- 'hints' => $importing_question->hints,
388
- 'question_order' => $importing_question->question_order,
389
- 'question_type_new' => $importing_question->question_type_new,
390
- 'question_settings' => $importing_question->question_settings,
391
- 'category' => $importing_question->category,
392
- 'deleted' => 0
393
- ),
394
- array(
395
- '%d',
396
- '%s',
397
- '%s',
398
- '%s',
399
- '%d',
400
- '%s',
401
- '%d',
402
- '%s',
403
- '%s',
404
- '%s',
405
- '%d'
406
- )
407
- );
408
- if ( false !== $results ) {
409
- $mlwQuizMasterNext->alertManager->newAlert( __( 'The question has been created successfully.', 'quiz-master-next' ), 'success' );
410
- $mlwQuizMasterNext->audit_manager->new_audit( "Question Has Been Added: {$importing_question->question_name}" );
411
- } else {
412
- $mlwQuizMasterNext->alertManager->newAlert( sprintf( __( 'There has been an error in this action. Please share this with the developer. Error Code: %s', 'quiz-master-next' ), '0023' ), 'error' );
413
- $mlwQuizMasterNext->log_manager->add( "Error 0023", $wpdb->last_error.' from '.$wpdb->last_query, 0, 'error' );
414
- }
415
- }
416
-
417
- //Load questions
418
- $questions = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}mlw_questions WHERE quiz_id=%d AND deleted='0' ORDER BY question_order ASC", $quiz_id ) );
419
- $answers = array();
420
- foreach( $questions as $mlw_question_info ) {
421
- if ( is_serialized( $mlw_question_info->answer_array ) && is_array( @unserialize( $mlw_question_info->answer_array ) ) ) {
422
- $mlw_qmn_answer_array_each = @unserialize( $mlw_question_info->answer_array );
423
- $answers[ $mlw_question_info->question_id ] = $mlw_qmn_answer_array_each;
424
- } else {
425
- $mlw_answer_array_correct = array(0, 0, 0, 0, 0, 0);
426
- $mlw_answer_array_correct[ $mlw_question_info->correct_answer - 1 ] = 1;
427
- $answers[ $mlw_question_info->question_id ] = array(
428
- array( $mlw_question_info->answer_one, $mlw_question_info->answer_one_points, $mlw_answer_array_correct[0] ),
429
- array( $mlw_question_info->answer_two, $mlw_question_info->answer_two_points, $mlw_answer_array_correct[1] ),
430
- array( $mlw_question_info->answer_three, $mlw_question_info->answer_three_points, $mlw_answer_array_correct[2] ),
431
- array( $mlw_question_info->answer_four, $mlw_question_info->answer_four_points, $mlw_answer_array_correct[3] ),
432
- array( $mlw_question_info->answer_five, $mlw_question_info->answer_five_points, $mlw_answer_array_correct[4] ),
433
- array( $mlw_question_info->answer_six, $mlw_question_info->answer_six_points, $mlw_answer_array_correct[5] )
434
- );
435
- }
436
- }
437
-
438
- //Load Question Types
439
- $qmn_question_types = $mlwQuizMasterNext->pluginHelper->get_question_type_options();
440
-
441
-
442
- //Load question type edit fields and convert to JavaScript
443
- $qmn_question_type_fields = $mlwQuizMasterNext->pluginHelper->get_question_type_edit_fields();
444
- echo "<script>
445
- var qmn_question_type_fields = " . json_encode( $qmn_question_type_fields ) . ";
446
- </script>";
447
-
448
- echo "<script>
449
- var questions_list = [";
450
- foreach( $questions as $question ) {
451
-
452
- // Load Required
453
- if ( is_serialized( $question->question_settings ) && is_array( @unserialize( $question->question_settings ) ) ) {
454
- $mlw_question_settings = @unserialize( $question->question_settings );
455
- } else {
456
- $mlw_question_settings = array();
457
- $mlw_question_settings['required'] = 1;
458
- }
459
-
460
- // Load Answers
461
- $answer_string = "";
462
- foreach( $answers[ $question->question_id ] as $answer_single ) {
463
- $answer_string .= "{answer: '" . esc_js( str_replace('\\', '\\\\', $answer_single[0] ) ) . "',points: " . $answer_single[1] . ",correct: " . $answer_single[2] . "},";
464
- }
465
-
466
- // Load Type
467
- $type_slug = $question->question_type_new;
468
- $type_name = $question->question_type_new;
469
- foreach( $qmn_question_types as $type ) {
470
- if ( $type["slug"] == $question->question_type_new ) {
471
- $type_name = $type["name"];
472
- }
473
- }
474
-
475
- // Parse Javascript Object
476
- echo "{
477
- id: ".$question->question_id.",
478
- question: '".esc_js( str_replace('\\', '\\\\', $question->question_name ) )."',
479
- answers: [".$answer_string."],
480
- correct_info: '".esc_js( $question->question_answer_info )."',
481
- hint: '".esc_js($question->hints, ENT_QUOTES)."',
482
- type: '".$question->question_type_new."',
483
- type_name: '".$type_name."',
484
- comment: ".$question->comments.",
485
- order: ".$question->question_order.",
486
- required: ".$mlw_question_settings['required'].",
487
- category: '".esc_js($question->category)."'
488
- },";
489
- }
490
-
491
- echo "];
492
- </script>";
493
-
494
- // Load Categories
495
- $qmn_quiz_categories = $wpdb->get_results( $wpdb->prepare( "SELECT category FROM {$wpdb->prefix}mlw_questions WHERE quiz_id=%d AND deleted='0'
496
- GROUP BY category", $quiz_id ) );
497
-
498
- $is_new_quiz = $wpdb->num_rows;
499
- ?>
500
- <button class="add-new-h2" id="new_question_button"><?php _e('Add Question', 'quiz-master-next'); ?></button>
501
- <button class="add-new-h2" id="from_other_quiz_button"><?php _e('Add Question From Other Survey/Quiz', 'quiz-master-next'); ?></button>
502
- <button class="add-new-h2" id="save_question_order"><?php _e('Save Question Order', 'quiz-master-next'); ?></button>
503
- <form style="display:none;" action="" method="post" name="save_question_order_form" id="save_question_order_form">
504
- <input type="hidden" name="save_question_order_input" id="save_question_order_input" value="" />
505
- <?php wp_nonce_field('qmn_question_order','qmn_question_order_nonce'); ?>
506
- </form>
507
- <br />
508
- <p class="search-box">
509
- <label class="screen-reader-text" for="question_search">Search Questions:</label>
510
- <input type="search" id="question_search" name="question_search" value="">
511
- <a href="#" class="button">Search Questions</a>
512
- </p>
513
- <div class="tablenav top">
514
- <div class="tablenav-pages">
515
- <span class="displaying-num"><?php echo sprintf(_n('One question', '%s questions', count($questions), 'quiz-master-next'), number_format_i18n(count($questions))); ?></span>
516
- </div>
517
- </div>
518
- <table class="widefat">
519
- <thead>
520
- <tr>
521
- <th><?php _e('Question Order', 'quiz-master-next'); ?></th>
522
- <th><?php _e('Question Type', 'quiz-master-next'); ?></th>
523
- <th><?php _e('Category', 'quiz-master-next'); ?></th>
524
- <th><?php _e('Question', 'quiz-master-next'); ?></th>
525
- </tr>
526
- </thead>
527
- <tfoot>
528
- <tr>
529
- <th><?php _e('Question Order', 'quiz-master-next'); ?></th>
530
- <th><?php _e('Question Type', 'quiz-master-next'); ?></th>
531
- <th><?php _e('Category', 'quiz-master-next'); ?></th>
532
- <th><?php _e('Question', 'quiz-master-next'); ?></th>
533
- </tr>
534
- </tfoot>
535
- <tbody id="the-list">
536
- </tbody>
537
- </table>
538
-
539
- <div class="question_area" id="question_area">
540
- <h2 class="question_area_header_text">Add New Question</h2>
541
- <form action="" method="post" class="question_form">
542
- <fieldset>
543
- <legend>Question Type</legend>
544
- <div class="row">
545
- <label class="option_label"><?php _e('Question Type', 'quiz-master-next'); ?></label>
546
- <select class="option_input" name="question_type" id="question_type">
547
- <?php
548
- foreach( $qmn_question_types as $type ) {
549
- echo "<option value='{$type['slug']}'>{$type['name']}</option>";
550
- }
551
- ?>
552
- </select>
553
- </div>
554
- </fieldset>
555
- <fieldset>
556
- <legend>Question And Answers</legend>
557
- <p id="question_type_info"></p>
558
- <?php wp_editor( '', "question_name" ); ?>
559
- <div id="answer_area">
560
- <div class="answer_headers">
561
- <div class="answer_number">&nbsp;</div>
562
- <div class="answer_text"><?php _e( 'Answers', 'quiz-master-next' ); ?></div>
563
- <div class="answer_points"><?php _e( 'Points Worth', 'quiz-master-next' ); ?></div>
564
- <div class="answer_correct"><?php _e( 'Correct Answer', 'quiz-master-next' ); ?></div>
565
- </div>
566
- <div class="answers" id="answers">
567
-
568
- </div>
569
- <a href="#" class="button" id="new_answer_button"><?php _e( 'Add New Answer!', 'quiz-master-next' ); ?></a>
570
- </div>
571
- </fieldset>
572
- <fieldset>
573
- <legend>Question Options</legend>
574
- <div id="correct_answer_area" class="row">
575
- <label class="option_label"><?php _e('Correct Answer Info', 'quiz-master-next'); ?></label>
576
- <textarea class="option_input" type="text" name="correct_answer_info" value="" id="correct_answer_info"></textarea>
577
- </div>
578
-
579
- <div id="hint_area" class="row">
580
- <label class="option_label"><?php _e('Hint', 'quiz-master-next'); ?></label>
581
- <input class="option_input" type="text" name="hint" value="" id="hint"/>
582
- </div>
583
-
584
- <div id="comment_area" class="row">
585
- <label class="option_label"><?php _e('Comment Field', 'quiz-master-next'); ?></label>
586
- <div class="option_input">
587
- <input type="radio" class="comments_radio" id="commentsRadio1" name="comments" value="0" /><label for="commentsRadio1"><?php _e('Small Text Field', 'quiz-master-next'); ?></label><br>
588
- <input type="radio" class="comments_radio" id="commentsRadio3" name="comments" value="2" /><label for="commentsRadio3"><?php _e('Large Text Field', 'quiz-master-next'); ?></label><br>
589
- <input type="radio" class="comments_radio" id="commentsRadio2" name="comments" checked="checked" value="1" /><label for="commentsRadio2"><?php _e('None', 'quiz-master-next'); ?></label><br>
590
- </div>
591
- </div>
592
-
593
- <div class="row">
594
- <label class="option_label"><?php _e('Question Order', 'quiz-master-next'); ?></label>
595
- <input class="option_input" type="number" step="1" min="1" name="new_question_order" value="<?php echo count($questions)+1; ?>" id="new_question_order"/>
596
- </div>
597
-
598
- <div id="required_area" class="row">
599
- <label class="option_label"><?php _e('Required?', 'quiz-master-next'); ?></label>
600
- <select class="option_input" name="required" id="required">
601
- <option value="0" selected="selected"><?php _e('Yes', 'quiz-master-next'); ?></option>
602
- <option value="1"><?php _e('No', 'quiz-master-next'); ?></option>
603
- </select>
604
- </div>
605
-
606
- <div id="category_area" class="row">
607
- <label class="option_label"><?php _e('Category', 'quiz-master-next'); ?></label>
608
- <div class="option_input">
609
- <?php
610
- foreach( $qmn_quiz_categories as $category ) {
611
- if ( $category->category != '' ) {
612
- ?>
613
- <input type="radio" class="category_radio" name="new_category" id="new_category<?php echo esc_attr($category->category); ?>" value="<?php echo esc_attr($category->category); ?>">
614
- <label for="new_category<?php echo esc_attr($category->category); ?>"><?php echo $category->category; ?></label>
615
- <br />
616
- <?php
617
- }
618
- }
619
- ?>
620
- <input type="radio" name="new_category" id="new_category_new" value="new_category"><label for="new_category_new">New: <input type='text' name='new_new_category' value='' /></label>
621
- </div>
622
- </div>
623
- </fieldset>
624
- <input type="hidden" name="new_question_answer_total" id="new_question_answer_total" value="0" />
625
- <input type="hidden" id="question_submission" name="question_submission" value="new_question" />
626
- <?php wp_nonce_field( 'qsm_question_save','qsm_question_save_nonce' ); ?>
627
- <input type="hidden" name="quiz_id" value="<?php echo $quiz_id; ?>" />
628
- <input type="hidden" name="question_id" id="question_id" value="0" />
629
- <input type='submit' class='button-primary' value='<?php _e('Create Question', 'quiz-master-next'); ?>' />
630
- </form>
631
- </div>
632
-
633
- <!--Dialogs-->
634
- <div id="delete_dialog" title="Delete Question?" style="display:none;">
635
- <h3><b><?php _e('Are you sure you want to delete this question?', 'quiz-master-next'); ?></b></h3>
636
- <form action='' method='post'>
637
- <?php wp_nonce_field( 'qsm_delete_question','qsm_delete_question_nonce' ); ?>
638
- <input type='hidden' id='delete_question_id' name='delete_question_id' value='' />
639
- <input type='hidden' name='quiz_id' value='<?php echo $quiz_id; ?>' />
640
- <p class='submit'><input type='submit' class='button-primary' value='<?php _e('Delete Question', 'quiz-master-next'); ?>' /></p>
641
- </form>
642
- </div>
643
-
644
- <div id="duplicate_dialog" title="Duplicate Question?" style="display:none;">
645
- <h3><b><?php _e('Are you sure you want to duplicate this question?', 'quiz-master-next'); ?></b></h3>
646
- <form action='' method='post'>
647
- <?php wp_nonce_field( 'qsm_duplicate_question','qsm_duplicate_question_nonce' ); ?>
648
- <input type='hidden' id='duplicate_question_id' name='duplicate_question_id' value='' />
649
- <input type='hidden' name='quiz_id' value='<?php echo $quiz_id; ?>' />
650
- <p class='submit'><input type='submit' class='button-primary' value='<?php _e ('Duplicate Question', 'quiz-master-next'); ?>' /></p>
651
- </form>
652
- </div>
653
-
654
- <div id="from_other_quiz_dialog" title="Add Question From Other Quiz" style="display:none;">
655
- <h3><?php _e('Select a question to import into this quiz', 'quiz-master-next'); ?></h3>
656
- <p>
657
- <label class="screen-reader-text" for="question_search">Search Questions:</label>
658
- <input type="search" id="dialog_question_search" name="dialog_question_search" value="">
659
- <button class="button" id="dialog_question_search_button">Search Questions</button>
660
- </p>
661
- <div class="other_quiz_questions">
662
-
663
- </div>
664
- <form action='' method='post' id="copy_question_form">
665
- <?php wp_nonce_field('add_question_from_quiz','add_question_from_quiz_nonce'); ?>
666
- <input type='hidden' id='copy_question_id' name='copy_question_id' value='' />
667
- <input type='hidden' name='quiz_id' value='<?php echo $quiz_id; ?>' />
668
- </form>
669
- </div>
670
- <?php
671
- }
672
-
673
- add_action( 'wp_ajax_qsm_load_all_quiz_questions', 'qsm_load_all_quiz_questions_ajax' );
674
- add_action( 'wp_ajax_nopriv_qsm_load_all_quiz_questions', 'qsm_load_all_quiz_questions_ajax' );
675
-
676
- /**
677
- * Loads all the questions and echos out JSON
678
- *
679
- * @since 0.1.0
680
- * @return void
681
- */
682
- function qsm_load_all_quiz_questions_ajax() {
683
- global $wpdb;
684
- global $mlwQuizMasterNext;
685
-
686
- // Loads questions
687
- $questions = $wpdb->get_results( "SELECT {$wpdb->prefix}mlw_questions.question_id, {$wpdb->prefix}mlw_questions.question_name, {$wpdb->prefix}mlw_quizzes.quiz_name FROM {$wpdb->prefix}mlw_questions
688
- LEFT JOIN {$wpdb->prefix}mlw_quizzes ON {$wpdb->prefix}mlw_questions.quiz_id={$wpdb->prefix}mlw_quizzes.quiz_id WHERE {$wpdb->prefix}mlw_questions.deleted='0' ORDER BY {$wpdb->prefix}mlw_questions.question_id DESC" );
689
-
690
- // Creates question array
691
- $question_json = array();
692
- foreach ( $questions as $question ) {
693
- $question_json[] = array(
694
- 'id' => $question->question_id,
695
- 'question' => $question->question_name,
696
- 'quiz' => $question->quiz_name
697
- );
698
- }
699
-
700
- // Echos JSON and dies
701
- echo json_encode( $question_json );
702
- die();
703
- }
704
-
705
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
php/rest-api.php ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This file handles all of the current REST API endpoints
4
+ *
5
+ * @since 5.2.0
6
+ * @package QSM
7
+ */
8
+
9
+ add_action( 'rest_api_init', 'qsm_register_rest_routes' );
10
+
11
+ /**
12
+ * Registers REST API endpoints
13
+ *
14
+ * @since 5.2.0
15
+ */
16
+ function qsm_register_rest_routes() {
17
+ register_rest_route( 'quiz-survey-master/v1', '/questions/', array(
18
+ 'methods' => 'GET',
19
+ 'callback' => 'qsm_rest_get_questions',
20
+ ) );
21
+ register_rest_route( 'quiz-survey-master/v1', '/questions/', array(
22
+ 'methods' => 'POST',
23
+ 'callback' => 'qsm_rest_create_question',
24
+ ) );
25
+ register_rest_route( 'quiz-survey-master/v1', '/questions/(?P<id>\d+)', array(
26
+ 'methods' => 'PUT',
27
+ 'callback' => 'qsm_rest_save_question',
28
+ ) );
29
+ register_rest_route( 'quiz-survey-master/v1', '/questions/(?P<id>\d+)', array(
30
+ 'methods' => 'GET',
31
+ 'callback' => 'qsm_rest_get_question',
32
+ ) );
33
+ }
34
+
35
+ /**
36
+ * Gets a single questions
37
+ *
38
+ * @since 5.2.0
39
+ * @param WP_REST_Request $request The request sent from WP REST API.
40
+ * @return array Something.
41
+ */
42
+ function qsm_rest_get_question( WP_REST_Request $request ) {
43
+ // Makes sure user is logged in.
44
+ if ( is_user_logged_in() ) {
45
+ $current_user = wp_get_current_user();
46
+ if ( 0 !== $current_user ) {
47
+ $question = QSM_Questions::load_question( $request['id'] );
48
+ if ( ! empty( $question ) ) {
49
+ $question['page'] = isset( $question['page'] ) ? $question['page'] : 0;
50
+ $question = array(
51
+ 'id' => $question['question_id'],
52
+ 'quizID' => $question['quiz_id'],
53
+ 'type' => $question['question_type_new'],
54
+ 'name' => esc_js( $question['question_name'] ),
55
+ 'answerInfo' => esc_js( $question['question_answer_info'] ),
56
+ 'comments' => $question['comments'],
57
+ 'hint' => esc_js( $question['hints'] ),
58
+ 'category' => esc_js( $question['category'] ),
59
+ 'required' => $question['settings']['required'],
60
+ 'answers' => $question['answers'],
61
+ 'page' => $question['page'],
62
+ );
63
+ }
64
+ return $question;
65
+ }
66
+ }
67
+ return array(
68
+ 'status' => 'error',
69
+ 'msg' => 'User not logged in',
70
+ );
71
+ }
72
+
73
+ /**
74
+ * Gets all questions
75
+ *
76
+ * @since 5.2.0
77
+ * @param WP_REST_Request $request The request sent from WP REST API.
78
+ * @return array Something.
79
+ */
80
+ function qsm_rest_get_questions( WP_REST_Request $request ) {
81
+ // Makes sure user is logged in.
82
+ if ( is_user_logged_in() ) {
83
+ $current_user = wp_get_current_user();
84
+ if ( 0 !== $current_user ) {
85
+ $quiz_id = isset( $request['quizID'] ) ? intval( $request['quizID'] ) : 0;
86
+ if ( 0 !== $quiz_id ) {
87
+ $questions = QSM_Questions::load_questions_by_pages( $quiz_id );
88
+ } else {
89
+ $questions = QSM_Questions::load_questions( 0 );
90
+ }
91
+
92
+ $question_array = array();
93
+ foreach ( $questions as $question ) {
94
+ $question['page'] = isset( $question['page'] ) ? $question['page'] : 0;
95
+ $question_array[] = array(
96
+ 'id' => $question['question_id'],
97
+ 'quizID' => $question['quiz_id'],
98
+ 'type' => $question['question_type_new'],
99
+ 'name' => esc_js( $question['question_name'] ),
100
+ 'answerInfo' => esc_js( $question['question_answer_info'] ),
101
+ 'comments' => $question['comments'],
102
+ 'hint' => esc_js( $question['hints'] ),
103
+ 'category' => esc_js( $question['category'] ),
104
+ 'required' => $question['settings']['required'],
105
+ 'answers' => $question['answers'],
106
+ 'page' => $question['page'],
107
+ );
108
+ }
109
+ return $question_array;
110
+ }
111
+ }
112
+ return array(
113
+ 'status' => 'error',
114
+ 'msg' => 'User not logged in',
115
+ );
116
+ }
117
+
118
+ /**
119
+ * REST API endpoint function for creating questions
120
+ *
121
+ * @since 5.2.0
122
+ * @param WP_REST_Request $request The request sent from WP REST API.
123
+ * @return array An array that contains the key 'id' for the new question.
124
+ */
125
+ function qsm_rest_create_question( WP_REST_Request $request ) {
126
+
127
+ // Makes sure user is logged in.
128
+ if ( is_user_logged_in() ) {
129
+ $current_user = wp_get_current_user();
130
+ if ( 0 !== $current_user ) {
131
+ try {
132
+ $data = array(
133
+ 'quiz_id' => $request['quizID'],
134
+ 'type' => $request['type'],
135
+ 'name' => $request['name'],
136
+ 'answer_info' => $request['answerInfo'],
137
+ 'comments' => $request['comments'],
138
+ 'hint' => $request['hint'],
139
+ 'order' => 1,
140
+ 'category' => $request['category'],
141
+ );
142
+ $settings = array(
143
+ 'required' => $request['required'],
144
+ );
145
+ $intial_answers = $request['answers'];
146
+ $answers = array();
147
+ if ( is_array( $intial_answers ) ) {
148
+ $answers = $intial_answers;
149
+ }
150
+ $question_id = QSM_Questions::create_question( $data, $answers, $settings );
151
+ return array(
152
+ 'status' => 'success',
153
+ 'id' => $question_id,
154
+ );
155
+ } catch ( Exception $e ) {
156
+ $msg = $e->getMessage();
157
+ return array(
158
+ 'status' => 'error',
159
+ 'msg' => "There was an error when creating your question. Please try again. Error from WordPress: $msg",
160
+ );
161
+ }
162
+ }
163
+ }
164
+ return array(
165
+ 'status' => 'error',
166
+ 'msg' => 'User not logged in',
167
+ );
168
+ }
169
+
170
+ /**
171
+ * REST API endpoint function for saving questions
172
+ *
173
+ * @since 5.2.0
174
+ * @param WP_REST_Request $request The request sent from WP REST API.
175
+ * @return array An array that contains the key 'id' for the new question.
176
+ */
177
+ function qsm_rest_save_question( WP_REST_Request $request ) {
178
+
179
+ // Makes sure user is logged in.
180
+ if ( is_user_logged_in() ) {
181
+ $current_user = wp_get_current_user();
182
+ if ( 0 !== $current_user ) {
183
+ try {
184
+ $id = intval( $request['id'] );
185
+ $data = array(
186
+ 'quiz_id' => $request['quizID'],
187
+ 'type' => $request['type'],
188
+ 'name' => $request['name'],
189
+ 'answer_info' => $request['answerInfo'],
190
+ 'comments' => $request['comments'],
191
+ 'hint' => $request['hint'],
192
+ 'order' => 1,
193
+ 'category' => $request['category'],
194
+ );
195
+ $settings = array(
196
+ 'required' => $request['required'],
197
+ );
198
+ $intial_answers = $request['answers'];
199
+ $answers = array();
200
+ if ( is_array( $intial_answers ) ) {
201
+ $answers = $intial_answers;
202
+ }
203
+ $question_id = QSM_Questions::save_question( $id, $data, $answers, $settings );
204
+ return array(
205
+ 'status' => 'success',
206
+ );
207
+ } catch ( Exception $e ) {
208
+ $msg = $e->getMessage();
209
+ return array(
210
+ 'status' => 'error',
211
+ 'msg' => "There was an error when creating your question. Please try again. Error from WordPress: $msg",
212
+ );
213
+ }
214
+ }
215
+ }
216
+ return array(
217
+ 'status' => 'error',
218
+ 'msg' => 'User not logged in',
219
+ );
220
+ }
php/template-variables.php CHANGED
@@ -67,7 +67,7 @@ add_filter('mlw_qmn_template_variable_quiz_page', 'mlw_qmn_variable_current_user
67
  */
68
  function qsm_variable_facebook_share( $content, $mlw_quiz_array ) {
69
  while ( false !== strpos($content, '%FACEBOOK_SHARE%') ) {
70
- wp_enqueue_script( 'qmn_quiz_social_share', plugins_url( '../js/qmn_social_share.js' , __FILE__ ) );
71
  $settings = (array) get_option( 'qmn-settings' );
72
  $facebook_app_id = '483815031724529';
73
  if ( isset( $settings['facebook_app_id'] ) ) {
@@ -89,7 +89,7 @@ function qsm_variable_facebook_share( $content, $mlw_quiz_array ) {
89
  */
90
  function qsm_variable_twitter_share( $content, $mlw_quiz_array ) {
91
  while ( false !== strpos($content, '%TWITTER_SHARE%') ) {
92
- wp_enqueue_script( 'qmn_quiz_social_share', plugins_url( '../js/qmn_social_share.js' , __FILE__ ) );
93
 
94
  global $mlwQuizMasterNext;
95
  $sharing = $mlwQuizMasterNext->pluginHelper->get_section_setting( 'quiz_text', 'twitter_sharing_text', '' );
67
  */
68
  function qsm_variable_facebook_share( $content, $mlw_quiz_array ) {
69
  while ( false !== strpos($content, '%FACEBOOK_SHARE%') ) {
70
+ wp_enqueue_script( 'qmn_quiz_social_share', plugins_url( '../../js/qmn_social_share.js' , __FILE__ ) );
71
  $settings = (array) get_option( 'qmn-settings' );
72
  $facebook_app_id = '483815031724529';
73
  if ( isset( $settings['facebook_app_id'] ) ) {
89
  */
90
  function qsm_variable_twitter_share( $content, $mlw_quiz_array ) {
91
  while ( false !== strpos($content, '%TWITTER_SHARE%') ) {
92
+ wp_enqueue_script( 'qmn_quiz_social_share', plugins_url( '../../js/qmn_social_share.js' , __FILE__ ) );
93
 
94
  global $mlwQuizMasterNext;
95
  $sharing = $mlwQuizMasterNext->pluginHelper->get_section_setting( 'quiz_text', 'twitter_sharing_text', '' );
readme.txt CHANGED
@@ -1,10 +1,10 @@
1
  === Quiz And Survey Master (Formerly Quiz Master Next) ===
2
  Contributors: fpcorso
3
- Tags: quiz, survey, lead, test, score, exam, questionnaire, answer, question
4
  Requires at least: 4.8
5
  Tested up to: 4.9
6
  Requires PHP: 5.2
7
- Stable tag: 5.1.7
8
  License: GPLv2
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -110,40 +110,18 @@ This is usually a theme conflict. You can [checkout out our common conflict solu
110
 
111
  == Changelog ==
112
 
113
- = 5.1.7 (January 2, 2018) =
114
- * Closed Bug: Quizzes/Surveys table not working on certain installs - ([Issue #598](https://github.com/fpcorso/quiz_master_next/issues/598))
115
-
116
- = 5.1.6 (December 25, 2017) =
117
- * Closed Bug: Timezone ID '' is invalid - ([Issue #606](https://github.com/fpcorso/quiz_master_next/issues/606))
118
- * Closed Bug: Required contact fields not working correctly when the loggedin_user_contact option is set to no - ([Issue #603](https://github.com/fpcorso/quiz_master_next/issues/603))
119
-
120
- = 5.1.5 (November 27, 2017) =
121
- * IMPORTANT FIX: 5.1.4 had a fatal error for sites using out of date PHP versions. Please update to this!
122
-
123
- = 5.1.4 (November 27, 2017) =
124
- * Closed Bug: Headers already sent message - ([Issue #596](https://github.com/fpcorso/quiz_master_next/issues/596))
125
- * Closed Bug: Styling for hints is missing causing them to be hard to read - ([Issue #587](https://github.com/fpcorso/quiz_master_next/issues/587))
126
-
127
- = 5.1.3 (November 18, 2017) =
128
- * Closed Bug: MathJax library not loading - ([Issue #590](https://github.com/fpcorso/quiz_master_next/issues/590))
129
- * Closed Bug: Fatal error: Call to a member function register_question_type - ([Issue #509](https://github.com/fpcorso/quiz_master_next/issues/509))
130
-
131
- = 5.1.2 (October 17, 2017) =
132
- * Closed Bug: Special characters fail the uppercase validation in open answer/fill in the blank questions - ([Issue #580](https://github.com/fpcorso/quiz_master_next/issues/580))
133
-
134
- = 5.1.1 (October 4, 2017) =
135
- * Closed Bug: Variable function names break Certificate addon - ([Issue #578](https://github.com/fpcorso/quiz_master_next/issues/578))
136
-
137
- = 5.1.0 (October 2, 2017) =
138
- * Closed Enhancement: Add all active quizzes function to API - ([Issue #552](https://github.com/fpcorso/quiz_master_next/issues/552))
139
- * Closed User Request: Shortcode or variable for dynamic link to specific quiz/survey - ([Issue #524](https://github.com/fpcorso/quiz_master_next/issues/524))
140
- * Closed Enhancement: Use locale's date to generate date strings - ([Issue #479](https://github.com/fpcorso/quiz_master_next/issues/479))
141
- * Closed User Request: Allow users to change the date to European Date DD.MM.YYYY - ([Issue #439](https://github.com/fpcorso/quiz_master_next/issues/439))
142
- * Closed User Request: More Space in the Correct Answer Info textbox - ([Issue #417](https://github.com/fpcorso/quiz_master_next/issues/417))
143
 
144
  ([Read Full Changelog](https://github.com/fpcorso/quiz_master_next/blob/master/CHANGELOG.md))
145
 
146
  == Upgrade Notice ==
147
 
148
- = 5.1.5 =
149
- IMPORTANT FIX: 5.1.4 had a fatal error for sites using out of date PHP versions. Please update to this!
1
  === Quiz And Survey Master (Formerly Quiz Master Next) ===
2
  Contributors: fpcorso
3
+ Tags: quiz, survey, lead, test, score, exam, questionnaire, question
4
  Requires at least: 4.8
5
  Tested up to: 4.9
6
  Requires PHP: 5.2
7
+ Stable tag: 5.2.0
8
  License: GPLv2
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
110
 
111
  == Changelog ==
112
 
113
+ = 5.2.0 (February 25, 2018) =
114
+ * Closed Enhancement: Make Quiz Results Extendable/Filterable - ([Issue #622](https://github.com/fpcorso/quiz_master_next/issues/622))
115
+ * Closed Enhancement: New Question Editor - ([Issue #568](https://github.com/fpcorso/quiz_master_next/issues/568))
116
+ * Closed Bug: Pagination Bug - ([Issue #477](https://github.com/fpcorso/quiz_master_next/issues/477))
117
+ * Closed Bug: Questions shift - ([Issue #467](https://github.com/fpcorso/quiz_master_next/issues/467))
118
+ * Closed User Request: Remove duplicate question popup confirmation - ([Issue #396](https://github.com/fpcorso/quiz_master_next/issues/396))
119
+ * Closed User Request: Question Grouping - ([Issue #356](https://github.com/fpcorso/quiz_master_next/issues/356))
120
+ * Closed User Request: Ability To Move Submit Button To Last Question Page - ([Issue #321](https://github.com/fpcorso/quiz_master_next/issues/321))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
 
122
  ([Read Full Changelog](https://github.com/fpcorso/quiz_master_next/blob/master/CHANGELOG.md))
123
 
124
  == Upgrade Notice ==
125
 
126
+ = 5.2.0 =
127
+ Update for a new question editor! Includes a variety of bug fixes and minor changes too.
templates/qmn_amethyst.css CHANGED
@@ -285,23 +285,22 @@ border: 1px solid #e3e3e3;
285
  }
286
 
287
  .qmn_pagination {
288
- position: relative;
289
- display: block;
290
- padding: 15px 0 15px 0;
291
- border-top: 1px solid #f3f3f3;
 
 
 
 
 
 
 
 
 
 
292
  }
293
 
294
- .mlw_previous,
295
- .mlw_next {
296
- position: absolute;
297
- top: 15px;
298
- font-size: 14px;
299
- text-transform: uppercase;
300
- }
301
-
302
- .mlw_previous { left: 0; }
303
- .mlw_next { right: 0; }
304
-
305
  .qmn_page_counter_message {
306
  font-size: 14px;
307
  color: #999;
@@ -401,7 +400,6 @@ border: 1px solid #e3e3e3;
401
  .mlw_next,
402
  .qmn_page_counter_message {
403
  display: inline-block;
404
- max-width: 100px;
405
  text-align: center;
406
  position: relative;
407
  top: 0;
285
  }
286
 
287
  .qmn_pagination {
288
+ position: relative;
289
+ display: flex;
290
+ align-items: stretch;
291
+ flex-direction: column;
292
+ padding: 15px 0 15px 0;
293
+ border-top: 1px solid #f3f3f3;
294
+ }
295
+
296
+ @media screen and (min-width: 500px) {
297
+ .qmn_pagination {
298
+ justify-content: space-between;
299
+ align-items: center;
300
+ flex-direction: row;
301
+ }
302
  }
303
 
 
 
 
 
 
 
 
 
 
 
 
304
  .qmn_page_counter_message {
305
  font-size: 14px;
306
  color: #999;
400
  .mlw_next,
401
  .qmn_page_counter_message {
402
  display: inline-block;
 
403
  text-align: center;
404
  position: relative;
405
  top: 0;
templates/qmn_base.css CHANGED
@@ -284,23 +284,22 @@ border: 1px solid #e3e3e3;
284
  }
285
 
286
  .qmn_pagination {
287
- position: relative;
288
- display: block;
289
- padding: 15px 0 15px 0;
290
- border-top: 1px solid #f3f3f3;
 
 
 
 
 
 
 
 
 
 
291
  }
292
 
293
- .mlw_previous,
294
- .mlw_next {
295
- position: absolute;
296
- top: 15px;
297
- font-size: 14px;
298
- text-transform: uppercase;
299
- }
300
-
301
- .mlw_previous { left: 0; }
302
- .mlw_next { right: 0; }
303
-
304
  .qmn_page_counter_message {
305
  font-size: 14px;
306
  color: #999;
@@ -548,7 +547,6 @@ border: 1px solid #e3e3e3;
548
  .mlw_next,
549
  .qmn_page_counter_message {
550
  display: inline-block;
551
- max-width: 100px;
552
  text-align: center;
553
  position: relative;
554
  top: 0;
284
  }
285
 
286
  .qmn_pagination {
287
+ position: relative;
288
+ display: flex;
289
+ align-items: stretch;
290
+ flex-direction: column;
291
+ padding: 15px 0 15px 0;
292
+ border-top: 1px solid #f3f3f3;
293
+ }
294
+
295
+ @media screen and (min-width: 500px) {
296
+ .qmn_pagination {
297
+ justify-content: space-between;
298
+ align-items: center;
299
+ flex-direction: row;
300
+ }
301
  }
302
 
 
 
 
 
 
 
 
 
 
 
 
303
  .qmn_page_counter_message {
304
  font-size: 14px;
305
  color: #999;
547
  .mlw_next,
548
  .qmn_page_counter_message {
549
  display: inline-block;
 
550
  text-align: center;
551
  position: relative;
552
  top: 0;
templates/qmn_emerald.css CHANGED
@@ -284,23 +284,22 @@ border: 1px solid #e3e3e3;
284
  }
285
 
286
  .qmn_pagination {
287
- position: relative;
288
- display: block;
289
- padding: 15px 0 15px 0;
290
- border-top: 1px solid #f3f3f3;
 
 
 
 
 
 
 
 
 
 
291
  }
292
 
293
- .mlw_previous,
294
- .mlw_next {
295
- position: absolute;
296
- top: 15px;
297
- font-size: 14px;
298
- text-transform: uppercase;
299
- }
300
-
301
- .mlw_previous { left: 0; }
302
- .mlw_next { right: 0; }
303
-
304
  .qmn_page_counter_message {
305
  font-size: 14px;
306
  color: #999;
@@ -400,7 +399,6 @@ border: 1px solid #e3e3e3;
400
  .mlw_next,
401
  .qmn_page_counter_message {
402
  display: inline-block;
403
- max-width: 100px;
404
  text-align: center;
405
  position: relative;
406
  top: 0;
284
  }
285
 
286
  .qmn_pagination {
287
+ position: relative;
288
+ display: flex;
289
+ align-items: stretch;
290
+ flex-direction: column;
291
+ padding: 15px 0 15px 0;
292
+ border-top: 1px solid #f3f3f3;
293
+ }
294
+
295
+ @media screen and (min-width: 500px) {
296
+ .qmn_pagination {
297
+ justify-content: space-between;
298
+ align-items: center;
299
+ flex-direction: row;
300
+ }
301
  }
302
 
 
 
 
 
 
 
 
 
 
 
 
303
  .qmn_page_counter_message {
304
  font-size: 14px;
305
  color: #999;
399
  .mlw_next,
400
  .qmn_page_counter_message {
401
  display: inline-block;
 
402
  text-align: center;
403
  position: relative;
404
  top: 0;
templates/qmn_gray.css CHANGED
@@ -285,23 +285,22 @@ border: 1px solid #e3e3e3;
285
  }
286
 
287
  .qmn_pagination {
288
- position: relative;
289
- display: block;
290
- padding: 15px 0 15px 0;
291
- border-top: 1px solid #f3f3f3;
 
 
292
  }
293
-
294
- .mlw_previous,
295
- .mlw_next {
296
- position: absolute;
297
- top: 15px;
298
- font-size: 14px;
299
- text-transform: uppercase;
300
  }
301
 
302
- .mlw_previous { left: 0; }
303
- .mlw_next { right: 0; }
304
-
305
  .qmn_page_counter_message {
306
  font-size: 14px;
307
  color: #999;
@@ -367,7 +366,6 @@ border: 1px solid #e3e3e3;
367
  .mlw_next,
368
  .qmn_page_counter_message {
369
  display: inline-block;
370
- max-width: 100px;
371
  text-align: center;
372
  position: relative;
373
  top: 0;
285
  }
286
 
287
  .qmn_pagination {
288
+ position: relative;
289
+ display: flex;
290
+ align-items: stretch;
291
+ flex-direction: column;
292
+ padding: 15px 0 15px 0;
293
+ border-top: 1px solid #f3f3f3;
294
  }
295
+
296
+ @media screen and (min-width: 500px) {
297
+ .qmn_pagination {
298
+ justify-content: space-between;
299
+ align-items: center;
300
+ flex-direction: row;
301
+ }
302
  }
303
 
 
 
 
304
  .qmn_page_counter_message {
305
  font-size: 14px;
306
  color: #999;
366
  .mlw_next,
367
  .qmn_page_counter_message {
368
  display: inline-block;
 
369
  text-align: center;
370
  position: relative;
371
  top: 0;
templates/qmn_primary.css CHANGED
@@ -286,22 +286,21 @@ border: 1px solid #e3e3e3;
286
 
287
  .qmn_pagination {
288
  position: relative;
289
- display: block;
 
 
290
  padding: 15px 0 15px 0;
291
  border-top: 1px solid #f3f3f3;
292
  }
293
 
294
- .mlw_previous,
295
- .mlw_next {
296
- position: absolute;
297
- top: 15px;
298
- font-size: 14px;
299
- text-transform: uppercase;
300
  }
301
 
302
- .mlw_previous { left: 0; }
303
- .mlw_next { right: 0; }
304
-
305
  .qmn_page_counter_message {
306
  font-size: 14px;
307
  color: #999;
@@ -401,7 +400,6 @@ border: 1px solid #e3e3e3;
401
  .mlw_next,
402
  .qmn_page_counter_message {
403
  display: inline-block;
404
- max-width: 100px;
405
  text-align: center;
406
  position: relative;
407
  top: 0;
286
 
287
  .qmn_pagination {
288
  position: relative;
289
+ display: flex;
290
+ align-items: stretch;
291
+ flex-direction: column;
292
  padding: 15px 0 15px 0;
293
  border-top: 1px solid #f3f3f3;
294
  }
295
 
296
+ @media screen and (min-width: 500px) {
297
+ .qmn_pagination {
298
+ justify-content: space-between;
299
+ align-items: center;
300
+ flex-direction: row;
301
+ }
302
  }
303
 
 
 
 
304
  .qmn_page_counter_message {
305
  font-size: 14px;
306
  color: #999;
400
  .mlw_next,
401
  .qmn_page_counter_message {
402
  display: inline-block;
 
403
  text-align: center;
404
  position: relative;
405
  top: 0;
templates/qmn_turquoise.css CHANGED
@@ -285,23 +285,22 @@ border: 1px solid #e3e3e3;
285
  }
286
 
287
  .qmn_pagination {
288
- position: relative;
289
- display: block;
290
- padding: 15px 0 15px 0;
291
- border-top: 1px solid #f3f3f3;
 
 
 
 
 
 
 
 
 
 
292
  }
293
 
294
- .mlw_previous,
295
- .mlw_next {
296
- position: absolute;
297
- top: 15px;
298
- font-size: 14px;
299
- text-transform: uppercase;
300
- }
301
-
302
- .mlw_previous { left: 0; }
303
- .mlw_next { right: 0; }
304
-
305
  .qmn_page_counter_message {
306
  font-size: 14px;
307
  color: #999;
@@ -401,7 +400,6 @@ border: 1px solid #e3e3e3;
401
  .mlw_next,
402
  .qmn_page_counter_message {
403
  display: inline-block;
404
- max-width: 100px;
405
  text-align: center;
406
  position: relative;
407
  top: 0;
285
  }
286
 
287
  .qmn_pagination {
288
+ position: relative;
289
+ display: flex;
290
+ align-items: stretch;
291
+ flex-direction: column;
292
+ padding: 15px 0 15px 0;
293
+ border-top: 1px solid #f3f3f3;
294
+ }
295
+
296
+ @media screen and (min-width: 500px) {
297
+ .qmn_pagination {
298
+ justify-content: space-between;
299
+ align-items: center;
300
+ flex-direction: row;
301
+ }
302
  }
303
 
 
 
 
 
 
 
 
 
 
 
 
304
  .qmn_page_counter_message {
305
  font-size: 14px;
306
  color: #999;
400
  .mlw_next,
401
  .qmn_page_counter_message {
402
  display: inline-block;
 
403
  text-align: center;
404
  position: relative;
405
  top: 0;