-code">
+              "namedChunks": false,
56
+              "aot": true,
57
+              "extractLicenses": true,
58
+              "vendorChunk": false,
59
+              "buildOptimizer": true,
60
+              "budgets": [
61
+                {
62
+                  "type": "initial",
63
+                  "maximumWarning": "2mb",
64
+                  "maximumError": "5mb"
65
+                }
66
+              ]
67
+            },
68
+            "ci": {
69
+              "progress": false
70
+            }
71
+          }
72
+        },
73
+        "serve": {
74
+          "builder": "@angular-devkit/build-angular:dev-server",
75
+          "options": {
76
+            "browserTarget": "app:build"
77
+          },
78
+          "configurations": {
79
+            "production": {
80
+              "browserTarget": "app:build:production"
81
+            },
82
+            "ci": {
83
+              "progress": false
84
+            }
85
+          }
86
+        },
87
+        "extract-i18n": {
88
+          "builder": "@angular-devkit/build-angular:extract-i18n",
89
+          "options": {
90
+            "browserTarget": "app:build"
91
+          }
92
+        },
93
+        "test": {
94
+          "builder": "@angular-devkit/build-angular:karma",
95
+          "options": {
96
+            "main": "src/test.ts",
97
+            "polyfills": "src/polyfills.ts",
98
+            "tsConfig": "tsconfig.spec.json",
99
+            "karmaConfig": "karma.conf.js",
100
+            "styles": [],
101
+            "scripts": [],
102
+            "assets": [
103
+              {
104
+                "glob": "favicon.ico",
105
+                "input": "src/",
106
+                "output": "/"
107
+              },
108
+              {
109
+                "glob": "**/*",
110
+                "input": "src/assets",
111
+                "output": "/assets"
112
+              }
113
+            ]
114
+          },
115
+          "configurations": {
116
+            "ci": {
117
+              "progress": false,
118
+              "watch": false
119
+            }
120
+          }
121
+        },
122
+        "lint": {
123
+          "builder": "@angular-eslint/builder:lint",
124
+          "options": {
125
+            "lintFilePatterns": [
126
+              "src/**/*.ts",
127
+              "src/**/*.html"
128
+            ]
129
+          }
130
+        },
131
+        "e2e": {
132
+          "builder": "@angular-devkit/build-angular:protractor",
133
+          "options": {
134
+            "protractorConfig": "e2e/protractor.conf.js",
135
+            "devServerTarget": "app:serve"
136
+          },
137
+          "configurations": {
138
+            "production": {
139
+              "devServerTarget": "app:serve:production"
140
+            },
141
+            "ci": {
142
+              "devServerTarget": "app:serve:ci"
143
+            }
144
+          }
145
+        },
146
+        "ionic-cordova-build": {
147
+          "builder": "@ionic/angular-toolkit:cordova-build",
148
+          "options": {
149
+            "browserTarget": "app:build"
150
+          },
151
+          "configurations": {
152
+            "production": {
153
+              "browserTarget": "app:build:production"
154
+            }
155
+          }
156
+        },
157
+        "ionic-cordova-serve": {
158
+          "builder": "@ionic/angular-toolkit:cordova-serve",
159
+          "options": {
160
+            "cordovaBuildTarget": "app:ionic-cordova-build",
161
+            "devServerTarget": "app:serve"
162
+          },
163
+          "configurations": {
164
+            "production": {
165
+              "cordovaBuildTarget": "app:ionic-cordova-build:production",
166
+              "devServerTarget": "app:serve:production"
167
+            }
168
+          }
169
+        }
170
+      }
171
+    }
172
+  },
173
+  "cli": {
174
+    "analytics": false,
175
+    "defaultCollection": "@ionic/angular-toolkit"
176
+  },
177
+  "schematics": {
178
+    "@ionic/angular-toolkit:component": {
179
+      "styleext": "scss"
180
+    },
181
+    "@ionic/angular-toolkit:page": {
182
+      "styleext": "scss"
183
+    }
184
+  }
185
+}

+ 10 - 0
capacitor.config.ts

@@ -0,0 +1,10 @@
1
+import { CapacitorConfig } from '@capacitor/cli';
2
+
3
+const config: CapacitorConfig = {
4
+  appId: 'io.ionic.starter',
5
+  appName: 'Tune2Win',
6
+  webDir: 'www',
7
+  bundledWebRuntime: false
8
+};
9
+
10
+export default config;

+ 37 - 0
e2e/protractor.conf.js

@@ -0,0 +1,37 @@
1
+// @ts-check
2
+// Protractor configuration file, see link for more information
3
+// https://github.com/angular/protractor/blob/master/lib/config.ts
4
+
5
+const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter');
6
+
7
+/**
8
+ * @type { import("protractor").Config }
9
+ */
10
+exports.config = {
11
+  allScriptsTimeout: 11000,
12
+  specs: [
13
+    './src/**/*.e2e-spec.ts'
14
+  ],
15
+  capabilities: {
16
+    browserName: 'chrome'
17
+  },
18
+  directConnect: true,
19
+  SELENIUM_PROMISE_MANAGER: false,
20
+  baseUrl: 'http://localhost:4200/',
21
+  framework: 'jasmine',
22
+  jasmineNodeOpts: {
23
+    showColors: true,
24
+    defaultTimeoutInterval: 30000,
25
+    print: function() {}
26
+  },
27
+  onPrepare() {
28
+    require('ts-node').register({
29
+      project: require('path').join(__dirname, './tsconfig.json')
30
+    });
31
+    jasmine.getEnv().addReporter(new SpecReporter({
32
+      spec: {
33
+        displayStacktrace: StacktraceOption.PRETTY
34
+      }
35
+    }));
36
+  }
37
+};

+ 14 - 0
e2e/src/app.e2e-spec.ts

@@ -0,0 +1,14 @@
1
+import { AppPage } from './app.po';
2
+
3
+describe('new App', () => {
4
+  let page: AppPage;
5
+
6
+  beforeEach(() => {
7
+    page = new AppPage();
8
+  });
9
+
10
+  it('should display welcome message', () => {
11
+    page.navigateTo();
12
+    expect(page.getPageTitle()).toContain('Tab 1');
13
+  });
14
+});

+ 11 - 0
e2e/src/app.po.ts

@@ -0,0 +1,11 @@
1
+import { browser, by, element } from 'protractor';
2
+
3
+export class AppPage {
4
+  navigateTo() {
5
+    return browser.get('/');
6
+  }
7
+
8
+  getPageTitle() {
9
+    return element(by.css('ion-title')).getText();
10
+  }
11
+}

+ 12 - 0
e2e/tsconfig.json

@@ -0,0 +1,12 @@
1
+{
2
+  "extends": "../tsconfig.json",
3
+  "compilerOptions": {
4
+    "outDir": "../out-tsc/e2e",
5
+    "module": "commonjs",
6
+    "target": "es2018",
7
+    "types": [
8
+      "jasmine",
9
+      "node"
10
+    ]
11
+  }
12
+}

+ 7 - 0
ionic.config.json

@@ -0,0 +1,7 @@
1
+{
2
+  "name": "Tune2Win",
3
+  "integrations": {
4
+    "capacitor": {}
5
+  },
6
+  "type": "angular"
7
+}

+ 9 - 0
ios/.gitignore

@@ -0,0 +1,9 @@
1
+App/build
2
+App/Pods
3
+App/Podfile.lock
4
+App/App/public
5
+DerivedData
6
+xcuserdata
7
+
8
+# Cordova plugins for Capacitor
9
+capacitor-cordova-ios-plugins

+ 416 - 0
ios/App/App.xcodeproj/project.pbxproj

@@ -0,0 +1,416 @@
1
+// !$*UTF8*$!
2
+{
3
+	archiveVersion = 1;
4
+	classes = {
5
+	};
6
+	objectVersion = 48;
7
+	objects = {
8
+
9
+/* Begin PBXBuildFile section */
10
+		1EDEF1D527C21110006F183C /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1EDEF1D427C21110006F183C /* HealthKit.framework */; };
11
+		2FAD9763203C412B000D30F8 /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = 2FAD9762203C412B000D30F8 /* config.xml */; };
12
+		50379B232058CBB4000EE86E /* capacitor.config.json in Resources */ = {isa = PBXBuildFile; fileRef = 50379B222058CBB4000EE86E /* capacitor.config.json */; };
13
+		504EC3081FED79650016851F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504EC3071FED79650016851F /* AppDelegate.swift */; };
14
+		504EC30D1FED79650016851F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30B1FED79650016851F /* Main.storyboard */; };
15
+		504EC30F1FED79650016851F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30E1FED79650016851F /* Assets.xcassets */; };
16
+		504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC3101FED79650016851F /* LaunchScreen.storyboard */; };
17
+		50B271D11FEDC1A000F3C39B /* public in Resources */ = {isa = PBXBuildFile; fileRef = 50B271D01FEDC1A000F3C39B /* public */; };
18
+		A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */; };
19
+/* End PBXBuildFile section */
20
+
21
+/* Begin PBXFileReference section */
22
+		1EDEF1D327C21110006F183C /* App.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = App.entitlements; sourceTree = "<group>"; };
23
+		1EDEF1D427C21110006F183C /* HealthKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HealthKit.framework; path = System/Library/Frameworks/HealthKit.framework; sourceTree = SDKROOT; };
24
+		2FAD9762203C412B000D30F8 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = config.xml; sourceTree = "<group>"; };
25
+		50379B222058CBB4000EE86E /* capacitor.config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = capacitor.config.json; sourceTree = "<group>"; };
26
+		504EC3041FED79650016851F /* App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = App.app; sourceTree = BUILT_PRODUCTS_DIR; };
27
+		504EC3071FED79650016851F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
28
+		504EC30C1FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
29
+		504EC30E1FED79650016851F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
30
+		504EC3111FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
31
+		504EC3131FED79650016851F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
32
+		50B271D01FEDC1A000F3C39B /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = "<group>"; };
33
+		AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App.framework; sourceTree = BUILT_PRODUCTS_DIR; };
34
+		AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.release.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.release.xcconfig"; sourceTree = "<group>"; };
35
+		FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.debug.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.debug.xcconfig"; sourceTree = "<group>"; };
36
+/* End PBXFileReference section */
37
+
38
+/* Begin PBXFrameworksBuildPhase section */
39
+		504EC3011FED79650016851F /* Frameworks */ = {
40
+			isa = PBXFrameworksBuildPhase;
41
+			buildActionMask = 2147483647;
42
+			files = (
43
+				A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */,
44
+				1EDEF1D527C21110006F183C /* HealthKit.framework in Frameworks */,
45
+			);
46
+			runOnlyForDeploymentPostprocessing = 0;
47
+		};
48
+/* End PBXFrameworksBuildPhase section */
49
+
50
+/* Begin PBXGroup section */
51
+		27E2DDA53C4D2A4D1A88CE4A /* Frameworks */ = {
52
+			isa = PBXGroup;
53
+			children = (
54
+				1EDEF1D427C21110006F183C /* HealthKit.framework */,
55
+				AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */,
56
+			);
57
+			name = Frameworks;
58
+			sourceTree = "<group>";
59
+		};
60
+		504EC2FB1FED79650016851F = {
61
+			isa = PBXGroup;
62
+			children = (
63
+				504EC3061FED79650016851F /* App */,
64
+				504EC3051FED79650016851F /* Products */,
65
+				7F8756D8B27F46E3366F6CEA /* Pods */,
66
+				27E2DDA53C4D2A4D1A88CE4A /* Frameworks */,
67
+			);
68
+			sourceTree = "<group>";
69
+		};
70
+		504EC3051FED79650016851F /* Products */ = {
71
+			isa = PBXGroup;
72
+			children = (
73
+				504EC3041FED79650016851F /* App.app */,
74
+			);
75
+			name = Products;
76
+			sourceTree = "<group>";
77
+		};
78
+		504EC3061FED79650016851F /* App */ = {
79
+			isa = PBXGroup;
80
+			children = (
81
+				1EDEF1D327C21110006F183C /* App.entitlements */,
82
+				50379B222058CBB4000EE86E /* capacitor.config.json */,
83
+				504EC3071FED79650016851F /* AppDelegate.swift */,
84
+				504EC30B1FED79650016851F /* Main.storyboard */,
85
+				504EC30E1FED79650016851F /* Assets.xcassets */,
86
+				504EC3101FED79650016851F /* LaunchScreen.storyboard */,
87
+				504EC3131FED79650016851F /* Info.plist */,
88
+				2FAD9762203C412B000D30F8 /* config.xml */,
89
+				50B271D01FEDC1A000F3C39B /* public */,
90
+			);
91
+			path = App;
92
+			sourceTree = "<group>";
93
+		};
94
+		7F8756D8B27F46E3366F6CEA /* Pods */ = {
95
+			isa = PBXGroup;
96
+			children = (
97
+				FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */,
98
+				AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */,
99
+			);
100
+			name = Pods;
101
+			sourceTree = "<group>";
102
+		};
103
+/* End PBXGroup section */
104
+
105
+/* Begin PBXNativeTarget section */
106
+		504EC3031FED79650016851F /* App */ = {
107
+			isa = PBXNativeTarget;
108
+			buildConfigurationList = 504EC3161FED79650016851F /* Build configuration list for PBXNativeTarget "App" */;
109
+			buildPhases = (
110
+				6634F4EFEBD30273BCE97C65 /* [CP] Check Pods Manifest.lock */,
111
+				504EC3001FED79650016851F /* Sources */,
112
+				504EC3011FED79650016851F /* Frameworks */,
113
+				504EC3021FED79650016851F /* Resources */,
114
+				9592DBEFFC6D2A0C8D5DEB22 /* [CP] Embed Pods Frameworks */,
115
+			);
116
+			buildRules = (
117
+			);
118
+			dependencies = (
119
+			);
120
+			name = App;
121
+			productName = App;
122
+			productReference = 504EC3041FED79650016851F /* App.app */;
123
+			productType = "com.apple.product-type.application";
124
+		};
125
+/* End PBXNativeTarget section */
126
+
127
+/* Begin PBXProject section */
128
+		504EC2FC1FED79650016851F /* Project object */ = {
129
+			isa = PBXProject;
130
+			attributes = {
131
+				LastSwiftUpdateCheck = 0920;
132
+				LastUpgradeCheck = 0920;
133
+				TargetAttributes = {
134
+					504EC3031FED79650016851F = {
135
+						CreatedOnToolsVersion = 9.2;
136
+						LastSwiftMigration = 1100;
137
+						ProvisioningStyle = Automatic;
138
+					};
139
+				};
140
+			};
141
+			buildConfigurationList = 504EC2FF1FED79650016851F /* Build configuration list for PBXProject "App" */;
142
+			compatibilityVersion = "Xcode 8.0";
143
+			developmentRegion = en;
144
+			hasScannedForEncodings = 0;
145
+			knownRegions = (
146
+				en,
147
+				Base,
148
+			);
149
+			mainGroup = 504EC2FB1FED79650016851F;
150
+			productRefGroup = 504EC3051FED79650016851F /* Products */;
151
+			projectDirPath = "";
152
+			projectRoot = "";
153
+			targets = (
154
+				504EC3031FED79650016851F /* App */,
155
+			);
156
+		};
157
+/* End PBXProject section */
158
+
159
+/* Begin PBXResourcesBuildPhase section */
160
+		504EC3021FED79650016851F /* Resources */ = {
161
+			isa = PBXResourcesBuildPhase;
162
+			buildActionMask = 2147483647;
163
+			files = (
164
+				504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */,
165
+				50B271D11FEDC1A000F3C39B /* public in Resources */,
166
+				504EC30F1FED79650016851F /* Assets.xcassets in Resources */,
167
+				50379B232058CBB4000EE86E /* capacitor.config.json in Resources */,
168
+				504EC30D1FED79650016851F /* Main.storyboard in Resources */,
169
+				2FAD9763203C412B000D30F8 /* config.xml in Resources */,
170
+			);
171
+			runOnlyForDeploymentPostprocessing = 0;
172
+		};
173
+/* End PBXResourcesBuildPhase section */
174
+
175
+/* Begin PBXShellScriptBuildPhase section */
176
+		6634F4EFEBD30273BCE97C65 /* [CP] Check Pods Manifest.lock */ = {
177
+			isa = PBXShellScriptBuildPhase;
178
+			buildActionMask = 2147483647;
179
+			files = (
180
+			);
181
+			inputPaths = (
182
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
183
+				"${PODS_ROOT}/Manifest.lock",
184
+			);
185
+			name = "[CP] Check Pods Manifest.lock";
186
+			outputPaths = (
187
+				"$(DERIVED_FILE_DIR)/Pods-App-checkManifestLockResult.txt",
188
+			);
189
+			runOnlyForDeploymentPostprocessing = 0;
190
+			shellPath = /bin/sh;
191
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
192
+			showEnvVarsInLog = 0;
193
+		};
194
+		9592DBEFFC6D2A0C8D5DEB22 /* [CP] Embed Pods Frameworks */ = {
195
+			isa = PBXShellScriptBuildPhase;
196
+			buildActionMask = 2147483647;
197
+			files = (
198
+			);
199
+			inputPaths = (
200
+			);
201
+			name = "[CP] Embed Pods Frameworks";
202
+			outputPaths = (
203
+			);
204
+			runOnlyForDeploymentPostprocessing = 0;
205
+			shellPath = /bin/sh;
206
+			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-App/Pods-App-frameworks.sh\"\n";
207
+			showEnvVarsInLog = 0;
208
+		};
209
+/* End PBXShellScriptBuildPhase section */
210
+
211
+/* Begin PBXSourcesBuildPhase section */
212
+		504EC3001FED79650016851F /* Sources */ = {
213
+			isa = PBXSourcesBuildPhase;
214
+			buildActionMask = 2147483647;
215
+			files = (
216
+				504EC3081FED79650016851F /* AppDelegate.swift in Sources */,
217
+			);
218
+			runOnlyForDeploymentPostprocessing = 0;
219
+		};
220
+/* End PBXSourcesBuildPhase section */
221
+
222
+/* Begin PBXVariantGroup section */
223
+		504EC30B1FED79650016851F /* Main.storyboard */ = {
224
+			isa = PBXVariantGroup;
225
+			children = (
226
+				504EC30C1FED79650016851F /* Base */,
227
+			);
228
+			name = Main.storyboard;
229
+			sourceTree = "<group>";
230
+		};
231
+		504EC3101FED79650016851F /* LaunchScreen.storyboard */ = {
232
+			isa = PBXVariantGroup;
233
+			children = (
234
+				504EC3111FED79650016851F /* Base */,
235
+			);
236
+			name = LaunchScreen.storyboard;
237
+			sourceTree = "<group>";
238
+		};
239
+/* End PBXVariantGroup section */
240
+
241
+/* Begin XCBuildConfiguration section */
242
+		504EC3141FED79650016851F /* Debug */ = {
243
+			isa = XCBuildConfiguration;
244
+			buildSettings = {
245
+				ALWAYS_SEARCH_USER_PATHS = NO;
246
+				CLANG_ANALYZER_NONNULL = YES;
247
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
248
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
249
+				CLANG_CXX_LIBRARY = "libc++";
250
+				CLANG_ENABLE_MODULES = YES;
251
+				CLANG_ENABLE_OBJC_ARC = YES;
252
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
253
+				CLANG_WARN_BOOL_CONVERSION = YES;
254
+				CLANG_WARN_COMMA = YES;
255
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
256
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
257
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
258
+				CLANG_WARN_EMPTY_BODY = YES;
259
+				CLANG_WARN_ENUM_CONVERSION = YES;
260
+				CLANG_WARN_INFINITE_RECURSION = YES;
261
+				CLANG_WARN_INT_CONVERSION = YES;
262
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
263
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
264
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
265
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
266
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
267
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
268
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
269
+				CLANG_WARN_UNREACHABLE_CODE = YES;
270
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
271
+				CODE_SIGN_IDENTITY = "iPhone Developer";
272
+				COPY_PHASE_STRIP = NO;
273
+				DEBUG_INFORMATION_FORMAT = dwarf;
274
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
275
+				ENABLE_TESTABILITY = YES;
276
+				GCC_C_LANGUAGE_STANDARD = gnu11;
277
+				GCC_DYNAMIC_NO_PIC = NO;
278
+				GCC_NO_COMMON_BLOCKS = YES;
279
+				GCC_OPTIMIZATION_LEVEL = 0;
280
+				GCC_PREPROCESSOR_DEFINITIONS = (
281
+					"DEBUG=1",
282
+					"$(inherited)",
283
+				);
284
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
285
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
286
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
287
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
288
+				GCC_WARN_UNUSED_FUNCTION = YES;
289
+				GCC_WARN_UNUSED_VARIABLE = YES;
290
+				IPHONEOS_DEPLOYMENT_TARGET = 12.0;
291
+				MTL_ENABLE_DEBUG_INFO = YES;
292
+				ONLY_ACTIVE_ARCH = YES;
293
+				SDKROOT = iphoneos;
294
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
295
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
296
+			};
297
+			name = Debug;
298
+		};
299
+		504EC3151FED79650016851F /* Release */ = {
300
+			isa = XCBuildConfiguration;
301
+			buildSettings = {
302
+				ALWAYS_SEARCH_USER_PATHS = NO;
303
+				CLANG_ANALYZER_NONNULL = YES;
304
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
305
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
306
+				CLANG_CXX_LIBRARY = "libc++";
307
+				CLANG_ENABLE_MODULES = YES;
308
+				CLANG_ENABLE_OBJC_ARC = YES;
309
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
310
+				CLANG_WARN_BOOL_CONVERSION = YES;
311
+				CLANG_WARN_COMMA = YES;
312
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
313
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
314
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
315
+				CLANG_WARN_EMPTY_BODY = YES;
316
+				CLANG_WARN_ENUM_CONVERSION = YES;
317
+				CLANG_WARN_INFINITE_RECURSION = YES;
318
+				CLANG_WARN_INT_CONVERSION = YES;
319
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
320
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
321
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
322
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
323
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
324
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
325
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
326
+				CLANG_WARN_UNREACHABLE_CODE = YES;
327
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
328
+				CODE_SIGN_IDENTITY = "iPhone Developer";
329
+				COPY_PHASE_STRIP = NO;
330
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
331
+				ENABLE_NS_ASSERTIONS = NO;
332
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
333
+				GCC_C_LANGUAGE_STANDARD = gnu11;
334
+				GCC_NO_COMMON_BLOCKS = YES;
335
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
336
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
337
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
338
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
339
+				GCC_WARN_UNUSED_FUNCTION = YES;
340
+				GCC_WARN_UNUSED_VARIABLE = YES;
341
+				IPHONEOS_DEPLOYMENT_TARGET = 12.0;
342
+				MTL_ENABLE_DEBUG_INFO = NO;
343
+				SDKROOT = iphoneos;
344
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
345
+				VALIDATE_PRODUCT = YES;
346
+			};
347
+			name = Release;
348
+		};
349
+		504EC3171FED79650016851F /* Debug */ = {
350
+			isa = XCBuildConfiguration;
351
+			baseConfigurationReference = FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */;
352
+			buildSettings = {
353
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
354
+				CODE_SIGN_ENTITLEMENTS = App/App.entitlements;
355
+				CODE_SIGN_IDENTITY = "Apple Development";
356
+				CODE_SIGN_STYLE = Automatic;
357
+				DEVELOPMENT_TEAM = 5QTJEGL2H2;
358
+				INFOPLIST_FILE = App/Info.plist;
359
+				IPHONEOS_DEPLOYMENT_TARGET = 12.0;
360
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
361
+				OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
362
+				PRODUCT_BUNDLE_IDENTIFIER = net.simplico.tune2win;
363
+				PRODUCT_NAME = "$(TARGET_NAME)";
364
+				PROVISIONING_PROFILE_SPECIFIER = "";
365
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
366
+				SWIFT_VERSION = 5.0;
367
+				TARGETED_DEVICE_FAMILY = "1,2";
368
+			};
369
+			name = Debug;
370
+		};
371
+		504EC3181FED79650016851F /* Release */ = {
372
+			isa = XCBuildConfiguration;
373
+			baseConfigurationReference = AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */;
374
+			buildSettings = {
375
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
376
+				CODE_SIGN_ENTITLEMENTS = App/App.entitlements;
377
+				CODE_SIGN_IDENTITY = "Apple Development";
378
+				CODE_SIGN_STYLE = Automatic;
379
+				DEVELOPMENT_TEAM = 5QTJEGL2H2;
380
+				INFOPLIST_FILE = App/Info.plist;
381
+				IPHONEOS_DEPLOYMENT_TARGET = 12.0;
382
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
383
+				PRODUCT_BUNDLE_IDENTIFIER = net.simplico.tune2win;
384
+				PRODUCT_NAME = "$(TARGET_NAME)";
385
+				PROVISIONING_PROFILE_SPECIFIER = "";
386
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
387
+				SWIFT_VERSION = 5.0;
388
+				TARGETED_DEVICE_FAMILY = "1,2";
389
+			};
390
+			name = Release;
391
+		};
392
+/* End XCBuildConfiguration section */
393
+
394
+/* Begin XCConfigurationList section */
395
+		504EC2FF1FED79650016851F /* Build configuration list for PBXProject "App" */ = {
396
+			isa = XCConfigurationList;
397
+			buildConfigurations = (
398
+				504EC3141FED79650016851F /* Debug */,
399
+				504EC3151FED79650016851F /* Release */,
400
+			);
401
+			defaultConfigurationIsVisible = 0;
402
+			defaultConfigurationName = Release;
403
+		};
404
+		504EC3161FED79650016851F /* Build configuration list for PBXNativeTarget "App" */ = {
405
+			isa = XCConfigurationList;
406
+			buildConfigurations = (
407
+				504EC3171FED79650016851F /* Debug */,
408
+				504EC3181FED79650016851F /* Release */,
409
+			);
410
+			defaultConfigurationIsVisible = 0;
411
+			defaultConfigurationName = Release;
412
+		};
413
+/* End XCConfigurationList section */
414
+	};
415
+	rootObject = 504EC2FC1FED79650016851F /* Project object */;
416
+}

