", {
32 | class: 'inner'
33 | }));
34 |
35 | // If the original checkbox is checked, add checked class to the ios checkbox.
36 | if (org_checkbox.is(":checked")) {
37 | ios_checkbox.addClass("checked");
38 | }
39 |
40 | // Hide the original checkbox and print the new one.
41 | org_checkbox.hide().after(ios_checkbox);
42 |
43 | if (org_checkbox.is(":disabled")){
44 | // In case the original checkbox is disabled don't register the click event.
45 | return ios_checkbox.css('opacity','0.6');
46 | }
47 |
48 | // Add click event listener to the ios checkbox
49 | ios_checkbox.click(function() {
50 | // Toggel the check state
51 | ios_checkbox.toggleClass("checked");
52 | // Check if the ios checkbox is checked
53 | if (ios_checkbox.hasClass("checked")) {
54 | // Update state
55 | org_checkbox.prop('checked', true);
56 | } else {
57 | // Update state
58 | org_checkbox.prop('checked', false);
59 | }
60 |
61 | // Run click even in case it was registered to the original checkbox element.
62 | org_checkbox.click();
63 | });
64 | });
65 | return this;
66 | }
67 | });
68 | })(jQuery);
69 |
--------------------------------------------------------------------------------
/libs/iosCheckbox/iosCheckbox.min.css:
--------------------------------------------------------------------------------
1 | .ios-ui-select{border:none;height:36px;background:#ddd;-webkit-border-radius:18px;border-radius:18px;width:60px;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out;-webkit-box-shadow:none;box-shadow:none;cursor:pointer;position:relative;display:inline-block}.ios-ui-select.checked{-webkit-box-shadow:inset 0 0 0 36px #6ddc5f;box-shadow:inset 0 0 0 36px #6ddc5f}.ios-ui-select.checked .inner{left:27px}.ios-ui-select .inner{width:30px;height:30px;position:absolute;top:3px;left:3px;-webkit-border-radius:100%;border-radius:100%;background:#fff;-webkit-transition:all 350ms cubic-bezier(0,.89,.44,1);-moz-transition:all 350ms cubic-bezier(0,.89,.44,1);-o-transition:all 350ms cubic-bezier(0,.89,.44,1);transition:all 350ms cubic-bezier(0,.89,.44,1);-webkit-box-shadow:0 1px 2px 0 rgba(0,0,0,.2),0 3px 4px 0 rgba(0,0,0,.1);box-shadow:0 1px 2px 0 rgba(0,0,0,.2),0 3px 4px 0 rgba(0,0,0,.1)}
--------------------------------------------------------------------------------
/libs/iosCheckbox/iosCheckbox.min.js:
--------------------------------------------------------------------------------
1 | !function(e){e.fn.extend({iosCheckbox:function(){if(this.destroy=function(){e(this).each(function(){e(this).next(".ios-ui-select").remove()})},"true"!==e(this).attr("data-ios-checkbox"))return e(this).attr("data-ios-checkbox","true"),e(this).each(function(){var c=e(this),i=jQuery("
",{class:"ios-ui-select"}).append(jQuery("
",{class:"inner"}));if(c.is(":checked")&&i.addClass("checked"),c.hide().after(i),c.is(":disabled"))return i.css("opacity","0.6");i.click(function(){i.toggleClass("checked"),i.hasClass("checked")?c.prop("checked",!0):c.prop("checked",!1),c.click()})}),this}})}(jQuery);
2 |
--------------------------------------------------------------------------------
/libs/selectivity-3.1.0/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # CHANGELOG
2 |
3 | ## 3.1.0
4 |
5 | - Add `data` property to `change` events.
6 | - Don't crash when some, but not all, result items have children (#227, thanks to @watsab).
7 | - Trim template results to avoid runtime errors (#210, thanks to @darekzak).
8 | - Fix clear button if item text is too long (#211, thanks to @dmarchuk).
9 | - React: Don't use `componentWillReceiveProps()` for forward compatibility with React 17.
10 |
11 | ## 3.0.6
12 |
13 | - Fix updating event listeners after initial render in React API.
14 | - Rerender single-value inputs when their enabled state changes.
15 |
16 | ## 3.0.5
17 |
18 | - Fix issue where dropdown is hard to close on Firefox (#194, thanks to @dmarchuk).
19 | - Filter selected children from results (#201, thanks to @ne0guille).
20 | - Move submenu up if otherwise it would fall below the fold of the page.
21 |
22 | ## 3.0.4
23 |
24 | - Improved compatibility with React 15.5 (no more deprecation warnings).
25 | - Improved HTML5 validation support (#188, thanks to @r4z3c).
26 | - Fix #180: Existing selection highlighted by default on multi-value search results (thanks to
27 | @ahamid).
28 | - Fix #177: Don't close dropdown when clicking scrollbar (thanks to @JEkedorff).
29 |
30 | ## 3.0.3
31 |
32 | - Fix issue when a single-value Selectivity input is reset to null throught the React API.
33 |
34 | ## 3.0.2
35 |
36 | - Fix #161: React API: Value should be re-set when the items change.
37 |
38 | ## 3.0.1
39 |
40 | - Fix #156: Don't crash when unsubscribing from non-subscribed event listener.
41 | - Don't rely on `react-dom-server` in React templates plugin to avoid issues with React 15.4.
42 | - Fix #158: Expose Selectivity object as `$.Selectivity` in jQuery builds.
43 | - Yarn compatibility: Get rid of peerDependencies.
44 |
45 | ## 3.0.0
46 |
47 | - Made jQuery dependency fully optional.
48 | - As a result, all callbacks that received jQuery containers as argument(s) now receive plain
49 | DOM nodes instead.
50 | - Added optional React API.
51 | - Fix #128: Added NPM package.
52 | - Added options:
53 | - `shouldOpenSubmenu()` - Callback that determines whether a submenu should be opened.
54 | - `selectable` - Allows to make items unselectable without having to disable them. This is
55 | mainly useful for items that trigger submenus.
56 | - Removed Bower and Component support.
57 | - Moved option validation into its own plugin.
58 | - Introduced the `"selectivity-change"` event. It's exactly the same as the `"change"` event
59 | (which is still supported as well) from version 2, but with the added benefit it cannot be
60 | confused with `"change"` events that bubble from internal ` ` elements. The React API's
61 | `onChange` property uses the new event.
62 | - Rewrote the AJAX plugin:
63 | - It now relies on the `fetch()` method for performing AJAX requests. This method is only
64 | available on modern browsers, so you'll need a polyfill if you want to use this with old
65 | browsers, unless you're using a jQuery build in which case the `jquery/ajax` plugin can
66 | provide a shim based on `$.ajax()` (requires jQuery 3.0 or higher).
67 | - Please check the documentation for the new options that can be passed.
68 | - Renamed the option `suppressMouseWheelSelector` to just `suppressWheelSelector`.
69 | - Renamed the `Selectivity.InputTypes` map to `Selectivity.Inputs`.
70 | - Removed dist directory from the repository.
71 | - Improved submenu positioning by automatically opening them on the left-hand side if there's
72 | insufficient space on the right side.
73 | - Improve searching behavior with multiple submenus open.
74 | - Fix #107: Remove the dropdown after timeout to fix "hover" behavior.
75 | - Fix #136: Update original `` element on "change" instead of "selectivity-selected".
76 | - Fix: When a Selectivity instance is clicked but its dropdown should not open, at least it should
77 | be focused.
78 | - Fix #144: Properly handle dynamically changing readOnly option.
79 | - Fix #145: Make sure size detection works outside the DOM (thanks to @Rkokie). Also the
80 | ".selectivity-width-detector" element is no longer needed.
81 | - Fix #146: Selectivity created from `` element now uses "s9y\_" prefix for its ID (thanks
82 | to @dr-itz).
83 | - Fix: Provide correct offset in pagination when results are filtered.
84 |
85 | ## 2.1.0
86 |
87 | - Implemented `disabled` property on items. When an item is disabled it cannot be selected and by
88 | default is rendered with grey text.
89 | - PR #63: Fix problem with `closeOnSelect` behavior.
90 | - PR #80: Added CSS classes for `hover` and `open` states.
91 | - Fix #66: Respect `removeOnly` option when set after initialization.
92 | - Fix #67: Pass `queryOptions` to `url` function in AJAX module.
93 | - Fix #75: Make sure Enter key doesn't submit forms.
94 | - Fix #93: Make the rerenderSelection() method public and document that `triggerChange: false`
95 | doesn't automatically update the UI.
96 | - Fixed issue where the cursor position was constantly reset when using a tokenizer.
97 | - Miscellaneous smaller fixes and styling tweaks.
98 |
99 | ## 2.0.0
100 |
--------------------------------------------------------------------------------
/libs/selectivity-3.1.0/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014-2016 Arend van Beelen jr.
4 | (c) 2016 Speakap BV
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
24 |
--------------------------------------------------------------------------------
/libs/selectivity-3.1.0/selectivity-jquery.css:
--------------------------------------------------------------------------------
1 | /**
2 | * All CSS that comes with Selectivity.js can be used as is, or tweaked to your heart's content :)
3 | *
4 | * Please realize though there is no "API contract" regarding styling of CSS classes, meaning that
5 | * any customized CSS made may need to be updated without warning if you want to upgrade the
6 | * Selectivity version you use. You can mitigate this problem by using your own templates instead of
7 | * those defined in src/templates.js, since templates will at the very least continue working across
8 | * patch versions and any changes necessary to templates will be documented in the changelog.
9 | */
10 | .selectivity-clearfix {
11 | clear: both; }
12 |
13 | .selectivity-input {
14 | display: inline-block;
15 | width: 250px; }
16 | .selectivity-input select {
17 | display: none; }
18 |
19 | .selectivity-input:focus {
20 | outline: none; }
21 |
22 | .selectivity-placeholder {
23 | color: #999; }
24 |
25 | /**
26 | * Dropdown
27 | */
28 | .selectivity-dropdown {
29 | background: #fff;
30 | border-radius: 4px;
31 | -webkit-box-shadow: 0 1px 5px 1px rgba(0, 0, 0, 0.15), 0 10px 16px 0 rgba(0, 0, 0, 0.2);
32 | box-shadow: 0 1px 5px 1px rgba(0, 0, 0, 0.15), 0 10px 16px 0 rgba(0, 0, 0, 0.2);
33 | position: fixed;
34 | z-index: 1046; }
35 |
36 | .selectivity-search-input-container {
37 | border-bottom: 1px solid #eee; }
38 |
39 | .selectivity-search-input {
40 | background: transparent;
41 | border: 0;
42 | outline: 0;
43 | width: 100%; }
44 |
45 | .selectivity-results-container {
46 | max-height: 28em;
47 | overflow: auto;
48 | position: relative; }
49 |
50 | .selectivity-load-more,
51 | .selectivity-result-item {
52 | cursor: pointer;
53 | padding: 7px; }
54 |
55 | .selectivity-result-children .selectivity-result-item {
56 | padding-left: 17px; }
57 |
58 | .selectivity-load-more.highlight,
59 | .selectivity-result-item.highlight {
60 | background: #4484c7;
61 | color: #fff; }
62 |
63 | .selectivity-result-item.disabled {
64 | cursor: default;
65 | color: #999; }
66 |
67 | .selectivity-result-item:first-child {
68 | border-radius: 4px 4px 0 0; }
69 |
70 | .selectivity-dropdown.has-search-input .selectivity-result-item:first-child {
71 | border-radius: 0; }
72 |
73 | .selectivity-result-label {
74 | font-weight: bold; }
75 |
76 | .selectivity-load-more,
77 | .selectivity-result-item:last-child,
78 | .selectivity-result-children:last-child .selectivity-result-item:last-child {
79 | border-radius: 0 0 4px 4px; }
80 |
81 | .selectivity-result-children .selectivity-result-item:last-child {
82 | border-radius: 0; }
83 |
84 | .selectivity-error,
85 | .selectivity-loading,
86 | .selectivity-search-input-container,
87 | .selectivity-result-label {
88 | padding: 7px; }
89 |
90 | /**
91 | * Multi-selection input
92 | */
93 | .selectivity-multiple-input-container {
94 | background: #eee;
95 | border-radius: 2px;
96 | cursor: text;
97 | max-height: 10em;
98 | min-height: calc(2em + 4px);
99 | overflow: auto;
100 | padding: 5px; }
101 |
102 | .selectivity-multiple-input-container .selectivity-placeholder {
103 | height: calc(2em + 4px);
104 | line-height: calc(2em + 4px); }
105 |
106 | .selectivity-multiple-input,
107 | input[type='text'].selectivity-multiple-input {
108 | background-color: transparent;
109 | border: none;
110 | float: left;
111 | font: inherit;
112 | height: calc(2em + 4px);
113 | max-width: 100%;
114 | outline: 0;
115 | padding: 0; }
116 | .selectivity-multiple-input:focus,
117 | input[type='text'].selectivity-multiple-input:focus {
118 | background-color: transparent;
119 | -webkit-box-shadow: none;
120 | box-shadow: none;
121 | outline: none; }
122 |
123 | .selectivity-multiple-input::-ms-clear {
124 | display: none; }
125 |
126 | .selectivity-multiple-selected-item {
127 | background: #4484c7;
128 | border-radius: 3px;
129 | color: #fff;
130 | cursor: default;
131 | float: left;
132 | line-height: 2em;
133 | margin: 2px;
134 | padding: 0 5px;
135 | position: relative;
136 | -moz-user-select: none;
137 | -ms-user-select: none;
138 | -webkit-user-select: none;
139 | user-select: none;
140 | white-space: nowrap; }
141 | .selectivity-multiple-selected-item.highlighted {
142 | background-color: #ccc; }
143 |
144 | .selectivity-multiple-selected-item-remove {
145 | color: #fff;
146 | cursor: pointer;
147 | margin-left: -5px;
148 | padding: 5px; }
149 |
150 | /**
151 | * Single-selection input
152 | */
153 | .selectivity-single-select {
154 | background: #eee;
155 | border-radius: 2px;
156 | cursor: pointer;
157 | min-height: 2em;
158 | padding: 5px;
159 | position: relative;
160 | -webkit-box-sizing: content-box;
161 | box-sizing: content-box; }
162 |
163 | .selectivity-single-select-input {
164 | opacity: 0; }
165 |
166 | .selectivity-single-result-container {
167 | position: absolute;
168 | top: 0.8em;
169 | right: 15px;
170 | left: 5px;
171 | overflow: hidden;
172 | -o-text-overflow: ellipsis;
173 | text-overflow: ellipsis;
174 | white-space: nowrap; }
175 |
176 | .selectivity-single-selected-item {
177 | color: #000; }
178 |
179 | .selectivity-single-selected-item-remove {
180 | color: #000;
181 | float: right;
182 | padding: 0 5px;
183 | position: relative;
184 | z-index: 1; }
185 |
186 | .selectivity-caret {
187 | position: absolute;
188 | right: 5px;
189 | top: 0.7em; }
190 |
191 | @media only screen and (max-device-width: 480px) {
192 | .selectivity-single-select {
193 | background: #eee;
194 | border-radius: 2px; }
195 |
196 | .selectivity-single-result-container {
197 | right: 5px; }
198 |
199 | .selectivity-caret {
200 | display: none; } }
201 | /**
202 | * Submenu
203 | */
204 | .selectivity-submenu-icon {
205 | position: absolute;
206 | right: 4px; }
207 |
--------------------------------------------------------------------------------
/libs/selectivity-3.1.0/selectivity-jquery.min.css:
--------------------------------------------------------------------------------
1 | .selectivity-clearfix{clear:both}.selectivity-input{display:inline-block;width:250px}.selectivity-input select{display:none}.selectivity-input:focus{outline:0}.selectivity-placeholder{color:#999}.selectivity-dropdown{background:#fff;border-radius:4px;-webkit-box-shadow:0 1px 5px 1px rgba(0,0,0,.15),0 10px 16px 0 rgba(0,0,0,.2);box-shadow:0 1px 5px 1px rgba(0,0,0,.15),0 10px 16px 0 rgba(0,0,0,.2);position:fixed;z-index:1046}.selectivity-search-input-container{border-bottom:1px solid #eee}.selectivity-search-input{background:0 0;border:0;outline:0;width:100%}.selectivity-results-container{max-height:28em;overflow:auto;position:relative}.selectivity-load-more,.selectivity-result-item{cursor:pointer;padding:7px}.selectivity-result-children .selectivity-result-item{padding-left:17px}.selectivity-load-more.highlight,.selectivity-result-item.highlight{background:#4484c7;color:#fff}.selectivity-result-item.disabled{cursor:default;color:#999}.selectivity-result-item:first-child{border-radius:4px 4px 0 0}.selectivity-dropdown.has-search-input .selectivity-result-item:first-child{border-radius:0}.selectivity-result-label{font-weight:700}.selectivity-load-more,.selectivity-result-children:last-child .selectivity-result-item:last-child,.selectivity-result-item:last-child{border-radius:0 0 4px 4px}.selectivity-result-children .selectivity-result-item:last-child{border-radius:0}.selectivity-error,.selectivity-loading,.selectivity-result-label,.selectivity-search-input-container{padding:7px}.selectivity-multiple-input-container{background:#eee;border-radius:2px;cursor:text;max-height:10em;min-height:calc(2em + 4px);overflow:auto;padding:5px}.selectivity-multiple-input-container .selectivity-placeholder{height:calc(2em + 4px);line-height:calc(2em + 4px)}.selectivity-multiple-input,input[type=text].selectivity-multiple-input{background-color:transparent;border:0;float:left;font:inherit;height:calc(2em + 4px);max-width:100%;outline:0;padding:0}.selectivity-multiple-input:focus,input[type=text].selectivity-multiple-input:focus{background-color:transparent;-webkit-box-shadow:none;box-shadow:none;outline:0}.selectivity-multiple-input::-ms-clear{display:none}.selectivity-multiple-selected-item{background:#4484c7;border-radius:3px;color:#fff;cursor:default;float:left;line-height:2em;margin:2px;padding:0 5px;position:relative;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none;white-space:nowrap}.selectivity-multiple-selected-item.highlighted{background-color:#ccc}.selectivity-multiple-selected-item-remove{color:#fff;cursor:pointer;margin-left:-5px;padding:5px}.selectivity-single-select{background:#eee;border-radius:2px;cursor:pointer;min-height:2em;padding:5px;position:relative;-webkit-box-sizing:content-box;box-sizing:content-box}.selectivity-single-select-input{opacity:0}.selectivity-single-result-container{position:absolute;top:.8em;right:15px;left:5px;overflow:hidden;-o-text-overflow:ellipsis;text-overflow:ellipsis;white-space:nowrap}.selectivity-single-selected-item{color:#000}.selectivity-single-selected-item-remove{color:#000;float:right;padding:0 5px;position:relative;z-index:1}.selectivity-caret{position:absolute;right:5px;top:.7em}@media only screen and (max-device-width:480px){.selectivity-single-select{background:#eee;border-radius:2px}.selectivity-single-result-container{right:5px}.selectivity-caret{display:none}}.selectivity-submenu-icon{position:absolute;right:4px}
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "engines": {
3 | "node": ">=20.10.0",
4 | "npm": ">=10.2.3"
5 | },
6 | "volta": {
7 | "node": "20.11.1"
8 | },
9 | "devDependencies": {
10 | "@wordpress/env": "9.5.0",
11 | "npm-run-all": "^4.1.5",
12 | "rimraf": "^5.0.5"
13 | },
14 | "scripts": {
15 | "export:wp-content:themes": "npm run cli cp -- -r wp-content/themes .export/wp-content",
16 | "export:wp-content:uploads": "npm run cli cp -- -r wp-content/uploads .export/wp-content",
17 | "export:wp-content": "rimraf .export/wp-content && mkdir -p .export/wp-content/uploads && run-p export:wp-content:*",
18 | "export:db": "mkdir -p .export/sql && npm run wp db -- export .export/sql/local.sql",
19 | "export": "run-p export:*",
20 | "import:wp-content:themes": "npm run cli cp -- -r .export/wp-content/themes wp-content",
21 | "import:wp-content:uploads": "npm run cli cp -- -r .export/wp-content/uploads wp-content",
22 | "import:wp-content": "run-p import:wp-content:*",
23 | "import:db": "npm run wp db -- import .export/sql/local.sql",
24 | "import": "run-p import:*",
25 | "wp-env": "wp-env",
26 | "start": "wp-env start && open http://localhost:8888",
27 | "stop": "npm run export && wp-env stop",
28 | "cli": "wp-env run cli",
29 | "wp": "wp-env run --env-cwd=wp-content/plugins/smart-custom-fields cli wp",
30 | "composer": "wp-env run --env-cwd=wp-content/plugins/smart-custom-fields cli composer",
31 | "pretest": "wp-env start && npm run composer install -- --no-interaction",
32 | "test:lint:php": "npm run composer lint",
33 | "test:lint": "run-s test:lint:*",
34 | "test:unit:php": "wp-env start && wp-env run --env-cwd=\"wp-content/plugins/smart-custom-fields\" tests-wordpress vendor/bin/phpunit -c .phpunit.xml.dist --verbose",
35 | "test:unit": "run-s test:unit:*",
36 | "test": "run-s test:*",
37 | "clean:zip": "rimraf smart-custom-fields.zip",
38 | "zip:pack": "rsync -a --exclude='/bin' --exclude='/vendor' --exclude='/node_modules' --exclude='.*' --exclude='*.ruleset.xml' --exclude='*.config.js' --exclude='*.xml.dist' --exclude='/tests' --exclude='package*.json' --exclude='/smart-custom-fields.zip' ./ smart-custom-fields",
39 | "zip:archive": "zip -9 -qmr smart-custom-fields.zip smart-custom-fields",
40 | "zip": "npm run clean:zip && npm run zip:pack && wp-env start && npm run composer install -- --no-dev -d smart-custom-fields && npm run zip:archive"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 | get_error_message();
61 | }
62 |
63 | // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
64 | throw new Exception( 'WordPress died: ' . $message );
65 | }
66 | tests_add_filter( 'wp_die_handler', 'fail_if_died' );
67 |
68 | $GLOBALS['wp_tests_options'] = array(
69 | 'gutenberg-experiments' => array(
70 | 'gutenberg-widget-experiments' => '1',
71 | ),
72 | );
73 |
74 | // Start up the WP testing environment.
75 | require $_tests_dir . '/includes/bootstrap.php';
76 |
77 | // Use existing behavior for wp_die during actual test execution.
78 | remove_filter( 'wp_die_handler', 'fail_if_died' );
79 |
--------------------------------------------------------------------------------
/tests/test-smart-custom-fields-ajax.php:
--------------------------------------------------------------------------------
1 | Ajax = new Smart_Custom_Fields_Ajax();
15 |
16 | $Cache = Smart_Custom_Fields_Cache::get_instance();
17 | $Cache->flush();
18 | }
19 |
20 | /**
21 | * Tear down.
22 | */
23 | public function tear_down() {
24 | parent::tear_down();
25 | $Cache = Smart_Custom_Fields_Cache::get_instance();
26 | $Cache->flush();
27 | }
28 |
29 | /**
30 | * @group delete_term
31 | */
32 | public function test_delete_term() {
33 | $taxonomy = 'category';
34 | $term_id = $this->factory->term->create( array( 'taxonomy' => $taxonomy ) );
35 | $term = get_term( $term_id, $taxonomy );
36 | $Meta = new Smart_Custom_Fields_Meta( $term );
37 |
38 | $Meta->add( 'text', 'text' );
39 | $this->Ajax->delete_term( $term_id, '', $taxonomy, $term );
40 | $this->assertSame( array(), $Meta->get( 'text' ) );
41 | }
42 |
43 | /**
44 | * Register custom fields using filter hook.
45 | *
46 | * @param array $settings Array of Smart_Custom_Fields_Setting object.
47 | * @param string $type Post type or Role.
48 | * @param int $id Post ID or User ID.
49 | * @param string $meta_type post or user.
50 | */
51 | public function _register( $settings, $type, $id, $meta_type ) {
52 | if ( type === 'category' ) {
53 | $Setting = SCF::add_setting( 'id-1', 'Register Test' );
54 | $Setting->add_group(
55 | 0,
56 | false,
57 | array(
58 | array(
59 | 'name' => 'text',
60 | 'label' => 'text field',
61 | 'type' => 'text',
62 | ),
63 | )
64 | );
65 | $settings[ $Setting->get_id() ] = $Setting;
66 | }
67 | return $settings;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/tests/test-smart-custom-fields-controller-base.php:
--------------------------------------------------------------------------------
1 | post_id = $this->factory->post->create(
22 | array(
23 | 'post_type' => 'post',
24 | 'post_status' => 'publish',
25 | )
26 | );
27 |
28 | // The auto draft post for custom fields
29 | $this->new_post_id = $this->factory->post->create(
30 | array(
31 | 'post_type' => 'post',
32 | 'post_status' => 'auto-draft',
33 | )
34 | );
35 |
36 | add_filter( 'smart-cf-register-fields', array( $this, '_register' ), 10, 4 );
37 |
38 | require_once plugin_dir_path( __FILE__ ) . '../classes/controller/class.controller-base.php';
39 | $this->Controller = new Smart_Custom_Fields_Controller_Base();
40 |
41 | $Cache = Smart_Custom_Fields_Cache::get_instance();
42 | $Cache->flush();
43 | }
44 |
45 | /**
46 | * Tear down.
47 | */
48 | public function tear_down() {
49 | parent::tear_down();
50 | $Cache = Smart_Custom_Fields_Cache::get_instance();
51 | $Cache->flush();
52 | }
53 |
54 | /**
55 | * @group get_multiple_data_field_value
56 | */
57 | public function test_get_multiple_data_field_value() {
58 | // When $index is null
59 | $object = get_post( $this->post_id );
60 | $Field = SCF::get_field( $object, 'checkbox-has-default' );
61 | $this->assertSame( array( 'a' ), $this->Controller->get_multiple_data_field_value( $object, $Field, null ) );
62 | $Field = SCF::get_field( $object, 'checkbox' );
63 | $this->assertSame( array(), $this->Controller->get_multiple_data_field_value( $object, $Field, null ) );
64 |
65 | // When isn't saved meta data. At that time ,$index is ignored.
66 | $object = get_post( $this->new_post_id );
67 | $Field = SCF::get_field( $object, 'checkbox-has-default' );
68 | $this->assertSame( array( 'a' ), $this->Controller->get_multiple_data_field_value( $object, $Field, 0 ) );
69 | $Field = SCF::get_field( $object, 'checkbox' );
70 | $this->assertSame( array(), $this->Controller->get_multiple_data_field_value( $object, $Field, 0 ) );
71 | }
72 |
73 | /**
74 | * @group get_multiple_data_field_value
75 | */
76 | public function test_get_multiple_data_field_value__saved() {
77 | $object = get_post( $this->post_id );
78 | $Meta = new Smart_Custom_Fields_Meta( $object );
79 | $Field = SCF::get_field( $object, 'checkbox-has-default' );
80 | $Meta->add( 'checkbox-has-default', 'a' );
81 | $Meta->add( 'checkbox-has-default', 'b' );
82 | $this->assertSame( array( 'a', 'b' ), $this->Controller->get_multiple_data_field_value( $object, $Field, 0 ) );
83 | $Field = SCF::get_field( $object, 'checkbox' );
84 | $Meta->add( 'checkbox', 'a' );
85 | $Meta->add( 'checkbox', 'b' );
86 | $this->assertSame( array( 'a', 'b' ), $this->Controller->get_multiple_data_field_value( $object, $Field, 0 ) );
87 | }
88 |
89 | /**
90 | * @group get_multiple_data_field_value
91 | */
92 | public function test_get_multiple_data_field_value__saved_multi() {
93 | $object = get_post( $this->post_id );
94 | $Meta = new Smart_Custom_Fields_Meta( $object );
95 | $Field = SCF::get_field( $object, 'repeat-checkbox' );
96 | $POST = array(
97 | SCF_Config::NAME => array(
98 | 'repeat-checkbox' => array(
99 | array(),
100 | array( 'a', 'b' ),
101 | array( 'b', 'c' ),
102 | ),
103 | ),
104 | );
105 | $Meta->save( $POST );
106 | $this->assertSame( array(), $this->Controller->get_multiple_data_field_value( $object, $Field, 0 ) );
107 | $this->assertSame( array( 'a', 'b' ), $this->Controller->get_multiple_data_field_value( $object, $Field, 1 ) );
108 | }
109 |
110 | /**
111 | * @group get_single_data_field_value
112 | */
113 | public function test_get_single_data_field_value() {
114 | // When $index is null
115 | $object = get_post( $this->post_id );
116 | $Field = SCF::get_field( $object, 'text-has-default' );
117 | $this->assertSame( 'a', $this->Controller->get_single_data_field_value( $object, $Field, null ) );
118 | $Field = SCF::get_field( $object, 'text' );
119 | $this->assertSame( '', $this->Controller->get_single_data_field_value( $object, $Field, null ) );
120 |
121 | // When isn't saved meta data. At that time ,$index is ignored.
122 | $object = get_post( $this->new_post_id );
123 | $Field = SCF::get_field( $object, 'text-has-default' );
124 | $this->assertSame( 'a', $this->Controller->get_single_data_field_value( $object, $Field, 0 ) );
125 | $Field = SCF::get_field( $object, 'text' );
126 | $this->assertSame( '', $this->Controller->get_single_data_field_value( $object, $Field, 0 ) );
127 | }
128 |
129 | /**
130 | * @group get_single_data_field_value
131 | */
132 | public function test_get_single_data_field_value__saved() {
133 | $object = get_post( $this->post_id );
134 | $Meta = new Smart_Custom_Fields_Meta( $object );
135 | $Field = SCF::get_field( $object, 'text-has-default' );
136 | $Meta->add( 'text-has-default', 'b' );
137 | $Meta->add( 'text-has-default', 'c' );
138 | $this->assertSame( 'b', $this->Controller->get_single_data_field_value( $object, $Field, 0 ) );
139 | $this->assertSame( 'c', $this->Controller->get_single_data_field_value( $object, $Field, 1 ) );
140 |
141 | $Field = SCF::get_field( $object, 'text' );
142 | $Meta->add( 'text', 'b' );
143 | $Meta->add( 'text', 'c' );
144 | $this->assertSame( 'b', $this->Controller->get_single_data_field_value( $object, $Field, 0 ) );
145 | $this->assertSame( 'c', $this->Controller->get_single_data_field_value( $object, $Field, 1 ) );
146 | }
147 |
148 | /**
149 | * Register custom fields using filter hook
150 | *
151 | * @param array $settings Array of Smart_Custom_Fields_Setting object.
152 | * @param string $type Post type or Role.
153 | * @param int $id Post ID or User ID.
154 | * @param string $meta_type post or user.
155 | */
156 | public function _register( $settings, $type, $id, $meta_type ) {
157 | if (
158 | ( 'post' === $type && $id === $this->post_id ) ||
159 | ( 'post' === $type && $id === $this->new_post_id ) ||
160 | ( 'editor' === $type ) ||
161 | ( 'category' === $type ) ||
162 | ( 'option' === $meta_type && 'menu-slug' === $id )
163 | ) {
164 | $Setting = SCF::add_setting( 'id-1', 'Register Test' );
165 | $Setting->add_group(
166 | 0,
167 | false,
168 | array(
169 | array(
170 | 'name' => 'text',
171 | 'label' => 'text',
172 | 'type' => 'text',
173 | ),
174 | )
175 | );
176 | $Setting->add_group(
177 | 'text-has-default',
178 | false,
179 | array(
180 | array(
181 | 'name' => 'text-has-default',
182 | 'label' => 'text has default',
183 | 'type' => 'text',
184 | 'default' => 'a',
185 | ),
186 | )
187 | );
188 | $Setting->add_group(
189 | 'checkbox',
190 | false,
191 | array(
192 | array(
193 | 'name' => 'checkbox',
194 | 'label' => 'checkbox field',
195 | 'type' => 'check',
196 | 'choices' => array( 'a', 'b', 'c' ),
197 | ),
198 | )
199 | );
200 | $Setting->add_group(
201 | 'checkbox-has-default',
202 | false,
203 | array(
204 | array(
205 | 'name' => 'checkbox-has-default',
206 | 'label' => 'checkbox has default',
207 | 'type' => 'check',
208 | 'choices' => array( 'a', 'b', 'c' ),
209 | 'default' => array( 'a' ),
210 | ),
211 | )
212 | );
213 | $Setting->add_group(
214 | 'checkbox-key-value',
215 | false,
216 | array(
217 | array(
218 | 'name' => 'checkbox-key-value',
219 | 'label' => 'checkbox key value',
220 | 'type' => 'check',
221 | 'choices' => array(
222 | 'a' => 'apple',
223 | 'b' => 'banana',
224 | 'c' => 'carrot',
225 | ),
226 | 'default' => array( 'a' ),
227 | ),
228 | )
229 | );
230 | $Setting->add_group(
231 | 'group',
232 | true,
233 | array(
234 | array(
235 | 'name' => 'repeat-text',
236 | 'label' => 'repeat text',
237 | 'type' => 'text',
238 | ),
239 | array(
240 | 'name' => 'repeat-checkbox',
241 | 'label' => 'repeat checkbox',
242 | 'type' => 'check',
243 | 'choices' => array( 'a', 'b', 'c' ),
244 | ),
245 | )
246 | );
247 | $settings[ $Setting->get_id() ] = $Setting;
248 | }
249 | return $settings;
250 | }
251 | }
252 |
--------------------------------------------------------------------------------
/tests/test-smart-custom-fields-revision.php:
--------------------------------------------------------------------------------
1 | Revision = new Smart_Custom_Fields_Revisions();
26 |
27 | // The post for custom fields
28 | $this->post_id = $this->factory->post->create(
29 | array(
30 | 'post_type' => 'post',
31 | 'post_status' => 'publish',
32 | )
33 | );
34 |
35 | // The revision post for custom fields
36 | $this->revision_id = $this->factory->post->create(
37 | array(
38 | 'post_type' => 'revision',
39 | 'post_parent' => $this->post_id,
40 | 'post_status' => 'inherit',
41 | 'post_name' => $this->post_id . '-autosave-v1',
42 | )
43 | );
44 |
45 | add_filter( 'smart-cf-register-fields', array( $this, '_register' ), 10, 4 );
46 |
47 | $Cache = Smart_Custom_Fields_Cache::get_instance();
48 | $Cache->flush();
49 | }
50 |
51 | /**
52 | * Tear down.
53 | */
54 | public function tear_down() {
55 | parent::tear_down();
56 | $Cache = Smart_Custom_Fields_Cache::get_instance();
57 | $Cache->flush();
58 | }
59 |
60 | /**
61 | * @group wp_restore_post_revision
62 | */
63 | public function test_wp_restore_post_revision() {
64 | // Meta data for the post
65 | add_post_meta( $this->post_id, 'text', 'text' );
66 | add_post_meta( $this->post_id, 'checkbox', 1 );
67 |
68 | // Meta data for the revision post
69 | add_metadata( 'post', $this->revision_id, 'text', 'text-revision' );
70 | add_metadata( 'post', $this->revision_id, 'checkbox', 2 );
71 |
72 | $this->assertEquals( 'text', get_post_meta( $this->post_id, 'text', true ) );
73 | $this->assertEquals( array( 1 ), get_post_meta( $this->post_id, 'checkbox' ) );
74 |
75 | $this->Revision->wp_restore_post_revision( $this->post_id, $this->revision_id );
76 |
77 | $this->assertEquals( 'text-revision', get_post_meta( $this->post_id, 'text', true ) );
78 | $this->assertEquals( array( 2 ), get_post_meta( $this->post_id, 'checkbox' ) );
79 | }
80 |
81 | /**
82 | * @group wp_insert_post
83 | */
84 | public function test_wp_insert_post() {
85 | $_REQUEST[ SCF_Config::PREFIX . 'fields-nonce' ] = wp_create_nonce( SCF_Config::NAME . '-fields' );
86 |
87 | $_POST = array(
88 | SCF_Config::NAME => array(
89 | 'text' => array( 'text' ),
90 | ),
91 | );
92 | $this->Revision->wp_insert_post( $this->revision_id );
93 | $this->assertEquals( 'text', SCF::get( 'text', $this->revision_id ) );
94 |
95 | $this->Revision->wp_insert_post( $this->post_id );
96 | $this->assertEquals( '', SCF::get( 'text', $this->post_id ) );
97 | }
98 |
99 | /**
100 | * @group get_post_metadata
101 | */
102 | public function test_get_post_metadata() {
103 | update_metadata( 'post', $this->revision_id, 'text', 'text' );
104 |
105 | $meta = $this->Revision->get_post_metadata( 'default-value', $this->post_id, 'text', true );
106 | $this->assertEquals( 'default-value', $meta );
107 |
108 | global $wp_query, $post;
109 | $wp_query->is_preview = true;
110 | $post = get_post( $this->post_id );
111 | $meta = $this->Revision->get_post_metadata( 'default-value', $this->post_id, 'text', true );
112 | $this->assertEquals( 'text', $meta );
113 | }
114 |
115 | /**
116 | * Register custom fields using filter hook.
117 | *
118 | * @param array $settings Array of Smart_Custom_Fields_Setting object.
119 | * @param string $type Post type or Role.
120 | * @param int $id Post ID or User ID.
121 | * @param string $meta_type post or user.
122 | * @return array
123 | */
124 | public function _register( $settings, $type, $id, $meta_type ) {
125 | if ( 'post' === $type && ( $id === $this->post_id || $id === $this->revision_id ) ) {
126 | $Setting = SCF::add_setting( 'id-1', 'Register Test' );
127 | $Setting->add_group(
128 | 0,
129 | false,
130 | array(
131 | array(
132 | 'name' => 'text',
133 | 'label' => 'text',
134 | 'type' => 'text',
135 | ),
136 | )
137 | );
138 | $Setting->add_group(
139 | 'text-has-default',
140 | false,
141 | array(
142 | array(
143 | 'name' => 'text-has-default',
144 | 'label' => 'text has default',
145 | 'type' => 'text',
146 | 'default' => 'a',
147 | ),
148 | )
149 | );
150 | $Setting->add_group(
151 | 'checkbox',
152 | false,
153 | array(
154 | array(
155 | 'name' => 'checkbox',
156 | 'label' => 'checkbox field',
157 | 'type' => 'check',
158 | 'choices' => array( 'a', 'b', 'c' ),
159 | ),
160 | )
161 | );
162 | $Setting->add_group(
163 | 'checkbox-has-default',
164 | false,
165 | array(
166 | array(
167 | 'name' => 'checkbox-has-default',
168 | 'label' => 'checkbox has default',
169 | 'type' => 'check',
170 | 'choices' => array( 'a', 'b', 'c' ),
171 | 'default' => array( 'a' ),
172 | ),
173 | )
174 | );
175 | $Setting->add_group(
176 | 'checkbox-key-value',
177 | false,
178 | array(
179 | array(
180 | 'name' => 'checkbox-key-value',
181 | 'label' => 'checkbox key value',
182 | 'type' => 'check',
183 | 'choices' => array(
184 | 'a' => 'apple',
185 | 'b' => 'banana',
186 | 'c' => 'carrot',
187 | ),
188 | 'default' => array( 'a' ),
189 | ),
190 | )
191 | );
192 | $Setting->add_group(
193 | 'group',
194 | true,
195 | array(
196 | array(
197 | 'name' => 'repeat-text',
198 | 'label' => 'repeat text',
199 | 'type' => 'text',
200 | ),
201 | array(
202 | 'name' => 'repeat-checkbox',
203 | 'label' => 'repeat checkbox',
204 | 'type' => 'check',
205 | 'choices' => array( 'a', 'b', 'c' ),
206 | ),
207 | )
208 | );
209 | $settings[ $Setting->get_id() ] = $Setting;
210 | }
211 | return $settings;
212 | }
213 | }
214 |
--------------------------------------------------------------------------------
/tests/test-smart-custom-fields.php:
--------------------------------------------------------------------------------
1 | post_ids = $this->factory->post->create_many(
16 | 5,
17 | array(
18 | 'post_type' => SCF_Config::NAME,
19 | )
20 | );
21 |
22 | foreach ( $this->post_ids as $post_id ) {
23 | update_post_meta( $post_id, SCF_Config::PREFIX . 'repeat-multiple-data', 'dummy' );
24 | }
25 |
26 | for ( $i = 1; $i <= 5; $i++ ) {
27 | update_option( SCF_Config::PREFIX . $i, 'dummy' );
28 | }
29 |
30 | $Cache = Smart_Custom_Fields_Cache::get_instance();
31 | $Cache->flush();
32 | }
33 |
34 | /**
35 | * Tear down.
36 | */
37 | public function tear_down() {
38 | parent::tear_down();
39 | $Cache = Smart_Custom_Fields_Cache::get_instance();
40 | $Cache->flush();
41 | }
42 |
43 | /**
44 | * @group uninstall
45 | */
46 | public function test_uninstall__post() {
47 | Smart_Custom_Fields::uninstall();
48 | $posts = get_posts(
49 | array(
50 | 'post_type' => SCF_Config::NAME,
51 | 'posts_per_page' => -1,
52 | 'post_status' => 'any',
53 | )
54 | );
55 | $this->assertEquals( 0, count( $posts ) );
56 | }
57 |
58 | /**
59 | * @group uninstall
60 | */
61 | public function test_uninstall__repeat_multiple_data() {
62 | Smart_Custom_Fields::uninstall();
63 |
64 | // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
65 | global $wpdb;
66 | $var = $wpdb->get_var(
67 | $wpdb->prepare(
68 | "
69 | SELECT count( * ) FROM $wpdb->postmeta
70 | WHERE meta_key = %s
71 | ",
72 | SCF_Config::PREFIX . 'repeat-multiple-data'
73 | )
74 | );
75 | // phpcs:enable
76 |
77 | $this->assertEquals( 0, $var );
78 | }
79 |
80 | /**
81 | * @group uninstall
82 | */
83 | public function test_uninstall__option() {
84 | Smart_Custom_Fields::uninstall();
85 |
86 | // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
87 | global $wpdb;
88 | $var = $wpdb->get_var(
89 | $wpdb->prepare(
90 | "
91 | SELECT count( * ) FROM $wpdb->options
92 | WHERE option_name LIKE %s
93 | ",
94 | SCF_Config::PREFIX . '%'
95 | )
96 | );
97 | // phpcs:enable
98 |
99 | $this->assertEquals( 0, $var );
100 | }
101 | }
102 |
--------------------------------------------------------------------------------