+ 7 - 0
ios/App/App.xcodeproj/project.xcworkspace/contents.xcworkspacedata

@@ -0,0 +1,7 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<Workspace
3
+   version = "1.0">
4
+   <FileRef
5
+      location = "self:App.xcodeproj">
6
+   </FileRef>
7
+</Workspace>

+ 10 - 0
ios/App/App.xcworkspace/contents.xcworkspacedata

@@ -0,0 +1,10 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<Workspace
3
+   version = "1.0">
4
+   <FileRef
5
+      location = "group:App.xcodeproj">
6
+   </FileRef>
7
+   <FileRef
8
+      location = "group:Pods/Pods.xcodeproj">
9
+   </FileRef>
10
+</Workspace>

+ 8 - 0
ios/App/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist

@@ -0,0 +1,8 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+<plist version="1.0">
4
+<dict>
5
+	<key>IDEDidComputeMac32BitWarning</key>
6
+	<true/>
7
+</dict>
8
+</plist>

+ 10 - 0
ios/App/App/App.entitlements

@@ -0,0 +1,10 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+<plist version="1.0">
4
+<dict>
5
+	<key>com.apple.developer.healthkit</key>
6
+	<true/>
7
+	<key>com.apple.developer.healthkit.access</key>
8
+	<array/>
9
+</dict>
10
+</plist>

+ 60 - 0
ios/App/App/AppDelegate.swift

@@ -0,0 +1,60 @@
1
+import UIKit
2
+import Capacitor
3
+
4
+@UIApplicationMain
5
+class AppDelegate: UIResponder, UIApplicationDelegate {
6
+
7
+    var window: UIWindow?
8
+
9
+    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
10
+        // Override point for customization after application launch.
11
+        return true
12
+    }
13
+
14
+    func applicationWillResignActive(_ application: UIApplication) {
15
+        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
16
+        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
17
+    }
18
+
19
+    func applicationDidEnterBackground(_ application: UIApplication) {
20
+        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
21
+        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
22
+    }
23
+
24
+    func applicationWillEnterForeground(_ application: UIApplication) {
25
+        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
26
+    }
27
+
28
+    func applicationDidBecomeActive(_ application: UIApplication) {
29
+        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
30
+    }
31
+
32
+    func applicationWillTerminate(_ application: UIApplication) {
33
+        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
34
+    }
35
+
36
+    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
37
+        // Called when the app was launched with a url. Feel free to add additional processing here,
38
+        // but if you want the App API to support tracking app url opens, make sure to keep this call
39
+        return ApplicationDelegateProxy.shared.application(app, open: url, options: options)
40
+    }
41
+
42
+    func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
43
+        // Called when the app was launched with an activity, including Universal Links.
44
+        // Feel free to add additional processing here, but if you want the App API to support
45
+        // tracking app url opens, make sure to keep this call
46
+        return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler)
47
+    }
48
+
49
+    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
50
+        super.touchesBegan(touches, with: event)
51
+
52
+        let statusBarRect = UIApplication.shared.statusBarFrame
53
+        guard let touchPoint = event?.allTouches?.first?.location(in: self.window) else { return }
54
+
55
+        if statusBarRect.contains(touchPoint) {
56
+            NotificationCenter.default.post(name: .capacitorStatusBarTapped, object: nil)
57
+        }
58
+    }
59
+
60
+}

BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x-1.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@3x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@1x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x-1.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@3x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x-1.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@3x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@2x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@3x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png


+ 116 - 0
ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json

@@ -0,0 +1,116 @@
1
+{
2
+  "images" : [
3
+    {
4
+      "size" : "20x20",
5
+      "idiom" : "iphone",
6
+      "filename" : "AppIcon-20x20@2x.png",
7
+      "scale" : "2x"
8
+    },
9
+    {
10
+      "size" : "20x20",
11
+      "idiom" : "iphone",
12
+      "filename" : "AppIcon-20x20@3x.png",
13
+      "scale" : "3x"
14
+    },
15
+    {
16
+      "size" : "29x29",
17
+      "idiom" : "iphone",
18
+      "filename" : "AppIcon-29x29@2x-1.png",
19
+      "scale" : "2x"
20
+    },
21
+    {
22
+      "size" : "29x29",
23
+      "idiom" : "iphone",
24
+      "filename" : "AppIcon-29x29@3x.png",
25
+      "scale" : "3x"
26
+    },
27
+    {
28
+      "size" : "40x40",
29
+      "idiom" : "iphone",
30
+      "filename" : "AppIcon-40x40@2x.png",
31
+      "scale" : "2x"
32
+    },
33
+    {
34
+      "size" : "40x40",
35
+      "idiom" : "iphone",
36
+      "filename" : "AppIcon-40x40@3x.png",
37
+      "scale" : "3x"
38
+    },
39
+    {
40
+      "size" : "60x60",
41
+      "idiom" : "iphone",
42
+      "filename" : "AppIcon-60x60@2x.png",
43
+      "scale" : "2x"
44
+    },
45
+    {
46
+      "size" : "60x60",
47
+      "idiom" : "iphone",
48
+      "filename" : "AppIcon-60x60@3x.png",
49
+      "scale" : "3x"
50
+    },
51
+    {
52
+      "size" : "20x20",
53
+      "idiom" : "ipad",
54
+      "filename" : "AppIcon-20x20@1x.png",
55
+      "scale" : "1x"
56
+    },
57
+    {
58
+      "size" : "20x20",
59
+      "idiom" : "ipad",
60
+      "filename" : "AppIcon-20x20@2x-1.png",
61
+      "scale" : "2x"
62
+    },
63
+    {
64
+      "size" : "29x29",
65
+      "idiom" : "ipad",
66
+      "filename" : "AppIcon-29x29@1x.png",
67
+      "scale" : "1x"
68
+    },
69
+    {
70
+      "size" : "29x29",
71
+      "idiom" : "ipad",
72
+      "filename" : "AppIcon-29x29@2x.png",
73
+      "scale" : "2x"
74
+    },
75
+    {
76
+      "size" : "40x40",
77
+      "idiom" : "ipad",
78
+      "filename" : "AppIcon-40x40@1x.png",
79
+      "scale" : "1x"
80
+    },
81
+    {
82
+      "size" : "40x40",
83
+      "idiom" : "ipad",
84
+      "filename" : "AppIcon-40x40@2x-1.png",
85
+      "scale" : "2x"
86
+    },
87
+    {
88
+      "size" : "76x76",
89
+      "idiom" : "ipad",
90
+      "filename" : "AppIcon-76x76@1x.png",
91
+      "scale" : "1x"
92
+    },
93
+    {
94
+      "size" : "76x76",
95
+      "idiom" : "ipad",
96
+      "filename" : "AppIcon-76x76@2x.png",
97
+      "scale" : "2x"
98
+    },
99
+    {
100
+      "size" : "83.5x83.5",
101
+      "idiom" : "ipad",
102
+      "filename" : "AppIcon-83.5x83.5@2x.png",
103
+      "scale" : "2x"
104
+    },
105
+    {
106
+      "size" : "1024x1024",
107
+      "idiom" : "ios-marketing",
108
+      "filename" : "AppIcon-512@2x.png",
109
+      "scale" : "1x"
110
+    }
111
+  ],
112
+  "info" : {
113
+    "version" : 1,
114
+    "author" : "xcode"
115
+  }
116
+}

+ 6 - 0
ios/App/App/Assets.xcassets/Contents.json

@@ -0,0 +1,6 @@
1
+{
2
+  "info" : {
3
+    "version" : 1,
4
+    "author" : "xcode"
5
+  }
6
+}

+ 23 - 0
ios/App/App/Assets.xcassets/Splash.imageset/Contents.json

@@ -0,0 +1,23 @@
1
+{
2
+  "images" : [
3
+    {
4
+      "idiom" : "universal",
5
+      "filename" : "splash-2732x2732-2.png",
6
+      "scale" : "1x"
7
+    },
8
+    {
9
+      "idiom" : "universal",
10
+      "filename" : "splash-2732x2732-1.png",
11
+      "scale" : "2x"
12
+    },
13
+    {
14
+      "idiom" : "universal",
15
+      "filename" : "splash-2732x2732.png",
16
+      "scale" : "3x"
17
+    }
18
+  ],
19
+  "info" : {
20
+    "version" : 1,
21
+    "author" : "xcode"
22
+  }
23
+}

BIN
ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png


BIN
ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png


BIN
ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png


+ 32 - 0
ios/App/App/Base.lproj/LaunchScreen.storyboard

@@ -0,0 +1,32 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17132" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
3
+    <device id="retina4_7" orientation="portrait" appearance="light"/>
4
+    <dependencies>
5
+        <deployment identifier="iOS"/>
6
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17105"/>
7
+        <capability name="System colors in document resources" minToolsVersion="11.0"/>
8
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
9
+    </dependencies>
10
+    <scenes>
11
+        <!--View Controller-->
12
+        <scene sceneID="EHf-IW-A2E">
13
+            <objects>
14
+                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
15
+                    <imageView key="view" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Splash" id="snD-IY-ifK">
16
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
17
+                        <autoresizingMask key="autoresizingMask"/>
18
+                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
19
+                    </imageView>
20
+                </viewController>
21
+                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
22
+            </objects>
23
+            <point key="canvasLocation" x="53" y="375"/>
24
+        </scene>
25
+    </scenes>
26
+    <resources>
27
+        <image name="Splash" width="1366" height="1366"/>
28
+        <systemColor name="systemBackgroundColor">
29
+            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
30
+        </systemColor>
31
+    </resources>
32
+</document>

+ 19 - 0
ios/App/App/Base.lproj/Main.storyboard

@@ -0,0 +1,19 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14111" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
3
+    <device id="retina4_7" orientation="portrait">
4
+        <adaptation id="fullscreen"/>
5
+    </device>
6
+    <dependencies>
7
+        <deployment identifier="iOS"/>
8
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
9
+    </dependencies>
10
+    <scenes>
11
+        <!--Bridge View Controller-->
12
+        <scene sceneID="tne-QT-ifu">
13
+            <objects>
14
+                <viewController id="BYZ-38-t0r" customClass="CAPBridgeViewController" customModule="Capacitor" sceneMemberID="viewController"/>
15
+                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
16
+            </objects>
17
+        </scene>
18
+    </scenes>
19
+</document>

+ 64 - 0
ios/App/App/Info.plist

@@ -0,0 +1,64 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+<plist version="1.0">
4
+<dict>
5
+	<key>CFBundleDevelopmentRegion</key>
6
+	<string>en</string>
7
+	<key>CFBundleDisplayName</key>
8
+	<string>Tune2Win</string>
9
+	<key>CFBundleExecutable</key>
10
+	<string>$(EXECUTABLE_NAME)</string>
11
+	<key>CFBundleIdentifier</key>
12
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
13
+	<key>CFBundleInfoDictionaryVersion</key>
14
+	<string>6.0</string>
15
+	<key>CFBundleName</key>
16
+	<string>$(PRODUCT_NAME)</string>
17
+	<key>CFBundlePackageType</key>
18
+	<string>APPL</string>
19
+	<key>CFBundleShortVersionString</key>
20
+	<string>1.0</string>
21
+	<key>CFBundleVersion</key>
22
+	<string>1</string>
23
+	<key>LSRequiresIPhoneOS</key>
24
+	<true/>
25
+	<key>NSAppTransportSecurity</key>
26
+	<dict>
27
+		<key>NSAllowsArbitraryLoads</key>
28
+		<true/>
29
+	</dict>
30
+    <key>NSContactsUsageDescription</key>
31
+    <string>Get Contact for your trainings</string>
32
+    <key>NSCalendarsUsageDescription</key>
33
+    <string>Access Calendar for trainings</string>
34
+	<key>NSHealthClinicalHealthRecordsShareUsageDescription</key>
35
+	<string>Get data for improve athlete</string>
36
+	<key>NSHealthShareUsageDescription</key>
37
+	<string>Get data for improve athlete</string>
38
+	<key>NSHealthUpdateUsageDescription</key>
39
+	<string>Get data for improve athlete</string>
40
+	<key>UILaunchStoryboardName</key>
41
+	<string>LaunchScreen</string>
42
+	<key>UIMainStoryboardFile</key>
43
+	<string>Main</string>
44
+	<key>UIRequiredDeviceCapabilities</key>
45
+	<array>
46
+		<string>armv7</string>
47
+	</array>
48
+	<key>UISupportedInterfaceOrientations</key>
49
+	<array>
50
+		<string>UIInterfaceOrientationPortrait</string>
51
+		<string>UIInterfaceOrientationLandscapeLeft</string>
52
+		<string>UIInterfaceOrientationLandscapeRight</string>
53
+	</array>
54
+	<key>UISupportedInterfaceOrientations~ipad</key>
55
+	<array>
56
+		<string>UIInterfaceOrientationPortrait</string>
57
+		<string>UIInterfaceOrientationPortraitUpsideDown</string>
58
+		<string>UIInterfaceOrientationLandscapeLeft</string>
59
+		<string>UIInterfaceOrientationLandscapeRight</string>
60
+	</array>
61
+	<key>UIViewControllerBasedStatusBarAppearance</key>
62
+	<true/>
63
+</dict>
64
+</plist>

+ 9 - 0
ios/App/App/capacitor.config.json

@@ -0,0 +1,9 @@
1
+{
2
+	"appId": "io.ionic.starter",
3
+	"appName": "Tune2Win",
4
+	"webDir": "www",
5
+	"bundledWebRuntime": false,
6
+	"server": {
7
+		"url": "http://192.168.1.38:8100"
8
+	}
9
+}

+ 14 - 0
ios/App/App/config.xml

@@ -0,0 +1,14 @@
1
+<?xml version='1.0' encoding='utf-8'?>
2
+<widget version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
3
+  <access origin="*" />
4
+  
5
+  <feature name="Calendar">
6
+    <param name="ios-package" value="Calendar"/>
7
+  </feature>
8
+
9
+  <feature name="HealthKit">
10
+    <param name="ios-package" value="HealthKit"/>
11
+  </feature>
12
+
13
+  
14
+</widget>

+ 22 - 0
ios/App/Podfile

@@ -0,0 +1,22 @@
1
+platform :ios, '12.0'
2
+use_frameworks!
3
+
4
+# workaround to avoid Xcode caching of Pods that requires
5
+# Product -> Clean Build Folder after new Cordova plugins installed
6
+# Requires CocoaPods 1.6 or newer
7
+install! 'cocoapods', :disable_input_output_paths => true
8
+
9
+def capacitor_pods
10
+  pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
11
+  pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
12
+  pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app'
13
+  pod 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics'
14
+  pod 'CapacitorKeyboard', :path => '../../node_modules/@capacitor/keyboard'
15
+  pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar'
16
+  pod 'CordovaPlugins', :path => '../capacitor-cordova-ios-plugins'
17
+end
18
+
19
+target 'App' do
20
+  capacitor_pods
21
+  # Add your Pods here
22
+end

+ 44 - 0
karma.conf.js

@@ -0,0 +1,44 @@
1
+// Karma configuration file, see link for more information
2
+// https://karma-runner.github.io/1.0/config/configuration-file.html
3
+
4
+module.exports = function (config) {
5
+  config.set({
6
+    basePath: '',
7
+    frameworks: ['jasmine', '@angular-devkit/build-angular'],
8
+    plugins: [
9
+      require('karma-jasmine'),
10
+      require('karma-chrome-launcher'),
11
+      require('karma-jasmine-html-reporter'),
12
+      require('karma-coverage'),
13
+      require('@angular-devkit/build-angular/plugins/karma')
14
+    ],
15
+    client: {
16
+      jasmine: {
17
+        // you can add configuration options for Jasmine here
18
+        // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
19
+        // for example, you can disable the random execution with `random: false`
20
+        // or set a specific seed with `seed: 4321`
21
+      },
22
+      clearContext: false // leave Jasmine Spec Runner output visible in browser
23
+    },
24
+    jasmineHtmlReporter: {
25
+      suppressAll: true // removes the duplicated traces
26
+    },
27
+    coverageReporter: {
28
+      dir: require('path').join(__dirname, './coverage/ngv'),
29
+      subdir: '.',
30
+      reporters: [
31
+        { type: 'html' },
32
+        { type: 'text-summary' }
33
+      ]
34
+    },
35
+    reporters: ['progress', 'kjhtml'],
36
+    port: 9876,
37
+    colors: true,
38
+    logLevel: config.LOG_INFO,
39
+    autoWatch: true,
40
+    browsers: ['Chrome'],
41
+    singleRun: false,
42
+    restartOnFileChange: true
43
+  });
44
+};

File diff suppressed because it is too large
+ 39378 - 0
package-lock.json


+ 75 - 0
package.json

@@ -0,0 +1,75 @@
1
+{
2
+  "name": "Tune2Win",
3
+  "version": "0.0.1",
4
+  "author": "Ionic Framework",
5
+  "homepage": "https://ionicframework.com/",
6
+  "scripts": {
7
+    "ng": "ng",
8
+    "start": "ng serve",
9
+    "build": "ng build",
10
+    "test": "ng test",
11
+    "lint": "ng lint",
12
+    "e2e": "ng e2e"
13
+  },
14
+  "private": true,
15
+  "dependencies": {
16
+    "@angular/common": "~13.0.0",
17
+    "@angular/core": "~13.0.0",
18
+    "@angular/forms": "~13.0.0",
19
+    "@angular/platform-browser": "~13.0.0",
20
+    "@angular/platform-browser-dynamic": "~13.0.0",
21
+    "@angular/router": "~13.0.0",
22
+    "@awesome-cordova-plugins/calendar": "^5.39.1",
23
+    "@awesome-cordova-plugins/health": "^5.39.1",
24
+    "@capacitor/app": "1.1.0",
25
+    "@capacitor/core": "3.4.1",
26
+    "@capacitor/haptics": "1.1.4",
27
+    "@capacitor/ios": "3.4.1",
28
+    "@capacitor/keyboard": "1.2.2",
29
+    "@capacitor/status-bar": "1.0.8",
30
+    "@ionic/angular": "^6.0.0",
31
+    "@ionic/storage-angular": "^3.0.6",
32
+    "chart.js": "^3.7.1",
33
+    "cordova-plugin-calendar": "^5.1.6",
34
+    "cordova-plugin-health": "^2.0.3",
35
+    "date-fns": "^2.28.0",
36
+    "ng2-charts": "^3.0.0-rc.7",
37
+    "rxjs": "~6.6.0",
38
+    "tslib": "^2.2.0",
39
+    "zone.js": "~0.11.4"
40
+  },
41
+  "devDependencies": {
42
+    "@angular-devkit/build-angular": "~13.0.1",
43
+    "@angular-eslint/builder": "~13.0.1",
44
+    "@angular-eslint/eslint-plugin": "~13.0.1",
45
+    "@angular-eslint/eslint-plugin-template": "~13.0.1",
46
+    "@angular-eslint/template-parser": "~13.0.1",
47
+    "@angular/cli": "~13.0.1",
48
+    "@angular/compiler": "~13.0.0",
49
+    "@angular/compiler-cli": "~13.0.0",
50
+    "@angular/language-service": "~13.0.0",
51
+    "@capacitor/cli": "3.4.1",
52
+    "@ionic/angular-toolkit": "^5.0.0",
53
+    "@types/jasmine": "~3.6.0",
54
+    "@types/jasminewd2": "~2.0.3",
55
+    "@types/node": "^12.11.1",
56
+    "@typescript-eslint/eslint-plugin": "5.3.0",
57
+    "@typescript-eslint/parser": "5.3.0",
58
+    "eslint": "^7.6.0",
59
+    "eslint-plugin-import": "2.22.1",
60
+    "eslint-plugin-jsdoc": "30.7.6",
61
+    "eslint-plugin-prefer-arrow": "1.2.2",
62
+    "jasmine-core": "~3.8.0",
63
+    "jasmine-spec-reporter": "~5.0.0",
64
+    "karma": "~6.3.2",
65
+    "karma-chrome-launcher": "~3.1.0",
66
+    "karma-coverage": "~2.0.3",
67
+    "karma-coverage-istanbul-reporter": "~3.0.2",
68
+    "karma-jasmine": "~4.0.0",
69
+    "karma-jasmine-html-reporter": "^1.5.0",
70
+    "protractor": "~7.0.0",
71
+    "ts-node": "~8.3.0",
72
+    "typescript": "~4.4.4"
73
+  },
74
+  "description": "An Ionic project"
75
+}

BIN
resources/icon.png


BIN
resources/ios/icon/icon-1024.png


BIN
resources/ios/icon/icon-108@2x.png


BIN
resources/ios/icon/icon-20.png


BIN
resources/ios/icon/icon-20@2x.png


BIN
resources/ios/icon/icon-20@3x.png


BIN
resources/ios/icon/icon-24@2x.png


BIN
resources/ios/icon/icon-27.5@2x.png


BIN
resources/ios/icon/icon-29.png


BIN
resources/ios/icon/icon-29@2x.png


BIN
resources/ios/icon/icon-29@3x.png


BIN
resources/ios/icon/icon-40.png


BIN
resources/ios/icon/icon-40@2x.png


BIN
resources/ios/icon/icon-40@3x.png


BIN
resources/ios/icon/icon-44@2x.png


BIN
resources/ios/icon/icon-50.png


BIN
resources/ios/icon/icon-50@2x.png


BIN
resources/ios/icon/icon-60.png


BIN
resources/ios/icon/icon-60@2x.png


BIN
resources/ios/icon/icon-60@3x.png


BIN
resources/ios/icon/icon-72.png


BIN
resources/ios/icon/icon-72@2x.png


BIN
resources/ios/icon/icon-76.png


BIN
resources/ios/icon/icon-76@2x.png


BIN
resources/ios/icon/icon-83.5@2x.png


BIN
resources/ios/icon/icon-86@2x.png


BIN
resources/ios/icon/icon-98@2x.png


BIN
resources/ios/icon/icon.png


BIN
resources/ios/icon/icon@2x.png


BIN
resources/ios/splash/Default-1792h~iphone.png


BIN
resources/ios/splash/Default-2436h.png


BIN
resources/ios/splash/Default-2688h~iphone.png


BIN
resources/ios/splash/Default-568h@2x~iphone.png


BIN
resources/ios/splash/Default-667h.png


BIN
resources/ios/splash/Default-736h.png


BIN
resources/ios/splash/Default-Landscape-1792h~iphone.png


BIN
resources/ios/splash/Default-Landscape-2436h.png


BIN
resources/ios/splash/Default-Landscape-2688h~iphone.png


BIN
resources/ios/splash/Default-Landscape-736h.png


BIN
resources/ios/splash/Default-Landscape@2x~ipad.png


BIN
resources/ios/splash/Default-Landscape@~ipadpro.png


BIN
resources/ios/splash/Default-Landscape~ipad.png


BIN
resources/ios/splash/Default-Portrait@2x~ipad.png


BIN
resources/ios/splash/Default-Portrait@~ipadpro.png


BIN
resources/ios/splash/Default-Portrait~ipad.png


BIN
resources/ios/splash/Default@2x~iphone.png


BIN
resources/ios/splash/Default@2x~universal~anyany.png


BIN
resources/ios/splash/Default~iphone.png


+ 0 - 0
resources/splash.png


Some files were not shown because too many files changed in this diff

tum/whitesports - Gogs: Simplico Git Service

Нет описания

option.php 75KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500
  1. <?php
  2. /**
  3. * Option API
  4. *
  5. * @package WordPress
  6. * @subpackage Option
  7. */
  8. /**
  9. * Retrieves an option value based on an option name.
  10. *
  11. * If the option does not exist, and a default value is not provided,
  12. * boolean false is returned. This could be used to check whether you need
  13. * to initialize an option during installation of a plugin, however that
  14. * can be done better by using add_option() which will not overwrite
  15. * existing options.
  16. *
  17. * Not initializing an option and using boolean `false` as a return value
  18. * is a bad practice as it triggers an additional database query.
  19. *
  20. * The type of the returned value can be different from the type that was passed
  21. * when saving or updating the option. If the option value was serialized,
  22. * then it will be unserialized when it is returned. In this case the type will
  23. * be the same. For example, storing a non-scalar value like an array will
  24. * return the same array.
  25. *
  26. * In most cases non-string scalar and null values will be converted and returned
  27. * as string equivalents.
  28. *
  29. * Exceptions:
  30. * 1. When the option has not been saved in the database, the `$default` value
  31. * is returned if provided. If not, boolean `false` is returned.
  32. * 2. When one of the Options API filters is used: {@see 'pre_option_{$option}'},
  33. * {@see 'default_option_{$option}'}, or {@see 'option_{$option}'}, the returned
  34. * value may not match the expected type.
  35. * 3. When the option has just been saved in the database, and get_option()
  36. * is used right after, non-string scalar and null values are not converted to
  37. * string equivalents and the original type is returned.
  38. *
  39. * Examples:
  40. *
  41. * When adding options like this: `add_option( 'my_option_name', 'value' );`
  42. * and then retrieving them with `get_option( 'my_option_name' );`, the returned
  43. * values will be:
  44. *
  45. * `false` returns `string(0) ""`
  46. * `true` returns `string(1) "1"`
  47. * `0` returns `string(1) "0"`
  48. * `1` returns `string(1) "1"`
  49. * `'0'` returns `string(1) "0"`
  50. * `'1'` returns `string(1) "1"`
  51. * `null` returns `string(0) ""`
  52. *
  53. * When adding options with non-scalar values like
  54. * `add_option( 'my_array', array( false, 'str', null ) );`, the returned value
  55. * will be identical to the original as it is serialized before saving
  56. * it in the database:
  57. *
  58. * array(3) {
  59. * [0] => bool(false)
  60. * [1] => string(3) "str"
  61. * [2] => NULL
  62. * }
  63. *
  64. * @since 1.5.0
  65. *
  66. * @global wpdb $wpdb WordPress database abstraction object.
  67. *
  68. * @param string $option Name of the option to retrieve. Expected to not be SQL-escaped.
  69. * @param mixed $default Optional. Default value to return if the option does not exist.
  70. * @return mixed Value of the option. A value of any type may be returned, including
  71. * scalar (string, boolean, float, integer), null, array, object.
  72. * Scalar and null values will be returned as strings as long as they originate
  73. * from a database stored option value. If there is no option in the database,
  74. * boolean `false` is returned.
  75. */
  76. function get_option( $option, $default = false ) {
  77. global $wpdb;
  78. $option = trim( $option );
  79. if ( empty( $option ) ) {
  80. return false;
  81. }
  82. /*
  83. * Until a proper _deprecated_option() function can be introduced,
  84. * redirect requests to deprecated keys to the new, correct ones.
  85. */
  86. $deprecated_keys = array(
  87. 'blacklist_keys' => 'disallowed_keys',
  88. 'comment_whitelist' => 'comment_previously_approved',
  89. );
  90. if ( ! wp_installing() && isset( $deprecated_keys[ $option ] ) ) {
  91. _deprecated_argument(
  92. __FUNCTION__,
  93. '5.5.0',
  94. sprintf(
  95. /* translators: 1: Deprecated option key, 2: New option key. */
  96. __( 'The "%1$s" option key has been renamed to "%2$s".' ),
  97. $option,
  98. $deprecated_keys[ $option ]
  99. )
  100. );
  101. return get_option( $deprecated_keys[ $option ], $default );
  102. }
  103. /**
  104. * Filters the value of an existing option before it is retrieved.
  105. *
  106. * The dynamic portion of the hook name, `$option`, refers to the option name.
  107. *
  108. * Returning a truthy value from the filter will effectively short-circuit retrieval
  109. * and return the passed value instead.
  110. *
  111. * @since 1.5.0
  112. * @since 4.4.0 The `$option` parameter was added.
  113. * @since 4.9.0 The `$default` parameter was added.
  114. *
  115. * @param mixed $pre_option The value to return instead of the option value. This differs
  116. * from `$default`, which is used as the fallback value in the event
  117. * the option doesn't exist elsewhere in get_option().
  118. * Default false (to skip past the short-circuit).
  119. * @param string $option Option name.
  120. * @param mixed $default The fallback value to return if the option does not exist.
  121. * Default false.
  122. */
  123. $pre = apply_filters( "pre_option_{$option}", false, $option, $default );
  124. if ( false !== $pre ) {
  125. return $pre;
  126. }
  127. if ( defined( 'WP_SETUP_CONFIG' ) ) {
  128. return false;
  129. }
  130. // Distinguish between `false` as a default, and not passing one.
  131. $passed_default = func_num_args() > 1;
  132. if ( ! wp_installing() ) {
  133. // Prevent non-existent options from triggering multiple queries.
  134. $notoptions = wp_cache_get( 'notoptions', 'options' );
  135. if ( isset( $notoptions[ $option ] ) ) {
  136. /**
  137. * Filters the default value for an option.
  138. *
  139. * The dynamic portion of the hook name, `$option`, refers to the option name.
  140. *
  141. * @since 3.4.0
  142. * @since 4.4.0 The `$option` parameter was added.
  143. * @since 4.7.0 The `$passed_default` parameter was added to distinguish between a `false` value and the default parameter value.
  144. *
  145. * @param mixed $default The default value to return if the option does not exist
  146. * in the database.
  147. * @param string $option Option name.
  148. * @param bool $passed_default Was `get_option()` passed a default value?
  149. */
  150. return apply_filters( "default_option_{$option}", $default, $option, $passed_default );
  151. }
  152. $alloptions = wp_load_alloptions();
  153. if ( isset( $alloptions[ $option ] ) ) {
  154. $value = $alloptions[ $option ];
  155. } else {
  156. $value = wp_cache_get( $option, 'options' );
  157. if ( false === $value ) {
  158. $row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
  159. // Has to be get_row() instead of get_var() because of funkiness with 0, false, null values.
  160. if ( is_object( $row ) ) {
  161. $value = $row->option_value;
  162. wp_cache_add( $option, $value, 'options' );
  163. } else { // Option does not exist, so we must cache its non-existence.
  164. if ( ! is_array( $notoptions ) ) {
  165. $notoptions = array();
  166. }
  167. $notoptions[ $option ] = true;
  168. wp_cache_set( 'notoptions', $notoptions, 'options' );
  169. /** This filter is documented in wp-includes/option.php */
  170. return apply_filters( "default_option_{$option}", $default, $option, $passed_default );
  171. }
  172. }
  173. }
  174. } else {
  175. $suppress = $wpdb->suppress_errors();
  176. $row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
  177. $wpdb->suppress_errors( $suppress );
  178. if ( is_object( $row ) ) {
  179. $value = $row->option_value;
  180. } else {
  181. /** This filter is documented in wp-includes/option.php */
  182. return apply_filters( "default_option_{$option}", $default, $option, $passed_default );
  183. }
  184. }
  185. // If home is not set, use siteurl.
  186. if ( 'home' === $option && '' === $value ) {
  187. return get_option( 'siteurl' );
  188. }
  189. if ( in_array( $option, array( 'siteurl', 'home', 'category_base', 'tag_base' ), true ) ) {
  190. $value = untrailingslashit( $value );
  191. }
  192. /**
  193. * Filters the value of an existing option.
  194. *
  195. * The dynamic portion of the hook name, `$option`, refers to the option name.
  196. *
  197. * @since 1.5.0 As 'option_' . $setting
  198. * @since 3.0.0
  199. * @since 4.4.0 The `$option` parameter was added.
  200. *
  201. * @param mixed $value Value of the option. If stored serialized, it will be
  202. * unserialized prior to being returned.
  203. * @param string $option Option name.
  204. */
  205. return apply_filters( "option_{$option}", maybe_unserialize( $value ), $option );
  206. }
  207. /**
  208. * Protects WordPress special option from being modified.
  209. *
  210. * Will die if $option is in protected list. Protected options are 'alloptions'
  211. * and 'notoptions' options.
  212. *
  213. * @since 2.2.0
  214. *
  215. * @param string $option Option name.
  216. */
  217. function wp_protect_special_option( $option ) {
  218. if ( 'alloptions' === $option || 'notoptions' === $option ) {
  219. wp_die(
  220. sprintf(
  221. /* translators: %s: Option name. */
  222. __( '%s is a protected WP option and may not be modified' ),
  223. esc_html( $option )
  224. )
  225. );
  226. }
  227. }
  228. /**
  229. * Prints option value after sanitizing for forms.
  230. *
  231. * @since 1.5.0
  232. *
  233. * @param string $option Option name.
  234. */
  235. function form_option( $option ) {
  236. echo esc_attr( get_option( $option ) );
  237. }
  238. /**
  239. * Loads and caches all autoloaded options, if available or all options.
  240. *
  241. * @since 2.2.0
  242. * @since 5.3.1 The `$force_cache` parameter was added.
  243. *
  244. * @global wpdb $wpdb WordPress database abstraction object.
  245. *
  246. * @param bool $force_cache Optional. Whether to force an update of the local cache
  247. * from the persistent cache. Default false.
  248. * @return array List of all options.
  249. */
  250. function wp_load_alloptions( $force_cache = false ) {
  251. global $wpdb;
  252. if ( ! wp_installing() || ! is_multisite() ) {
  253. $alloptions = wp_cache_get( 'alloptions', 'options', $force_cache );
  254. } else {
  255. $alloptions = false;
  256. }
  257. if ( ! $alloptions ) {
  258. $suppress = $wpdb->suppress_errors();
  259. $alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options WHERE autoload = 'yes'" );
  260. if ( ! $alloptions_db ) {
  261. $alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options" );
  262. }
  263. $wpdb->suppress_errors( $suppress );
  264. $alloptions = array();
  265. foreach ( (array) $alloptions_db as $o ) {
  266. $alloptions[ $o->option_name ] = $o->option_value;
  267. }
  268. if ( ! wp_installing() || ! is_multisite() ) {
  269. /**
  270. * Filters all options before caching them.
  271. *
  272. * @since 4.9.0
  273. *
  274. * @param array $alloptions Array with all options.
  275. */
  276. $alloptions = apply_filters( 'pre_cache_alloptions', $alloptions );
  277. wp_cache_add( 'alloptions', $alloptions, 'options' );
  278. }
  279. }
  280. /**
  281. * Filters all options after retrieving them.
  282. *
  283. * @since 4.9.0
  284. *
  285. * @param array $alloptions Array with all options.
  286. */
  287. return apply_filters( 'alloptions', $alloptions );
  288. }
  289. /**
  290. * Loads and caches certain often requested site options if is_multisite() and a persistent cache is not being used.
  291. *
  292. * @since 3.0.0
  293. *
  294. * @global wpdb $wpdb WordPress database abstraction object.
  295. *
  296. * @param int $network_id Optional site ID for which to query the options. Defaults to the current site.
  297. */
  298. function wp_load_core_site_options( $network_id = null ) {
  299. global $wpdb;
  300. if ( ! is_multisite() || wp_using_ext_object_cache() || wp_installing() ) {
  301. return;
  302. }
  303. if ( empty( $network_id ) ) {
  304. $network_id = get_current_network_id();
  305. }
  306. $core_options = array( 'site_name', 'siteurl', 'active_sitewide_plugins', '_site_transient_timeout_theme_roots', '_site_transient_theme_roots', 'site_admins', 'can_compress_scripts', 'global_terms_enabled', 'ms_files_rewriting' );
  307. $core_options_in = "'" . implode( "', '", $core_options ) . "'";
  308. $options = $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value FROM $wpdb->sitemeta WHERE meta_key IN ($core_options_in) AND site_id = %d", $network_id ) );
  309. foreach ( $options as $option ) {
  310. $key = $option->meta_key;
  311. $cache_key = "{$network_id}:$key";
  312. $option->meta_value = maybe_unserialize( $option->meta_value );
  313. wp_cache_set( $cache_key, $option->meta_value, 'site-options' );
  314. }
  315. }
  316. /**
  317. * Updates the value of an option that was already added.
  318. *
  319. * You do not need to serialize values. If the value needs to be serialized,
  320. * then it will be serialized before it is inserted into the database.
  321. * Remember, resources cannot be serialized or added as an option.
  322. *
  323. * If the option does not exist, it will be created.
  324. * This function is designed to work with or without a logged-in user. In terms of security,
  325. * plugin developers should check the current user's capabilities before updating any options.
  326. *
  327. * @since 1.0.0
  328. * @since 4.2.0 The `$autoload` parameter was added.
  329. *
  330. * @global wpdb $wpdb WordPress database abstraction object.
  331. *
  332. * @param string $option Name of the option to update. Expected to not be SQL-escaped.
  333. * @param mixed $value Option value. Must be serializable if non-scalar. Expected to not be SQL-escaped.
  334. * @param string|bool $autoload Optional. Whether to load the option when WordPress starts up. For existing options,
  335. * `$autoload` can only be updated using `update_option()` if `$value` is also changed.
  336. * Accepts 'yes'|true to enable or 'no'|false to disable. For non-existent options,
  337. * the default value is 'yes'. Default null.
  338. * @return bool True if the value was updated, false otherwise.
  339. */
  340. function update_option( $option, $value, $autoload = null ) {
  341. global $wpdb;
  342. $option = trim( $option );
  343. if ( empty( $option ) ) {
  344. return false;
  345. }
  346. /*
  347. * Until a proper _deprecated_option() function can be introduced,
  348. * redirect requests to deprecated keys to the new, correct ones.
  349. */
  350. $deprecated_keys = array(
  351. 'blacklist_keys' => 'disallowed_keys',
  352. 'comment_whitelist' => 'comment_previously_approved',
  353. );
  354. if ( ! wp_installing() && isset( $deprecated_keys[ $option ] ) ) {
  355. _deprecated_argument(
  356. __FUNCTION__,
  357. '5.5.0',
  358. sprintf(
  359. /* translators: 1: Deprecated option key, 2: New option key. */
  360. __( 'The "%1$s" option key has been renamed to "%2$s".' ),
  361. $option,
  362. $deprecated_keys[ $option ]
  363. )
  364. );
  365. return update_option( $deprecated_keys[ $option ], $value, $autoload );
  366. }
  367. wp_protect_special_option( $option );
  368. if ( is_object( $value ) ) {
  369. $value = clone $value;
  370. }
  371. $value = sanitize_option( $option, $value );
  372. $old_value = get_option( $option );
  373. /**
  374. * Filters a specific option before its value is (maybe) serialized and updated.
  375. *
  376. * The dynamic portion of the hook name, `$option`, refers to the option name.
  377. *
  378. * @since 2.6.0
  379. * @since 4.4.0 The `$option` parameter was added.
  380. *
  381. * @param mixed $value The new, unserialized option value.
  382. * @param mixed $old_value The old option value.
  383. * @param string $option Option name.
  384. */
  385. $value = apply_filters( "pre_update_option_{$option}", $value, $old_value, $option );
  386. /**
  387. * Filters an option before its value is (maybe) serialized and updated.
  388. *
  389. * @since 3.9.0
  390. *
  391. * @param mixed $value The new, unserialized option value.
  392. * @param string $option Name of the option.
  393. * @param mixed $old_value The old option value.
  394. */
  395. $value = apply_filters( 'pre_update_option', $value, $option, $old_value );
  396. /*
  397. * If the new and old values are the same, no need to update.
  398. *
  399. * Unserialized values will be adequate in most cases. If the unserialized
  400. * data differs, the (maybe) serialized data is checked to avoid
  401. * unnecessary database calls for otherwise identical object instances.
  402. *
  403. * See https://core.trac.wordpress.org/ticket/38903
  404. */
  405. if ( $value === $old_value || maybe_serialize( $value ) === maybe_serialize( $old_value ) ) {
  406. return false;
  407. }
  408. /** This filter is documented in wp-includes/option.php */
  409. if ( apply_filters( "default_option_{$option}", false, $option, false ) === $old_value ) {
  410. // Default setting for new options is 'yes'.
  411. if ( null === $autoload ) {
  412. $autoload = 'yes';
  413. }
  414. return add_option( $option, $value, '', $autoload );
  415. }
  416. $serialized_value = maybe_serialize( $value );
  417. /**
  418. * Fires immediately before an option value is updated.
  419. *
  420. * @since 2.9.0
  421. *
  422. * @param string $option Name of the option to update.
  423. * @param mixed $old_value The old option value.
  424. * @param mixed $value The new option value.
  425. */
  426. do_action( 'update_option', $option, $old_value, $value );
  427. $update_args = array(
  428. 'option_value' => $serialized_value,
  429. );
  430. if ( null !== $autoload ) {
  431. $update_args['autoload'] = ( 'no' === $autoload || false === $autoload ) ? 'no' : 'yes';
  432. }
  433. $result = $wpdb->update( $wpdb->options, $update_args, array( 'option_name' => $option ) );
  434. if ( ! $result ) {
  435. return false;
  436. }
  437. $notoptions = wp_cache_get( 'notoptions', 'options' );
  438. if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
  439. unset( $notoptions[ $option ] );
  440. wp_cache_set( 'notoptions', $notoptions, 'options' );
  441. }
  442. if ( ! wp_installing() ) {
  443. $alloptions = wp_load_alloptions( true );
  444. if ( isset( $alloptions[ $option ] ) ) {
  445. $alloptions[ $option ] = $serialized_value;
  446. wp_cache_set( 'alloptions', $alloptions, 'options' );
  447. } else {
  448. wp_cache_set( $option, $serialized_value, 'options' );
  449. }
  450. }
  451. /**
  452. * Fires after the value of a specific option has been successfully updated.
  453. *
  454. * The dynamic portion of the hook name, `$option`, refers to the option name.
  455. *
  456. * @since 2.0.1
  457. * @since 4.4.0 The `$option` parameter was added.
  458. *
  459. * @param mixed $old_value The old option value.
  460. * @param mixed $value The new option value.
  461. * @param string $option Option name.
  462. */
  463. do_action( "update_option_{$option}", $old_value, $value, $option );
  464. /**
  465. * Fires after the value of an option has been successfully updated.
  466. *
  467. * @since 2.9.0
  468. *
  469. * @param string $option Name of the updated option.
  470. * @param mixed $old_value The old option value.
  471. * @param mixed $value The new option value.
  472. */
  473. do_action( 'updated_option', $option, $old_value, $value );
  474. return true;
  475. }
  476. /**
  477. * Adds a new option.
  478. *
  479. * You do not need to serialize values. If the value needs to be serialized,
  480. * then it will be serialized before it is inserted into the database.
  481. * Remember, resources cannot be serialized or added as an option.
  482. *
  483. * You can create options without values and then update the values later.
  484. * Existing options will not be updated and checks are performed to ensure that you
  485. * aren't adding a protected WordPress option. Care should be taken to not name
  486. * options the same as the ones which are protected.
  487. *
  488. * @since 1.0.0
  489. *
  490. * @global wpdb $wpdb WordPress database abstraction object.
  491. *
  492. * @param string $option Name of the option to add. Expected to not be SQL-escaped.
  493. * @param mixed $value Optional. Option value. Must be serializable if non-scalar.
  494. * Expected to not be SQL-escaped.
  495. * @param string $deprecated Optional. Description. Not used anymore.
  496. * @param string|bool $autoload Optional. Whether to load the option when WordPress starts up.
  497. * Default is enabled. Accepts 'no' to disable for legacy reasons.
  498. * @return bool True if the option was added, false otherwise.
  499. */
  500. function add_option( $option, $value = '', $deprecated = '', $autoload = 'yes' ) {
  501. global $wpdb;
  502. if ( ! empty( $deprecated ) ) {
  503. _deprecated_argument( __FUNCTION__, '2.3.0' );
  504. }
  505. $option = trim( $option );
  506. if ( empty( $option ) ) {
  507. return false;
  508. }
  509. /*
  510. * Until a proper _deprecated_option() function can be introduced,
  511. * redirect requests to deprecated keys to the new, correct ones.
  512. */
  513. $deprecated_keys = array(
  514. 'blacklist_keys' => 'disallowed_keys',
  515. 'comment_whitelist' => 'comment_previously_approved',
  516. );
  517. if ( ! wp_installing() && isset( $deprecated_keys[ $option ] ) ) {
  518. _deprecated_argument(
  519. __FUNCTION__,
  520. '5.5.0',
  521. sprintf(
  522. /* translators: 1: Deprecated option key, 2: New option key. */
  523. __( 'The "%1$s" option key has been renamed to "%2$s".' ),
  524. $option,
  525. $deprecated_keys[ $option ]
  526. )
  527. );
  528. return add_option( $deprecated_keys[ $option ], $value, $deprecated, $autoload );
  529. }
  530. wp_protect_special_option( $option );
  531. if ( is_object( $value ) ) {
  532. $value = clone $value;
  533. }
  534. $value = sanitize_option( $option, $value );
  535. // Make sure the option doesn't already exist.
  536. // We can check the 'notoptions' cache before we ask for a DB query.
  537. $notoptions = wp_cache_get( 'notoptions', 'options' );
  538. if ( ! is_array( $notoptions ) || ! isset( $notoptions[ $option ] ) ) {
  539. /** This filter is documented in wp-includes/option.php */
  540. if ( apply_filters( "default_option_{$option}", false, $option, false ) !== get_option( $option ) ) {
  541. return false;
  542. }
  543. }
  544. $serialized_value = maybe_serialize( $value );
  545. $autoload = ( 'no' === $autoload || false === $autoload ) ? 'no' : 'yes';
  546. /**
  547. * Fires before an option is added.
  548. *
  549. * @since 2.9.0
  550. *
  551. * @param string $option Name of the option to add.
  552. * @param mixed $value Value of the option.
  553. */
  554. do_action( 'add_option', $option, $value );
  555. $result = $wpdb->query( $wpdb->prepare( "INSERT INTO `$wpdb->options` (`option_name`, `option_value`, `autoload`) VALUES (%s, %s, %s) ON DUPLICATE KEY UPDATE `option_name` = VALUES(`option_name`), `option_value` = VALUES(`option_value`), `autoload` = VALUES(`autoload`)", $option, $serialized_value, $autoload ) );
  556. if ( ! $result ) {
  557. return false;
  558. }
  559. if ( ! wp_installing() ) {
  560. if ( 'yes' === $autoload ) {
  561. $alloptions = wp_load_alloptions( true );
  562. $alloptions[ $option ] = $serialized_value;
  563. wp_cache_set( 'alloptions', $alloptions, 'options' );
  564. } else {
  565. wp_cache_set( $option, $serialized_value, 'options' );
  566. }
  567. }
  568. // This option exists now.
  569. $notoptions = wp_cache_get( 'notoptions', 'options' ); // Yes, again... we need it to be fresh.
  570. if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
  571. unset( $notoptions[ $option ] );
  572. wp_cache_set( 'notoptions', $notoptions, 'options' );
  573. }
  574. /**
  575. * Fires after a specific option has been added.
  576. *
  577. * The dynamic portion of the hook name, `$option`, refers to the option name.
  578. *
  579. * @since 2.5.0 As "add_option_{$name}"
  580. * @since 3.0.0
  581. *
  582. * @param string $option Name of the option to add.
  583. * @param mixed $value Value of the option.
  584. */
  585. do_action( "add_option_{$option}", $option, $value );
  586. /**
  587. * Fires after an option has been added.
  588. *
  589. * @since 2.9.0
  590. *
  591. * @param string $option Name of the added option.
  592. * @param mixed $value Value of the option.
  593. */
  594. do_action( 'added_option', $option, $value );
  595. return true;
  596. }
  597. /**
  598. * Removes option by name. Prevents removal of protected WordPress options.
  599. *
  600. * @since 1.2.0
  601. *
  602. * @global wpdb $wpdb WordPress database abstraction object.
  603. *
  604. * @param string $option Name of the option to delete. Expected to not be SQL-escaped.
  605. * @return bool True if the option was deleted, false otherwise.
  606. */
  607. function delete_option( $option ) {
  608. global $wpdb;
  609. $option = trim( $option );
  610. if ( empty( $option ) ) {
  611. return false;
  612. }
  613. wp_protect_special_option( $option );
  614. // Get the ID, if no ID then return.
  615. $row = $wpdb->get_row( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name = %s", $option ) );
  616. if ( is_null( $row ) ) {
  617. return false;
  618. }
  619. /**
  620. * Fires immediately before an option is deleted.
  621. *
  622. * @since 2.9.0
  623. *
  624. * @param string $option Name of the option to delete.
  625. */
  626. do_action( 'delete_option', $option );
  627. $result = $wpdb->delete( $wpdb->options, array( 'option_name' => $option ) );
  628. if ( ! wp_installing() ) {
  629. if ( 'yes' === $row->autoload ) {
  630. $alloptions = wp_load_alloptions( true );
  631. if ( is_array( $alloptions ) && isset( $alloptions[ $option ] ) ) {
  632. unset( $alloptions[ $option ] );
  633. wp_cache_set( 'alloptions', $alloptions, 'options' );
  634. }
  635. } else {
  636. wp_cache_delete( $option, 'options' );
  637. }
  638. }
  639. if ( $result ) {
  640. /**
  641. * Fires after a specific option has been deleted.
  642. *
  643. * The dynamic portion of the hook name, `$option`, refers to the option name.
  644. *
  645. * @since 3.0.0
  646. *
  647. * @param string $option Name of the deleted option.
  648. */
  649. do_action( "delete_option_{$option}", $option );
  650. /**
  651. * Fires after an option has been deleted.
  652. *
  653. * @since 2.9.0
  654. *
  655. * @param string $option Name of the deleted option.
  656. */
  657. do_action( 'deleted_option', $option );
  658. return true;
  659. }
  660. return false;
  661. }
  662. /**
  663. * Deletes a transient.
  664. *
  665. * @since 2.8.0
  666. *
  667. * @param string $transient Transient name. Expected to not be SQL-escaped.
  668. * @return bool True if the transient was deleted, false otherwise.
  669. */
  670. function delete_transient( $transient ) {
  671. /**
  672. * Fires immediately before a specific transient is deleted.
  673. *
  674. * The dynamic portion of the hook name, `$transient`, refers to the transient name.
  675. *
  676. * @since 3.0.0
  677. *
  678. * @param string $transient Transient name.
  679. */
  680. do_action( "delete_transient_{$transient}", $transient );
  681. if ( wp_using_ext_object_cache() ) {
  682. $result = wp_cache_delete( $transient, 'transient' );
  683. } else {
  684. $option_timeout = '_transient_timeout_' . $transient;
  685. $option = '_transient_' . $transient;
  686. $result = delete_option( $option );
  687. if ( $result ) {
  688. delete_option( $option_timeout );
  689. }
  690. }
  691. if ( $result ) {
  692. /**
  693. * Fires after a transient is deleted.
  694. *
  695. * @since 3.0.0
  696. *
  697. * @param string $transient Deleted transient name.
  698. */
  699. do_action( 'deleted_transient', $transient );
  700. }
  701. return $result;
  702. }
  703. /**
  704. * Retrieves the value of a transient.
  705. *
  706. * If the transient does not exist, does not have a value, or has expired,
  707. * then the return value will be false.
  708. *
  709. * @since 2.8.0
  710. *
  711. * @param string $transient Transient name. Expected to not be SQL-escaped.
  712. * @return mixed Value of transient.
  713. */
  714. function get_transient( $transient ) {
  715. /**
  716. * Filters the value of an existing transient before it is retrieved.
  717. *
  718. * The dynamic portion of the hook name, `$transient`, refers to the transient name.
  719. *
  720. * Returning a truthy value from the filter will effectively short-circuit retrieval
  721. * and return the passed value instead.
  722. *
  723. * @since 2.8.0
  724. * @since 4.4.0 The `$transient` parameter was added
  725. *
  726. * @param mixed $pre_transient The default value to return if the transient does not exist.
  727. * Any value other than false will short-circuit the retrieval
  728. * of the transient, and return that value.
  729. * @param string $transient Transient name.
  730. */
  731. $pre = apply_filters( "pre_transient_{$transient}", false, $transient );
  732. if ( false !== $pre ) {
  733. return $pre;
  734. }
  735. if ( wp_using_ext_object_cache() ) {
  736. $value = wp_cache_get( $transient, 'transient' );
  737. } else {
  738. $transient_option = '_transient_' . $transient;
  739. if ( ! wp_installing() ) {
  740. // If option is not in alloptions, it is not autoloaded and thus has a timeout.
  741. $alloptions = wp_load_alloptions();
  742. if ( ! isset( $alloptions[ $transient_option ] ) ) {
  743. $transient_timeout = '_transient_timeout_' . $transient;
  744. $timeout = get_option( $transient_timeout );
  745. if ( false !== $timeout && $timeout < time() ) {
  746. delete_option( $transient_option );
  747. delete_option( $transient_timeout );
  748. $value = false;
  749. }
  750. }
  751. }
  752. if ( ! isset( $value ) ) {
  753. $value = get_option( $transient_option );
  754. }
  755. }
  756. /**
  757. * Filters an existing transient's value.
  758. *
  759. * The dynamic portion of the hook name, `$transient`, refers to the transient name.
  760. *
  761. * @since 2.8.0
  762. * @since 4.4.0 The `$transient` parameter was added
  763. *
  764. * @param mixed $value Value of transient.
  765. * @param string $transient Transient name.
  766. */
  767. return apply_filters( "transient_{$transient}", $value, $transient );
  768. }
  769. /**
  770. * Sets/updates the value of a transient.
  771. *
  772. * You do not need to serialize values. If the value needs to be serialized,
  773. * then it will be serialized before it is set.
  774. *
  775. * @since 2.8.0
  776. *
  777. * @param string $transient Transient name. Expected to not be SQL-escaped.
  778. * Must be 172 characters or fewer in length.
  779. * @param mixed $value Transient value. Must be serializable if non-scalar.
  780. * Expected to not be SQL-escaped.
  781. * @param int $expiration Optional. Time until expiration in seconds. Default 0 (no expiration).
  782. * @return bool True if the value was set, false otherwise.
  783. */
  784. function set_transient( $transient, $value, $expiration = 0 ) {
  785. $expiration = (int) $expiration;
  786. /**
  787. * Filters a specific transient before its value is set.
  788. *
  789. * The dynamic portion of the hook name, `$transient`, refers to the transient name.
  790. *
  791. * @since 3.0.0
  792. * @since 4.2.0 The `$expiration` parameter was added.
  793. * @since 4.4.0 The `$transient` parameter was added.
  794. *
  795. * @param mixed $value New value of transient.
  796. * @param int $expiration Time until expiration in seconds.
  797. * @param string $transient Transient name.
  798. */
  799. $value = apply_filters( "pre_set_transient_{$transient}", $value, $expiration, $transient );
  800. /**
  801. * Filters the expiration for a transient before its value is set.
  802. *
  803. * The dynamic portion of the hook name, `$transient`, refers to the transient name.
  804. *
  805. * @since 4.4.0
  806. *
  807. * @param int $expiration Time until expiration in seconds. Use 0 for no expiration.
  808. * @param mixed $value New value of transient.
  809. * @param string $transient Transient name.
  810. */
  811. $expiration = apply_filters( "expiration_of_transient_{$transient}", $expiration, $value, $transient );
  812. if ( wp_using_ext_object_cache() ) {
  813. $result = wp_cache_set( $transient, $value, 'transient', $expiration );
  814. } else {
  815. $transient_timeout = '_transient_timeout_' . $transient;
  816. $transient_option = '_transient_' . $transient;
  817. if ( false === get_option( $transient_option ) ) {
  818. $autoload = 'yes';
  819. if ( $expiration ) {
  820. $autoload = 'no';
  821. add_option( $transient_timeout, time() + $expiration, '', 'no' );
  822. }
  823. $result = add_option( $transient_option, $value, '', $autoload );
  824. } else {
  825. // If expiration is requested, but the transient has no timeout option,
  826. // delete, then re-create transient rather than update.
  827. $update = true;
  828. if ( $expiration ) {
  829. if ( false === get_option( $transient_timeout ) ) {
  830. delete_option( $transient_option );
  831. add_option( $transient_timeout, time() + $expiration, '', 'no' );
  832. $result = add_option( $transient_option, $value, '', 'no' );
  833. $update = false;
  834. } else {
  835. update_option( $transient_timeout, time() + $expiration );
  836. }
  837. }
  838. if ( $update ) {
  839. $result = update_option( $transient_option, $value );
  840. }
  841. }
  842. }
  843. if ( $result ) {
  844. /**
  845. * Fires after the value for a specific transient has been set.
  846. *
  847. * The dynamic portion of the hook name, `$transient`, refers to the transient name.
  848. *
  849. * @since 3.0.0
  850. * @since 3.6.0 The `$value` and `$expiration` parameters were added.
  851. * @since 4.4.0 The `$transient` parameter was added.
  852. *
  853. * @param mixed $value Transient value.
  854. * @param int $expiration Time until expiration in seconds.
  855. * @param string $transient The name of the transient.
  856. */
  857. do_action( "set_transient_{$transient}", $value, $expiration, $transient );
  858. /**
  859. * Fires after the value for a transient has been set.
  860. *
  861. * @since 3.0.0
  862. * @since 3.6.0 The `$value` and `$expiration` parameters were added.
  863. *
  864. * @param string $transient The name of the transient.
  865. * @param mixed $value Transient value.
  866. * @param int $expiration Time until expiration in seconds.
  867. */
  868. do_action( 'setted_transient', $transient, $value, $expiration );
  869. }
  870. return $result;
  871. }
  872. /**
  873. * Deletes all expired transients.
  874. *
  875. * The multi-table delete syntax is used to delete the transient record
  876. * from table a, and the corresponding transient_timeout record from table b.
  877. *
  878. * @since 4.9.0
  879. *
  880. * @param bool $force_db Optional. Force cleanup to run against the database even when an external object cache is used.
  881. */
  882. function delete_expired_transients( $force_db = false ) {
  883. global $wpdb;
  884. if ( ! $force_db && wp_using_ext_object_cache() ) {
  885. return;
  886. }
  887. $wpdb->query(
  888. $wpdb->prepare(
  889. "DELETE a, b FROM {$wpdb->options} a, {$wpdb->options} b
  890. WHERE a.option_name LIKE %s
  891. AND a.option_name NOT LIKE %s
  892. AND b.option_name = CONCAT( '_transient_timeout_', SUBSTRING( a.option_name, 12 ) )
  893. AND b.option_value < %d",
  894. $wpdb->esc_like( '_transient_' ) . '%',
  895. $wpdb->esc_like( '_transient_timeout_' ) . '%',
  896. time()
  897. )
  898. );
  899. if ( ! is_multisite() ) {
  900. // Single site stores site transients in the options table.
  901. $wpdb->query(
  902. $wpdb->prepare(
  903. "DELETE a, b FROM {$wpdb->options} a, {$wpdb->options} b
  904. WHERE a.option_name LIKE %s
  905. AND a.option_name NOT LIKE %s
  906. AND b.option_name = CONCAT( '_site_transient_timeout_', SUBSTRING( a.option_name, 17 ) )
  907. AND b.option_value < %d",
  908. $wpdb->esc_like( '_site_transient_' ) . '%',
  909. $wpdb->esc_like( '_site_transient_timeout_' ) . '%',
  910. time()
  911. )
  912. );
  913. } elseif ( is_multisite() && is_main_site() && is_main_network() ) {
  914. // Multisite stores site transients in the sitemeta table.
  915. $wpdb->query(
  916. $wpdb->prepare(
  917. "DELETE a, b FROM {$wpdb->sitemeta} a, {$wpdb->sitemeta} b
  918. WHERE a.meta_key LIKE %s
  919. AND a.meta_key NOT LIKE %s
  920. AND b.meta_key = CONCAT( '_site_transient_timeout_', SUBSTRING( a.meta_key, 17 ) )
  921. AND b.meta_value < %d",
  922. $wpdb->esc_like( '_site_transient_' ) . '%',
  923. $wpdb->esc_like( '_site_transient_timeout_' ) . '%',
  924. time()
  925. )
  926. );
  927. }
  928. }
  929. /**
  930. * Saves and restores user interface settings stored in a cookie.
  931. *
  932. * Checks if the current user-settings cookie is updated and stores it. When no
  933. * cookie exists (different browser used), adds the last saved cookie restoring
  934. * the settings.
  935. *
  936. * @since 2.7.0
  937. */
  938. function wp_user_settings() {
  939. if ( ! is_admin() || wp_doing_ajax() ) {
  940. return;
  941. }
  942. $user_id = get_current_user_id();
  943. if ( ! $user_id ) {
  944. return;
  945. }
  946. if ( ! is_user_member_of_blog() ) {
  947. return;
  948. }
  949. $settings = (string) get_user_option( 'user-settings', $user_id );
  950. if ( isset( $_COOKIE[ 'wp-settings-' . $user_id ] ) ) {
  951. $cookie = preg_replace( '/[^A-Za-z0-9=&_]/', '', $_COOKIE[ 'wp-settings-' . $user_id ] );
  952. // No change or both empty.
  953. if ( $cookie == $settings ) {
  954. return;
  955. }
  956. $last_saved = (int) get_user_option( 'user-settings-time', $user_id );
  957. $current = isset( $_COOKIE[ 'wp-settings-time-' . $user_id ] ) ? preg_replace( '/[^0-9]/', '', $_COOKIE[ 'wp-settings-time-' . $user_id ] ) : 0;
  958. // The cookie is newer than the saved value. Update the user_option and leave the cookie as-is.
  959. if ( $current > $last_saved ) {
  960. update_user_option( $user_id, 'user-settings', $cookie, false );
  961. update_user_option( $user_id, 'user-settings-time', time() - 5, false );
  962. return;
  963. }
  964. }
  965. // The cookie is not set in the current browser or the saved value is newer.
  966. $secure = ( 'https' === parse_url( admin_url(), PHP_URL_SCHEME ) );
  967. setcookie( 'wp-settings-' . $user_id, $settings, time() + YEAR_IN_SECONDS, SITECOOKIEPATH, null, $secure );
  968. setcookie( 'wp-settings-time-' . $user_id, time(), time() + YEAR_IN_SECONDS, SITECOOKIEPATH, null, $secure );
  969. $_COOKIE[ 'wp-settings-' . $user_id ] = $settings;
  970. }
  971. /**
  972. * Retrieves user interface setting value based on setting name.
  973. *
  974. * @since 2.7.0
  975. *
  976. * @param string $name The name of the setting.
  977. * @param string|false $default Optional. Default value to return when $name is not set. Default false.
  978. * @return mixed The last saved user setting or the default value/false if it doesn't exist.
  979. */
  980. function get_user_setting( $name, $default = false ) {
  981. $all_user_settings = get_all_user_settings();
  982. return isset( $all_user_settings[ $name ] ) ? $all_user_settings[ $name ] : $default;
  983. }
  984. /**
  985. * Adds or updates user interface setting.
  986. *
  987. * Both $name and $value can contain only ASCII letters, numbers, hyphens, and underscores.
  988. *
  989. * This function has to be used before any output has started as it calls setcookie().
  990. *
  991. * @since 2.8.0
  992. *
  993. * @param string $name The name of the setting.
  994. * @param string $value The value for the setting.
  995. * @return bool|null True if set successfully, false otherwise.
  996. * Null if the current user is not a member of the site.
  997. */
  998. function set_user_setting( $name, $value ) {
  999. if ( headers_sent() ) {
  1000. return false;
  1001. }
  1002. $all_user_settings = get_all_user_settings();
  1003. $all_user_settings[ $name ] = $value;
  1004. return wp_set_all_user_settings( $all_user_settings );
  1005. }
  1006. /**
  1007. * Deletes user interface settings.
  1008. *
  1009. * Deleting settings would reset them to the defaults.
  1010. *
  1011. * This function has to be used before any output has started as it calls setcookie().
  1012. *
  1013. * @since 2.7.0
  1014. *
  1015. * @param string $names The name or array of names of the setting to be deleted.
  1016. * @return bool|null True if deleted successfully, false otherwise.
  1017. * Null if the current user is not a member of the site.
  1018. */
  1019. function delete_user_setting( $names ) {
  1020. if ( headers_sent() ) {
  1021. return false;
  1022. }
  1023. $all_user_settings = get_all_user_settings();
  1024. $names = (array) $names;
  1025. $deleted = false;
  1026. foreach ( $names as $name ) {
  1027. if ( isset( $all_user_settings[ $name ] ) ) {
  1028. unset( $all_user_settings[ $name ] );
  1029. $deleted = true;
  1030. }
  1031. }
  1032. if ( $deleted ) {
  1033. return wp_set_all_user_settings( $all_user_settings );
  1034. }
  1035. return false;
  1036. }
  1037. /**
  1038. * Retrieves all user interface settings.
  1039. *
  1040. * @since 2.7.0
  1041. *
  1042. * @global array $_updated_user_settings
  1043. *
  1044. * @return array The last saved user settings or empty array.
  1045. */
  1046. function get_all_user_settings() {
  1047. global $_updated_user_settings;
  1048. $user_id = get_current_user_id();
  1049. if ( ! $user_id ) {
  1050. return array();
  1051. }
  1052. if ( isset( $_updated_user_settings ) && is_array( $_updated_user_settings ) ) {
  1053. return $_updated_user_settings;
  1054. }
  1055. $user_settings = array();
  1056. if ( isset( $_COOKIE[ 'wp-settings-' . $user_id ] ) ) {
  1057. $cookie = preg_replace( '/[^A-Za-z0-9=&_-]/', '', $_COOKIE[ 'wp-settings-' . $user_id ] );
  1058. if ( strpos( $cookie, '=' ) ) { // '=' cannot be 1st char.
  1059. parse_str( $cookie, $user_settings );
  1060. }
  1061. } else {
  1062. $option = get_user_option( 'user-settings', $user_id );
  1063. if ( $option && is_string( $option ) ) {
  1064. parse_str( $option, $user_settings );
  1065. }
  1066. }
  1067. $_updated_user_settings = $user_settings;
  1068. return $user_settings;
  1069. }
  1070. /**
  1071. * Private. Sets all user interface settings.
  1072. *
  1073. * @since 2.8.0
  1074. * @access private
  1075. *
  1076. * @global array $_updated_user_settings
  1077. *
  1078. * @param array $user_settings User settings.
  1079. * @return bool|null True if set successfully, false if the current user could not be found.
  1080. * Null if the current user is not a member of the site.
  1081. */
  1082. function wp_set_all_user_settings( $user_settings ) {
  1083. global $_updated_user_settings;
  1084. $user_id = get_current_user_id();
  1085. if ( ! $user_id ) {
  1086. return false;
  1087. }
  1088. if ( ! is_user_member_of_blog() ) {
  1089. return;
  1090. }
  1091. $settings = '';
  1092. foreach ( $user_settings as $name => $value ) {
  1093. $_name = preg_replace( '/[^A-Za-z0-9_-]+/', '', $name );
  1094. $_value = preg_replace( '/[^A-Za-z0-9_-]+/', '', $value );
  1095. if ( ! empty( $_name ) ) {
  1096. $settings .= $_name . '=' . $_value . '&';
  1097. }
  1098. }
  1099. $settings = rtrim( $settings, '&' );
  1100. parse_str( $settings, $_updated_user_settings );
  1101. update_user_option( $user_id, 'user-settings', $settings, false );
  1102. update_user_option( $user_id, 'user-settings-time', time(), false );
  1103. return true;
  1104. }
  1105. /**
  1106. * Deletes the user settings of the current user.
  1107. *
  1108. * @since 2.7.0
  1109. */
  1110. function delete_all_user_settings() {
  1111. $user_id = get_current_user_id();
  1112. if ( ! $user_id ) {
  1113. return;
  1114. }
  1115. update_user_option( $user_id, 'user-settings', '', false );
  1116. setcookie( 'wp-settings-' . $user_id, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH );
  1117. }
  1118. /**
  1119. * Retrieve an option value for the current network based on name of option.
  1120. *
  1121. * @since 2.8.0
  1122. * @since 4.4.0 The `$use_cache` parameter was deprecated.
  1123. * @since 4.4.0 Modified into wrapper for get_network_option()
  1124. *
  1125. * @see get_network_option()
  1126. *
  1127. * @param string $option Name of the option to retrieve. Expected to not be SQL-escaped.
  1128. * @param mixed $default Optional. Value to return if the option doesn't exist. Default false.
  1129. * @param bool $deprecated Whether to use cache. Multisite only. Always set to true.
  1130. * @return mixed Value set for the option.
  1131. */
  1132. function get_site_option( $option, $default = false, $deprecated = true ) {
  1133. return get_network_option( null, $option, $default );
  1134. }
  1135. /**
  1136. * Adds a new option for the current network.
  1137. *
  1138. * Existing options will not be updated. Note that prior to 3.3 this wasn't the case.
  1139. *
  1140. * @since 2.8.0
  1141. * @since 4.4.0 Modified into wrapper for add_network_option()
  1142. *
  1143. * @see add_network_option()
  1144. *
  1145. * @param string $option Name of the option to add. Expected to not be SQL-escaped.
  1146. * @param mixed $value Option value, can be anything. Expected to not be SQL-escaped.
  1147. * @return bool True if the option was added, false otherwise.
  1148. */
  1149. function add_site_option( $option, $value ) {
  1150. return add_network_option( null, $option, $value );
  1151. }
  1152. /**
  1153. * Removes a option by name for the current network.
  1154. *
  1155. * @since 2.8.0
  1156. * @since 4.4.0 Modified into wrapper for delete_network_option()
  1157. *
  1158. * @see delete_network_option()
  1159. *
  1160. * @param string $option Name of the option to delete. Expected to not be SQL-escaped.
  1161. * @return bool True if the option was deleted, false otherwise.
  1162. */
  1163. function delete_site_option( $option ) {
  1164. return delete_network_option( null, $option );
  1165. }
  1166. /**
  1167. * Updates the value of an option that was already added for the current network.
  1168. *
  1169. * @since 2.8.0
  1170. * @since 4.4.0 Modified into wrapper for update_network_option()
  1171. *
  1172. * @see update_network_option()
  1173. *
  1174. * @param string $option Name of the option. Expected to not be SQL-escaped.
  1175. * @param mixed $value Option value. Expected to not be SQL-escaped.
  1176. * @return bool True if the value was updated, false otherwise.
  1177. */
  1178. function update_site_option( $option, $value ) {
  1179. return update_network_option( null, $option, $value );
  1180. }
  1181. /**
  1182. * Retrieves a network's option value based on the option name.
  1183. *
  1184. * @since 4.4.0
  1185. *
  1186. * @see get_option()
  1187. *
  1188. * @global wpdb $wpdb WordPress database abstraction object.
  1189. *
  1190. * @param int $network_id ID of the network. Can be null to default to the current network ID.
  1191. * @param string $option Name of the option to retrieve. Expected to not be SQL-escaped.
  1192. * @param mixed $default Optional. Value to return if the option doesn't exist. Default false.
  1193. * @return mixed Value set for the option.
  1194. */
  1195. function get_network_option( $network_id, $option, $default = false ) {
  1196. global $wpdb;
  1197. if ( $network_id && ! is_numeric( $network_id ) ) {
  1198. return false;
  1199. }
  1200. $network_id = (int) $network_id;
  1201. // Fallback to the current network if a network ID is not specified.
  1202. if ( ! $network_id ) {
  1203. $network_id = get_current_network_id();
  1204. }
  1205. /**
  1206. * Filters the value of an existing network option before it is retrieved.
  1207. *
  1208. * The dynamic portion of the hook name, `$option`, refers to the option name.
  1209. *
  1210. * Returning a truthy value from the filter will effectively short-circuit retrieval
  1211. * and return the passed value instead.
  1212. *
  1213. * @since 2.9.0 As 'pre_site_option_' . $key
  1214. * @since 3.0.0
  1215. * @since 4.4.0 The `$option` parameter was added.
  1216. * @since 4.7.0 The `$network_id` parameter was added.
  1217. * @since 4.9.0 The `$default` parameter was added.
  1218. *
  1219. * @param mixed $pre_option The value to return instead of the option value. This differs
  1220. * from `$default`, which is used as the fallback value in the event
  1221. * the option doesn't exist elsewhere in get_network_option().
  1222. * Default false (to skip past the short-circuit).
  1223. * @param string $option Option name.
  1224. * @param int $network_id ID of the network.
  1225. * @param mixed $default The fallback value to return if the option does not exist.
  1226. * Default false.
  1227. */
  1228. $pre = apply_filters( "pre_site_option_{$option}", false, $option, $network_id, $default );
  1229. if ( false !== $pre ) {
  1230. return $pre;
  1231. }
  1232. // Prevent non-existent options from triggering multiple queries.
  1233. $notoptions_key = "$network_id:notoptions";
  1234. $notoptions = wp_cache_get( $notoptions_key, 'site-options' );
  1235. if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
  1236. /**
  1237. * Filters a specific default network option.
  1238. *
  1239. * The dynamic portion of the hook name, `$option`, refers to the option name.
  1240. *
  1241. * @since 3.4.0
  1242. * @since 4.4.0 The `$option` parameter was added.
  1243. * @since 4.7.0 The `$network_id` parameter was added.
  1244. *
  1245. * @param mixed $default The value to return if the site option does not exist
  1246. * in the database.
  1247. * @param string $option Option name.
  1248. * @param int $network_id ID of the network.
  1249. */
  1250. return apply_filters( "default_site_option_{$option}", $default, $option, $network_id );
  1251. }
  1252. if ( ! is_multisite() ) {
  1253. /** This filter is documented in wp-includes/option.php */
  1254. $default = apply_filters( 'default_site_option_' . $option, $default, $option, $network_id );
  1255. $value = get_option( $option, $default );
  1256. } else {
  1257. $cache_key = "$network_id:$option";
  1258. $value = wp_cache_get( $cache_key, 'site-options' );
  1259. if ( ! isset( $value ) || false === $value ) {
  1260. $row = $wpdb->get_row( $wpdb->prepare( "SELECT meta_value FROM $wpdb->sitemeta WHERE meta_key = %s AND site_id = %d", $option, $network_id ) );
  1261. // Has to be get_row() instead of get_var() because of funkiness with 0, false, null values.
  1262. if ( is_object( $row ) ) {
  1263. $value = $row->meta_value;
  1264. $value = maybe_unserialize( $value );
  1265. wp_cache_set( $cache_key, $value, 'site-options' );
  1266. } else {
  1267. if ( ! is_array( $notoptions ) ) {
  1268. $notoptions = array();
  1269. }
  1270. $notoptions[ $option ] = true;
  1271. wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
  1272. /** This filter is documented in wp-includes/option.php */
  1273. $value = apply_filters( 'default_site_option_' . $option, $default, $option, $network_id );
  1274. }
  1275. }
  1276. }
  1277. if ( ! is_array( $notoptions ) ) {
  1278. $notoptions = array();
  1279. wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
  1280. }
  1281. /**
  1282. * Filters the value of an existing network option.
  1283. *
  1284. * The dynamic portion of the hook name, `$option`, refers to the option name.
  1285. *
  1286. * @since 2.9.0 As 'site_option_' . $key
  1287. * @since 3.0.0
  1288. * @since 4.4.0 The `$option` parameter was added.
  1289. * @since 4.7.0 The `$network_id` parameter was added.
  1290. *
  1291. * @param mixed $value Value of network option.
  1292. * @param string $option Option name.
  1293. * @param int $network_id ID of the network.
  1294. */
  1295. return apply_filters( "site_option_{$option}", $value, $option, $network_id );
  1296. }
  1297. /**
  1298. * Adds a new network option.
  1299. *
  1300. * Existing options will not be updated.
  1301. *
  1302. * @since 4.4.0
  1303. *
  1304. * @see add_option()
  1305. *
  1306. * @global wpdb $wpdb WordPress database abstraction object.
  1307. *
  1308. * @param int $network_id ID of the network. Can be null to default to the current network ID.
  1309. * @param string $option Name of the option to add. Expected to not be SQL-escaped.
  1310. * @param mixed $value Option value, can be anything. Expected to not be SQL-escaped.
  1311. * @return bool True if the option was added, false otherwise.
  1312. */
  1313. function add_network_option( $network_id, $option, $value ) {
  1314. global $wpdb;
  1315. if ( $network_id && ! is_numeric( $network_id ) ) {
  1316. return false;
  1317. }
  1318. $network_id = (int) $network_id;
  1319. // Fallback to the current network if a network ID is not specified.
  1320. if ( ! $network_id ) {
  1321. $network_id = get_current_network_id();
  1322. }
  1323. wp_protect_special_option( $option );
  1324. /**
  1325. * Filters the value of a specific network option before it is added.
  1326. *
  1327. * The dynamic portion of the hook name, `$option`, refers to the option name.
  1328. *
  1329. * @since 2.9.0 As 'pre_add_site_option_' . $key
  1330. * @since 3.0.0
  1331. * @since 4.4.0 The `$option` parameter was added.
  1332. * @since 4.7.0 The `$network_id` parameter was added.
  1333. *
  1334. * @param mixed $value Value of network option.
  1335. * @param string $option Option name.
  1336. * @param int $network_id ID of the network.
  1337. */
  1338. $value = apply_filters( "pre_add_site_option_{$option}", $value, $option, $network_id );
  1339. $notoptions_key = "$network_id:notoptions";
  1340. if ( ! is_multisite() ) {
  1341. $result = add_option( $option, $value, '', 'no' );
  1342. } else {
  1343. $cache_key = "$network_id:$option";
  1344. // Make sure the option doesn't already exist.
  1345. // We can check the 'notoptions' cache before we ask for a DB query.
  1346. $notoptions = wp_cache_get( $notoptions_key, 'site-options' );
  1347. if ( ! is_array( $notoptions ) || ! isset( $notoptions[ $option ] ) ) {
  1348. if ( false !== get_network_option( $network_id, $option, false ) ) {
  1349. return false;
  1350. }
  1351. }
  1352. $value = sanitize_option( $option, $value );
  1353. $serialized_value = maybe_serialize( $value );
  1354. $result = $wpdb->insert(
  1355. $wpdb->sitemeta,
  1356. array(
  1357. 'site_id' => $network_id,
  1358. 'meta_key' => $option,
  1359. 'meta_value' => $serialized_value,
  1360. )
  1361. );
  1362. if ( ! $result ) {
  1363. return false;
  1364. }
  1365. wp_cache_set( $cache_key, $value, 'site-options' );
  1366. // This option exists now.
  1367. $notoptions = wp_cache_get( $notoptions_key, 'site-options' ); // Yes, again... we need it to be fresh.
  1368. if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
  1369. unset( $notoptions[ $option ] );
  1370. wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
  1371. }
  1372. }
  1373. if ( $result ) {
  1374. /**
  1375. * Fires after a specific network option has been successfully added.
  1376. *
  1377. * The dynamic portion of the hook name, `$option`, refers to the option name.
  1378. *
  1379. * @since 2.9.0 As "add_site_option_{$key}"
  1380. * @since 3.0.0
  1381. * @since 4.7.0 The `$network_id` parameter was added.
  1382. *
  1383. * @param string $option Name of the network option.
  1384. * @param mixed $value Value of the network option.
  1385. * @param int $network_id ID of the network.
  1386. */
  1387. do_action( "add_site_option_{$option}", $option, $value, $network_id );
  1388. /**
  1389. * Fires after a network option has been successfully added.
  1390. *
  1391. * @since 3.0.0
  1392. * @since 4.7.0 The `$network_id` parameter was added.
  1393. *
  1394. * @param string $option Name of the network option.
  1395. * @param mixed $value Value of the network option.
  1396. * @param int $network_id ID of the network.
  1397. */
  1398. do_action( 'add_site_option', $option, $value, $network_id );
  1399. return true;
  1400. }
  1401. return false;
  1402. }
  1403. /**
  1404. * Removes a network option by name.
  1405. *
  1406. * @since 4.4.0
  1407. *
  1408. * @see delete_option()
  1409. *
  1410. * @global wpdb $wpdb WordPress database abstraction object.
  1411. *
  1412. * @param int $network_id ID of the network. Can be null to default to the current network ID.
  1413. * @param string $option Name of the option to delete. Expected to not be SQL-escaped.
  1414. * @return bool True if the option was deleted, false otherwise.
  1415. */
  1416. function delete_network_option( $network_id, $option ) {
  1417. global $wpdb;
  1418. if ( $network_id && ! is_numeric( $network_id ) ) {
  1419. return false;
  1420. }
  1421. $network_id = (int) $network_id;
  1422. // Fallback to the current network if a network ID is not specified.
  1423. if ( ! $network_id ) {
  1424. $network_id = get_current_network_id();
  1425. }
  1426. /**
  1427. * Fires immediately before a specific network option is deleted.
  1428. *
  1429. * The dynamic portion of the hook name, `$option`, refers to the option name.
  1430. *
  1431. * @since 3.0.0
  1432. * @since 4.4.0 The `$option` parameter was added.
  1433. * @since 4.7.0 The `$network_id` parameter was added.
  1434. *
  1435. * @param string $option Option name.
  1436. * @param int $network_id ID of the network.
  1437. */
  1438. do_action( "pre_delete_site_option_{$option}", $option, $network_id );
  1439. if ( ! is_multisite() ) {
  1440. $result = delete_option( $option );
  1441. } else {
  1442. $row = $wpdb->get_row( $wpdb->prepare( "SELECT meta_id FROM {$wpdb->sitemeta} WHERE meta_key = %s AND site_id = %d", $option, $network_id ) );
  1443. if ( is_null( $row ) || ! $row->meta_id ) {
  1444. return false;
  1445. }
  1446. $cache_key = "$network_id:$option";
  1447. wp_cache_delete( $cache_key, 'site-options' );
  1448. $result = $wpdb->delete(
  1449. $wpdb->sitemeta,
  1450. array(
  1451. 'meta_key' => $option,
  1452. 'site_id' => $network_id,
  1453. )
  1454. );
  1455. }
  1456. if ( $result ) {
  1457. /**
  1458. * Fires after a specific network option has been deleted.
  1459. *
  1460. * The dynamic portion of the hook name, `$option`, refers to the option name.
  1461. *
  1462. * @since 2.9.0 As "delete_site_option_{$key}"
  1463. * @since 3.0.0
  1464. * @since 4.7.0 The `$network_id` parameter was added.
  1465. *
  1466. * @param string $option Name of the network option.
  1467. * @param int $network_id ID of the network.
  1468. */
  1469. do_action( "delete_site_option_{$option}", $option, $network_id );
  1470. /**
  1471. * Fires after a network option has been deleted.
  1472. *
  1473. * @since 3.0.0
  1474. * @since 4.7.0 The `$network_id` parameter was added.
  1475. *
  1476. * @param string $option Name of the network option.
  1477. * @param int $network_id ID of the network.
  1478. */
  1479. do_action( 'delete_site_option', $option, $network_id );
  1480. return true;
  1481. }
  1482. return false;
  1483. }
  1484. /**
  1485. * Updates the value of a network option that was already added.
  1486. *
  1487. * @since 4.4.0
  1488. *
  1489. * @see update_option()
  1490. *
  1491. * @global wpdb $wpdb WordPress database abstraction object.
  1492. *
  1493. * @param int $network_id ID of the network. Can be null to default to the current network ID.
  1494. * @param string $option Name of the option. Expected to not be SQL-escaped.
  1495. * @param mixed $value Option value. Expected to not be SQL-escaped.
  1496. * @return bool True if the value was updated, false otherwise.
  1497. */
  1498. function update_network_option( $network_id, $option, $value ) {
  1499. global $wpdb;
  1500. if ( $network_id && ! is_numeric( $network_id ) ) {
  1501. return false;
  1502. }
  1503. $network_id = (int) $network_id;
  1504. // Fallback to the current network if a network ID is not specified.
  1505. if ( ! $network_id ) {
  1506. $network_id = get_current_network_id();
  1507. }
  1508. wp_protect_special_option( $option );
  1509. $old_value = get_network_option( $network_id, $option, false );
  1510. /**
  1511. * Filters a specific network option before its value is updated.
  1512. *
  1513. * The dynamic portion of the hook name, `$option`, refers to the option name.
  1514. *
  1515. * @since 2.9.0 As 'pre_update_site_option_' . $key
  1516. * @since 3.0.0
  1517. * @since 4.4.0 The `$option` parameter was added.
  1518. * @since 4.7.0 The `$network_id` parameter was added.
  1519. *
  1520. * @param mixed $value New value of the network option.
  1521. * @param mixed $old_value Old value of the network option.
  1522. * @param string $option Option name.
  1523. * @param int $network_id ID of the network.
  1524. */
  1525. $value = apply_filters( "pre_update_site_option_{$option}", $value, $old_value, $option, $network_id );
  1526. /*
  1527. * If the new and old values are the same, no need to update.
  1528. *
  1529. * Unserialized values will be adequate in most cases. If the unserialized
  1530. * data differs, the (maybe) serialized data is checked to avoid
  1531. * unnecessary database calls for otherwise identical object instances.
  1532. *
  1533. * See https://core.trac.wordpress.org/ticket/44956
  1534. */
  1535. if ( $value === $old_value || maybe_serialize( $value ) === maybe_serialize( $old_value ) ) {
  1536. return false;
  1537. }
  1538. if ( false === $old_value ) {
  1539. return add_network_option( $network_id, $option, $value );
  1540. }
  1541. $notoptions_key = "$network_id:notoptions";
  1542. $notoptions = wp_cache_get( $notoptions_key, 'site-options' );
  1543. if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
  1544. unset( $notoptions[ $option ] );
  1545. wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
  1546. }
  1547. if ( ! is_multisite() ) {
  1548. $result = update_option( $option, $value, 'no' );
  1549. } else {
  1550. $value = sanitize_option( $option, $value );
  1551. $serialized_value = maybe_serialize( $value );
  1552. $result = $wpdb->update(
  1553. $wpdb->sitemeta,
  1554. array( 'meta_value' => $serialized_value ),
  1555. array(
  1556. 'site_id' => $network_id,
  1557. 'meta_key' => $option,
  1558. )
  1559. );
  1560. if ( $result ) {
  1561. $cache_key = "$network_id:$option";
  1562. wp_cache_set( $cache_key, $value, 'site-options' );
  1563. }
  1564. }
  1565. if ( $result ) {
  1566. /**
  1567. * Fires after the value of a specific network option has been successfully updated.
  1568. *
  1569. * The dynamic portion of the hook name, `$option`, refers to the option name.
  1570. *
  1571. * @since 2.9.0 As "update_site_option_{$key}"
  1572. * @since 3.0.0
  1573. * @since 4.7.0 The `$network_id` parameter was added.
  1574. *
  1575. * @param string $option Name of the network option.
  1576. * @param mixed $value Current value of the network option.
  1577. * @param mixed $old_value Old value of the network option.
  1578. * @param int $network_id ID of the network.
  1579. */
  1580. do_action( "update_site_option_{$option}", $option, $value, $old_value, $network_id );
  1581. /**
  1582. * Fires after the value of a network option has been successfully updated.
  1583. *
  1584. * @since 3.0.0
  1585. * @since 4.7.0 The `$network_id` parameter was added.
  1586. *
  1587. * @param string $option Name of the network option.
  1588. * @param mixed $value Current value of the network option.
  1589. * @param mixed $old_value Old value of the network option.
  1590. * @param int $network_id ID of the network.
  1591. */
  1592. do_action( 'update_site_option', $option, $value, $old_value, $network_id );
  1593. return true;
  1594. }
  1595. return false;
  1596. }
  1597. /**
  1598. * Deletes a site transient.
  1599. *
  1600. * @since 2.9.0
  1601. *
  1602. * @param string $transient Transient name. Expected to not be SQL-escaped.
  1603. * @return bool True if the transient was deleted, false otherwise.
  1604. */
  1605. function delete_site_transient( $transient ) {
  1606. /**
  1607. * Fires immediately before a specific site transient is deleted.
  1608. *
  1609. * The dynamic portion of the hook name, `$transient`, refers to the transient name.
  1610. *
  1611. * @since 3.0.0
  1612. *
  1613. * @param string $transient Transient name.
  1614. */
  1615. do_action( "delete_site_transient_{$transient}", $transient );
  1616. if ( wp_using_ext_object_cache() ) {
  1617. $result = wp_cache_delete( $transient, 'site-transient' );
  1618. } else {
  1619. $option_timeout = '_site_transient_timeout_' . $transient;
  1620. $option = '_site_transient_' . $transient;
  1621. $result = delete_site_option( $option );
  1622. if ( $result ) {
  1623. delete_site_option( $option_timeout );
  1624. }
  1625. }
  1626. if ( $result ) {
  1627. /**
  1628. * Fires after a transient is deleted.
  1629. *
  1630. * @since 3.0.0
  1631. *
  1632. * @param string $transient Deleted transient name.
  1633. */
  1634. do_action( 'deleted_site_transient', $transient );
  1635. }
  1636. return $result;
  1637. }
  1638. /**
  1639. * Retrieves the value of a site transient.
  1640. *
  1641. * If the transient does not exist, does not have a value, or has expired,
  1642. * then the return value will be false.
  1643. *
  1644. * @since 2.9.0
  1645. *
  1646. * @see get_transient()
  1647. *
  1648. * @param string $transient Transient name. Expected to not be SQL-escaped.
  1649. * @return mixed Value of transient.
  1650. */
  1651. function get_site_transient( $transient ) {
  1652. /**
  1653. * Filters the value of an existing site transient before it is retrieved.
  1654. *
  1655. * The dynamic portion of the hook name, `$transient`, refers to the transient name.
  1656. *
  1657. * Returning a truthy value from the filter will effectively short-circuit retrieval
  1658. * and return the passed value instead.
  1659. *
  1660. * @since 2.9.0
  1661. * @since 4.4.0 The `$transient` parameter was added.
  1662. *
  1663. * @param mixed $pre_site_transient The default value to return if the site transient does not exist.
  1664. * Any value other than false will short-circuit the retrieval
  1665. * of the transient, and return that value.
  1666. * @param string $transient Transient name.
  1667. */
  1668. $pre = apply_filters( "pre_site_transient_{$transient}", false, $transient );
  1669. if ( false !== $pre ) {
  1670. return $pre;
  1671. }
  1672. if ( wp_using_ext_object_cache() ) {
  1673. $value = wp_cache_get( $transient, 'site-transient' );
  1674. } else {
  1675. // Core transients that do not have a timeout. Listed here so querying timeouts can be avoided.
  1676. $no_timeout = array( 'update_core', 'update_plugins', 'update_themes' );
  1677. $transient_option = '_site_transient_' . $transient;
  1678. if ( ! in_array( $transient, $no_timeout, true ) ) {
  1679. $transient_timeout = '_site_transient_timeout_' . $transient;
  1680. $timeout = get_site_option( $transient_timeout );
  1681. if ( false !== $timeout && $timeout < time() ) {
  1682. delete_site_option( $transient_option );
  1683. delete_site_option( $transient_timeout );
  1684. $value = false;
  1685. }
  1686. }
  1687. if ( ! isset( $value ) ) {
  1688. $value = get_site_option( $transient_option );
  1689. }
  1690. }
  1691. /**
  1692. * Filters the value of an existing site transient.
  1693. *
  1694. * The dynamic portion of the hook name, `$transient`, refers to the transient name.
  1695. *
  1696. * @since 2.9.0
  1697. * @since 4.4.0 The `$transient` parameter was added.
  1698. *
  1699. * @param mixed $value Value of site transient.
  1700. * @param string $transient Transient name.
  1701. */
  1702. return apply_filters( "site_transient_{$transient}", $value, $transient );
  1703. }
  1704. /**
  1705. * Sets/updates the value of a site transient.
  1706. *
  1707. * You do not need to serialize values. If the value needs to be serialized,
  1708. * then it will be serialized before it is set.
  1709. *
  1710. * @since 2.9.0
  1711. *
  1712. * @see set_transient()
  1713. *
  1714. * @param string $transient Transient name. Expected to not be SQL-escaped. Must be
  1715. * 167 characters or fewer in length.
  1716. * @param mixed $value Transient value. Expected to not be SQL-escaped.
  1717. * @param int $expiration Optional. Time until expiration in seconds. Default 0 (no expiration).
  1718. * @return bool True if the value was set, false otherwise.
  1719. */
  1720. function set_site_transient( $transient, $value, $expiration = 0 ) {
  1721. /**
  1722. * Filters the value of a specific site transient before it is set.
  1723. *
  1724. * The dynamic portion of the hook name, `$transient`, refers to the transient name.
  1725. *
  1726. * @since 3.0.0
  1727. * @since 4.4.0 The `$transient` parameter was added.
  1728. *
  1729. * @param mixed $value New value of site transient.
  1730. * @param string $transient Transient name.
  1731. */
  1732. $value = apply_filters( "pre_set_site_transient_{$transient}", $value, $transient );
  1733. $expiration = (int) $expiration;
  1734. /**
  1735. * Filters the expiration for a site transient before its value is set.
  1736. *
  1737. * The dynamic portion of the hook name, `$transient`, refers to the transient name.
  1738. *
  1739. * @since 4.4.0
  1740. *
  1741. * @param int $expiration Time until expiration in seconds. Use 0 for no expiration.
  1742. * @param mixed $value New value of site transient.
  1743. * @param string $transient Transient name.
  1744. */
  1745. $expiration = apply_filters( "expiration_of_site_transient_{$transient}", $expiration, $value, $transient );
  1746. if ( wp_using_ext_object_cache() ) {
  1747. $result = wp_cache_set( $transient, $value, 'site-transient', $expiration );
  1748. } else {
  1749. $transient_timeout = '_site_transient_timeout_' . $transient;
  1750. $option = '_site_transient_' . $transient;
  1751. if ( false === get_site_option( $option ) ) {
  1752. if ( $expiration ) {
  1753. add_site_option( $transient_timeout, time() + $expiration );
  1754. }
  1755. $result = add_site_option( $option, $value );
  1756. } else {
  1757. if ( $expiration ) {
  1758. update_site_option( $transient_timeout, time() + $expiration );
  1759. }
  1760. $result = update_site_option( $option, $value );
  1761. }
  1762. }
  1763. if ( $result ) {
  1764. /**
  1765. * Fires after the value for a specific site transient has been set.
  1766. *
  1767. * The dynamic portion of the hook name, `$transient`, refers to the transient name.
  1768. *
  1769. * @since 3.0.0
  1770. * @since 4.4.0 The `$transient` parameter was added
  1771. *
  1772. * @param mixed $value Site transient value.
  1773. * @param int $expiration Time until expiration in seconds.
  1774. * @param string $transient Transient name.
  1775. */
  1776. do_action( "set_site_transient_{$transient}", $value, $expiration, $transient );
  1777. /**
  1778. * Fires after the value for a site transient has been set.
  1779. *
  1780. * @since 3.0.0
  1781. *
  1782. * @param string $transient The name of the site transient.
  1783. * @param mixed $value Site transient value.
  1784. * @param int $expiration Time until expiration in seconds.
  1785. */
  1786. do_action( 'setted_site_transient', $transient, $value, $expiration );
  1787. }
  1788. return $result;
  1789. }
  1790. /**
  1791. * Registers default settings available in WordPress.
  1792. *
  1793. * The settings registered here are primarily useful for the REST API, so this
  1794. * does not encompass all settings available in WordPress.
  1795. *
  1796. * @since 4.7.0
  1797. */
  1798. function register_initial_settings() {
  1799. register_setting(
  1800. 'general',
  1801. 'blogname',
  1802. array(
  1803. 'show_in_rest' => array(
  1804. 'name' => 'title',
  1805. ),
  1806. 'type' => 'string',
  1807. 'description' => __( 'Site title.' ),
  1808. )
  1809. );
  1810. register_setting(
  1811. 'general',
  1812. 'blogdescription',
  1813. array(
  1814. 'show_in_rest' => array(
  1815. 'name' => 'description',
  1816. ),
  1817. 'type' => 'string',
  1818. 'description' => __( 'Site tagline.' ),
  1819. )
  1820. );
  1821. if ( ! is_multisite() ) {
  1822. register_setting(
  1823. 'general',
  1824. 'siteurl',
  1825. array(
  1826. 'show_in_rest' => array(
  1827. 'name' => 'url',
  1828. 'schema' => array(
  1829. 'format' => 'uri',
  1830. ),
  1831. ),
  1832. 'type' => 'string',
  1833. 'description' => __( 'Site URL.' ),
  1834. )
  1835. );
  1836. }
  1837. if ( ! is_multisite() ) {
  1838. register_setting(
  1839. 'general',
  1840. 'admin_email',
  1841. array(
  1842. 'show_in_rest' => array(
  1843. 'name' => 'email',
  1844. 'schema' => array(
  1845. 'format' => 'email',
  1846. ),
  1847. ),
  1848. 'type' => 'string',
  1849. 'description' => __( 'This address is used for admin purposes, like new user notification.' ),
  1850. )
  1851. );
  1852. }
  1853. register_setting(
  1854. 'general',
  1855. 'timezone_string',
  1856. array(
  1857. 'show_in_rest' => array(
  1858. 'name' => 'timezone',
  1859. ),
  1860. 'type' => 'string',
  1861. 'description' => __( 'A city in the same timezone as you.' ),
  1862. )
  1863. );
  1864. register_setting(
  1865. 'general',
  1866. 'date_format',
  1867. array(
  1868. 'show_in_rest' => true,
  1869. 'type' => 'string',
  1870. 'description' => __( 'A date format for all date strings.' ),
  1871. )
  1872. );
  1873. register_setting(
  1874. 'general',
  1875. 'time_format',
  1876. array(
  1877. 'show_in_rest' => true,
  1878. 'type' => 'string',
  1879. 'description' => __( 'A time format for all time strings.' ),
  1880. )
  1881. );
  1882. register_setting(
  1883. 'general',
  1884. 'start_of_week',
  1885. array(
  1886. 'show_in_rest' => true,
  1887. 'type' => 'integer',
  1888. 'description' => __( 'A day number of the week that the week should start on.' ),
  1889. )
  1890. );
  1891. register_setting(
  1892. 'general',
  1893. 'WPLANG',
  1894. array(
  1895. 'show_in_rest' => array(
  1896. 'name' => 'language',
  1897. ),
  1898. 'type' => 'string',
  1899. 'description' => __( 'WordPress locale code.' ),
  1900. 'default' => 'en_US',
  1901. )
  1902. );
  1903. register_setting(
  1904. 'writing',
  1905. 'use_smilies',
  1906. array(
  1907. 'show_in_rest' => true,
  1908. 'type' => 'boolean',
  1909. 'description' => __( 'Convert emoticons like :-) and :-P to graphics on display.' ),
  1910. 'default' => true,
  1911. )
  1912. );
  1913. register_setting(
  1914. 'writing',
  1915. 'default_category',
  1916. array(
  1917. 'show_in_rest' => true,
  1918. 'type' => 'integer',
  1919. 'description' => __( 'Default post category.' ),
  1920. )
  1921. );
  1922. register_setting(
  1923. 'writing',
  1924. 'default_post_format',
  1925. array(
  1926. 'show_in_rest' => true,
  1927. 'type' => 'string',
  1928. 'description' => __( 'Default post format.' ),
  1929. )
  1930. );
  1931. register_setting(
  1932. 'reading',
  1933. 'posts_per_page',
  1934. array(
  1935. 'show_in_rest' => true,
  1936. 'type' => 'integer',
  1937. 'description' => __( 'Blog pages show at most.' ),
  1938. 'default' => 10,
  1939. )
  1940. );
  1941. register_setting(
  1942. 'discussion',
  1943. 'default_ping_status',
  1944. array(
  1945. 'show_in_rest' => array(
  1946. 'schema' => array(
  1947. 'enum' => array( 'open', 'closed' ),
  1948. ),
  1949. ),
  1950. 'type' => 'string',
  1951. 'description' => __( 'Allow link notifications from other blogs (pingbacks and trackbacks) on new articles.' ),
  1952. )
  1953. );
  1954. register_setting(
  1955. 'discussion',
  1956. 'default_comment_status',
  1957. array(
  1958. 'show_in_rest' => array(
  1959. 'schema' => array(
  1960. 'enum' => array( 'open', 'closed' ),
  1961. ),
  1962. ),
  1963. 'type' => 'string',
  1964. 'description' => __( 'Allow people to submit comments on new posts.' ),
  1965. )
  1966. );
  1967. }
  1968. /**
  1969. * Registers a setting and its data.
  1970. *
  1971. * @since 2.7.0
  1972. * @since 4.7.0 `$args` can be passed to set flags on the setting, similar to `register_meta()`.
  1973. * @since 5.5.0 `$new_whitelist_options` was renamed to `$new_allowed_options`.
  1974. * Please consider writing more inclusive code.
  1975. *
  1976. * @global array $new_allowed_options
  1977. * @global array $wp_registered_settings
  1978. *
  1979. * @param string $option_group A settings group name. Should correspond to an allowed option key name.
  1980. * Default allowed option key names include 'general', 'discussion', 'media',
  1981. * 'reading', 'writing', 'misc', 'options', and 'privacy'.
  1982. * @param string $option_name The name of an option to sanitize and save.
  1983. * @param array $args {
  1984. * Data used to describe the setting when registered.
  1985. *
  1986. * @type string $type The type of data associated with this setting.
  1987. * Valid values are 'string', 'boolean', 'integer', 'number', 'array', and 'object'.
  1988. * @type string $description A description of the data attached to this setting.
  1989. * @type callable $sanitize_callback A callback function that sanitizes the option's value.
  1990. * @type bool|array $show_in_rest Whether data associated with this setting should be included in the REST API.
  1991. * When registering complex settings, this argument may optionally be an
  1992. * array with a 'schema' key.
  1993. * @type mixed $default Default value when calling `get_option()`.
  1994. * }
  1995. */
  1996. function register_setting( $option_group, $option_name, $args = array() ) {
  1997. global $new_allowed_options, $wp_registered_settings;
  1998. /*
  1999. * In 5.5.0, the `$new_whitelist_options` global variable was renamed to `$new_allowed_options`.
  2000. * Please consider writing more inclusive code.
  2001. */
  2002. $GLOBALS['new_whitelist_options'] = &$new_allowed_options;
  2003. $defaults = array(
  2004. 'type' => 'string',
  2005. 'group' => $option_group,
  2006. 'description' => '',
  2007. 'sanitize_callback' => null,
  2008. 'show_in_rest' => false,
  2009. );
  2010. // Back-compat: old sanitize callback is added.
  2011. if ( is_callable( $args ) ) {
  2012. $args = array(
  2013. 'sanitize_callback' => $args,
  2014. );
  2015. }
  2016. /**
  2017. * Filters the registration arguments when registering a setting.
  2018. *
  2019. * @since 4.7.0
  2020. *
  2021. * @param array $args Array of setting registration arguments.
  2022. * @param array $defaults Array of default arguments.
  2023. * @param string $option_group Setting group.
  2024. * @param string $option_name Setting name.
  2025. */
  2026. $args = apply_filters( 'register_setting_args', $args, $defaults, $option_group, $option_name );
  2027. $args = wp_parse_args( $args, $defaults );
  2028. // Require an item schema when registering settings with an array type.
  2029. if ( false !== $args['show_in_rest'] && 'array' === $args['type'] && ( ! is_array( $args['show_in_rest'] ) || ! isset( $args['show_in_rest']['schema']['items'] ) ) ) {
  2030. _doing_it_wrong( __FUNCTION__, __( 'When registering an "array" setting to show in the REST API, you must specify the schema for each array item in "show_in_rest.schema.items".' ), '5.4.0' );
  2031. }
  2032. if ( ! is_array( $wp_registered_settings ) ) {
  2033. $wp_registered_settings = array();
  2034. }
  2035. if ( 'misc' === $option_group ) {
  2036. _deprecated_argument(
  2037. __FUNCTION__,
  2038. '3.0.0',
  2039. sprintf(
  2040. /* translators: %s: misc */
  2041. __( 'The "%s" options group has been removed. Use another settings group.' ),
  2042. 'misc'
  2043. )
  2044. );
  2045. $option_group = 'general';
  2046. }
  2047. if ( 'privacy' === $option_group ) {
  2048. _deprecated_argument(
  2049. __FUNCTION__,
  2050. '3.5.0',
  2051. sprintf(
  2052. /* translators: %s: privacy */
  2053. __( 'The "%s" options group has been removed. Use another settings group.' ),
  2054. 'privacy'
  2055. )
  2056. );
  2057. $option_group = 'reading';
  2058. }
  2059. $new_allowed_options[ $option_group ][] = $option_name;
  2060. if ( ! empty( $args['sanitize_callback'] ) ) {
  2061. add_filter( "sanitize_option_{$option_name}", $args['sanitize_callback'] );
  2062. }
  2063. if ( array_key_exists( 'default', $args ) ) {
  2064. add_filter( "default_option_{$option_name}", 'filter_default_option', 10, 3 );
  2065. }
  2066. /**
  2067. * Fires immediately before the setting is registered but after its filters are in place.
  2068. *
  2069. * @since 5.5.0
  2070. *
  2071. * @param string $option_group Setting group.
  2072. * @param string $option_name Setting name.
  2073. * @param array $args Array of setting registration arguments.
  2074. */
  2075. do_action( 'register_setting', $option_group, $option_name, $args );
  2076. $wp_registered_settings[ $option_name ] = $args;
  2077. }
  2078. /**
  2079. * Unregisters a setting.
  2080. *
  2081. * @since 2.7.0
  2082. * @since 4.7.0 `$sanitize_callback` was deprecated. The callback from `register_setting()` is now used instead.
  2083. * @since 5.5.0 `$new_whitelist_options` was renamed to `$new_allowed_options`.
  2084. * Please consider writing more inclusive code.
  2085. *
  2086. * @global array $new_allowed_options
  2087. * @global array $wp_registered_settings
  2088. *
  2089. * @param string $option_group The settings group name used during registration.
  2090. * @param string $option_name The name of the option to unregister.
  2091. * @param callable|string $deprecated Deprecated.
  2092. */
  2093. function unregister_setting( $option_group, $option_name, $deprecated = '' ) {
  2094. global $new_allowed_options, $wp_registered_settings;
  2095. /*
  2096. * In 5.5.0, the `$new_whitelist_options` global variable was renamed to `$new_allowed_options`.
  2097. * Please consider writing more inclusive code.
  2098. */
  2099. $GLOBALS['new_whitelist_options'] = &$new_allowed_options;
  2100. if ( 'misc' === $option_group ) {
  2101. _deprecated_argument(
  2102. __FUNCTION__,
  2103. '3.0.0',
  2104. sprintf(
  2105. /* translators: %s: misc */
  2106. __( 'The "%s" options group has been removed. Use another settings group.' ),
  2107. 'misc'
  2108. )
  2109. );
  2110. $option_group = 'general';
  2111. }
  2112. if ( 'privacy' === $option_group ) {
  2113. _deprecated_argument(
  2114. __FUNCTION__,
  2115. '3.5.0',
  2116. sprintf(
  2117. /* translators: %s: privacy */
  2118. __( 'The "%s" options group has been removed. Use another settings group.' ),
  2119. 'privacy'
  2120. )
  2121. );
  2122. $option_group = 'reading';
  2123. }
  2124. $pos = array_search( $option_name, (array) $new_allowed_options[ $option_group ], true );
  2125. if ( false !== $pos ) {
  2126. unset( $new_allowed_options[ $option_group ][ $pos ] );
  2127. }
  2128. if ( '' !== $deprecated ) {
  2129. _deprecated_argument(
  2130. __FUNCTION__,
  2131. '4.7.0',
  2132. sprintf(
  2133. /* translators: 1: $sanitize_callback, 2: register_setting() */
  2134. __( '%1$s is deprecated. The callback from %2$s is used instead.' ),
  2135. '<code>$sanitize_callback</code>',
  2136. '<code>register_setting()</code>'
  2137. )
  2138. );
  2139. remove_filter( "sanitize_option_{$option_name}", $deprecated );
  2140. }
  2141. if ( isset( $wp_registered_settings[ $option_name ] ) ) {
  2142. // Remove the sanitize callback if one was set during registration.
  2143. if ( ! empty( $wp_registered_settings[ $option_name ]['sanitize_callback'] ) ) {
  2144. remove_filter( "sanitize_option_{$option_name}", $wp_registered_settings[ $option_name ]['sanitize_callback'] );
  2145. }
  2146. // Remove the default filter if a default was provided during registration.
  2147. if ( array_key_exists( 'default', $wp_registered_settings[ $option_name ] ) ) {
  2148. remove_filter( "default_option_{$option_name}", 'filter_default_option', 10 );
  2149. }
  2150. /**
  2151. * Fires immediately before the setting is unregistered and after its filters have been removed.
  2152. *
  2153. * @since 5.5.0
  2154. *
  2155. * @param string $option_group Setting group.
  2156. * @param string $option_name Setting name.
  2157. */
  2158. do_action( 'unregister_setting', $option_group, $option_name );
  2159. unset( $wp_registered_settings[ $option_name ] );
  2160. }
  2161. }
  2162. /**
  2163. * Retrieves an array of registered settings.
  2164. *
  2165. * @since 4.7.0
  2166. *
  2167. * @global array $wp_registered_settings
  2168. *
  2169. * @return array List of registered settings, keyed by option name.
  2170. */
  2171. function get_registered_settings() {
  2172. global $wp_registered_settings;
  2173. if ( ! is_array( $wp_registered_settings ) ) {
  2174. return array();
  2175. }
  2176. return $wp_registered_settings;
  2177. }
  2178. /**
  2179. * Filters the default value for the option.
  2180. *
  2181. * For settings which register a default setting in `register_setting()`, this
  2182. * function is added as a filter to `default_option_{$option}`.
  2183. *
  2184. * @since 4.7.0
  2185. *
  2186. * @param mixed $default Existing default value to return.
  2187. * @param string $option Option name.
  2188. * @param bool $passed_default Was `get_option()` passed a default value?
  2189. * @return mixed Filtered default value.
  2190. */
  2191. function filter_default_option( $default, $option, $passed_default ) {
  2192. if ( $passed_default ) {
  2193. return $default;
  2194. }
  2195. $registered = get_registered_settings();
  2196. if ( empty( $registered[ $option ] ) ) {
  2197. return $default;
  2198. }
  2199. return $registered[ $option ]['default'];
  2200. }