DuracellTomi's Google Tag Manager for WordPress - Version 1.13

Version Description

WARNING! If you are using the geo or weather options of this plugin, make sure your hosting is using PHP 7.0 or newer!

If you are using the WooCommerce integration with enhanced ecommerce, once again you will need to update your GTM container. Please check the setup article to see what needs to be changed. The goal is to keep this setup in the upcoming versions.

  • Added: Google Business Vertical option to populate Google Ads dynamic remarketing
  • Added: Make automatic cookie blocking mode of Cookiebot to work with your Google Tag Manager container (new option in the Integration tab)
  • Added: support for server side containers with custom domains
  • Added: improved duplacate WooCommerce order tracking prevention by also checking the age of the order. You can adjust the value in minutes on the plugin options page - by Code-Craze
  • Fixed: prices rounded to 2 decimals in the data layer (WooCommerce integration)
  • Fixed: select_item event fired multiple times (at least twice)
  • Fixed: frontend protection to preveent double tracking transactions had a bug
  • Fixed: missing product detail and first checkout step tracking in WooCommerce shops with Enhanced Ecommerce
  • Fixed: JavaScript type error if product category is a number
  • Updated: WhichBrowser v2.1.1 (requires PHP 7.0 or newer)
  • Updated: descriptions of WooCommerce tracking methods to emphasize the importance to migrate from standard to enhanced ecommerce
  • Updated: added links to enhanced ecommerce setup guides (GA3 and GA4)
Download this release

Release Info

Developer duracelltomi
Plugin Icon 128x128 DuracellTomi's Google Tag Manager for WordPress
Version 1.13
Comparing to
See all releases

Code changes from version 1.12.3 to 1.13

Files changed (40) hide show
  1. admin/admin.php +1484 -1418
  2. common/readoptions.php +465 -434
  3. duracelltomi-google-tag-manager-for-wordpress.php +3 -3
  4. integration/whichbrowser/bootstrap.php +30 -0
  5. integration/whichbrowser/data/applications-bots.php +120 -8
  6. integration/whichbrowser/data/applications-browsers.php +121 -3
  7. integration/whichbrowser/data/applications-others.php +10 -0
  8. integration/whichbrowser/data/browsers-chrome.php +41 -0
  9. integration/whichbrowser/data/indices/models-android.php +1354 -1022
  10. integration/whichbrowser/data/indices/models-firefoxos.php +1 -0
  11. integration/whichbrowser/data/indices/models-tizen.php +15 -0
  12. integration/whichbrowser/data/models-android.php +582 -57
  13. integration/whichbrowser/data/models-firefoxos.php +1 -0
  14. integration/whichbrowser/data/models-ios.php +24 -0
  15. integration/whichbrowser/data/models-tizen.php +10 -0
  16. integration/whichbrowser/data/profiles.php +56 -0
  17. integration/whichbrowser/data/regexes/applications-bots.php +1 -1
  18. integration/whichbrowser/data/regexes/applications-browsers.php +1 -1
  19. integration/whichbrowser/data/regexes/applications-others.php +1 -1
  20. integration/whichbrowser/src/Analyser/Camouflage.php +0 -6
  21. integration/whichbrowser/src/Analyser/Derive.php +12 -0
  22. integration/whichbrowser/src/Analyser/Header.php +4 -2
  23. integration/whichbrowser/src/Analyser/Header/Useragent.php +2 -1
  24. integration/whichbrowser/src/Analyser/Header/Useragent/Browser.php +78 -10
  25. integration/whichbrowser/src/Analyser/Header/Useragent/Device/Ereader.php +0 -1
  26. integration/whichbrowser/src/Analyser/Header/Useragent/Device/Mobile.php +3 -5
  27. integration/whichbrowser/src/Analyser/Header/Useragent/Device/Television.php +84 -18
  28. integration/whichbrowser/src/Analyser/Header/Useragent/Engine.php +11 -0
  29. integration/whichbrowser/src/Analyser/Header/Useragent/Os.php +15 -15
  30. integration/whichbrowser/src/Data/Applications.php +0 -2
  31. integration/whichbrowser/src/Model/Primitive/Base.php +1 -1
  32. integration/whichbrowser/src/Model/Primitive/NameVersion.php +8 -3
  33. integration/whichbrowser/src/Model/Version.php +1 -1
  34. integration/woocommerce.php +1149 -1113
  35. js/admin-subtabs.js +5 -1
  36. js/gtm4wp-woocommerce-enhanced.js +12 -2
  37. license.txt +621 -621
  38. public/frontend.php +915 -904
  39. readme.txt +906 -877
  40. uninstall.php +9 -9
admin/admin.php CHANGED
@@ -1,1418 +1,1484 @@
1
- <?php
2
- define( 'GTM4WP_ADMINSLUG', 'gtm4wp-settings' );
3
- define( 'GTM4WP_ADMIN_GROUP', 'gtm4wp-admin-group' );
4
-
5
- define( 'GTM4WP_ADMIN_GROUP_GENERAL', 'gtm4wp-admin-group-general' );
6
- define( 'GTM4WP_ADMIN_GROUP_GTMID', 'gtm4wp-admin-group-gtm-id' );
7
- define( 'GTM4WP_ADMIN_GROUP_PLACEMENT', 'gtm4wp-admin-code-placement' );
8
- define( 'GTM4WP_ADMIN_GROUP_INFO', 'gtm4wp-admin-group-datalayer-info' );
9
-
10
- define( 'GTM4WP_ADMIN_GROUP_INCLUDES', 'gtm4wp-admin-group-includes' );
11
- define( 'GTM4WP_ADMIN_GROUP_EVENTS', 'gtm4wp-admin-group-events' );
12
- define( 'GTM4WP_ADMIN_GROUP_SCROLLER', 'gtm4wp-admin-group-scroller' );
13
- define( 'GTM4WP_ADMIN_GROUP_BLACKLIST', 'gtm4wp-admin-group-blacklist-tags' );
14
- define( 'GTM4WP_ADMIN_GROUP_INTEGRATION', 'gtm4wp-admin-group-integration' );
15
- define( 'GTM4WP_ADMIN_GROUP_ADVANCED', 'gtm4wp-admin-group-advanced' );
16
- define( 'GTM4WP_ADMIN_GROUP_CREDITS', 'gtm4wp-admin-group-credits' );
17
-
18
- define( 'GTM4WP_USER_NOTICES_KEY', 'gtm4wp_user_notices_dismisses' );
19
-
20
- define( 'GTM4WP_PHASE_STABLE', 'gtm4wp-phase-stable' );
21
- define( 'GTM4WP_PHASE_BETA', 'gtm4wp-phase-beta' );
22
- define( 'GTM4WP_PHASE_EXPERIMENTAL', 'gtm4wp-phase-experimental' );
23
- define( 'GTM4WP_PHASE_DEPRECATED', 'gtm4wp-phase-deprecated' );
24
-
25
- $GLOBALS['gtm4wp_def_user_notices_dismisses'] = array(
26
- 'enter-gtm-code' => false,
27
- 'wc-ga-plugin-warning' => false,
28
- 'wc-gayoast-plugin-warning' => false,
29
- 'php56-warning' => false,
30
- 'deprecated-warning' => false,
31
- );
32
-
33
- $GLOBALS['gtm4wp_includefieldtexts'] = array(
34
- GTM4WP_OPTION_INCLUDE_POSTTYPE => array(
35
- 'label' => __( 'Posttype of current post/archive', 'duracelltomi-google-tag-manager' ),
36
- 'description' => __( 'Check this option to include the type of the current post or archive page (post, page or any custom post type).', 'duracelltomi-google-tag-manager' ),
37
- 'phase' => GTM4WP_PHASE_STABLE,
38
- ),
39
- GTM4WP_OPTION_INCLUDE_CATEGORIES => array(
40
- 'label' => __( 'Category list of current post/archive', 'duracelltomi-google-tag-manager' ),
41
- 'description' => __( 'Check this option to include the category names of the current post or archive page', 'duracelltomi-google-tag-manager' ),
42
- 'phase' => GTM4WP_PHASE_STABLE,
43
- ),
44
- GTM4WP_OPTION_INCLUDE_TAGS => array(
45
- 'label' => __( 'Tags of current post', 'duracelltomi-google-tag-manager' ),
46
- 'description' => __( 'Check this option to include the tags of the current post.', 'duracelltomi-google-tag-manager' ),
47
- 'phase' => GTM4WP_PHASE_STABLE,
48
- ),
49
- GTM4WP_OPTION_INCLUDE_AUTHORID => array(
50
- 'label' => __( 'Post author ID', 'duracelltomi-google-tag-manager' ),
51
- 'description' => __( 'Check this option to include the ID of the author on the current post or author page.', 'duracelltomi-google-tag-manager' ),
52
- 'phase' => GTM4WP_PHASE_STABLE,
53
- ),
54
- GTM4WP_OPTION_INCLUDE_AUTHOR => array(
55
- 'label' => __( 'Post author name', 'duracelltomi-google-tag-manager' ),
56
- 'description' => __( 'Check this option to include the name of the author on the current post or author page.', 'duracelltomi-google-tag-manager' ),
57
- 'phase' => GTM4WP_PHASE_STABLE,
58
- ),
59
- GTM4WP_OPTION_INCLUDE_POSTDATE => array(
60
- 'label' => __( 'Post date', 'duracelltomi-google-tag-manager' ),
61
- 'description' => __( 'Check this option to include the date of the current post. This will include 4 dataLayer variables: full date, post year, post month, post date.', 'duracelltomi-google-tag-manager' ),
62
- 'phase' => GTM4WP_PHASE_STABLE,
63
- ),
64
- GTM4WP_OPTION_INCLUDE_POSTTITLE => array(
65
- 'label' => __( 'Post title', 'duracelltomi-google-tag-manager' ),
66
- 'description' => __( 'Check this option to include the title of the current post.', 'duracelltomi-google-tag-manager' ),
67
- 'phase' => GTM4WP_PHASE_STABLE,
68
- ),
69
- GTM4WP_OPTION_INCLUDE_POSTCOUNT => array(
70
- 'label' => __( 'Post count', 'duracelltomi-google-tag-manager' ),
71
- 'description' => __( 'Check this option to include the count of the posts currently shown on the page and the total number of posts in the category/tag/any taxonomy.', 'duracelltomi-google-tag-manager' ),
72
- 'phase' => GTM4WP_PHASE_STABLE,
73
- ),
74
- GTM4WP_OPTION_INCLUDE_POSTID => array(
75
- 'label' => __( 'Post ID', 'duracelltomi-google-tag-manager' ),
76
- 'description' => __( 'Check this option to include the post id.', 'duracelltomi-google-tag-manager' ),
77
- 'phase' => GTM4WP_PHASE_STABLE,
78
- ),
79
- GTM4WP_OPTION_INCLUDE_POSTFORMAT => array(
80
- 'label' => __( 'Post Format', 'duracelltomi-google-tag-manager' ),
81
- 'description' => __( 'Check this option to include the post format.', 'duracelltomi-google-tag-manager' ),
82
- 'phase' => GTM4WP_PHASE_STABLE,
83
- ),
84
- GTM4WP_OPTION_INCLUDE_POSTTERMLIST => array(
85
- "label" => __( "Post Terms", 'duracelltomi-google-tag-manager' ),
86
- "description" => __( "Check this option to include taxonomy values associated with a given post.", 'duracelltomi-google-tag-manager' ),
87
- "phase" => GTM4WP_PHASE_STABLE
88
- ),
89
- GTM4WP_OPTION_INCLUDE_SEARCHDATA => array(
90
- 'label' => __( 'Search data', 'duracelltomi-google-tag-manager' ),
91
- 'description' => __( 'Check this option to include the search term, referring page URL and number of results on the search page.', 'duracelltomi-google-tag-manager' ),
92
- 'phase' => GTM4WP_PHASE_STABLE,
93
- ),
94
- GTM4WP_OPTION_INCLUDE_LOGGEDIN => array(
95
- 'label' => __( 'Logged in status', 'duracelltomi-google-tag-manager' ),
96
- 'description' => __( 'Check this option to include whether there is a logged in user on your website.', 'duracelltomi-google-tag-manager' ),
97
- 'phase' => GTM4WP_PHASE_STABLE,
98
- ),
99
- GTM4WP_OPTION_INCLUDE_USERROLE => array(
100
- 'label' => __( 'Logged in user role', 'duracelltomi-google-tag-manager' ),
101
- 'description' => __( 'Check this option to include the role of the logged in user.', 'duracelltomi-google-tag-manager' ),
102
- 'phase' => GTM4WP_PHASE_STABLE,
103
- ),
104
- GTM4WP_OPTION_INCLUDE_USERID => array(
105
- 'label' => __( 'Logged in user ID', 'duracelltomi-google-tag-manager' ),
106
- 'description' => __( 'Check this option to include the ID of the logged in user.', 'duracelltomi-google-tag-manager' ),
107
- 'phase' => GTM4WP_PHASE_STABLE,
108
- ),
109
- GTM4WP_OPTION_INCLUDE_USERNAME => array(
110
- 'label' => __( 'Logged in user name', 'duracelltomi-google-tag-manager' ),
111
- 'description' => __( 'Check this option to include the username of the logged in user.', 'duracelltomi-google-tag-manager' ),
112
- 'phase' => GTM4WP_PHASE_STABLE,
113
- ),
114
- GTM4WP_OPTION_INCLUDE_USEREMAIL => array(
115
- 'label' => __( 'Logged in user email', 'duracelltomi-google-tag-manager' ),
116
- 'description' => __( 'Check this option to include the email address of the logged in user.', 'duracelltomi-google-tag-manager' ),
117
- 'phase' => GTM4WP_PHASE_STABLE,
118
- ),
119
- GTM4WP_OPTION_INCLUDE_USERREGDATE => array(
120
- 'label' => __( 'Logged in user creation date', 'duracelltomi-google-tag-manager' ),
121
- 'description' => __( 'Check this option to include the date of creation (registration) of the logged in user.', 'duracelltomi-google-tag-manager' ),
122
- 'phase' => GTM4WP_PHASE_STABLE,
123
- ),
124
- GTM4WP_OPTION_INCLUDE_VISITOR_IP => array(
125
- 'label' => __( 'Visitor IP', 'duracelltomi-google-tag-manager' ),
126
- 'description' => __( 'Check this option to include the IP address of the visitor. You might use this to filter internal traffic inside your GTM container. Please be aware that per GDPR its not allowed to transmit this full IP address to Google Analytics or to any other measurement system without explicit consent from the visitor.', 'duracelltomi-google-tag-manager' ),
127
- 'phase' => GTM4WP_PHASE_STABLE,
128
- ),
129
- GTM4WP_OPTION_INCLUDE_REMARKETING => array(
130
- 'label' => __( 'Remarketing variable', 'duracelltomi-google-tag-manager' ),
131
- 'description' => __( 'Check this option to include a dataLayer variable where all dataLayer values are stored to be included in your Google Ads remarketing tag as a custom variable field', 'duracelltomi-google-tag-manager' ),
132
- 'phase' => GTM4WP_PHASE_DEPRECATED,
133
- ),
134
- GTM4WP_OPTION_INCLUDE_BROWSERDATA => array(
135
- 'label' => __( 'Browser data *', 'duracelltomi-google-tag-manager' ),
136
- 'description' => __( 'Check this option to include the name, version and engine data of the browser the visitor uses.', 'duracelltomi-google-tag-manager' )
137
- ),
138
- GTM4WP_OPTION_INCLUDE_OSDATA => array(
139
- 'label' => __( 'OS data *', 'duracelltomi-google-tag-manager' ),
140
- 'description' => __( 'Check this option to include the name and version of the operating system the visitor uses.', 'duracelltomi-google-tag-manager' )
141
- ),
142
- GTM4WP_OPTION_INCLUDE_DEVICEDATA => array(
143
- 'label' => __( 'Device data *', 'duracelltomi-google-tag-manager' ),
144
- 'description' => __( 'Check this option to include the type of device the user is currently using (desktop, tablet or mobile) including manufacturer and model data.', 'duracelltomi-google-tag-manager' )
145
- ),
146
- GTM4WP_OPTION_INCLUDE_MISCGEO => array(
147
- 'label' => __( 'Geo data', 'duracelltomi-google-tag-manager' ),
148
- 'description' => __( 'Add geo data (latitude, longitude, country, city, etc) of the current visitor (provided by ipstack.com)', 'duracelltomi-google-tag-manager' ),
149
- 'phase' => GTM4WP_PHASE_EXPERIMENTAL,
150
- ),
151
- GTM4WP_OPTION_INCLUDE_MISCGEOAPI => array(
152
- 'label' => __( 'IPStack.com API key', 'duracelltomi-google-tag-manager' ),
153
- 'description' => sprintf( __( 'Enter your IPStack.com API key here. <a href="%s" target="_blank">Get a free API key here</a>.', 'duracelltomi-google-tag-manager' ), 'https://ipstack.com/product?utm_source=gtm4wp&utm_medium=link&utm_campaign=gtm4wp-google-tag-manager-for-wordpress' ),
154
- 'phase' => GTM4WP_PHASE_EXPERIMENTAL,
155
- ),
156
- GTM4WP_OPTION_INCLUDE_MISCGEOCF => array(
157
- 'label' => __( 'Cloudflare country code', 'duracelltomi-google-tag-manager' ),
158
- 'description' => __( 'Add the country code of the user provided by Cloudflare (if Cloudflare is used with your site)', 'duracelltomi-google-tag-manager' ),
159
- 'phase' => GTM4WP_PHASE_EXPERIMENTAL,
160
- ),
161
- GTM4WP_OPTION_INCLUDE_WEATHER => array(
162
- 'label' => __( 'Weather data', 'duracelltomi-google-tag-manager' ),
163
- 'description' => sprintf(
164
- __(
165
- 'Check this option to include the current weather conditions around the current visitor.<br /><br />' .
166
- '<strong>Attention!</strong> This feature uses <a href="%s" target="_blank">ipstack.com</a> and ' .
167
- '<a href="%s" target="_blank">openweathermap.org</a> to collect data.<br />' .
168
- "Depending on your website's traffic, additional fees may apply!<br />" .
169
- 'This plugin caches weather data for 1 hour to lower the need to access those services.<br /><br />' .
170
- 'If you activate weather data, <strong>you will need</strong> to add an IPStack.com API key regardless of whether you ' .
171
- "activate the 'Geo data' option!",
172
- 'duracelltomi-google-tag-manager'
173
- ),
174
- 'https://ipstack.com/product?utm_source=gtm4wp&utm_medium=link&utm_campaign=gtm4wp-google-tag-manager-for-wordpress',
175
- 'http://openweathermap.org/price?utm_source=gtm4wp&utm_medium=link&utm_campaign=gtm4wp-google-tag-manager-for-wordpress'
176
- ),
177
- 'phase' => GTM4WP_PHASE_EXPERIMENTAL,
178
- ),
179
- GTM4WP_OPTION_INCLUDE_WEATHERUNITS => array(
180
- 'label' => __( 'Weather data units', 'duracelltomi-google-tag-manager' ),
181
- 'description' => __( 'Select which temperature units you would like to use.', 'duracelltomi-google-tag-manager' ),
182
- 'phase' => GTM4WP_PHASE_EXPERIMENTAL,
183
- ),
184
- GTM4WP_OPTION_INCLUDE_WEATHEROWMAPI => array(
185
- 'label' => __( 'OpenWeatherMap API key', 'duracelltomi-google-tag-manager' ),
186
- 'description' => sprintf( __( 'Enter your OpenWeatherMap API key here. <a href="%s" target="_blank">Get a free API key here</a>.', 'duracelltomi-google-tag-manager' ), 'http://openweathermap.org/price?utm_source=gtm4wp&utm_medium=link&utm_campaign=gtm4wp-google-tag-manager-for-wordpress' ),
187
- 'phase' => GTM4WP_PHASE_EXPERIMENTAL,
188
- ),
189
- GTM4WP_OPTION_INCLUDE_SITEID => array(
190
- 'label' => __( 'Site ID', 'duracelltomi-google-tag-manager' ),
191
- 'description' => __( 'ID of the current site in a WordPress Multisite environment', 'duracelltomi-google-tag-manager' ),
192
- 'phase' => GTM4WP_PHASE_STABLE,
193
- ),
194
- GTM4WP_OPTION_INCLUDE_SITENAME => array(
195
- 'label' => __( 'Site name', 'duracelltomi-google-tag-manager' ),
196
- 'description' => __( 'Name of the current site in a WordPress Multisite environment', 'duracelltomi-google-tag-manager' ),
197
- 'phase' => GTM4WP_PHASE_STABLE,
198
- ),
199
- );
200
-
201
- $GLOBALS['gtm4wp_eventfieldtexts'] = array(
202
- GTM4WP_OPTION_EVENTS_FORMMOVE => array(
203
- 'label' => __( 'Form fill events (gtm4wp.formElementEnter & gtm4wp.formElementLeave)', 'duracelltomi-google-tag-manager' ),
204
- 'description' => __( 'Check this option to include a Tag Manager event when a visitor moves between elements of a form (comment, contact, etc).', 'duracelltomi-google-tag-manager' ),
205
- 'phase' => GTM4WP_PHASE_STABLE,
206
- ),
207
- GTM4WP_OPTION_EVENTS_NEWUSERREG => array(
208
- 'label' => __( 'New user registration', 'duracelltomi-google-tag-manager' ),
209
- 'description' => __( 'Check this option to include a Tag Manager event when a new user registration has been completed on the frontend of your site (admin events not included)', 'duracelltomi-google-tag-manager' ),
210
- 'phase' => GTM4WP_PHASE_STABLE,
211
- ),
212
- GTM4WP_OPTION_EVENTS_USERLOGIN => array(
213
- 'label' => __( 'User logged in', 'duracelltomi-google-tag-manager' ),
214
- 'description' => __( 'Check this option to include a Tag Manager event when an existing user has been logged in on the frontend of your site (admin events not included)', 'duracelltomi-google-tag-manager' ),
215
- 'phase' => GTM4WP_PHASE_STABLE,
216
- ),
217
- GTM4WP_OPTION_EVENTS_YOUTUBE => array(
218
- 'label' => __( 'YouTube video events', 'duracelltomi-google-tag-manager' ),
219
- 'description' => __( 'Check this option to include a Tag Manager event when a visitor interacts with a YouTube video embeded on your site.', 'duracelltomi-google-tag-manager' ),
220
- 'phase' => GTM4WP_PHASE_EXPERIMENTAL,
221
- ),
222
- GTM4WP_OPTION_EVENTS_VIMEO => array(
223
- 'label' => __( 'Vimeo video events', 'duracelltomi-google-tag-manager' ),
224
- 'description' => __( 'Check this option to include a Tag Manager event when a visitor interacts with a Vimeo video embeded on your site.', 'duracelltomi-google-tag-manager' ),
225
- 'phase' => GTM4WP_PHASE_EXPERIMENTAL,
226
- ),
227
- GTM4WP_OPTION_EVENTS_SOUNDCLOUD => array(
228
- 'label' => __( 'Soundcloud events', 'duracelltomi-google-tag-manager' ),
229
- 'description' => __( 'Check this option to include a Tag Manager event when a visitor interacts with a Soundcloud media embeded on your site.', 'duracelltomi-google-tag-manager' ),
230
- 'phase' => GTM4WP_PHASE_EXPERIMENTAL,
231
- )
232
- );
233
-
234
- $GLOBALS['gtm4wp_scrollerfieldtexts'] = array(
235
- GTM4WP_OPTION_SCROLLER_ENABLED => array(
236
- 'label' => __( 'Enabled', 'duracelltomi-google-tag-manager' ),
237
- 'description' => __( 'Enable scroll tracker script on your website.', 'duracelltomi-google-tag-manager' ),
238
- 'phase' => GTM4WP_PHASE_STABLE,
239
- ),
240
- GTM4WP_OPTION_SCROLLER_DEBUGMODE => array(
241
- 'label' => __( 'Debug mode', 'duracelltomi-google-tag-manager' ),
242
- 'description' => __( 'Fire console.log() commands instead of dataLayer events.', 'duracelltomi-google-tag-manager' ),
243
- 'phase' => GTM4WP_PHASE_STABLE,
244
- ),
245
- GTM4WP_OPTION_SCROLLER_CALLBACKTIME => array(
246
- 'label' => __( 'Time delay before location check', 'duracelltomi-google-tag-manager' ),
247
- 'description' => __( 'Enter the number of milliseconds after the script checks the current location. It prevents too many events being fired while scrolling.', 'duracelltomi-google-tag-manager' ),
248
- 'phase' => GTM4WP_PHASE_STABLE,
249
- ),
250
- GTM4WP_OPTION_SCROLLER_DISTANCE => array(
251
- 'label' => __( 'Minimum distance', 'duracelltomi-google-tag-manager' ),
252
- 'description' => __( 'The minimum amount of pixels that a visitor has to scroll before we treat the move as scrolling.', 'duracelltomi-google-tag-manager' ),
253
- 'phase' => GTM4WP_PHASE_STABLE,
254
- ),
255
- GTM4WP_OPTION_SCROLLER_CONTENTID => array(
256
- 'label' => __( 'Content ID', 'duracelltomi-google-tag-manager' ),
257
- 'description' => __( 'Enter the DOM ID of the content element in your template. Leave it empty for default(content). Do not include the # sign.', 'duracelltomi-google-tag-manager' ),
258
- 'phase' => GTM4WP_PHASE_STABLE,
259
- ),
260
- GTM4WP_OPTION_SCROLLER_READERTIME => array(
261
- 'label' => __( 'Scroller time', 'duracelltomi-google-tag-manager' ),
262
- 'description' => __( 'Enter the number of seconds after the the scroller user is being treated as a reader, someone who really reads the content, not just scrolls through it.', 'duracelltomi-google-tag-manager' ),
263
- 'phase' => GTM4WP_PHASE_STABLE,
264
- ),
265
- );
266
-
267
- $GLOBALS['gtm4wp_integratefieldtexts'] = array(
268
- GTM4WP_OPTION_INTEGRATE_WPCF7 => array(
269
- 'label' => __( 'Contact Form 7', 'duracelltomi-google-tag-manager' ),
270
- 'description' => __( 'Check this to include a dataLayer event after a successfull form submission.', 'duracelltomi-google-tag-manager' ),
271
- 'phase' => GTM4WP_PHASE_STABLE,
272
- 'plugintocheck' => 'contact-form-7/wp-contact-form-7.php',
273
- ),
274
- GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC => array(
275
- 'label' => __( 'Track classic e-commerce', 'duracelltomi-google-tag-manager' ),
276
- 'description' => sprintf( __( 'Choose this option if you would like to track e-commerce data using <a href="%s" target="_blank">classic transaction data</a>.', 'duracelltomi-google-tag-manager' ), 'https://developers.google.com/analytics/devguides/collection/analyticsjs/ecommerce' ),
277
- 'phase' => GTM4WP_PHASE_DEPRECATED,
278
- 'plugintocheck' => 'woocommerce/woocommerce.php',
279
- ),
280
- GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC => array(
281
- 'label' => __( 'Track enhanced e-commerce', 'duracelltomi-google-tag-manager' ),
282
- 'description' => sprintf( __( 'Choose this option if you would like to track e-commerce data using <a href="%s" target="_blank">enhanced ecommerce tracking</a>.', 'duracelltomi-google-tag-manager' ), 'https://developers.google.com/analytics/devguides/collection/analyticsjs/enhanced-ecommerce' ),
283
- 'phase' => GTM4WP_PHASE_STABLE,
284
- 'plugintocheck' => 'woocommerce/woocommerce.php',
285
- ),
286
- GTM4WP_OPTION_INTEGRATE_WCPRODPERIMPRESSION => array(
287
- 'label' => __( 'Products per impression', 'duracelltomi-google-tag-manager' ),
288
- 'description' => __(
289
- 'If you have many products shown on product category pages and/or on your site home, you could miss pageviews in Google Analytics due to the ' .
290
- 'amount of data that is needed to be sent. To prevent this, you can split product impression data into multiple Google Analytics events by ' .
291
- 'entering a number here (minimum 10-15 recommended) and adding gtm4wp.productImpressionEEC into your Google Analytics ecommerce event helper ' .
292
- "tag's trigger.<br /><br />Leave this value 0 to include product impression data in your pageview hit.",
293
- 'duracelltomi-google-tag-manager'
294
- ),
295
- 'phase' => GTM4WP_PHASE_STABLE
296
- ),
297
- GTM4WP_OPTION_INTEGRATE_WCEECCARTASFIRSTSTEP => array(
298
- 'label' => __( 'Cart as 1st checkout step', 'duracelltomi-google-tag-manager' ),
299
- 'description' => __( 'Enable this to track the cart page as the first checkout step in enhanced ecommerce instead of the checkout page itself', 'duracelltomi-google-tag-manager' ),
300
- 'phase' => GTM4WP_PHASE_STABLE
301
- ),
302
- GTM4WP_OPTION_INTEGRATE_WCEINCLUDECARTINDL => array(
303
- "label" => __( "Cart content in data layer", 'duracelltomi-google-tag-manager' ),
304
- "description" => __( "Enable this option to include the content of the cart in the data layer on each page. Needs WooCommerce v3.2 or newer. Especially useful for site personalization with Google Optimize.", 'duracelltomi-google-tag-manager' ),
305
- "phase" => GTM4WP_PHASE_STABLE
306
- ),
307
- GTM4WP_OPTION_INTEGRATE_WCUSEFULLCATEGORYPATH => array(
308
- 'label' => __( 'Include full category path.', 'duracelltomi-google-tag-manager' ),
309
- 'description' => __( 'Check this to inclulde the full category path of each product in enhanced ecommerce tracking. WARNING! This can lead to performance issues on large sites with lots of traffic!', 'duracelltomi-google-tag-manager' ),
310
- 'phase' => GTM4WP_PHASE_STABLE
311
- ),
312
- GTM4WP_OPTION_INTEGRATE_WCEECBRANDTAXONOMY => array(
313
- "label" => __( "Taxonomy to be used for product brands", 'duracelltomi-google-tag-manager' ),
314
- "description" => __( "Select which custom taxonomy is being used to add the brand of products", 'duracelltomi-google-tag-manager' ),
315
- "phase" => GTM4WP_PHASE_STABLE
316
- ),
317
- GTM4WP_OPTION_INTEGRATE_WCCUSTOMERDATA => array(
318
- 'label' => __( 'Customer data in data layer', 'duracelltomi-google-tag-manager' ),
319
- 'description' => __( 'Enable this to add all customer data (billing and shipping data, total number of orders and order value) into the data layer (WooCommerce 3.x required)', 'duracelltomi-google-tag-manager' ),
320
- 'phase' => GTM4WP_PHASE_STABLE
321
- ),
322
- GTM4WP_OPTION_INTEGRATE_WCORDERDATA => array(
323
- 'label' => __( 'Order data in data layer', 'duracelltomi-google-tag-manager' ),
324
- 'description' => __( 'Enable this to add all order attribute into the data layer on the order received page regardless and independently from classic and enhanced ecommerce tracking (WooCommerce 3.x required)', 'duracelltomi-google-tag-manager' ),
325
- 'phase' => GTM4WP_PHASE_STABLE
326
- ),
327
- GTM4WP_OPTION_INTEGRATE_WCEXCLUDETAX => array(
328
- 'label' => __( 'Exclude tax from revenue', 'duracelltomi-google-tag-manager' ),
329
- 'description' => __( 'Enable this to exclude tax from the revenue variable while generating the purchase data', 'duracelltomi-google-tag-manager' ),
330
- 'phase' => GTM4WP_PHASE_STABLE
331
- ),
332
- GTM4WP_OPTION_INTEGRATE_WCEXCLUDESHIPPING => array(
333
- 'label' => __( 'Exclude shipping from revenue', 'duracelltomi-google-tag-manager' ),
334
- 'description' => __( 'Enable this to exclude shipping costs from the revenue variable while generating the purchase data', 'duracelltomi-google-tag-manager' ),
335
- 'phase' => GTM4WP_PHASE_STABLE
336
- ),
337
- GTM4WP_OPTION_INTEGRATE_WCREMARKETING => array(
338
- 'label' => __( 'Google Ads Remarketing', 'duracelltomi-google-tag-manager' ),
339
- 'description' => __( 'Enable this to add Google Ads dynamic remarketing variables to the dataLayer', 'duracelltomi-google-tag-manager' ),
340
- 'phase' => GTM4WP_PHASE_DEPRECATED
341
- ),
342
- GTM4WP_OPTION_INTEGRATE_WCREMPRODIDPREFIX => array(
343
- 'label' => __( 'Product ID prefix', 'duracelltomi-google-tag-manager' ),
344
- 'description' => __( "Some product feed generator plugins prefix product IDs with a fixed text like 'woocommerce_gpf'. You can enter this prefix here so that tags in your website include this prefix as well.", 'duracelltomi-google-tag-manager' ),
345
- 'phase' => GTM4WP_PHASE_STABLE
346
- ),
347
- GTM4WP_OPTION_INTEGRATE_WCUSESKU => array(
348
- 'label' => __( 'Use SKU instead of ID', 'duracelltomi-google-tag-manager' ),
349
- 'description' => __( 'Check this to use product SKU instead of the ID of the products for remarketing and ecommerce tracking. Will fallback to ID if no SKU is set.', 'duracelltomi-google-tag-manager' ),
350
- 'phase' => GTM4WP_PHASE_STABLE
351
- ),
352
- GTM4WP_OPTION_INTEGRATE_WCNOORDERTRACKEDFLAG => array(
353
- 'label' => __( 'Do not flag orders as being tracked', 'duracelltomi-google-tag-manager' ),
354
- 'description' => __(
355
- 'Check this to prevent the plugin to flag orders as being already tracked.<br /><br />This ensures that no order data will be tracked ' .
356
- 'multiple times in any ad or measurement system so please only enable this feature if you really need it (with iDeal you might need this)!',
357
- 'duracelltomi-google-tag-manager'
358
- ),
359
- 'phase' => GTM4WP_PHASE_STABLE
360
- ),
361
-
362
- GTM4WP_OPTION_INTEGRATE_GOOGLEOPTIMIZEIDS => array(
363
- 'label' => __( 'Google Optimize container ID list', 'duracelltomi-google-tag-manager' ),
364
- 'description' => sprintf(
365
- __(
366
- 'Enter a comma separated list of Google Optimize container IDs that you would like to use on your site.<br />' .
367
- 'This plugin will add the <a href="%s">page-hiding snippet</a> to your pages.<br />',
368
- 'duracelltomi-google-tag-manager'
369
- ),
370
- 'https://developers.google.com/optimize/#the_page-hiding_snippet_code'
371
- ) .
372
- '<br /><span class="goid_validation_error">' . __( 'This does not seems to be a valid Google Optimize ID! Valid format: GTM-XXXXXX or OPT-XXXXXX where X can be numbers and capital letters. Use comma without any space (,) to enter multpile IDs.', 'duracelltomi-google-tag-manager' ) . '</span>',
373
- 'phase' => GTM4WP_PHASE_EXPERIMENTAL,
374
- ),
375
- GTM4WP_OPTION_INTEGRATE_GOOGLEOPTIMIZETIMEOUT => array(
376
- 'label' => __( 'Google Optimize page-hiding timeout', 'duracelltomi-google-tag-manager' ),
377
- 'description' => __( 'Enter here the amount of time in milliseconds that the page-hiding snippet should wait before page content gets visible even if Google Optimize has not been completely loaded yet.', 'duracelltomi-google-tag-manager' ),
378
- 'phase' => GTM4WP_PHASE_EXPERIMENTAL,
379
- ),
380
-
381
- GTM4WP_OPTION_INTEGRATE_AMPID => array(
382
- 'label' => __( "Google Tag Manager 'AMP' Container ID", 'duracelltomi-google-tag-manager' ),
383
- 'description' => sprintf( __( 'Enter a comma separated list of Google Tag Manager container IDs that you would like to use on your site. This plugin will add the <a href="%s">AMP GTM snippet</a> to your AMP pages.', 'duracelltomi-google-tag-manager' ), 'https://support.google.com/tagmanager/answer/6103696?hl=en' ) .
384
- '<br /><span class="ampid_validation_error">' . __( 'This does not seems to be a valid Google Tag Manager Container ID! Valid format: GTM-XXXXXX where X can be numbers and capital letters. Use comma without any space (,) to enter multpile IDs.', 'duracelltomi-google-tag-manager' ) . '</span>',
385
- 'phase' => GTM4WP_PHASE_EXPERIMENTAL,
386
- 'plugintocheck' => 'amp/amp.php',
387
- ),
388
- );
389
-
390
- $GLOBALS['gtm4wp_advancedfieldtexts'] = array(
391
- GTM4WP_OPTION_DATALAYER_NAME => array(
392
- 'label' => __( 'dataLayer variable name', 'duracelltomi-google-tag-manager' ),
393
- 'description' => __( 'In some cases you need to rename the dataLayer variable. You can enter your name here. Leave black for default name: dataLayer', 'duracelltomi-google-tag-manager' ),
394
- 'phase' => GTM4WP_PHASE_STABLE,
395
- ),
396
- GTM4WP_OPTION_ENV_GTM_AUTH => array(
397
- 'label' => __( 'Environment gtm_auth parameter', 'duracelltomi-google-tag-manager' ),
398
- 'description' => __( 'Enter the gtm_auth parameter of the Google Tag Manager environment that has to be activated on this site. Both gtm_auth and gtm_preview parameters are required to activate the desired environment.', 'duracelltomi-google-tag-manager' ),
399
- 'phase' => GTM4WP_PHASE_STABLE,
400
- ),
401
- GTM4WP_OPTION_ENV_GTM_PREVIEW => array(
402
- 'label' => __( 'Environment gtm_preview parameter', 'duracelltomi-google-tag-manager' ),
403
- 'description' => __( 'Enter the gtm_auth parameter of the Google Tag Manager environment that has to be activated on this site. Both gtm_auth and gtm_preview parameters are required to activate the desired environment.', 'duracelltomi-google-tag-manager' ),
404
- 'phase' => GTM4WP_PHASE_STABLE,
405
- ),
406
- GTM4WP_OPTION_DONOTTRACK => array(
407
- 'label' => __( "Include browser 'Do not track' setting", 'duracelltomi-google-tag-manager' ),
408
- 'description' => __( 'Add into the data layer whether the user has asked not to track any website interaction. You may want to respect this and disable all tags if this variable is set in the data layer.', 'duracelltomi-google-tag-manager' ),
409
- 'phase' => GTM4WP_PHASE_STABLE,
410
- ),
411
- GTM4WP_OPTION_LOADEARLY => array(
412
- 'label' => __( 'Load GTM container as early as possible', 'duracelltomi-google-tag-manager' ),
413
- 'description' => __( "Turning on this option will load your Google Tag Manager container as early as possible during page load. This can cause issues if you are using jQuery in your custom HTML tags that fire on 'Page View' events.", 'duracelltomi-google-tag-manager' ),
414
- 'phase' => GTM4WP_PHASE_STABLE,
415
- ),
416
- );
417
-
418
- function gtm4wp_admin_output_section( $args ) {
419
- echo '<span class="tabinfo">';
420
-
421
- switch ( $args['id'] ) {
422
- case GTM4WP_ADMIN_GROUP_GENERAL: {
423
- _e( 'This plugin is intended to be used by IT girls&guys and marketing staff. Please be sure you read the <a href="https://developers.google.com/tag-manager/" target="_blank">Google Tag Manager Help Center</a> before you start using this plugin.<br /><br />', 'duracelltomi-google-tag-manager' );
424
-
425
- break;
426
- }
427
-
428
- case GTM4WP_ADMIN_GROUP_INCLUDES: {
429
- _e( 'Here you can check what data is needed to be included in the dataLayer to be able to access them in Google Tag Manager', 'duracelltomi-google-tag-manager' );
430
- echo '<br />';
431
- printf( __( '* Browser, OS and Device data is provided using <a href="%s">WhichBrowser</a> library.', 'duracelltomi-google-tag-manager' ), 'http://whichbrowser.net/' );
432
-
433
- break;
434
- }
435
-
436
- case GTM4WP_ADMIN_GROUP_EVENTS: {
437
- _e( 'Fire tags in Google Tag Manager on special events on your website', 'duracelltomi-google-tag-manager' );
438
-
439
- break;
440
- }
441
-
442
- case GTM4WP_ADMIN_GROUP_SCROLLER: {
443
- _e( 'Fire tags based on how the visitor scrolls through your page.', 'duracelltomi-google-tag-manager' );
444
- echo '<br />';
445
- printf( __( 'Based on the script originaly posted to <a href="%s">Analytics Talk</a>', 'duracelltomi-google-tag-manager' ), 'http://cutroni.com/blog/2012/02/21/advanced-content-tracking-with-google-analytics-part-1/' );
446
-
447
- break;
448
- }
449
-
450
- case GTM4WP_ADMIN_GROUP_BLACKLIST: {
451
- _e( 'Here you can control which types of tags, triggers and variables can be executed on your site regardless of what tags are included in your container on the Google Tag Manager site. Use this to increase security!', 'duracelltomi-google-tag-manager' );
452
- echo '<br />';
453
- _e( 'Do not modify if you do not know what to do, since it can cause issues with your tag deployment!', 'duracelltomi-google-tag-manager' );
454
- echo '<br />';
455
- _e( 'For example blacklisting everything and only whitelisting the Google Analytics tag without whitelisting the URL variable type will cause your Google Analytics tags to be blocked anyway since the attached triggers (Page View) can not fire!', 'duracelltomi-google-tag-manager' );
456
-
457
- break;
458
- }
459
-
460
- case GTM4WP_ADMIN_GROUP_INTEGRATION: {
461
- _e( 'Google Tag Manager for WordPress can integrate with several popular plugins. Please check the plugins you would like to integrate with:', 'duracelltomi-google-tag-manager' );
462
-
463
- break;
464
- }
465
-
466
- case GTM4WP_ADMIN_GROUP_ADVANCED: {
467
- _e( 'You usually do not need to modify thoose settings. Please be carefull while hacking here.', 'duracelltomi-google-tag-manager' );
468
-
469
- break;
470
- }
471
-
472
- case GTM4WP_ADMIN_GROUP_CREDITS: {
473
- _e( 'Some info about the author of this plugin', 'duracelltomi-google-tag-manager' );
474
-
475
- break;
476
- }
477
- } // end switch
478
-
479
- echo '</span>';
480
- }
481
-
482
- function gtm4wp_admin_output_field( $args ) {
483
- global $gtm4wp_options;
484
-
485
- switch ( $args['label_for'] ) {
486
- case GTM4WP_ADMIN_GROUP_GTMID: {
487
- if ( defined( 'GTM4WP_HARDCODED_GTM_ID' ) ) {
488
- $_gtm_id_value = GTM4WP_HARDCODED_GTM_ID;
489
- $_input_readonly = ' readonly="readonly"';
490
- $_warning_after = '<br /><span class="gtm_wpconfig_set">WARNING! Container ID was set and fixed in wp-config.php. If you wish to change this value, please edit your wp-config.php and change the container ID or remove the GTM4WP_HARDCODED_GTM_ID constant!</span>';
491
- } else {
492
- $_gtm_id_value = $gtm4wp_options[ GTM4WP_OPTION_GTM_CODE ];
493
- $_input_readonly = '';
494
- $_warning_after = '';
495
- }
496
-
497
- echo '<input type="text" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_CODE . ']" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_CODE . ']" value="' . $_gtm_id_value . '" ' . $_input_readonly . '/><br />' . $args['description'];
498
- echo $_warning_after;
499
- echo '<br /><span class="gtmid_validation_error">' . __( 'This does not seems to be a valid Google Tag Manager ID! Valid format: GTM-XXXXX where X can be numbers and capital letters. Use comma without any space (,) to enter multpile container IDs.', 'duracelltomi-google-tag-manager' ) . '</span>';
500
-
501
- break;
502
- }
503
-
504
- case GTM4WP_ADMIN_GROUP_PLACEMENT: {
505
- echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_PLACEMENT . ']_' . GTM4WP_PLACEMENT_FOOTER . '" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_PLACEMENT . ']" value="' . GTM4WP_PLACEMENT_FOOTER . '" ' . ( $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] == GTM4WP_PLACEMENT_FOOTER ? 'checked="checked"' : '' ) . '/> ' . __( 'Footer of the page (not recommended by Google, no tweak in your template required)', 'duracelltomi-google-tag-manager' ) . '<br />';
506
- echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_PLACEMENT . ']_' . GTM4WP_PLACEMENT_BODYOPEN . '" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_PLACEMENT . ']" value="' . GTM4WP_PLACEMENT_BODYOPEN . '" ' . ( $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] == GTM4WP_PLACEMENT_BODYOPEN ? 'checked="checked"' : '' ) . '/> ' . __( 'Custom (needs tweak in your template)', 'duracelltomi-google-tag-manager' ) . '<br />';
507
- echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_PLACEMENT . ']_' . GTM4WP_PLACEMENT_BODYOPEN_AUTO . '" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_PLACEMENT . ']" value="' . GTM4WP_PLACEMENT_BODYOPEN_AUTO . '" ' . ( $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] == GTM4WP_PLACEMENT_BODYOPEN_AUTO ? 'checked="checked"' : '' ) . '/> ' . __( 'Codeless injection (no tweak, right placement but experimental, could break your frontend)', 'duracelltomi-google-tag-manager' ) . '<br />';
508
- echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_PLACEMENT . ']_' . GTM4WP_PLACEMENT_OFF . '" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_PLACEMENT . ']" value="' . GTM4WP_PLACEMENT_OFF . '" ' . ( $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] == GTM4WP_PLACEMENT_OFF ? 'checked="checked"' : '' ) . '/> ' . __( 'Off (only add data layer to the page source)', 'duracelltomi-google-tag-manager' ) . '<br /><br />' . $args['description'];
509
-
510
- break;
511
- }
512
-
513
- case GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_DATALAYER_NAME . ']': {
514
- echo '<input type="text" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_DATALAYER_NAME . ']" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_DATALAYER_NAME . ']" value="' . $gtm4wp_options[ GTM4WP_OPTION_DATALAYER_NAME ] . '" /><br />' . $args['description'];
515
- echo '<br /><span class="datalayername_validation_error">' . __( 'This does not seems to be a valid JavaScript variable name! Please check and try again', 'duracelltomi-google-tag-manager' ) . '</span>';
516
-
517
- break;
518
- }
519
-
520
- case GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_ENV_GTM_AUTH . ']': {
521
- if ( defined( 'GTM4WP_HARDCODED_GTM_ENV_AUTH' ) ) {
522
- $_gtm_auth_value = GTM4WP_HARDCODED_GTM_ENV_AUTH;
523
- $_input_readonly = ' readonly="readonly"';
524
- $_warning_after = '<br /><span class="gtm_wpconfig_set">WARNING! Environment auth parameter was set and fixed in wp-config.php. If you wish to change this value, please edit your wp-config.php and change the parameter value or remove the GTM4WP_HARDCODED_GTM_ENV_AUTH constant!</span>';
525
- } else {
526
- $_gtm_auth_value = $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_AUTH ];
527
- $_input_readonly = '';
528
- $_warning_after = '';
529
- }
530
-
531
- echo '<input type="text" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_ENV_GTM_AUTH . ']" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_ENV_GTM_AUTH . ']" value="' . $_gtm_auth_value . '" ' . $_input_readonly . '/><br />' . $args['description'];
532
- echo $_warning_after;
533
- echo '<br /><span class="gtmauth_validation_error">' . __( 'This does not seems to be a valid gtm_auth parameter! It should only contain letters, number and the &quot;-&quot; character. Please check and try again', 'duracelltomi-google-tag-manager' ) . '</span>';
534
-
535
- break;
536
- }
537
-
538
- case GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_ENV_GTM_PREVIEW . ']': {
539
- if ( defined( 'GTM4WP_HARDCODED_GTM_ENV_PREVIEW' ) ) {
540
- $_gtm_preview_value = GTM4WP_HARDCODED_GTM_ENV_PREVIEW;
541
- $_input_readonly = ' readonly="readonly"';
542
- $_warning_after = '<br /><span class="gtm_wpconfig_set">WARNING! Environment preview parameter was set and fixed in wp-config.php. If you wish to change this value, please edit your wp-config.php and change the parameter value or remove the GTM4WP_HARDCODED_GTM_ENV_PREVIEW constant!</span>';
543
- } else {
544
- $_gtm_preview_value = $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_PREVIEW ];
545
- $_input_readonly = '';
546
- $_warning_after = '';
547
- }
548
-
549
- echo '<input type="text" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_ENV_GTM_PREVIEW . ']" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_ENV_GTM_PREVIEW . ']" value="' . $_gtm_preview_value . '" ' . $_input_readonly . '/><br />' . $args['description'];
550
- echo $_warning_after;
551
- echo '<br /><span class="gtmpreview_validation_error">' . __( 'This does not seems to be a valid gtm_preview parameter! It should have the format &quot;env-NN&quot; where NN is an integer number. Please check and try again', 'duracelltomi-google-tag-manager' ) . '</span>';
552
-
553
- break;
554
- }
555
-
556
- case GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_BLACKLIST_ENABLE . ']': {
557
- echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_BLACKLIST_ENABLE . ']_0" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_BLACKLIST_ENABLE . ']" value="0" ' . ( $gtm4wp_options[ GTM4WP_OPTION_BLACKLIST_ENABLE ] == 0 ? 'checked="checked"' : '' ) . '/> ' . __( 'Disable feature: control everything on Google Tag Manager interface', 'duracelltomi-google-tag-manager' ) . '<br />';
558
- echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_BLACKLIST_ENABLE . ']_1" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_BLACKLIST_ENABLE . ']" value="1" ' . ( $gtm4wp_options[ GTM4WP_OPTION_BLACKLIST_ENABLE ] == 1 ? 'checked="checked"' : '' ) . '/> ' . __( 'Allow all, except the checked items on all blacklist tabs (blacklist)', 'duracelltomi-google-tag-manager' ) . '<br />';
559
- echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_BLACKLIST_ENABLE . ']_2" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_BLACKLIST_ENABLE . ']" value="2" ' . ( $gtm4wp_options[ GTM4WP_OPTION_BLACKLIST_ENABLE ] == 2 ? 'checked="checked"' : '' ) . '/> ' . __( 'Block all, except the checked items on all blacklist tabs (whitelist)', 'duracelltomi-google-tag-manager' ) . '<br />';
560
- echo $args['description'];
561
-
562
- break;
563
- }
564
-
565
- case GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_INCLUDE_WEATHERUNITS . ']': {
566
- echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_INCLUDE_WEATHERUNITS . ']_0" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_INCLUDE_WEATHERUNITS . ']" value="0" ' . ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_WEATHERUNITS ] == 0 ? 'checked="checked"' : '' ) . '/> ' . __( 'Celsius', 'duracelltomi-google-tag-manager' ) . '<br />';
567
- echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_INCLUDE_WEATHERUNITS . ']_1" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_INCLUDE_WEATHERUNITS . ']" value="1" ' . ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_WEATHERUNITS ] == 1 ? 'checked="checked"' : '' ) . '/> ' . __( 'Fahrenheit', 'duracelltomi-google-tag-manager' ) . '<br />';
568
- echo $args['description'];
569
-
570
- break;
571
- }
572
-
573
- case GTM4WP_ADMIN_GROUP_INFO: {
574
- echo $args['description'];
575
-
576
- break;
577
- }
578
-
579
- case GTM4WP_OPTIONS . "[" . GTM4WP_OPTION_INTEGRATE_WCEECBRANDTAXONOMY . "]": {
580
- echo '<select id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_INTEGRATE_WCEECBRANDTAXONOMY . ']" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_INTEGRATE_WCEECBRANDTAXONOMY . ']">';
581
- echo '<option value="">(not set)</option>';
582
-
583
- $gtm4wp_taxonomies = get_taxonomies(array(
584
- "show_ui" => true,
585
- "public" => true,
586
- "_builtin" => false
587
- ), "object", "and");
588
-
589
- foreach( $gtm4wp_taxonomies as $onetaxonomy ) {
590
- echo '<option value="' . $onetaxonomy->name . '"' . ( $gtm4wp_options[GTM4WP_OPTION_INTEGRATE_WCEECBRANDTAXONOMY] === $onetaxonomy->name ? ' selected="selected"' : '' ) . '>' . $onetaxonomy->label . '</option>';
591
- }
592
-
593
- echo '</select>';
594
-
595
- break;
596
- }
597
-
598
- default: {
599
- if ( preg_match( '/' . GTM4WP_OPTIONS . "\\[blacklist\\-[^\\]]+\\]/i", $args['label_for'] ) ) {
600
- if ( 'blacklist-sandboxed' == $args['entityid'] ) {
601
- echo '<input type="checkbox" id="' . $args['label_for'] . '" name="' . $args['label_for'] . '" value="1" ' . checked( 1, $gtm4wp_options[ GTM4WP_OPTION_BLACKLIST_SANDBOXED ], false ) . ' /><br />' . $args['description'];
602
- } else {
603
- echo '<input type="checkbox" id="' . $args['label_for'] . '" name="' . $args['label_for'] . '" value="1" ' . checked( 1, in_array( $args['entityid'], $gtm4wp_options[ GTM4WP_OPTION_BLACKLIST_STATUS ] ), false ) . ' /><br />' . $args['description'];
604
- }
605
- } else {
606
- $optval = $gtm4wp_options[ $args['optionfieldid'] ];
607
-
608
- switch ( gettype( $optval ) ) {
609
- case 'boolean': {
610
- echo '<input type="checkbox" id="' . GTM4WP_OPTIONS . '[' . $args['optionfieldid'] . ']" name="' . GTM4WP_OPTIONS . '[' . $args['optionfieldid'] . ']" value="1" ' . checked( 1, $optval, false ) . ' /><br />' . $args['description'];
611
-
612
- if ( isset( $args['plugintocheck'] ) && ( $args['plugintocheck'] != '' ) ) {
613
- if ( is_plugin_active( $args['plugintocheck'] ) ) {
614
- echo '<br />' . __( 'This plugin is <strong class="gtm4wp-plugin-active">active</strong>, it is strongly recommended to enable this integration!', 'duracelltomi-google-tag-manager' );
615
- } else {
616
- echo '<br />' . __( 'This plugin (' . $args['plugintocheck'] . ') is <strong class="gtm4wp-plugin-not-active">not active</strong>, enabling this integration could cause issues on frontend!', 'duracelltomi-google-tag-manager' );
617
- }
618
- }
619
-
620
- break;
621
- }
622
-
623
- case 'integer': {
624
- echo '<input type="number" step="1" min="0" class="small-text" id="' . GTM4WP_OPTIONS . '[' . $args['optionfieldid'] . ']" name="' . GTM4WP_OPTIONS . '[' . $args['optionfieldid'] . ']" value="' . esc_attr( $optval ) . '" /><br />' . $args['description'];
625
-
626
- if ( isset( $args['plugintocheck'] ) && ( $args['plugintocheck'] != '' ) ) {
627
- if ( is_plugin_active( $args['plugintocheck'] ) ) {
628
- echo '<br />' . __( 'This plugin is <strong class="gtm4wp-plugin-active">active</strong>, it is strongly recommended to enable this integration!', 'duracelltomi-google-tag-manager' );
629
- } else {
630
- echo '<br />' . __( 'This plugin is <strong class="gtm4wp-plugin-not-active">not active</strong>, enabling this integration could cause issues on frontend!', 'duracelltomi-google-tag-manager' );
631
- }
632
- }
633
-
634
- break;
635
- }
636
-
637
- default : {
638
- echo '<input type="text" id="' . GTM4WP_OPTIONS . '[' . $args['optionfieldid'] . ']" name="' . GTM4WP_OPTIONS . '[' . $args['optionfieldid'] . ']" value="' . esc_attr( $optval ) . '" size="80" /><br />' . $args['description'];
639
-
640
- if ( isset( $args['plugintocheck'] ) && ( $args['plugintocheck'] != '' ) ) {
641
- if ( is_plugin_active( $args['plugintocheck'] ) ) {
642
- echo '<br />' . __( 'This plugin is <strong class="gtm4wp-plugin-active">active</strong>, it is strongly recommended to enable this integration!', 'duracelltomi-google-tag-manager' );
643
- } else {
644
- echo '<br />' . __( 'This plugin is <strong class="gtm4wp-plugin-not-active">not active</strong>, enabling this integration could cause issues on frontend!', 'duracelltomi-google-tag-manager' );
645
- }
646
- }
647
- }
648
- } // end switch gettype optval
649
- }
650
- }
651
- } // end switch
652
- }
653
-
654
- function gtm4wp_sanitize_options( $options ) {
655
- global $wpdb, $gtm4wp_entity_ids;
656
-
657
- $output = gtm4wp_reload_options();
658
-
659
- foreach ( $output as $optionname => $optionvalue ) {
660
- if ( isset( $options[ $optionname ] ) ) {
661
- $newoptionvalue = $options[ $optionname ];
662
- } else {
663
- $newoptionvalue = '';
664
- }
665
-
666
- // "include" settings
667
- if ( substr( $optionname, 0, 8 ) == 'include-' ) {
668
- $output[ $optionname ] = (bool) $newoptionvalue;
669
-
670
- // dataLayer events
671
- } elseif ( substr( $optionname, 0, 6 ) == 'event-' ) {
672
- $output[ $optionname ] = (bool) $newoptionvalue;
673
-
674
- // clear oembed transients when feature is enabled because we need to hook into the oembed process to enable some 3rd party APIs
675
- if ( $output[ $optionname ] && ! $optionvalue ) {
676
- if ( GTM4WP_OPTION_EVENTS_YOUTUBE == $optionname ) {
677
- $wpdb->query( "DELETE FROM $wpdb->postmeta WHERE meta_value LIKE '%youtube.com%' AND meta_key LIKE '_oembed_%'" );
678
- }
679
-
680
- if ( GTM4WP_OPTION_EVENTS_VIMEO == $optionname ) {
681
- $wpdb->query( "DELETE FROM $wpdb->postmeta WHERE meta_value LIKE '%vimeo.com%' AND meta_key LIKE '_oembed_%'" );
682
- }
683
- }
684
-
685
- // blacklist / whitelist entities
686
- } elseif ( substr( $optionname, 0, 10 ) == 'blacklist-' ) {
687
- if ( GTM4WP_OPTION_BLACKLIST_ENABLE === $optionname ) {
688
- $output[ $optionname ] = (int) $options[ GTM4WP_OPTION_BLACKLIST_ENABLE ];
689
- } else if ( GTM4WP_OPTION_BLACKLIST_SANDBOXED == $optionname ) {
690
- $output[ $optionname ] = (bool) $newoptionvalue;
691
- } else if ( GTM4WP_OPTION_BLACKLIST_STATUS == $optionname ) {
692
- $selected_blacklist_entities = array();
693
-
694
- foreach( $gtm4wp_entity_ids as $gtm_entity_group_id => $gtm_entity_group_list ) {
695
- foreach( $gtm_entity_group_list as $gtm_entity_id => $gtm_entity_label ) {
696
- $entity_option_id = 'blacklist-' . $gtm_entity_group_id . '-' . $gtm_entity_id;
697
- if ( array_key_exists( $entity_option_id, $options ) ) {
698
- $newoptionvalue = (bool) $options[ $entity_option_id ];
699
- if ( $newoptionvalue ) {
700
- $selected_blacklist_entities[] = $gtm_entity_id;
701
- }
702
- }
703
- }
704
- }
705
-
706
- $output[ $optionname ] = implode( ',', $selected_blacklist_entities );
707
- }
708
-
709
- // Google Optimize settings
710
- } elseif ( $optionname == GTM4WP_OPTION_INTEGRATE_GOOGLEOPTIMIZEIDS ) {
711
- $_goid_val = trim( $newoptionvalue );
712
- if ( '' == $_goid_val ) {
713
- $_goid_list = array();
714
- } else {
715
- $_goid_list = explode( ',', $_goid_val );
716
- }
717
- $_goid_haserror = false;
718
-
719
- foreach ( $_goid_list as $one_go_id ) {
720
- $_goid_haserror = $_goid_haserror || ! preg_match( '/^(GTM|OPT)-[A-Z0-9]+$/', $one_go_id );
721
- }
722
-
723
- if ( $_goid_haserror && ( count( $_goid_list ) > 0 ) ) {
724
- add_settings_error( GTM4WP_ADMIN_GROUP, GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_INTEGRATE_GOOGLEOPTIMIZEIDS . ']', __( 'Invalid Google Optimize ID. Valid ID format: GTM-XXXXX or OPT-XXXXX. Use comma without additional space (,) to enter more than one ID.', 'duracelltomi-google-tag-manager' ) );
725
- } else {
726
- $output[ $optionname ] = $newoptionvalue;
727
- }
728
- } elseif ( $optionname == GTM4WP_OPTION_INTEGRATE_GOOGLEOPTIMIZETIMEOUT ) {
729
- $output[ $optionname ] = (int) $newoptionvalue;
730
-
731
- } elseif ( $optionname == GTM4WP_OPTION_INTEGRATE_WCPRODPERIMPRESSION ) {
732
- $output[ $optionname ] = (int) $newoptionvalue;
733
-
734
- } elseif ( $optionname == GTM4WP_OPTION_INTEGRATE_WCREMPRODIDPREFIX ) {
735
- $output[ $optionname ] = trim( (string) $newoptionvalue );
736
-
737
- } else if ( $optionname == GTM4WP_OPTION_INTEGRATE_WCEECBRANDTAXONOMY ) {
738
- $output[$optionname] = trim( (string) $newoptionvalue );
739
-
740
- // Accelerated Mobile Pages settings
741
- } elseif ( $optionname == GTM4WP_OPTION_INTEGRATE_AMPID ) {
742
- $_ampid_val = trim( $newoptionvalue );
743
- if ( '' == $_ampid_val ) {
744
- $_ampid_list = array();
745
- } else {
746
- $_ampid_list = explode( ',', $_ampid_val );
747
- }
748
- $_ampid_haserror = false;
749
-
750
- foreach ( $_ampid_list as $one_amp_id ) {
751
- $_ampid_haserror = $_ampid_haserror || ! preg_match( '/^GTM-[A-Z0-9]+$/', $one_amp_id );
752
- }
753
-
754
- if ( $_ampid_haserror && ( count( $_ampid_list ) > 0 ) ) {
755
- add_settings_error( GTM4WP_ADMIN_GROUP, GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_INTEGRATE_AMPID . ']', __( 'Invalid AMP Google Tag Manager Container ID. Valid ID format: GTM-XXXXX. Use comma without additional space (,) to enter more than one ID.', 'duracelltomi-google-tag-manager' ) );
756
- } else {
757
- $output[ $optionname ] = $newoptionvalue;
758
- }
759
-
760
- // integrations
761
- } elseif ( substr( $optionname, 0, 10 ) == 'integrate-' ) {
762
- $output[ $optionname ] = (bool) $newoptionvalue;
763
-
764
- // GTM code or dataLayer variable name
765
- } elseif ( ( $optionname == GTM4WP_OPTION_GTM_CODE ) || ( $optionname == GTM4WP_OPTION_DATALAYER_NAME ) || ( $optionname == GTM4WP_OPTION_ENV_GTM_AUTH ) || ( $optionname == GTM4WP_OPTION_ENV_GTM_PREVIEW ) ) {
766
- $newoptionvalue = trim( $newoptionvalue );
767
-
768
- if ( $optionname == GTM4WP_OPTION_GTM_CODE ) {
769
- $_gtmid_list = explode( ',', $newoptionvalue );
770
- $_gtmid_haserror = false;
771
-
772
- foreach ( $_gtmid_list as $one_gtm_id ) {
773
- $_gtmid_haserror = $_gtmid_haserror || ! preg_match( '/^GTM-[A-Z0-9]+$/', $one_gtm_id );
774
- }
775
-
776
- if ( $_gtmid_haserror ) {
777
- add_settings_error( GTM4WP_ADMIN_GROUP, GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_CODE . ']', __( 'Invalid Google Tag Manager ID. Valid ID format: GTM-XXXXX. Use comma without additional space (,) to enter more than one container ID.', 'duracelltomi-google-tag-manager' ) );
778
- } else {
779
- $output[ $optionname ] = $newoptionvalue;
780
- }
781
- } elseif ( ( $optionname == GTM4WP_OPTION_DATALAYER_NAME ) && ( $newoptionvalue != '' ) && ( ! preg_match( '/^[a-zA-Z][a-zA-Z0-9_-]*$/', $newoptionvalue ) ) ) {
782
- add_settings_error( GTM4WP_ADMIN_GROUP, GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_DATALAYER_NAME . ']', __( "Invalid dataLayer variable name. Please start with a character from a-z or A-Z followed by characters from a-z, A-Z, 0-9 or '_' or '-'!", 'duracelltomi-google-tag-manager' ) );
783
-
784
- } elseif ( ( $optionname == GTM4WP_OPTION_ENV_GTM_AUTH ) && ( $newoptionvalue != '' ) && ( ! preg_match( '/^[a-zA-Z0-9-_]+$/', $newoptionvalue ) ) ) {
785
- add_settings_error( GTM4WP_ADMIN_GROUP, GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_ENV_GTM_AUTH . ']', __( "Invalid gtm_auth environment parameter value. It should only contain letters, numbers or the '-' and '_' characters.", 'duracelltomi-google-tag-manager' ) );
786
-
787
- } elseif ( ( $optionname == GTM4WP_OPTION_ENV_GTM_PREVIEW ) && ( $newoptionvalue != '' ) && ( ! preg_match( '/^env-[0-9]+$/', $newoptionvalue ) ) ) {
788
- add_settings_error( GTM4WP_ADMIN_GROUP, GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_ENV_GTM_PREVIEW . ']', __( "Invalid gtm_preview environment parameter value. It should have the format 'env-NN' where NN is an integer number.", 'duracelltomi-google-tag-manager' ) );
789
-
790
- } else {
791
- $output[ $optionname ] = $newoptionvalue;
792
- }
793
-
794
- // GTM container code placement
795
- } elseif ( $optionname == GTM4WP_OPTION_GTM_PLACEMENT ) {
796
- $output[ $optionname ] = (int) $newoptionvalue;
797
- if ( ( $output[ $optionname ] < 0 ) || ( $output[ $optionname ] > 3 ) ) {
798
- $output[ $optionname ] = 0;
799
- }
800
-
801
- // scroll tracking content ID
802
- } elseif ( $optionname == GTM4WP_OPTION_SCROLLER_CONTENTID ) {
803
- $output[ $optionname ] = trim( str_replace( '#', '', $newoptionvalue ) );
804
-
805
- // anything else
806
- } else {
807
- switch ( gettype( $optionvalue ) ) {
808
- case 'boolean': {
809
- $output[ $optionname ] = (bool) $newoptionvalue;
810
-
811
- break;
812
- }
813
-
814
- case 'integer': {
815
- $output[ $optionname ] = (int) $newoptionvalue;
816
-
817
- break;
818
- }
819
-
820
- default: {
821
- $output[ $optionname ] = $newoptionvalue;
822
- }
823
- } // end switch
824
- }
825
- }
826
-
827
- return $output;
828
- }
829
-
830
- function gtm4wp_admin_init() {
831
- global $gtm4wp_includefieldtexts, $gtm4wp_eventfieldtexts, $gtm4wp_integratefieldtexts, $gtm4wp_scrollerfieldtexts,
832
- $gtm4wp_advancedfieldtexts, $gtm4wp_entity_ids;
833
-
834
- register_setting( GTM4WP_ADMIN_GROUP, GTM4WP_OPTIONS, 'gtm4wp_sanitize_options' );
835
-
836
- add_settings_section(
837
- GTM4WP_ADMIN_GROUP_GENERAL,
838
- __( 'General', 'duracelltomi-google-tag-manager' ),
839
- 'gtm4wp_admin_output_section',
840
- GTM4WP_ADMINSLUG
841
- );
842
-
843
- add_settings_field(
844
- GTM4WP_ADMIN_GROUP_GTMID,
845
- __( 'Google Tag Manager ID', 'duracelltomi-google-tag-manager' ),
846
- 'gtm4wp_admin_output_field',
847
- GTM4WP_ADMINSLUG,
848
- GTM4WP_ADMIN_GROUP_GENERAL,
849
- array(
850
- 'label_for' => GTM4WP_ADMIN_GROUP_GTMID,
851
- 'description' => __( 'Enter your Google Tag Manager ID here. Use comma without space (,) to enter multiple IDs.', 'duracelltomi-google-tag-manager' ),
852
- )
853
- );
854
-
855
- add_settings_field(
856
- GTM4WP_ADMIN_GROUP_PLACEMENT,
857
- __( 'Container code <code>&lt;noscript&gt;</code> part placement', 'duracelltomi-google-tag-manager' ),
858
- 'gtm4wp_admin_output_field',
859
- GTM4WP_ADMINSLUG,
860
- GTM4WP_ADMIN_GROUP_GENERAL,
861
- array(
862
- 'label_for' => GTM4WP_ADMIN_GROUP_PLACEMENT,
863
- 'description' => __( "Code placement decides where to put the second, so called noscript part of the GTM container code.<br />This code is usually only executed if your visitor has for some reason disabled JavaScript.<br/>The main GTM container code will be placed into the <code>&lt;head&gt;</code> section of your webpages anyway (where it belongs to).<br />If you select 'Custom' you need to edit your template file and add the following line just after the opening <code>&lt;body&gt;</code> tag:<br /><code>&lt;?php if ( function_exists( 'gtm4wp_the_gtm_tag' ) ) { gtm4wp_the_gtm_tag(); } ?&gt;</code>", 'duracelltomi-google-tag-manager' ),
864
- )
865
- );
866
-
867
- add_settings_section(
868
- GTM4WP_ADMIN_GROUP_INCLUDES,
869
- __( 'Basic data', 'duracelltomi-google-tag-manager' ),
870
- 'gtm4wp_admin_output_section',
871
- GTM4WP_ADMINSLUG
872
- );
873
-
874
- foreach ( $gtm4wp_includefieldtexts as $fieldid => $fielddata ) {
875
- $phase = isset( $fielddata['phase'] ) ? $fielddata['phase'] : GTM4WP_PHASE_STABLE;
876
-
877
- add_settings_field(
878
- 'gtm4wp-admin-' . $fieldid . '-id',
879
- $fielddata['label'] . '<span class="' . $phase . '"></span>',
880
- 'gtm4wp_admin_output_field',
881
- GTM4WP_ADMINSLUG,
882
- GTM4WP_ADMIN_GROUP_INCLUDES,
883
- array(
884
- 'label_for' => 'gtm4wp-options[' . $fieldid . ']',
885
- 'description' => $fielddata['description'],
886
- 'optionfieldid' => $fieldid,
887
- )
888
- );
889
- }
890
-
891
- add_settings_section(
892
- GTM4WP_ADMIN_GROUP_EVENTS,
893
- __( 'Events', 'duracelltomi-google-tag-manager' ),
894
- 'gtm4wp_admin_output_section',
895
- GTM4WP_ADMINSLUG
896
- );
897
-
898
- foreach ( $gtm4wp_eventfieldtexts as $fieldid => $fielddata ) {
899
- $phase = isset( $fielddata['phase'] ) ? $fielddata['phase'] : GTM4WP_PHASE_STABLE;
900
-
901
- add_settings_field(
902
- 'gtm4wp-admin-' . $fieldid . '-id',
903
- $fielddata['label'] . '<span class="' . $phase . '"></span>',
904
- 'gtm4wp_admin_output_field',
905
- GTM4WP_ADMINSLUG,
906
- GTM4WP_ADMIN_GROUP_EVENTS,
907
- array(
908
- 'label_for' => 'gtm4wp-options[' . $fieldid . ']',
909
- 'description' => $fielddata['description'],
910
- 'optionfieldid' => $fieldid,
911
- )
912
- );
913
- }
914
-
915
- add_settings_section(
916
- GTM4WP_ADMIN_GROUP_SCROLLER,
917
- __( 'Scroll tracking', 'duracelltomi-google-tag-manager' ),
918
- 'gtm4wp_admin_output_section',
919
- GTM4WP_ADMINSLUG
920
- );
921
-
922
- foreach ( $gtm4wp_scrollerfieldtexts as $fieldid => $fielddata ) {
923
- $phase = isset( $fielddata['phase'] ) ? $fielddata['phase'] : GTM4WP_PHASE_STABLE;
924
-
925
- add_settings_field(
926
- 'gtm4wp-admin-' . $fieldid . '-id',
927
- $fielddata['label'] . '<span class="' . $phase . '"></span>',
928
- 'gtm4wp_admin_output_field',
929
- GTM4WP_ADMINSLUG,
930
- GTM4WP_ADMIN_GROUP_SCROLLER,
931
- array(
932
- 'label_for' => 'gtm4wp-options[' . $fieldid . ']',
933
- 'description' => $fielddata['description'],
934
- 'optionfieldid' => $fieldid,
935
- )
936
- );
937
- }
938
-
939
- add_settings_section(
940
- GTM4WP_ADMIN_GROUP_BLACKLIST,
941
- __( 'Security', 'duracelltomi-google-tag-manager' ),
942
- 'gtm4wp_admin_output_section',
943
- GTM4WP_ADMINSLUG
944
- );
945
-
946
- add_settings_field(
947
- GTM4WP_OPTION_BLACKLIST_ENABLE,
948
- __( 'Enable blacklist/whitelist', 'duracelltomi-google-tag-manager' ),
949
- 'gtm4wp_admin_output_field',
950
- GTM4WP_ADMINSLUG,
951
- GTM4WP_ADMIN_GROUP_BLACKLIST,
952
- array(
953
- 'label_for' => GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_BLACKLIST_ENABLE . ']',
954
- 'description' => '',
955
- 'optionsfieldid' => GTM4WP_OPTION_BLACKLIST_ENABLE
956
- )
957
- );
958
-
959
- add_settings_field(
960
- GTM4WP_OPTION_BLACKLIST_SANDBOXED,
961
- __( 'Custom tag/variable templates', 'duracelltomi-google-tag-manager' ),
962
- 'gtm4wp_admin_output_field',
963
- GTM4WP_ADMINSLUG,
964
- GTM4WP_ADMIN_GROUP_BLACKLIST,
965
- array(
966
- 'label_for' => GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_BLACKLIST_SANDBOXED . ']',
967
- 'description' => '',
968
- 'entityid' => GTM4WP_OPTION_BLACKLIST_SANDBOXED
969
- )
970
- );
971
-
972
- foreach( $gtm4wp_entity_ids as $gtm_entity_group_id => $gtm_entity_group_list ) {
973
- foreach( $gtm_entity_group_list as $gtm_entity_id => $gtm_entity_label ) {
974
- add_settings_field(
975
- 'gtm4wp-admin-blacklist-' . $gtm_entity_group_id . '-' . $gtm_entity_id . '-id',
976
- $gtm_entity_label,
977
- 'gtm4wp_admin_output_field',
978
- GTM4WP_ADMINSLUG,
979
- GTM4WP_ADMIN_GROUP_BLACKLIST,
980
- array(
981
- 'label_for' => 'gtm4wp-options[blacklist-' . $gtm_entity_group_id . '-' . $gtm_entity_id . ']',
982
- 'description' => '',
983
- 'entityid' => $gtm_entity_id,
984
- )
985
- );
986
- }
987
- }
988
-
989
- add_settings_section(
990
- GTM4WP_ADMIN_GROUP_INTEGRATION,
991
- __( 'Integration', 'duracelltomi-google-tag-manager' ),
992
- 'gtm4wp_admin_output_section',
993
- GTM4WP_ADMINSLUG
994
- );
995
-
996
- foreach ( $gtm4wp_integratefieldtexts as $fieldid => $fielddata ) {
997
- $phase = isset( $fielddata['phase'] ) ? $fielddata['phase'] : GTM4WP_PHASE_STABLE;
998
-
999
- add_settings_field(
1000
- 'gtm4wp-admin-' . $fieldid . '-id',
1001
- $fielddata['label'] . '<span class="' . $phase . '"></span>',
1002
- 'gtm4wp_admin_output_field',
1003
- GTM4WP_ADMINSLUG,
1004
- GTM4WP_ADMIN_GROUP_INTEGRATION,
1005
- array(
1006
- 'label_for' => 'gtm4wp-options[' . $fieldid . ']',
1007
- 'description' => $fielddata['description'],
1008
- 'optionfieldid' => $fieldid,
1009
- 'plugintocheck' => isset( $fielddata['plugintocheck'] ) ? $fielddata['plugintocheck'] : '',
1010
- )
1011
- );
1012
- }
1013
-
1014
- add_settings_section(
1015
- GTM4WP_ADMIN_GROUP_ADVANCED,
1016
- __( 'Advanced', 'duracelltomi-google-tag-manager' ),
1017
- 'gtm4wp_admin_output_section',
1018
- GTM4WP_ADMINSLUG
1019
- );
1020
-
1021
- foreach ( $gtm4wp_advancedfieldtexts as $fieldid => $fielddata ) {
1022
- $phase = isset( $fielddata['phase'] ) ? $fielddata['phase'] : GTM4WP_PHASE_STABLE;
1023
-
1024
- add_settings_field(
1025
- 'gtm4wp-admin-' . $fieldid . '-id',
1026
- $fielddata['label'] . '<span class="' . $phase . '"></span>',
1027
- 'gtm4wp_admin_output_field',
1028
- GTM4WP_ADMINSLUG,
1029
- GTM4WP_ADMIN_GROUP_ADVANCED,
1030
- array(
1031
- 'label_for' => 'gtm4wp-options[' . $fieldid . ']',
1032
- 'description' => $fielddata['description'],
1033
- 'optionfieldid' => $fieldid,
1034
- 'plugintocheck' => isset( $fielddata['plugintocheck'] ) ? $fielddata['plugintocheck'] : '',
1035
- )
1036
- );
1037
- }
1038
-
1039
- add_settings_section(
1040
- GTM4WP_ADMIN_GROUP_CREDITS,
1041
- __( 'Credits', 'duracelltomi-google-tag-manager' ),
1042
- 'gtm4wp_admin_output_section',
1043
- GTM4WP_ADMINSLUG
1044
- );
1045
-
1046
- add_settings_field(
1047
- GTM4WP_ADMIN_GROUP_INFO,
1048
- __( 'Author', 'duracelltomi-google-tag-manager' ),
1049
- 'gtm4wp_admin_output_field',
1050
- GTM4WP_ADMINSLUG,
1051
- GTM4WP_ADMIN_GROUP_CREDITS,
1052
- array(
1053
- 'label_for' => GTM4WP_ADMIN_GROUP_INFO,
1054
- 'description' => '<strong>Thomas Geiger</strong><br />
1055
- Website: <a href="https://gtm4wp.com/" target="_blank">gtm4wp.com</a><br />
1056
- <a href="https://www.linkedin.com/in/duracelltomi" target="_blank">Me on LinkedIn</a><br />
1057
- <a href="http://www.linkedin.com/company/jabjab-online-marketing-ltd" target="_blank">JabJab Online Marketing on LinkedIn</a>',
1058
- )
1059
- );
1060
-
1061
- // apply oembed code changes on the admin as well since the oembed call on the admin is cached by WordPress into a transient
1062
- // that is applied on the frontend later
1063
- require_once dirname( __FILE__ ) . '/../integration/youtube.php';
1064
- require_once dirname( __FILE__ ) . '/../integration/vimeo.php';
1065
- require_once dirname( __FILE__ ) . '/../integration/soundcloud.php';
1066
- }
1067
-
1068
- function gtm4wp_show_admin_page() {
1069
- global $gtp4wp_plugin_url;
1070
- ?>
1071
- <div class="wrap">
1072
- <div id="gtm4wp-icon" class="icon32" style="background-image: url(<?php echo $gtp4wp_plugin_url; ?>admin/images/tag_manager-32.png);"><br /></div>
1073
- <h2><?php _e( 'Google Tag Manager for WordPress options', 'duracelltomi-google-tag-manager' ); ?></h2>
1074
- <form action="options.php" method="post">
1075
- <?php settings_fields( GTM4WP_ADMIN_GROUP ); ?>
1076
- <?php do_settings_sections( GTM4WP_ADMINSLUG ); ?>
1077
- <?php submit_button(); ?>
1078
-
1079
- </form>
1080
- </div>
1081
- <?php
1082
- }
1083
-
1084
- function gtm4wp_add_admin_page() {
1085
- add_options_page(
1086
- __( 'Google Tag Manager for WordPress settings', 'duracelltomi-google-tag-manager' ),
1087
- __( 'Google Tag Manager', 'duracelltomi-google-tag-manager' ),
1088
- 'manage_options',
1089
- GTM4WP_ADMINSLUG,
1090
- 'gtm4wp_show_admin_page'
1091
- );
1092
- }
1093
-
1094
- function gtm4wp_add_admin_js( $hook ) {
1095
- global $gtp4wp_plugin_url;
1096
-
1097
- if ( $hook == 'settings_page_' . GTM4WP_ADMINSLUG ) {
1098
- wp_register_script( 'admin-subtabs', $gtp4wp_plugin_url . 'js/admin-subtabs.js', array(), GTM4WP_VERSION );
1099
-
1100
- $subtabtexts = array(
1101
- 'posttabtitle' => __( 'Posts', 'duracelltomi-google-tag-manager' ),
1102
- 'searchtabtitle' => __( 'Search', 'duracelltomi-google-tag-manager' ),
1103
- 'visitortabtitle' => __( 'Visitors', 'duracelltomi-google-tag-manager' ),
1104
- 'adwordstabtitle' => __( 'Google Ads', 'duracelltomi-google-tag-manager' ),
1105
- 'browsertabtitle' => __( 'Browser/OS/Device', 'duracelltomi-google-tag-manager' ),
1106
- 'blocktagstabtitle' => __( 'Blacklist tags', 'duracelltomi-google-tag-manager' ),
1107
- 'blocktriggerstabtitle' => __( 'Blacklist triggers', 'duracelltomi-google-tag-manager' ),
1108
- 'blockmacrostabtitle' => __( 'Blacklist variables', 'duracelltomi-google-tag-manager' ),
1109
- 'wpcf7tabtitle' => __( 'Contact Form 7', 'duracelltomi-google-tag-manager' ),
1110
- 'wctabtitle' => __( 'WooCommerce', 'duracelltomi-google-tag-manager' ),
1111
- 'gotabtitle' => __( 'Google Optimize', 'duracelltomi-google-tag-manager' ),
1112
- 'amptabtitle' => __( 'Accelerated Mobile Pages', 'duracelltomi-google-tag-manager' ),
1113
- 'weathertabtitle' => __( 'Weather & geo data', 'duracelltomi-google-tag-manager' ),
1114
- 'generaleventstabtitle' => __( 'General events', 'duracelltomi-google-tag-manager' ),
1115
- 'mediaeventstabtitle' => __( 'Media events', 'duracelltomi-google-tag-manager' ),
1116
- 'depecratedeventstabtitle' => __( 'Deprecated', 'duracelltomi-google-tag-manager' ),
1117
- 'sitetabtitle' => __( 'Site', 'duracelltomi-google-tag-manager' ),
1118
- 'misctabtitle' => __( 'Misc', 'duracelltomi-google-tag-manager' ),
1119
- );
1120
- wp_localize_script( 'admin-subtabs', 'gtm4wp', $subtabtexts );
1121
-
1122
- wp_enqueue_script( 'admin-subtabs' );
1123
- wp_enqueue_script( 'admin-tabcreator', $gtp4wp_plugin_url . 'js/admin-tabcreator.js', array( 'jquery-core' ), GTM4WP_VERSION );
1124
-
1125
- wp_enqueue_style( 'gtm4wp-validate', $gtp4wp_plugin_url . 'css/admin-gtm4wp.css', array(), GTM4WP_VERSION );
1126
- }
1127
- }
1128
-
1129
- function gtm4wp_admin_head() {
1130
- echo '
1131
- <style type="text/css">
1132
- .gtmid_validation_error,
1133
- .goid_validation_error,
1134
- .goid_ga_validation_error,
1135
- .ampid_validation_error,
1136
- .datalayername_validation_error,
1137
- .gtmauth_validation_error,
1138
- .gtmpreview_validation_error,
1139
- .gtm_wpconfig_set {
1140
- color: #c00;
1141
- font-weight: bold;
1142
- }
1143
- .gtmid_validation_error,
1144
- .goid_validation_error,
1145
- .goid_ga_validation_error,
1146
- .ampid_validation_error,
1147
- .datalayername_validation_error,
1148
- .gtmauth_validation_error,
1149
- .gtmpreview_validation_error {
1150
- display: none;
1151
- }
1152
- </style>
1153
- <script type="text/javascript">
1154
- jQuery(function() {
1155
- jQuery( "#gtm4wp-options\\\\[gtm-code\\\\]" )
1156
- .bind( "blur", function() {
1157
- var gtmid_regex = /^GTM-[A-Z0-9]+$/;
1158
- var gtmid_list = jQuery( this ).val().trim().split( "," );
1159
-
1160
- var gtmid_haserror = false;
1161
- for( var i=0; i<gtmid_list.length; i++ ) {
1162
- gtmid_haserror = gtmid_haserror || !gtmid_regex.test( gtmid_list[ i ] );
1163
- }
1164
-
1165
- if ( gtmid_haserror ) {
1166
- jQuery( ".gtmid_validation_error" )
1167
- .show();
1168
- } else {
1169
- jQuery( ".gtmid_validation_error" )
1170
- .hide();
1171
- }
1172
- });
1173
-
1174
- jQuery( "#gtm4wp-options\\\\[integrate-google-optimize-idlist\\\\]" )
1175
- .bind( "blur", function() {
1176
- var goid_regex = /^(GTM|OPT)-[A-Z0-9]+$/;
1177
- var goid_val = jQuery( this ).val().trim();
1178
- if ( "" == goid_val ) {
1179
- goid_list = [];
1180
- } else {
1181
- var goid_list = goid_val.split( "," );
1182
- }
1183
-
1184
- var goid_haserror = false;
1185
- for( var i=0; i<goid_list.length; i++ ) {
1186
- goid_haserror = goid_haserror || !goid_regex.test( goid_list[ i ] );
1187
- }
1188
-
1189
- if ( goid_haserror && (goid_list.length > 0) ) {
1190
- jQuery( ".goid_validation_error" )
1191
- .show();
1192
- } else {
1193
- jQuery( ".goid_validation_error" )
1194
- .hide();
1195
- }
1196
- });
1197
-
1198
- jQuery( "#gtm4wp-options\\\\[integrate-google-optimize-gaid\\\\]" )
1199
- .bind( "blur", function() {
1200
- var gogaid_regex = /^UA-[0-9]+-[0-9]+$/;
1201
- var gogaid_val = jQuery( this ).val().trim();
1202
- if ( "" == gogaid_val ) {
1203
- gogaid_list = [];
1204
- } else {
1205
- var gogaid_list = gogaid_val.split( "," );
1206
- }
1207
-
1208
- var gogaid_haserror = false;
1209
- for( var i=0; i<gogaid_list.length; i++ ) {
1210
- gogaid_haserror = gogaid_haserror || !gogaid_regex.test( gogaid_list[ i ] );
1211
- }
1212
-
1213
- if ( gogaid_haserror && (gogaid_list.length > 0) ) {
1214
- jQuery( ".goid_ga_validation_error" )
1215
- .show();
1216
- } else {
1217
- jQuery( ".goid_ga_validation_error" )
1218
- .hide();
1219
- }
1220
- });
1221
-
1222
- jQuery( "#gtm4wp-options\\\\[integrate-amp-gtm\\\\]" )
1223
- .bind( "blur", function() {
1224
- var ampid_regex = /^GTM-[A-Z0-9]+$/;
1225
- var ampid_val = jQuery( this ).val().trim();
1226
- if ( "" == ampid_val ) {
1227
- ampid_list = [];
1228
- } else {
1229
- var ampid_list = ampid_val.split( "," );
1230
- }
1231
-
1232
- var ampid_haserror = false;
1233
- for( var i=0; i<ampid_list.length; i++ ) {
1234
- ampid_haserror = ampid_haserror || !ampid_regex.test( gogaid_list[ i ] );
1235
- }
1236
-
1237
- if ( ampid_haserror && (ampid_list.length > 0) ) {
1238
- jQuery( ".ampid_validation_error" )
1239
- .show();
1240
- } else {
1241
- jQuery( ".ampid_validation_error" )
1242
- .hide();
1243
- }
1244
- });
1245
-
1246
- jQuery( "#gtm4wp-options\\\\[gtm-datalayer-variable-name\\\\]" )
1247
- .bind( "blur", function() {
1248
- var currentval = jQuery( this ).val();
1249
-
1250
- jQuery( ".datalayername_validation_error" )
1251
- .hide();
1252
-
1253
- if ( currentval != "" ) {
1254
- // I know this is not the exact definition for a variable name but I think other kind of variable names should not be used.
1255
- var gtmvarname_regex = /^[a-zA-Z][a-zA-Z0-9_-]*$/;
1256
- if ( ! gtmvarname_regex.test( currentval ) ) {
1257
- jQuery( ".datalayername_validation_error" )
1258
- .show();
1259
- }
1260
- }
1261
- });
1262
-
1263
- jQuery( "#gtm4wp-options\\\\[gtm-env-gtm-auth\\\\]" )
1264
- .bind( "blur", function() {
1265
- var currentval = jQuery( this ).val();
1266
-
1267
- jQuery( ".gtmauth_validation_error" )
1268
- .hide();
1269
-
1270
- if ( currentval != "" ) {
1271
- var gtmauth_regex = /^[a-zA-Z0-9-_]+$/;
1272
- if ( ! gtmauth_regex.test( currentval ) ) {
1273
- jQuery( ".gtmauth_validation_error" )
1274
- .show();
1275
- }
1276
- }
1277
- });
1278
-
1279
- jQuery( "#gtm4wp-options\\\\[gtm-env-gtm-preview\\\\]" )
1280
- .bind( "blur", function() {
1281
- var currentval = jQuery( this ).val();
1282
-
1283
- jQuery( ".gtmpreview_validation_error" )
1284
- .hide();
1285
-
1286
- if ( currentval != "" ) {
1287
- var gtmpreview_regex = /^env-[0-9]+$/;
1288
- if ( ! gtmpreview_regex.test( currentval ) ) {
1289
- jQuery( ".gtmpreview_validation_error" )
1290
- .show();
1291
- }
1292
- }
1293
- });
1294
-
1295
- jQuery( document )
1296
- .on( "click", ".gtm4wp-notice .notice-dismiss", function( e ) {
1297
- jQuery.post(ajaxurl, {
1298
- action: "gtm4wp_dismiss_notice",
1299
- noticeid: jQuery( this ).closest(".gtm4wp-notice")
1300
- .attr( "data-href" )
1301
- .substring( 1 )
1302
- });
1303
- });
1304
- });
1305
- </script>';
1306
- }
1307
-
1308
- function gtm4wp_show_warning() {
1309
- global $gtm4wp_options, $gtp4wp_plugin_url, $gtm4wp_integratefieldtexts, $current_user,
1310
- $gtm4wp_def_user_notices_dismisses;
1311
-
1312
- $woo_plugin_active = is_plugin_active( $gtm4wp_integratefieldtexts[ GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC ]['plugintocheck'] );
1313
- if ( $woo_plugin_active && function_exists( 'WC' ) ) {
1314
- $woo = WC();
1315
- } else {
1316
- $woo = null;
1317
- }
1318
-
1319
- $gtm4wp_user_notices_dismisses = get_user_meta( $current_user->ID, GTM4WP_USER_NOTICES_KEY, true );
1320
- if ( $gtm4wp_user_notices_dismisses === '' ) {
1321
- if ( is_array( $gtm4wp_def_user_notices_dismisses ) ) {
1322
- $gtm4wp_user_notices_dismisses = $gtm4wp_def_user_notices_dismisses;
1323
- } else {
1324
- $gtm4wp_user_notices_dismisses = array();
1325
- }
1326
- } else {
1327
- $gtm4wp_user_notices_dismisses = @unserialize( $gtm4wp_user_notices_dismisses );
1328
- if ( false === $gtm4wp_user_notices_dismisses || !is_array( $gtm4wp_user_notices_dismisses ) ) {
1329
- $gtm4wp_user_notices_dismisses = array();
1330
- }
1331
- }
1332
- $gtm4wp_user_notices_dismisses = array_merge( $gtm4wp_def_user_notices_dismisses, $gtm4wp_user_notices_dismisses );
1333
-
1334
- if ( ( trim( $gtm4wp_options[ GTM4WP_OPTION_GTM_CODE ] ) == '' ) && ( false === $gtm4wp_user_notices_dismisses['enter-gtm-code'] ) ) {
1335
- echo '<div class="gtm4wp-notice notice notice-error is-dismissible" data-href="?enter-gtm-code"><p><strong>' . sprintf( __( 'To start using Google Tag Manager for WordPress, please <a href="%s">enter your GTM ID</a>', 'duracelltomi-google-tag-manager' ), 'options-general.php?page=' . GTM4WP_ADMINSLUG ) . '</strong></p></div>';
1336
- }
1337
-
1338
- if ( (
1339
- ( '' != $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_AUTH ] ) && ( '' == $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_PREVIEW ] )
1340
- ) || (
1341
- ( '' == $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_AUTH ] ) && ( '' != $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_PREVIEW ] )
1342
- ) ) {
1343
- echo '<div class="gtm4wp-notice notice notice-error" data-href="?incomplete-gtm-env-config"><p><strong>' . sprintf( __( 'Incomplete Google Tag Manager environment configuration: either gtm_preview or gtm_auth parameter value is missing!', 'duracelltomi-google-tag-manager' ), 'options-general.php?page=' . GTM4WP_ADMINSLUG ) . '</strong></p></div>';
1344
- }
1345
-
1346
- if ( ( false === $gtm4wp_user_notices_dismisses['wc-ga-plugin-warning'] ) || ( false === $gtm4wp_user_notices_dismisses['wc-gayoast-plugin-warning'] ) ) {
1347
- $is_wc_active = $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC ] ||
1348
- $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ||
1349
- $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ];
1350
-
1351
- if ( ( false === $gtm4wp_user_notices_dismisses['wc-ga-plugin-warning'] ) && $is_wc_active && is_plugin_active( 'woocommerce-google-analytics-integration/woocommerce-google-analytics-integration.php' ) ) {
1352
- echo '<div class="gtm4wp-notice notice notice-warning is-dismissible" data-href="?wc-ga-plugin-warning"><p><strong>' . __( 'Notice: you should deactivate the plugin "WooCommerce Google Analytics Integration" if you are using Google Analytics tags inside Google Tag Manager!', 'duracelltomi-google-tag-manager' ) . '</strong></p></div>';
1353
- }
1354
-
1355
- if ( ( false === $gtm4wp_user_notices_dismisses['wc-gayoast-plugin-warning'] ) && $is_wc_active && is_plugin_active( 'google-analytics-for-wordpress/googleanalytics.php' ) ) {
1356
- echo '<div class="gtm4wp-notice notice notice-warning is-dismissible" data-href="?wc-gayoast-plugin-warning"><p><strong>' . __( 'Notice: you should deactivate the plugin "Google Analytics for WordPress by MonsterInsights" if you are using Google Analytics tags inside Google Tag Manager!', 'duracelltomi-google-tag-manager' ) . '</strong></p></div>';
1357
- }
1358
- }
1359
-
1360
- if ( ( false === $gtm4wp_user_notices_dismisses['php56-warning'] ) && ( version_compare( PHP_VERSION, '5.6.0' ) < 0 ) ) {
1361
- echo '<div class="gtm4wp-notice notice notice-warning is-dismissible" data-href="?php56-warning"><p><strong>' . __( 'Warning: You are using an outdated version of PHP (v' . PHP_VERSION . ') that can cause issues with the plugin Google Tag Manager for WordPress. Please consider to upgrade your PHP.', 'duracelltomi-google-tag-manager' ) . '</strong></p></div>';
1362
- }
1363
- }
1364
-
1365
- function gtm4wp_dismiss_notice() {
1366
- global $gtm4wp_def_user_notices_dismisses, $current_user;
1367
-
1368
- $gtm4wp_user_notices_dismisses = get_user_meta( $current_user->ID, GTM4WP_USER_NOTICES_KEY, true );
1369
- if ( $gtm4wp_user_notices_dismisses === '' ) {
1370
- if ( is_array( $gtm4wp_def_user_notices_dismisses ) ) {
1371
- $gtm4wp_user_notices_dismisses = $gtm4wp_def_user_notices_dismisses;
1372
- } else {
1373
- $gtm4wp_user_notices_dismisses = array();
1374
- }
1375
- } else {
1376
- $gtm4wp_user_notices_dismisses = @unserialize( $gtm4wp_user_notices_dismisses );
1377
- if ( false === $gtm4wp_user_notices_dismisses || !is_array( $gtm4wp_user_notices_dismisses ) ) {
1378
- $gtm4wp_user_notices_dismisses = array();
1379
- }
1380
- }
1381
- $gtm4wp_user_notices_dismisses = array_merge( $gtm4wp_def_user_notices_dismisses, $gtm4wp_user_notices_dismisses );
1382
-
1383
- $noticeid = trim( basename( $_POST['noticeid'] ) );
1384
- if ( array_key_exists( $noticeid, $gtm4wp_user_notices_dismisses ) ) {
1385
- $gtm4wp_user_notices_dismisses[ $noticeid ] = true;
1386
- update_user_meta( $current_user->ID, GTM4WP_USER_NOTICES_KEY, serialize( $gtm4wp_user_notices_dismisses ) );
1387
- }
1388
- }
1389
-
1390
- function gtm4wp_add_plugin_action_links( $links, $file ) {
1391
- global $gtp4wp_plugin_basename;
1392
-
1393
- if ( $file != $gtp4wp_plugin_basename ) {
1394
- return $links;
1395
- }
1396
-
1397
- $settings_link = '<a href="' . menu_page_url( GTM4WP_ADMINSLUG, false ) . '">' . esc_html( __( 'Settings' ) ) . '</a>';
1398
-
1399
- array_unshift( $links, $settings_link );
1400
-
1401
- return $links;
1402
- }
1403
-
1404
- function gtm4wp_show_upgrade_notification( $current_plugin_metadata, $new_plugin_metadata ) {
1405
- if ( isset( $new_plugin_metadata->upgrade_notice ) && strlen( trim( $new_plugin_metadata->upgrade_notice ) ) > 0 ) {
1406
- echo '<p style="background-color: #d54e21; padding: 10px; color: #f9f9f9; margin-top: 10px"><strong>Important Upgrade Notice:</strong> ';
1407
- echo esc_html( $new_plugin_metadata->upgrade_notice ), '</p>';
1408
- }
1409
- }
1410
-
1411
- add_action( 'admin_init', 'gtm4wp_admin_init' );
1412
- add_action( 'admin_menu', 'gtm4wp_add_admin_page' );
1413
- add_action( 'admin_enqueue_scripts', 'gtm4wp_add_admin_js' );
1414
- add_action( 'admin_notices', 'gtm4wp_show_warning' );
1415
- add_action( 'admin_head', 'gtm4wp_admin_head' );
1416
- add_filter( 'plugin_action_links', 'gtm4wp_add_plugin_action_links', 10, 2 );
1417
- add_action( 'wp_ajax_gtm4wp_dismiss_notice', 'gtm4wp_dismiss_notice' );
1418
- add_action( 'in_plugin_update_message-duracelltomi-google-tag-manager-for-wordpress/duracelltomi-google-tag-manager-for-wordpress.php', 'gtm4wp_show_upgrade_notification', 10, 2 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ define( 'GTM4WP_ADMINSLUG', 'gtm4wp-settings' );
3
+ define( 'GTM4WP_ADMIN_GROUP', 'gtm4wp-admin-group' );
4
+
5
+ define( 'GTM4WP_ADMIN_GROUP_GENERAL', 'gtm4wp-admin-group-general' );
6
+ define( 'GTM4WP_ADMIN_GROUP_GTMID', 'gtm4wp-admin-group-gtm-id' );
7
+ define( 'GTM4WP_ADMIN_GROUP_PLACEMENT', 'gtm4wp-admin-code-placement' );
8
+ define( 'GTM4WP_ADMIN_GROUP_INFO', 'gtm4wp-admin-group-datalayer-info' );
9
+
10
+ define( 'GTM4WP_ADMIN_GROUP_INCLUDES', 'gtm4wp-admin-group-includes' );
11
+ define( 'GTM4WP_ADMIN_GROUP_EVENTS', 'gtm4wp-admin-group-events' );
12
+ define( 'GTM4WP_ADMIN_GROUP_SCROLLER', 'gtm4wp-admin-group-scroller' );
13
+ define( 'GTM4WP_ADMIN_GROUP_BLACKLIST', 'gtm4wp-admin-group-blacklist-tags' );
14
+ define( 'GTM4WP_ADMIN_GROUP_INTEGRATION', 'gtm4wp-admin-group-integration' );
15
+ define( 'GTM4WP_ADMIN_GROUP_ADVANCED', 'gtm4wp-admin-group-advanced' );
16
+ define( 'GTM4WP_ADMIN_GROUP_CREDITS', 'gtm4wp-admin-group-credits' );
17
+
18
+ define( 'GTM4WP_USER_NOTICES_KEY', 'gtm4wp_user_notices_dismisses' );
19
+
20
+ define( 'GTM4WP_PHASE_STABLE', 'gtm4wp-phase-stable' );
21
+ define( 'GTM4WP_PHASE_BETA', 'gtm4wp-phase-beta' );
22
+ define( 'GTM4WP_PHASE_EXPERIMENTAL', 'gtm4wp-phase-experimental' );
23
+ define( 'GTM4WP_PHASE_DEPRECATED', 'gtm4wp-phase-deprecated' );
24
+
25
+ $GLOBALS['gtm4wp_def_user_notices_dismisses'] = array(
26
+ 'enter-gtm-code' => false,
27
+ 'wc-ga-plugin-warning' => false,
28
+ 'wc-gayoast-plugin-warning' => false,
29
+ 'php72-warning' => false,
30
+ 'deprecated-warning' => false,
31
+ );
32
+
33
+ $GLOBALS['gtm4wp_includefieldtexts'] = array(
34
+ GTM4WP_OPTION_INCLUDE_POSTTYPE => array(
35
+ 'label' => __( 'Posttype of current post/archive', 'duracelltomi-google-tag-manager' ),
36
+ 'description' => __( 'Check this option to include the type of the current post or archive page (post, page or any custom post type).', 'duracelltomi-google-tag-manager' ),
37
+ 'phase' => GTM4WP_PHASE_STABLE,
38
+ ),
39
+ GTM4WP_OPTION_INCLUDE_CATEGORIES => array(
40
+ 'label' => __( 'Category list of current post/archive', 'duracelltomi-google-tag-manager' ),
41
+ 'description' => __( 'Check this option to include the category names of the current post or archive page', 'duracelltomi-google-tag-manager' ),
42
+ 'phase' => GTM4WP_PHASE_STABLE,
43
+ ),
44
+ GTM4WP_OPTION_INCLUDE_TAGS => array(
45
+ 'label' => __( 'Tags of current post', 'duracelltomi-google-tag-manager' ),
46
+ 'description' => __( 'Check this option to include the tags of the current post.', 'duracelltomi-google-tag-manager' ),
47
+ 'phase' => GTM4WP_PHASE_STABLE,
48
+ ),
49
+ GTM4WP_OPTION_INCLUDE_AUTHORID => array(
50
+ 'label' => __( 'Post author ID', 'duracelltomi-google-tag-manager' ),
51
+ 'description' => __( 'Check this option to include the ID of the author on the current post or author page.', 'duracelltomi-google-tag-manager' ),
52
+ 'phase' => GTM4WP_PHASE_STABLE,
53
+ ),
54
+ GTM4WP_OPTION_INCLUDE_AUTHOR => array(
55
+ 'label' => __( 'Post author name', 'duracelltomi-google-tag-manager' ),
56
+ 'description' => __( 'Check this option to include the name of the author on the current post or author page.', 'duracelltomi-google-tag-manager' ),
57
+ 'phase' => GTM4WP_PHASE_STABLE,
58
+ ),
59
+ GTM4WP_OPTION_INCLUDE_POSTDATE => array(
60
+ 'label' => __( 'Post date', 'duracelltomi-google-tag-manager' ),
61
+ 'description' => __( 'Check this option to include the date of the current post. This will include 4 dataLayer variables: full date, post year, post month, post date.', 'duracelltomi-google-tag-manager' ),
62
+ 'phase' => GTM4WP_PHASE_STABLE,
63
+ ),
64
+ GTM4WP_OPTION_INCLUDE_POSTTITLE => array(
65
+ 'label' => __( 'Post title', 'duracelltomi-google-tag-manager' ),
66
+ 'description' => __( 'Check this option to include the title of the current post.', 'duracelltomi-google-tag-manager' ),
67
+ 'phase' => GTM4WP_PHASE_STABLE,
68
+ ),
69
+ GTM4WP_OPTION_INCLUDE_POSTCOUNT => array(
70
+ 'label' => __( 'Post count', 'duracelltomi-google-tag-manager' ),
71
+ 'description' => __( 'Check this option to include the count of the posts currently shown on the page and the total number of posts in the category/tag/any taxonomy.', 'duracelltomi-google-tag-manager' ),
72
+ 'phase' => GTM4WP_PHASE_STABLE,
73
+ ),
74
+ GTM4WP_OPTION_INCLUDE_POSTID => array(
75
+ 'label' => __( 'Post ID', 'duracelltomi-google-tag-manager' ),
76
+ 'description' => __( 'Check this option to include the post id.', 'duracelltomi-google-tag-manager' ),
77
+ 'phase' => GTM4WP_PHASE_STABLE,
78
+ ),
79
+ GTM4WP_OPTION_INCLUDE_POSTFORMAT => array(
80
+ 'label' => __( 'Post Format', 'duracelltomi-google-tag-manager' ),
81
+ 'description' => __( 'Check this option to include the post format.', 'duracelltomi-google-tag-manager' ),
82
+ 'phase' => GTM4WP_PHASE_STABLE,
83
+ ),
84
+ GTM4WP_OPTION_INCLUDE_POSTTERMLIST => array(
85
+ "label" => __( "Post Terms", 'duracelltomi-google-tag-manager' ),
86
+ "description" => __( "Check this option to include taxonomy values associated with a given post.", 'duracelltomi-google-tag-manager' ),
87
+ "phase" => GTM4WP_PHASE_STABLE
88
+ ),
89
+ GTM4WP_OPTION_INCLUDE_SEARCHDATA => array(
90
+ 'label' => __( 'Search data', 'duracelltomi-google-tag-manager' ),
91
+ 'description' => __( 'Check this option to include the search term, referring page URL and number of results on the search page.', 'duracelltomi-google-tag-manager' ),
92
+ 'phase' => GTM4WP_PHASE_STABLE,
93
+ ),
94
+ GTM4WP_OPTION_INCLUDE_LOGGEDIN => array(
95
+ 'label' => __( 'Logged in status', 'duracelltomi-google-tag-manager' ),
96
+ 'description' => __( 'Check this option to include whether there is a logged in user on your website.', 'duracelltomi-google-tag-manager' ),
97
+ 'phase' => GTM4WP_PHASE_STABLE,
98
+ ),
99
+ GTM4WP_OPTION_INCLUDE_USERROLE => array(
100
+ 'label' => __( 'Logged in user role', 'duracelltomi-google-tag-manager' ),
101
+ 'description' => __( 'Check this option to include the role of the logged in user.', 'duracelltomi-google-tag-manager' ),
102
+ 'phase' => GTM4WP_PHASE_STABLE,
103
+ ),
104
+ GTM4WP_OPTION_INCLUDE_USERID => array(
105
+ 'label' => __( 'Logged in user ID', 'duracelltomi-google-tag-manager' ),
106
+ 'description' => __( 'Check this option to include the ID of the logged in user.', 'duracelltomi-google-tag-manager' ),
107
+ 'phase' => GTM4WP_PHASE_STABLE,
108
+ ),
109
+ GTM4WP_OPTION_INCLUDE_USERNAME => array(
110
+ 'label' => __( 'Logged in user name', 'duracelltomi-google-tag-manager' ),
111
+ 'description' => __( 'Check this option to include the username of the logged in user.', 'duracelltomi-google-tag-manager' ),
112
+ 'phase' => GTM4WP_PHASE_STABLE,
113
+ ),
114
+ GTM4WP_OPTION_INCLUDE_USEREMAIL => array(
115
+ 'label' => __( 'Logged in user email', 'duracelltomi-google-tag-manager' ),
116
+ 'description' => __( 'Check this option to include the email address of the logged in user.', 'duracelltomi-google-tag-manager' ),
117
+ 'phase' => GTM4WP_PHASE_STABLE,
118
+ ),
119
+ GTM4WP_OPTION_INCLUDE_USERREGDATE => array(
120
+ 'label' => __( 'Logged in user creation date', 'duracelltomi-google-tag-manager' ),
121
+ 'description' => __( 'Check this option to include the date of creation (registration) of the logged in user.', 'duracelltomi-google-tag-manager' ),
122
+ 'phase' => GTM4WP_PHASE_STABLE,
123
+ ),
124
+ GTM4WP_OPTION_INCLUDE_VISITOR_IP => array(
125
+ 'label' => __( 'Visitor IP', 'duracelltomi-google-tag-manager' ),
126
+ 'description' => __( 'Check this option to include the IP address of the visitor. You might use this to filter internal traffic inside your GTM container. Please be aware that per GDPR its not allowed to transmit this full IP address to Google Analytics or to any other measurement system without explicit consent from the visitor.', 'duracelltomi-google-tag-manager' ),
127
+ 'phase' => GTM4WP_PHASE_STABLE,
128
+ ),
129
+ GTM4WP_OPTION_INCLUDE_REMARKETING => array(
130
+ 'label' => __( 'Remarketing variable', 'duracelltomi-google-tag-manager' ),
131
+ 'description' => __( 'Check this option to include a dataLayer variable where all dataLayer values are stored to be included in your Google Ads remarketing tag as a custom variable field', 'duracelltomi-google-tag-manager' ),
132
+ 'phase' => GTM4WP_PHASE_DEPRECATED,
133
+ ),
134
+ GTM4WP_OPTION_INCLUDE_BROWSERDATA => array(
135
+ 'label' => __( 'Browser data *', 'duracelltomi-google-tag-manager' ),
136
+ 'description' => __( 'Check this option to include the name, version and engine data of the browser the visitor uses.', 'duracelltomi-google-tag-manager' )
137
+ ),
138
+ GTM4WP_OPTION_INCLUDE_OSDATA => array(
139
+ 'label' => __( 'OS data *', 'duracelltomi-google-tag-manager' ),
140
+ 'description' => __( 'Check this option to include the name and version of the operating system the visitor uses.', 'duracelltomi-google-tag-manager' )
141
+ ),
142
+ GTM4WP_OPTION_INCLUDE_DEVICEDATA => array(
143
+ 'label' => __( 'Device data *', 'duracelltomi-google-tag-manager' ),
144
+ 'description' => __( 'Check this option to include the type of device the user is currently using (desktop, tablet or mobile) including manufacturer and model data.', 'duracelltomi-google-tag-manager' )
145
+ ),
146
+ GTM4WP_OPTION_INCLUDE_MISCGEO => array(
147
+ 'label' => __( 'Geo data', 'duracelltomi-google-tag-manager' ),
148
+ 'description' => __( 'Add geo data (latitude, longitude, country, city, etc) of the current visitor (provided by ipstack.com)', 'duracelltomi-google-tag-manager' ),
149
+ 'phase' => GTM4WP_PHASE_EXPERIMENTAL,
150
+ ),
151
+ GTM4WP_OPTION_INCLUDE_MISCGEOAPI => array(
152
+ 'label' => __( 'IPStack.com API key', 'duracelltomi-google-tag-manager' ),
153
+ 'description' => sprintf( __( 'Enter your IPStack.com API key here. <a href="%s" target="_blank">Get a free API key here</a>.', 'duracelltomi-google-tag-manager' ), 'https://ipstack.com/product?utm_source=gtm4wp&utm_medium=link&utm_campaign=gtm4wp-google-tag-manager-for-wordpress' ),
154
+ 'phase' => GTM4WP_PHASE_EXPERIMENTAL,
155
+ ),
156
+ GTM4WP_OPTION_INCLUDE_MISCGEOCF => array(
157
+ 'label' => __( 'Cloudflare country code', 'duracelltomi-google-tag-manager' ),
158
+ 'description' => __( 'Add the country code of the user provided by Cloudflare (if Cloudflare is used with your site)', 'duracelltomi-google-tag-manager' ),
159
+ 'phase' => GTM4WP_PHASE_EXPERIMENTAL,
160
+ ),
161
+ GTM4WP_OPTION_INCLUDE_WEATHER => array(
162
+ 'label' => __( 'Weather data', 'duracelltomi-google-tag-manager' ),
163
+ 'description' => sprintf(
164
+ __(
165
+ 'Check this option to include the current weather conditions around the current visitor.<br /><br />' .
166
+ '<strong>Attention!</strong> This feature uses <a href="%s" target="_blank">ipstack.com</a> and ' .
167
+ '<a href="%s" target="_blank">openweathermap.org</a> to collect data.<br />' .
168
+ "Depending on your website's traffic, additional fees may apply!<br />" .
169
+ 'This plugin caches weather data for 1 hour to lower the need to access those services.<br /><br />' .
170
+ 'If you activate weather data, <strong>you will need</strong> to add an IPStack.com API key regardless of whether you ' .
171
+ "activate the 'Geo data' option!",
172
+ 'duracelltomi-google-tag-manager'
173
+ ),
174
+ 'https://ipstack.com/product?utm_source=gtm4wp&utm_medium=link&utm_campaign=gtm4wp-google-tag-manager-for-wordpress',
175
+ 'http://openweathermap.org/price?utm_source=gtm4wp&utm_medium=link&utm_campaign=gtm4wp-google-tag-manager-for-wordpress'
176
+ ),
177
+ 'phase' => GTM4WP_PHASE_EXPERIMENTAL,
178
+ ),
179
+ GTM4WP_OPTION_INCLUDE_WEATHERUNITS => array(
180
+ 'label' => __( 'Weather data units', 'duracelltomi-google-tag-manager' ),
181
+ 'description' => __( 'Select which temperature units you would like to use.', 'duracelltomi-google-tag-manager' ),
182
+ 'phase' => GTM4WP_PHASE_EXPERIMENTAL,
183
+ ),
184
+ GTM4WP_OPTION_INCLUDE_WEATHEROWMAPI => array(
185
+ 'label' => __( 'OpenWeatherMap API key', 'duracelltomi-google-tag-manager' ),
186
+ 'description' => sprintf( __( 'Enter your OpenWeatherMap API key here. <a href="%s" target="_blank">Get a free API key here</a>.', 'duracelltomi-google-tag-manager' ), 'http://openweathermap.org/price?utm_source=gtm4wp&utm_medium=link&utm_campaign=gtm4wp-google-tag-manager-for-wordpress' ),
187
+ 'phase' => GTM4WP_PHASE_EXPERIMENTAL,
188
+ ),
189
+ GTM4WP_OPTION_INCLUDE_SITEID => array(
190
+ 'label' => __( 'Site ID', 'duracelltomi-google-tag-manager' ),
191
+ 'description' => __( 'ID of the current site in a WordPress Multisite environment', 'duracelltomi-google-tag-manager' ),
192
+ 'phase' => GTM4WP_PHASE_STABLE,
193
+ ),
194
+ GTM4WP_OPTION_INCLUDE_SITENAME => array(
195
+ 'label' => __( 'Site name', 'duracelltomi-google-tag-manager' ),
196
+ 'description' => __( 'Name of the current site in a WordPress Multisite environment', 'duracelltomi-google-tag-manager' ),
197
+ 'phase' => GTM4WP_PHASE_STABLE,
198
+ ),
199
+ );
200
+
201
+ $GLOBALS['gtm4wp_eventfieldtexts'] = array(
202
+ GTM4WP_OPTION_EVENTS_FORMMOVE => array(
203
+ 'label' => __( 'Form fill events (gtm4wp.formElementEnter & gtm4wp.formElementLeave)', 'duracelltomi-google-tag-manager' ),
204
+ 'description' => __( 'Check this option to include a Tag Manager event when a visitor moves between elements of a form (comment, contact, etc).', 'duracelltomi-google-tag-manager' ),
205
+ 'phase' => GTM4WP_PHASE_STABLE,
206
+ ),
207
+ GTM4WP_OPTION_EVENTS_NEWUSERREG => array(
208
+ 'label' => __( 'New user registration', 'duracelltomi-google-tag-manager' ),
209
+ 'description' => __( 'Check this option to include a Tag Manager event when a new user registration has been completed on the frontend of your site (admin events not included)', 'duracelltomi-google-tag-manager' ),
210
+ 'phase' => GTM4WP_PHASE_STABLE,
211
+ ),
212
+ GTM4WP_OPTION_EVENTS_USERLOGIN => array(
213
+ 'label' => __( 'User logged in', 'duracelltomi-google-tag-manager' ),
214
+ 'description' => __( 'Check this option to include a Tag Manager event when an existing user has been logged in on the frontend of your site (admin events not included)', 'duracelltomi-google-tag-manager' ),
215
+ 'phase' => GTM4WP_PHASE_STABLE,
216
+ ),
217
+ GTM4WP_OPTION_EVENTS_YOUTUBE => array(
218
+ 'label' => __( 'YouTube video events', 'duracelltomi-google-tag-manager' ),
219
+ 'description' => __( 'Check this option to include a Tag Manager event when a visitor interacts with a YouTube video embeded on your site.', 'duracelltomi-google-tag-manager' ),
220
+ 'phase' => GTM4WP_PHASE_EXPERIMENTAL,
221
+ ),
222
+ GTM4WP_OPTION_EVENTS_VIMEO => array(
223
+ 'label' => __( 'Vimeo video events', 'duracelltomi-google-tag-manager' ),
224
+ 'description' => __( 'Check this option to include a Tag Manager event when a visitor interacts with a Vimeo video embeded on your site.', 'duracelltomi-google-tag-manager' ),
225
+ 'phase' => GTM4WP_PHASE_EXPERIMENTAL,
226
+ ),
227
+ GTM4WP_OPTION_EVENTS_SOUNDCLOUD => array(
228
+ 'label' => __( 'Soundcloud events', 'duracelltomi-google-tag-manager' ),
229
+ 'description' => __( 'Check this option to include a Tag Manager event when a visitor interacts with a Soundcloud media embeded on your site.', 'duracelltomi-google-tag-manager' ),
230
+ 'phase' => GTM4WP_PHASE_EXPERIMENTAL,
231
+ )
232
+ );
233
+
234
+ $GLOBALS['gtm4wp_scrollerfieldtexts'] = array(
235
+ GTM4WP_OPTION_SCROLLER_ENABLED => array(
236
+ 'label' => __( 'Enabled', 'duracelltomi-google-tag-manager' ),
237
+ 'description' => __( 'Enable scroll tracker script on your website.', 'duracelltomi-google-tag-manager' ),
238
+ 'phase' => GTM4WP_PHASE_STABLE,
239
+ ),
240
+ GTM4WP_OPTION_SCROLLER_DEBUGMODE => array(
241
+ 'label' => __( 'Debug mode', 'duracelltomi-google-tag-manager' ),
242
+ 'description' => __( 'Fire console.log() commands instead of dataLayer events.', 'duracelltomi-google-tag-manager' ),
243
+ 'phase' => GTM4WP_PHASE_STABLE,
244
+ ),
245
+ GTM4WP_OPTION_SCROLLER_CALLBACKTIME => array(
246
+ 'label' => __( 'Time delay before location check', 'duracelltomi-google-tag-manager' ),
247
+ 'description' => __( 'Enter the number of milliseconds after the script checks the current location. It prevents too many events being fired while scrolling.', 'duracelltomi-google-tag-manager' ),
248
+ 'phase' => GTM4WP_PHASE_STABLE,
249
+ ),
250
+ GTM4WP_OPTION_SCROLLER_DISTANCE => array(
251
+ 'label' => __( 'Minimum distance', 'duracelltomi-google-tag-manager' ),
252
+ 'description' => __( 'The minimum amount of pixels that a visitor has to scroll before we treat the move as scrolling.', 'duracelltomi-google-tag-manager' ),
253
+ 'phase' => GTM4WP_PHASE_STABLE,
254
+ ),
255
+ GTM4WP_OPTION_SCROLLER_CONTENTID => array(
256
+ 'label' => __( 'Content ID', 'duracelltomi-google-tag-manager' ),
257
+ 'description' => __( 'Enter the DOM ID of the content element in your template. Leave it empty for default(content). Do not include the # sign.', 'duracelltomi-google-tag-manager' ),
258
+ 'phase' => GTM4WP_PHASE_STABLE,
259
+ ),
260
+ GTM4WP_OPTION_SCROLLER_READERTIME => array(
261
+ 'label' => __( 'Scroller time', 'duracelltomi-google-tag-manager' ),
262
+ 'description' => __( 'Enter the number of seconds after the the scroller user is being treated as a reader, someone who really reads the content, not just scrolls through it.', 'duracelltomi-google-tag-manager' ),
263
+ 'phase' => GTM4WP_PHASE_STABLE,
264
+ ),
265
+ );
266
+
267
+ $GLOBALS['gtm4wp_integratefieldtexts'] = array(
268
+ GTM4WP_OPTION_INTEGRATE_WPCF7 => array(
269
+ 'label' => __( 'Contact Form 7', 'duracelltomi-google-tag-manager' ),
270
+ 'description' => __( 'Check this to include a dataLayer event after a successfull form submission.', 'duracelltomi-google-tag-manager' ),
271
+ 'phase' => GTM4WP_PHASE_STABLE,
272
+ 'plugintocheck' => 'contact-form-7/wp-contact-form-7.php',
273
+ ),
274
+ GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC => array(
275
+ 'label' => __( 'Track classic e-commerce', 'duracelltomi-google-tag-manager' ),
276
+ 'description' => __( 'This feature is deprecated and will be removed soon! You should upgrade to enhanced ecommerce as soon as possible.', 'duracelltomi-google-tag-manager' ),
277
+ 'phase' => GTM4WP_PHASE_DEPRECATED
278
+ ),
279
+ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC => array(
280
+ 'label' => __( 'Track enhanced e-commerce', 'duracelltomi-google-tag-manager' ),
281
+ 'description' => sprintf(
282
+ __(
283
+ 'Choose this option if you would like to track e-commerce data using '.
284
+ '<a href="%s" target="_blank">enhanced ecommerce tracking</a>.<br>'.
285
+ 'Use the plugin\'s official guides to setup your Google Tag Manager container:<br>'.
286
+ '<ul><li><a href="%s" target="_blank">Google Analytics 3 / Universal Analytics setup</a></li>'.
287
+ '<li><a href="%s" target="_blank">Google Analytics 4 setup</a></li></ul>'
288
+ , 'duracelltomi-google-tag-manager' )
289
+ , 'https://developers.google.com/analytics/devguides/collection/analyticsjs/enhanced-ecommerce'
290
+ , 'https://gtm4wp.com/how-to-articles/how-to-setup-enhanced-ecommerce-tracking'
291
+ , 'https://gtm4wp.com/how-to-articles/how-to-setup-enhanced-ecommerce-tracking-google-analytics-4-ga4-version' ),
292
+ 'phase' => GTM4WP_PHASE_STABLE,
293
+ 'plugintocheck' => 'woocommerce/woocommerce.php',
294
+ ),
295
+ GTM4WP_OPTION_INTEGRATE_WCPRODPERIMPRESSION => array(
296
+ 'label' => __( 'Products per impression', 'duracelltomi-google-tag-manager' ),
297
+ 'description' => __(
298
+ 'If you have many products shown on product category pages and/or on your site home, you could miss pageviews in Google Analytics due to the ' .
299
+ 'amount of data that is needed to be sent. To prevent this, you can split product impression data into multiple Google Analytics events by ' .
300
+ 'entering a number here (minimum 10-15 recommended) and adding gtm4wp.productImpressionEEC into your Google Analytics ecommerce event helper ' .
301
+ "tag's trigger.<br /><br />Leave this value 0 to include product impression data in your pageview hit.",
302
+ 'duracelltomi-google-tag-manager'
303
+ ),
304
+ 'phase' => GTM4WP_PHASE_STABLE
305
+ ),
306
+ GTM4WP_OPTION_INTEGRATE_WCEECCARTASFIRSTSTEP => array(
307
+ 'label' => __( 'Cart as 1st checkout step', 'duracelltomi-google-tag-manager' ),
308
+ 'description' => __( 'Enable this to track the cart page as the first checkout step in enhanced ecommerce instead of the checkout page itself', 'duracelltomi-google-tag-manager' ),
309
+ 'phase' => GTM4WP_PHASE_STABLE
310
+ ),
311
+ GTM4WP_OPTION_INTEGRATE_WCEINCLUDECARTINDL => array(
312
+ "label" => __( "Cart content in data layer", 'duracelltomi-google-tag-manager' ),
313
+ "description" => __( "Enable this option to include the content of the cart in the data layer on each page. Needs WooCommerce v3.2 or newer. Especially useful for site personalization with Google Optimize.", 'duracelltomi-google-tag-manager' ),
314
+ "phase" => GTM4WP_PHASE_STABLE
315
+ ),
316
+ GTM4WP_OPTION_INTEGRATE_WCUSEFULLCATEGORYPATH => array(
317
+ 'label' => __( 'Include full category path.', 'duracelltomi-google-tag-manager' ),
318
+ 'description' => __( 'Check this to inclulde the full category path of each product in enhanced ecommerce tracking. WARNING! This can lead to performance issues on large sites with lots of traffic!', 'duracelltomi-google-tag-manager' ),
319
+ 'phase' => GTM4WP_PHASE_STABLE
320
+ ),
321
+ GTM4WP_OPTION_INTEGRATE_WCEECBRANDTAXONOMY => array(
322
+ "label" => __( "Taxonomy to be used for product brands", 'duracelltomi-google-tag-manager' ),
323
+ "description" => __( "Select which custom taxonomy is being used to add the brand of products", 'duracelltomi-google-tag-manager' ),
324
+ "phase" => GTM4WP_PHASE_STABLE
325
+ ),
326
+ GTM4WP_OPTION_INTEGRATE_WCCUSTOMERDATA => array(
327
+ 'label' => __( 'Customer data in data layer', 'duracelltomi-google-tag-manager' ),
328
+ 'description' => __( 'Enable this to add all customer data (billing and shipping data, total number of orders and order value) into the data layer (WooCommerce 3.x required)', 'duracelltomi-google-tag-manager' ),
329
+ 'phase' => GTM4WP_PHASE_STABLE
330
+ ),
331
+ GTM4WP_OPTION_INTEGRATE_WCORDERDATA => array(
332
+ 'label' => __( 'Order data in data layer', 'duracelltomi-google-tag-manager' ),
333
+ 'description' => __( 'Enable this to add all order attribute into the data layer on the order received page regardless and independently from classic and enhanced ecommerce tracking (WooCommerce 3.x required)', 'duracelltomi-google-tag-manager' ),
334
+ 'phase' => GTM4WP_PHASE_STABLE
335
+ ),
336
+ GTM4WP_OPTION_INTEGRATE_WCEXCLUDETAX => array(
337
+ 'label' => __( 'Exclude tax from revenue', 'duracelltomi-google-tag-manager' ),
338
+ 'description' => __( 'Enable this to exclude tax from the revenue variable while generating the purchase data', 'duracelltomi-google-tag-manager' ),
339
+ 'phase' => GTM4WP_PHASE_STABLE
340
+ ), GTM4WP_OPTION_INTEGRATE_WCORDERMAXAGE => array(
341
+ 'label' => __( 'Only track orders younger than', 'duracelltomi-google-tag-manager' ),
342
+ 'description' => __( 'To prevent duplicate transaction tracking at the order received page, enter the maximum age (in minutes) of the order or its payment for the transaction to be measured. Viewing the order received page of older orders will be ignored from transaction tracking, as it is considered to be a measured in an earlier session.', 'duracelltomi-google-tag-manager' ),
343
+ 'phase' => GTM4WP_PHASE_EXPERIMENTAL
344
+ ),
345
+ GTM4WP_OPTION_INTEGRATE_WCEXCLUDESHIPPING => array(
346
+ 'label' => __( 'Exclude shipping from revenue', 'duracelltomi-google-tag-manager' ),
347
+ 'description' => __( 'Enable this to exclude shipping costs from the revenue variable while generating the purchase data', 'duracelltomi-google-tag-manager' ),
348
+ 'phase' => GTM4WP_PHASE_STABLE
349
+ ),
350
+ GTM4WP_OPTION_INTEGRATE_WCREMARKETING => array(
351
+ 'label' => __( 'Google Ads Remarketing', 'duracelltomi-google-tag-manager' ),
352
+ 'description' => __( 'Enable this to add Google Ads dynamic remarketing variables to the dataLayer', 'duracelltomi-google-tag-manager' ),
353
+ 'phase' => GTM4WP_PHASE_DEPRECATED
354
+ ),
355
+ GTM4WP_OPTION_INTEGRATE_WCBUSINESSVERTICAL => array(
356
+ 'label' => __( 'Google Ads Business Vertical', 'duracelltomi-google-tag-manager' ),
357
+ 'description' => sprintf(
358
+ __(
359
+ 'Select which vertical category to add next to each product to utilize dynamic remarketing for Google Ads.'.
360
+ '<br>Use the plugin\'s <a href="%s" target="_blank">official setup guide for dynamic remarketing</a> '.
361
+ 'to setup your Google Tag Manager container.'
362
+ , 'duracelltomi-google-tag-manager' )
363
+ , 'https://gtm4wp.com/how-to-articles/how-to-setup-dynamic-remarketing-in-google-ads-adwords'),
364
+ 'phase' => GTM4WP_PHASE_STABLE
365
+ ),
366
+ GTM4WP_OPTION_INTEGRATE_WCREMPRODIDPREFIX => array(
367
+ 'label' => __( 'Product ID prefix', 'duracelltomi-google-tag-manager' ),
368
+ 'description' => __( "Some product feed generator plugins prefix product IDs with a fixed text like 'woocommerce_gpf'. You can enter this prefix here so that tags in your website include this prefix as well.", 'duracelltomi-google-tag-manager' ),
369
+ 'phase' => GTM4WP_PHASE_STABLE
370
+ ),
371
+ GTM4WP_OPTION_INTEGRATE_WCUSESKU => array(
372
+ 'label' => __( 'Use SKU instead of ID', 'duracelltomi-google-tag-manager' ),
373
+ 'description' => __( 'Check this to use product SKU instead of the ID of the products for remarketing and ecommerce tracking. Will fallback to ID if no SKU is set.', 'duracelltomi-google-tag-manager' ),
374
+ 'phase' => GTM4WP_PHASE_STABLE
375
+ ),
376
+ GTM4WP_OPTION_INTEGRATE_WCNOORDERTRACKEDFLAG => array(
377
+ 'label' => __( 'Do not flag orders as being tracked', 'duracelltomi-google-tag-manager' ),
378
+ 'description' => __(
379
+ 'Check this to prevent the plugin to flag orders as being already tracked.<br /><br />This ensures that no order data will be tracked ' .
380
+ 'multiple times in any ad or measurement system so please only enable this feature if you really need it (with iDeal you might need this)!',
381
+ 'duracelltomi-google-tag-manager'
382
+ ),
383
+ 'phase' => GTM4WP_PHASE_STABLE
384
+ ),
385
+
386
+ GTM4WP_OPTION_INTEGRATE_GOOGLEOPTIMIZEIDS => array(
387
+ 'label' => __( 'Google Optimize container ID list', 'duracelltomi-google-tag-manager' ),
388
+ 'description' => sprintf(
389
+ __(
390
+ 'Enter a comma separated list of Google Optimize container IDs that you would like to use on your site.<br />' .
391
+ 'This plugin will add the <a href="%s">page-hiding snippet</a> to your pages.<br />',
392
+ 'duracelltomi-google-tag-manager'
393
+ ),
394
+ 'https://developers.google.com/optimize/#the_page-hiding_snippet_code'
395
+ ) .
396
+ '<br /><span class="goid_validation_error">' . __( 'This does not seems to be a valid Google Optimize ID! Valid format: GTM-XXXXXX or OPT-XXXXXX where X can be numbers and capital letters. Use comma without any space (,) to enter multpile IDs.', 'duracelltomi-google-tag-manager' ) . '</span>',
397
+ 'phase' => GTM4WP_PHASE_EXPERIMENTAL,
398
+ ),
399
+ GTM4WP_OPTION_INTEGRATE_GOOGLEOPTIMIZETIMEOUT => array(
400
+ 'label' => __( 'Google Optimize page-hiding timeout', 'duracelltomi-google-tag-manager' ),
401
+ 'description' => __( 'Enter here the amount of time in milliseconds that the page-hiding snippet should wait before page content gets visible even if Google Optimize has not been completely loaded yet.', 'duracelltomi-google-tag-manager' ),
402
+ 'phase' => GTM4WP_PHASE_EXPERIMENTAL,
403
+ ),
404
+
405
+ GTM4WP_OPTION_INTEGRATE_AMPID => array(
406
+ 'label' => __( "Google Tag Manager 'AMP' Container ID", 'duracelltomi-google-tag-manager' ),
407
+ 'description' => sprintf( __( 'Enter a comma separated list of Google Tag Manager container IDs that you would like to use on your site. This plugin will add the <a href="%s">AMP GTM snippet</a> to your AMP pages.', 'duracelltomi-google-tag-manager' ), 'https://support.google.com/tagmanager/answer/6103696?hl=en' ) .
408
+ '<br /><span class="ampid_validation_error">' . __( 'This does not seems to be a valid Google Tag Manager Container ID! Valid format: GTM-XXXXXX where X can be numbers and capital letters. Use comma without any space (,) to enter multpile IDs.', 'duracelltomi-google-tag-manager' ) . '</span>',
409
+ 'phase' => GTM4WP_PHASE_EXPERIMENTAL,
410
+ 'plugintocheck' => 'amp/amp.php',
411
+ ),
412
+
413
+ GTM4WP_OPTION_INTEGRATE_COOKIEBOT => array(
414
+ 'label' => __( 'Cookiebot auto blocking', 'duracelltomi-google-tag-manager' ),
415
+ 'description' => sprintf( __( 'Enable this checkbox if you wish to use the <a href="%s" target="_blank">automatic cookie blocking mode of Cookiebot with Google Tag Manager</a>.', 'duracelltomi-google-tag-manager' ), 'https://support.cookiebot.com/hc/en-us/articles/360009192739-Google-Tag-Manager-and-Automatic-cookie-blocking' ),
416
+ 'phase' => GTM4WP_PHASE_STABLE
417
+ ),
418
+ );
419
+
420
+ $GLOBALS['gtm4wp_advancedfieldtexts'] = array(
421
+ GTM4WP_OPTION_DATALAYER_NAME => array(
422
+ 'label' => __( 'dataLayer variable name', 'duracelltomi-google-tag-manager' ),
423
+ 'description' => __( 'In some cases you need to rename the dataLayer variable. You can enter your name here. Leave black for default name: dataLayer', 'duracelltomi-google-tag-manager' ),
424
+ 'phase' => GTM4WP_PHASE_STABLE,
425
+ ),
426
+ GTM4WP_OPTION_ENV_GTM_AUTH => array(
427
+ 'label' => __( 'Environment gtm_auth parameter', 'duracelltomi-google-tag-manager' ),
428
+ 'description' => __( 'Enter the gtm_auth parameter of the Google Tag Manager environment that has to be activated on this site. Both gtm_auth and gtm_preview parameters are required to activate the desired environment.', 'duracelltomi-google-tag-manager' ),
429
+ 'phase' => GTM4WP_PHASE_STABLE,
430
+ ),
431
+ GTM4WP_OPTION_ENV_GTM_PREVIEW => array(
432
+ 'label' => __( 'Environment gtm_preview parameter', 'duracelltomi-google-tag-manager' ),
433
+ 'description' => __( 'Enter the gtm_auth parameter of the Google Tag Manager environment that has to be activated on this site. Both gtm_auth and gtm_preview parameters are required to activate the desired environment.', 'duracelltomi-google-tag-manager' ),
434
+ 'phase' => GTM4WP_PHASE_STABLE,
435
+ ),
436
+ GTM4WP_OPTION_DONOTTRACK => array(
437
+ 'label' => __( "Include browser 'Do not track' setting", 'duracelltomi-google-tag-manager' ),
438
+ 'description' => __( 'Add into the data layer whether the user has asked not to track any website interaction. You may want to respect this and disable all tags if this variable is set in the data layer.', 'duracelltomi-google-tag-manager' ),
439
+ 'phase' => GTM4WP_PHASE_STABLE,
440
+ ),
441
+ GTM4WP_OPTION_LOADEARLY => array(
442
+ 'label' => __( 'Load GTM container as early as possible', 'duracelltomi-google-tag-manager' ),
443
+ 'description' => __( "Turning on this option will load your Google Tag Manager container as early as possible during page load. This can cause issues if you are using jQuery in your custom HTML tags that fire on 'Page View' events.", 'duracelltomi-google-tag-manager' ),
444
+ 'phase' => GTM4WP_PHASE_STABLE,
445
+ ),
446
+ GTM4WP_OPTION_GTMDOMAIN => array(
447
+ 'label' => __( 'Container domain name', 'duracelltomi-google-tag-manager' ),
448
+ 'description' => __( "Enter your custom domain name if you are using a server side GTM container for tracking. Leave this blank to use www.googletagmanager.com", 'duracelltomi-google-tag-manager' ),
449
+ 'phase' => GTM4WP_PHASE_STABLE,
450
+ )
451
+ );
452
+
453
+ function gtm4wp_admin_output_section( $args ) {
454
+ echo '<span class="tabinfo">';
455
+
456
+ switch ( $args['id'] ) {
457
+ case GTM4WP_ADMIN_GROUP_GENERAL: {
458
+ _e( 'This plugin is intended to be used by IT girls&guys and marketing staff. Please be sure you read the <a href="https://developers.google.com/tag-manager/" target="_blank">Google Tag Manager Help Center</a> before you start using this plugin.<br /><br />', 'duracelltomi-google-tag-manager' );
459
+
460
+ break;
461
+ }
462
+
463
+ case GTM4WP_ADMIN_GROUP_INCLUDES: {
464
+ _e( 'Here you can check what data is needed to be included in the dataLayer to be able to access them in Google Tag Manager', 'duracelltomi-google-tag-manager' );
465
+ echo '<br />';
466
+ printf( __( '* Browser, OS and Device data is provided using <a href="%s">WhichBrowser</a> library.', 'duracelltomi-google-tag-manager' ), 'http://whichbrowser.net/' );
467
+
468
+ break;
469
+ }
470
+
471
+ case GTM4WP_ADMIN_GROUP_EVENTS: {
472
+ _e( 'Fire tags in Google Tag Manager on special events on your website', 'duracelltomi-google-tag-manager' );
473
+
474
+ break;
475
+ }
476
+
477
+ case GTM4WP_ADMIN_GROUP_SCROLLER: {
478
+ _e( 'Fire tags based on how the visitor scrolls through your page.', 'duracelltomi-google-tag-manager' );
479
+ echo '<br />';
480
+ printf( __( 'Based on the script originaly posted to <a href="%s">Analytics Talk</a>', 'duracelltomi-google-tag-manager' ), 'http://cutroni.com/blog/2012/02/21/advanced-content-tracking-with-google-analytics-part-1/' );
481
+
482
+ break;
483
+ }
484
+
485
+ case GTM4WP_ADMIN_GROUP_BLACKLIST: {
486
+ _e( 'Here you can control which types of tags, triggers and variables can be executed on your site regardless of what tags are included in your container on the Google Tag Manager site. Use this to increase security!', 'duracelltomi-google-tag-manager' );
487
+ echo '<br />';
488
+ _e( 'Do not modify if you do not know what to do, since it can cause issues with your tag deployment!', 'duracelltomi-google-tag-manager' );
489
+ echo '<br />';
490
+ _e( 'For example blacklisting everything and only whitelisting the Google Analytics tag without whitelisting the URL variable type will cause your Google Analytics tags to be blocked anyway since the attached triggers (Page View) can not fire!', 'duracelltomi-google-tag-manager' );
491
+
492
+ break;
493
+ }
494
+
495
+ case GTM4WP_ADMIN_GROUP_INTEGRATION: {
496
+ _e( 'Google Tag Manager for WordPress can integrate with several popular plugins. Please check the plugins you would like to integrate with:', 'duracelltomi-google-tag-manager' );
497
+
498
+ break;
499
+ }
500
+
501
+ case GTM4WP_ADMIN_GROUP_ADVANCED: {
502
+ _e( 'You usually do not need to modify thoose settings. Please be carefull while hacking here.', 'duracelltomi-google-tag-manager' );
503
+
504
+ break;
505
+ }
506
+
507
+ case GTM4WP_ADMIN_GROUP_CREDITS: {
508
+ _e( 'Some info about the author of this plugin', 'duracelltomi-google-tag-manager' );
509
+
510
+ break;
511
+ }
512
+ } // end switch
513
+
514
+ echo '</span>';
515
+ }
516
+
517
+ function gtm4wp_admin_output_field( $args ) {
518
+ global $gtm4wp_options, $gtm4wp_business_verticals;
519
+
520
+ switch ( $args['label_for'] ) {
521
+ case GTM4WP_ADMIN_GROUP_GTMID: {
522
+ if ( defined( 'GTM4WP_HARDCODED_GTM_ID' ) ) {
523
+ $_gtm_id_value = GTM4WP_HARDCODED_GTM_ID;
524
+ $_input_readonly = ' readonly="readonly"';
525
+ $_warning_after = '<br /><span class="gtm_wpconfig_set">WARNING! Container ID was set and fixed in wp-config.php. If you wish to change this value, please edit your wp-config.php and change the container ID or remove the GTM4WP_HARDCODED_GTM_ID constant!</span>';
526
+ } else {
527
+ $_gtm_id_value = $gtm4wp_options[ GTM4WP_OPTION_GTM_CODE ];
528
+ $_input_readonly = '';
529
+ $_warning_after = '';
530
+ }
531
+
532
+ echo '<input type="text" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_CODE . ']" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_CODE . ']" value="' . $_gtm_id_value . '" ' . $_input_readonly . '/><br />' . $args['description'];
533
+ echo $_warning_after;
534
+ echo '<br /><span class="gtmid_validation_error">' . __( 'This does not seems to be a valid Google Tag Manager ID! Valid format: GTM-XXXXX where X can be numbers and capital letters. Use comma without any space (,) to enter multpile container IDs.', 'duracelltomi-google-tag-manager' ) . '</span>';
535
+
536
+ break;
537
+ }
538
+
539
+ case GTM4WP_ADMIN_GROUP_PLACEMENT: {
540
+ echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_PLACEMENT . ']_' . GTM4WP_PLACEMENT_FOOTER . '" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_PLACEMENT . ']" value="' . GTM4WP_PLACEMENT_FOOTER . '" ' . ( $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] == GTM4WP_PLACEMENT_FOOTER ? 'checked="checked"' : '' ) . '/> ' . __( 'Footer of the page (not recommended by Google, no tweak in your template required)', 'duracelltomi-google-tag-manager' ) . '<br />';
541
+ echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_PLACEMENT . ']_' . GTM4WP_PLACEMENT_BODYOPEN . '" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_PLACEMENT . ']" value="' . GTM4WP_PLACEMENT_BODYOPEN . '" ' . ( $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] == GTM4WP_PLACEMENT_BODYOPEN ? 'checked="checked"' : '' ) . '/> ' . __( 'Custom (needs tweak in your template)', 'duracelltomi-google-tag-manager' ) . '<br />';
542
+ echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_PLACEMENT . ']_' . GTM4WP_PLACEMENT_BODYOPEN_AUTO . '" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_PLACEMENT . ']" value="' . GTM4WP_PLACEMENT_BODYOPEN_AUTO . '" ' . ( $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] == GTM4WP_PLACEMENT_BODYOPEN_AUTO ? 'checked="checked"' : '' ) . '/> ' . __( 'Codeless injection (no tweak, right placement but experimental, could break your frontend)', 'duracelltomi-google-tag-manager' ) . '<br />';
543
+ echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_PLACEMENT . ']_' . GTM4WP_PLACEMENT_OFF . '" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_PLACEMENT . ']" value="' . GTM4WP_PLACEMENT_OFF . '" ' . ( $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] == GTM4WP_PLACEMENT_OFF ? 'checked="checked"' : '' ) . '/> ' . __( 'Off (only add data layer to the page source)', 'duracelltomi-google-tag-manager' ) . '<br /><br />' . $args['description'];
544
+
545
+ break;
546
+ }
547
+
548
+ case GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_DATALAYER_NAME . ']': {
549
+ echo '<input type="text" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_DATALAYER_NAME . ']" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_DATALAYER_NAME . ']" value="' . $gtm4wp_options[ GTM4WP_OPTION_DATALAYER_NAME ] . '" /><br />' . $args['description'];
550
+ echo '<br /><span class="datalayername_validation_error">' . __( 'This does not seems to be a valid JavaScript variable name! Please check and try again', 'duracelltomi-google-tag-manager' ) . '</span>';
551
+
552
+ break;
553
+ }
554
+
555
+ case GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_ENV_GTM_AUTH . ']': {
556
+ if ( defined( 'GTM4WP_HARDCODED_GTM_ENV_AUTH' ) ) {
557
+ $_gtm_auth_value = GTM4WP_HARDCODED_GTM_ENV_AUTH;
558
+ $_input_readonly = ' readonly="readonly"';
559
+ $_warning_after = '<br /><span class="gtm_wpconfig_set">WARNING! Environment auth parameter was set and fixed in wp-config.php. If you wish to change this value, please edit your wp-config.php and change the parameter value or remove the GTM4WP_HARDCODED_GTM_ENV_AUTH constant!</span>';
560
+ } else {
561
+ $_gtm_auth_value = $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_AUTH ];
562
+ $_input_readonly = '';
563
+ $_warning_after = '';
564
+ }
565
+
566
+ echo '<input type="text" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_ENV_GTM_AUTH . ']" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_ENV_GTM_AUTH . ']" value="' . $_gtm_auth_value . '" ' . $_input_readonly . '/><br />' . $args['description'];
567
+ echo $_warning_after;
568
+ echo '<br /><span class="gtmauth_validation_error">' . __( 'This does not seems to be a valid gtm_auth parameter! It should only contain letters, number and the &quot;-&quot; character. Please check and try again', 'duracelltomi-google-tag-manager' ) . '</span>';
569
+
570
+ break;
571
+ }
572
+
573
+ case GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_ENV_GTM_PREVIEW . ']': {
574
+ if ( defined( 'GTM4WP_HARDCODED_GTM_ENV_PREVIEW' ) ) {
575
+ $_gtm_preview_value = GTM4WP_HARDCODED_GTM_ENV_PREVIEW;
576
+ $_input_readonly = ' readonly="readonly"';
577
+ $_warning_after = '<br /><span class="gtm_wpconfig_set">WARNING! Environment preview parameter was set and fixed in wp-config.php. If you wish to change this value, please edit your wp-config.php and change the parameter value or remove the GTM4WP_HARDCODED_GTM_ENV_PREVIEW constant!</span>';
578
+ } else {
579
+ $_gtm_preview_value = $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_PREVIEW ];
580
+ $_input_readonly = '';
581
+ $_warning_after = '';
582
+ }
583
+
584
+ echo '<input type="text" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_ENV_GTM_PREVIEW . ']" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_ENV_GTM_PREVIEW . ']" value="' . $_gtm_preview_value . '" ' . $_input_readonly . '/><br />' . $args['description'];
585
+ echo $_warning_after;
586
+ echo '<br /><span class="gtmpreview_validation_error">' . __( 'This does not seems to be a valid gtm_preview parameter! It should have the format &quot;env-NN&quot; where NN is an integer number. Please check and try again', 'duracelltomi-google-tag-manager' ) . '</span>';
587
+
588
+ break;
589
+ }
590
+
591
+ case GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_BLACKLIST_ENABLE . ']': {
592
+ echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_BLACKLIST_ENABLE . ']_0" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_BLACKLIST_ENABLE . ']" value="0" ' . ( $gtm4wp_options[ GTM4WP_OPTION_BLACKLIST_ENABLE ] == 0 ? 'checked="checked"' : '' ) . '/> ' . __( 'Disable feature: control everything on Google Tag Manager interface', 'duracelltomi-google-tag-manager' ) . '<br />';
593
+ echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_BLACKLIST_ENABLE . ']_1" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_BLACKLIST_ENABLE . ']" value="1" ' . ( $gtm4wp_options[ GTM4WP_OPTION_BLACKLIST_ENABLE ] == 1 ? 'checked="checked"' : '' ) . '/> ' . __( 'Allow all, except the checked items on all blacklist tabs (blacklist)', 'duracelltomi-google-tag-manager' ) . '<br />';
594
+ echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_BLACKLIST_ENABLE . ']_2" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_BLACKLIST_ENABLE . ']" value="2" ' . ( $gtm4wp_options[ GTM4WP_OPTION_BLACKLIST_ENABLE ] == 2 ? 'checked="checked"' : '' ) . '/> ' . __( 'Block all, except the checked items on all blacklist tabs (whitelist)', 'duracelltomi-google-tag-manager' ) . '<br />';
595
+ echo $args['description'];
596
+
597
+ break;
598
+ }
599
+
600
+ case GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_INCLUDE_WEATHERUNITS . ']': {
601
+ echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_INCLUDE_WEATHERUNITS . ']_0" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_INCLUDE_WEATHERUNITS . ']" value="0" ' . ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_WEATHERUNITS ] == 0 ? 'checked="checked"' : '' ) . '/> ' . __( 'Celsius', 'duracelltomi-google-tag-manager' ) . '<br />';
602
+ echo '<input type="radio" id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_INCLUDE_WEATHERUNITS . ']_1" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_INCLUDE_WEATHERUNITS . ']" value="1" ' . ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_WEATHERUNITS ] == 1 ? 'checked="checked"' : '' ) . '/> ' . __( 'Fahrenheit', 'duracelltomi-google-tag-manager' ) . '<br />';
603
+ echo $args['description'];
604
+
605
+ break;
606
+ }
607
+
608
+ case GTM4WP_ADMIN_GROUP_INFO: {
609
+ echo $args['description'];
610
+
611
+ break;
612
+ }
613
+
614
+ case GTM4WP_OPTIONS . "[" . GTM4WP_OPTION_INTEGRATE_WCEECBRANDTAXONOMY . "]": {
615
+ echo '<select id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_INTEGRATE_WCEECBRANDTAXONOMY . ']" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_INTEGRATE_WCEECBRANDTAXONOMY . ']">';
616
+ echo '<option value="">(not set)</option>';
617
+
618
+ $gtm4wp_taxonomies = get_taxonomies(array(
619
+ "show_ui" => true,
620
+ "public" => true,
621
+ "_builtin" => false
622
+ ), "object", "and");
623
+
624
+ foreach( $gtm4wp_taxonomies as $onetaxonomy ) {
625
+ echo '<option value="' . $onetaxonomy->name . '"' . ( $gtm4wp_options[GTM4WP_OPTION_INTEGRATE_WCEECBRANDTAXONOMY] === $onetaxonomy->name ? ' selected="selected"' : '' ) . '>' . $onetaxonomy->label . '</option>';
626
+ }
627
+
628
+ echo '</select>';
629
+
630
+ break;
631
+ }
632
+
633
+ case GTM4WP_OPTIONS . "[" . GTM4WP_OPTION_INTEGRATE_WCBUSINESSVERTICAL . "]": {
634
+ echo '<select id="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_INTEGRATE_WCBUSINESSVERTICAL . ']" name="' . GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_INTEGRATE_WCBUSINESSVERTICAL . ']">';
635
+
636
+ foreach( $gtm4wp_business_verticals as $vertical_id => $vertical_display_name ) {
637
+ echo '<option value="' . $vertical_id . '"' . ( $gtm4wp_options[GTM4WP_OPTION_INTEGRATE_WCBUSINESSVERTICAL] === $vertical_id ? ' selected="selected"' : '' ) . '>' . $vertical_display_name . '</option>';
638
+ }
639
+
640
+ echo '</select><br>' . $args['description'];
641
+
642
+ break;
643
+ }
644
+
645
+ default: {
646
+ if ( preg_match( '/' . GTM4WP_OPTIONS . "\\[blacklist\\-[^\\]]+\\]/i", $args['label_for'] ) ) {
647
+ if ( 'blacklist-sandboxed' == $args['entityid'] ) {
648
+ echo '<input type="checkbox" id="' . $args['label_for'] . '" name="' . $args['label_for'] . '" value="1" ' . checked( 1, $gtm4wp_options[ GTM4WP_OPTION_BLACKLIST_SANDBOXED ], false ) . ' /><br />' . $args['description'];
649
+ } else {
650
+ echo '<input type="checkbox" id="' . $args['label_for'] . '" name="' . $args['label_for'] . '" value="1" ' . checked( 1, in_array( $args['entityid'], $gtm4wp_options[ GTM4WP_OPTION_BLACKLIST_STATUS ] ), false ) . ' /><br />' . $args['description'];
651
+ }
652
+ } else {
653
+ $optval = $gtm4wp_options[ $args['optionfieldid'] ];
654
+
655
+ switch ( gettype( $optval ) ) {
656
+ case 'boolean': {
657
+ echo '<input type="checkbox" id="' . GTM4WP_OPTIONS . '[' . $args['optionfieldid'] . ']" name="' . GTM4WP_OPTIONS . '[' . $args['optionfieldid'] . ']" value="1" ' . checked( 1, $optval, false ) . ' /><br />' . $args['description'];
658
+
659
+ if ( isset( $args['plugintocheck'] ) && ( $args['plugintocheck'] != '' ) ) {
660
+ if ( is_plugin_active( $args['plugintocheck'] ) ) {
661
+ echo '<br />' . __( 'This plugin is <strong class="gtm4wp-plugin-active">active</strong>, it is strongly recommended to enable this integration!', 'duracelltomi-google-tag-manager' );
662
+ } else {
663
+ echo '<br />' . __( 'This plugin (' . $args['plugintocheck'] . ') is <strong class="gtm4wp-plugin-not-active">not active</strong>, enabling this integration could cause issues on frontend!', 'duracelltomi-google-tag-manager' );
664
+ }
665
+ }
666
+
667
+ break;
668
+ }
669
+
670
+ case 'integer': {
671
+ echo '<input type="number" step="1" min="0" class="small-text" id="' . GTM4WP_OPTIONS . '[' . $args['optionfieldid'] . ']" name="' . GTM4WP_OPTIONS . '[' . $args['optionfieldid'] . ']" value="' . esc_attr( $optval ) . '" /><br />' . $args['description'];
672
+
673
+ if ( isset( $args['plugintocheck'] ) && ( $args['plugintocheck'] != '' ) ) {
674
+ if ( is_plugin_active( $args['plugintocheck'] ) ) {
675
+ echo '<br />' . __( 'This plugin is <strong class="gtm4wp-plugin-active">active</strong>, it is strongly recommended to enable this integration!', 'duracelltomi-google-tag-manager' );
676
+ } else {
677
+ echo '<br />' . __( 'This plugin is <strong class="gtm4wp-plugin-not-active">not active</strong>, enabling this integration could cause issues on frontend!', 'duracelltomi-google-tag-manager' );
678
+ }
679
+ }
680
+
681
+ break;
682
+ }
683
+
684
+ default : {
685
+ echo '<input type="text" id="' . GTM4WP_OPTIONS . '[' . $args['optionfieldid'] . ']" name="' . GTM4WP_OPTIONS . '[' . $args['optionfieldid'] . ']" value="' . esc_attr( $optval ) . '" size="80" /><br />' . $args['description'];
686
+
687
+ if ( isset( $args['plugintocheck'] ) && ( $args['plugintocheck'] != '' ) ) {
688
+ if ( is_plugin_active( $args['plugintocheck'] ) ) {
689
+ echo '<br />' . __( 'This plugin is <strong class="gtm4wp-plugin-active">active</strong>, it is strongly recommended to enable this integration!', 'duracelltomi-google-tag-manager' );
690
+ } else {
691
+ echo '<br />' . __( 'This plugin is <strong class="gtm4wp-plugin-not-active">not active</strong>, enabling this integration could cause issues on frontend!', 'duracelltomi-google-tag-manager' );
692
+ }
693
+ }
694
+ }
695
+ } // end switch gettype optval
696
+ }
697
+ }
698
+ } // end switch
699
+ }
700
+
701
+ function gtm4wp_sanitize_options( $options ) {
702
+ global $wpdb, $gtm4wp_entity_ids;
703
+
704
+ $output = gtm4wp_reload_options();
705
+
706
+ foreach ( $output as $optionname => $optionvalue ) {
707
+ if ( isset( $options[ $optionname ] ) ) {
708
+ $newoptionvalue = $options[ $optionname ];
709
+ } else {
710
+ $newoptionvalue = '';
711
+ }
712
+
713
+ // "include" settings
714
+ if ( substr( $optionname, 0, 8 ) == 'include-' ) {
715
+ $output[ $optionname ] = (bool) $newoptionvalue;
716
+
717
+ // dataLayer events
718
+ } elseif ( substr( $optionname, 0, 6 ) == 'event-' ) {
719
+ $output[ $optionname ] = (bool) $newoptionvalue;
720
+
721
+ // clear oembed transients when feature is enabled because we need to hook into the oembed process to enable some 3rd party APIs
722
+ if ( $output[ $optionname ] && ! $optionvalue ) {
723
+ if ( GTM4WP_OPTION_EVENTS_YOUTUBE == $optionname ) {
724
+ $wpdb->query( "DELETE FROM $wpdb->postmeta WHERE meta_value LIKE '%youtube.com%' AND meta_key LIKE '_oembed_%'" );
725
+ }
726
+
727
+ if ( GTM4WP_OPTION_EVENTS_VIMEO == $optionname ) {
728
+ $wpdb->query( "DELETE FROM $wpdb->postmeta WHERE meta_value LIKE '%vimeo.com%' AND meta_key LIKE '_oembed_%'" );
729
+ }
730
+ }
731
+
732
+ // blacklist / whitelist entities
733
+ } elseif ( substr( $optionname, 0, 10 ) == 'blacklist-' ) {
734
+ if ( GTM4WP_OPTION_BLACKLIST_ENABLE === $optionname ) {
735
+ $output[ $optionname ] = (int) $options[ GTM4WP_OPTION_BLACKLIST_ENABLE ];
736
+ } else if ( GTM4WP_OPTION_BLACKLIST_SANDBOXED == $optionname ) {
737
+ $output[ $optionname ] = (bool) $newoptionvalue;
738
+ } else if ( GTM4WP_OPTION_BLACKLIST_STATUS == $optionname ) {
739
+ $selected_blacklist_entities = array();
740
+
741
+ foreach( $gtm4wp_entity_ids as $gtm_entity_group_id => $gtm_entity_group_list ) {
742
+ foreach( $gtm_entity_group_list as $gtm_entity_id => $gtm_entity_label ) {
743
+ $entity_option_id = 'blacklist-' . $gtm_entity_group_id . '-' . $gtm_entity_id;
744
+ if ( array_key_exists( $entity_option_id, $options ) ) {
745
+ $newoptionvalue = (bool) $options[ $entity_option_id ];
746
+ if ( $newoptionvalue ) {
747
+ $selected_blacklist_entities[] = $gtm_entity_id;
748
+ }
749
+ }
750
+ }
751
+ }
752
+
753
+ $output[ $optionname ] = implode( ',', $selected_blacklist_entities );
754
+ }
755
+
756
+ // Google Optimize settings
757
+ } elseif ( $optionname == GTM4WP_OPTION_INTEGRATE_GOOGLEOPTIMIZEIDS ) {
758
+ $_goid_val = trim( $newoptionvalue );
759
+ if ( '' == $_goid_val ) {
760
+ $_goid_list = array();
761
+ } else {
762
+ $_goid_list = explode( ',', $_goid_val );
763
+ }
764
+ $_goid_haserror = false;
765
+
766
+ foreach ( $_goid_list as $one_go_id ) {
767
+ $_goid_haserror = $_goid_haserror || ! preg_match( '/^(GTM|OPT)-[A-Z0-9]+$/', $one_go_id );
768
+ }
769
+
770
+ if ( $_goid_haserror && ( count( $_goid_list ) > 0 ) ) {
771
+ add_settings_error( GTM4WP_ADMIN_GROUP, GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_INTEGRATE_GOOGLEOPTIMIZEIDS . ']', __( 'Invalid Google Optimize ID. Valid ID format: GTM-XXXXX or OPT-XXXXX. Use comma without additional space (,) to enter more than one ID.', 'duracelltomi-google-tag-manager' ) );
772
+ } else {
773
+ $output[ $optionname ] = $newoptionvalue;
774
+ }
775
+ } elseif ( $optionname == GTM4WP_OPTION_INTEGRATE_GOOGLEOPTIMIZETIMEOUT ) {
776
+ $output[ $optionname ] = (int) $newoptionvalue;
777
+
778
+ } elseif ( $optionname == GTM4WP_OPTION_INTEGRATE_WCPRODPERIMPRESSION ) {
779
+ $output[ $optionname ] = (int) $newoptionvalue;
780
+
781
+ } elseif ( $optionname == GTM4WP_OPTION_INTEGRATE_WCORDERMAXAGE ) {
782
+ $output[ $optionname ] = (int) $newoptionvalue;
783
+
784
+ }elseif ( $optionname == GTM4WP_OPTION_INTEGRATE_WCREMPRODIDPREFIX ) {
785
+ $output[ $optionname ] = trim( (string) $newoptionvalue );
786
+
787
+ } else if ( $optionname == GTM4WP_OPTION_INTEGRATE_WCEECBRANDTAXONOMY ) {
788
+ $output[$optionname] = trim( (string) $newoptionvalue );
789
+
790
+ } else if ( $optionname == GTM4WP_OPTION_INTEGRATE_WCBUSINESSVERTICAL ) {
791
+ $output[$optionname] = trim( (string) $newoptionvalue );
792
+
793
+ } else if ( $optionname == GTM4WP_OPTION_GTMDOMAIN ) {
794
+ // for PHP 7- compatibility
795
+ if ( !defined("FILTER_FLAG_HOSTNAME") ) {
796
+ define( "FILTER_FLAG_HOSTNAME", 0 );
797
+ }
798
+
799
+ $newoptionvalue = filter_var( $newoptionvalue, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME );
800
+ if ( $newoptionvalue === false ) {
801
+ $newoptionvalue = '';
802
+ }
803
+ $output[$optionname] = trim( (string) $newoptionvalue );
804
+
805
+ // Accelerated Mobile Pages settings
806
+ } elseif ( $optionname == GTM4WP_OPTION_INTEGRATE_AMPID ) {
807
+ $_ampid_val = trim( $newoptionvalue );
808
+ if ( '' == $_ampid_val ) {
809
+ $_ampid_list = array();
810
+ } else {
811
+ $_ampid_list = explode( ',', $_ampid_val );
812
+ }
813
+ $_ampid_haserror = false;
814
+
815
+ foreach ( $_ampid_list as $one_amp_id ) {
816
+ $_ampid_haserror = $_ampid_haserror || ! preg_match( '/^GTM-[A-Z0-9]+$/', $one_amp_id );
817
+ }
818
+
819
+ if ( $_ampid_haserror && ( count( $_ampid_list ) > 0 ) ) {
820
+ add_settings_error( GTM4WP_ADMIN_GROUP, GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_INTEGRATE_AMPID . ']', __( 'Invalid AMP Google Tag Manager Container ID. Valid ID format: GTM-XXXXX. Use comma without additional space (,) to enter more than one ID.', 'duracelltomi-google-tag-manager' ) );
821
+ } else {
822
+ $output[ $optionname ] = $newoptionvalue;
823
+ }
824
+
825
+ // integrations
826
+ } elseif ( substr( $optionname, 0, 10 ) == 'integrate-' ) {
827
+ $output[ $optionname ] = (bool) $newoptionvalue;
828
+
829
+ // GTM code or dataLayer variable name
830
+ } elseif ( ( $optionname == GTM4WP_OPTION_GTM_CODE ) || ( $optionname == GTM4WP_OPTION_DATALAYER_NAME ) || ( $optionname == GTM4WP_OPTION_ENV_GTM_AUTH ) || ( $optionname == GTM4WP_OPTION_ENV_GTM_PREVIEW ) ) {
831
+ $newoptionvalue = trim( $newoptionvalue );
832
+
833
+ if ( $optionname == GTM4WP_OPTION_GTM_CODE ) {
834
+ $_gtmid_list = explode( ',', $newoptionvalue );
835
+ $_gtmid_haserror = false;
836
+
837
+ foreach ( $_gtmid_list as $one_gtm_id ) {
838
+ $_gtmid_haserror = $_gtmid_haserror || ! preg_match( '/^GTM-[A-Z0-9]+$/', $one_gtm_id );
839
+ }
840
+
841
+ if ( $_gtmid_haserror ) {
842
+ add_settings_error( GTM4WP_ADMIN_GROUP, GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_GTM_CODE . ']', __( 'Invalid Google Tag Manager ID. Valid ID format: GTM-XXXXX. Use comma without additional space (,) to enter more than one container ID.', 'duracelltomi-google-tag-manager' ) );
843
+ } else {
844
+ $output[ $optionname ] = $newoptionvalue;
845
+ }
846
+ } elseif ( ( $optionname == GTM4WP_OPTION_DATALAYER_NAME ) && ( $newoptionvalue != '' ) && ( ! preg_match( '/^[a-zA-Z][a-zA-Z0-9_-]*$/', $newoptionvalue ) ) ) {
847
+ add_settings_error( GTM4WP_ADMIN_GROUP, GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_DATALAYER_NAME . ']', __( "Invalid dataLayer variable name. Please start with a character from a-z or A-Z followed by characters from a-z, A-Z, 0-9 or '_' or '-'!", 'duracelltomi-google-tag-manager' ) );
848
+
849
+ } elseif ( ( $optionname == GTM4WP_OPTION_ENV_GTM_AUTH ) && ( $newoptionvalue != '' ) && ( ! preg_match( '/^[a-zA-Z0-9-_]+$/', $newoptionvalue ) ) ) {
850
+ add_settings_error( GTM4WP_ADMIN_GROUP, GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_ENV_GTM_AUTH . ']', __( "Invalid gtm_auth environment parameter value. It should only contain letters, numbers or the '-' and '_' characters.", 'duracelltomi-google-tag-manager' ) );
851
+
852
+ } elseif ( ( $optionname == GTM4WP_OPTION_ENV_GTM_PREVIEW ) && ( $newoptionvalue != '' ) && ( ! preg_match( '/^env-[0-9]+$/', $newoptionvalue ) ) ) {
853
+ add_settings_error( GTM4WP_ADMIN_GROUP, GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_ENV_GTM_PREVIEW . ']', __( "Invalid gtm_preview environment parameter value. It should have the format 'env-NN' where NN is an integer number.", 'duracelltomi-google-tag-manager' ) );
854
+
855
+ } else {
856
+ $output[ $optionname ] = $newoptionvalue;
857
+ }
858
+
859
+ // GTM container code placement
860
+ } elseif ( $optionname == GTM4WP_OPTION_GTM_PLACEMENT ) {
861
+ $output[ $optionname ] = (int) $newoptionvalue;
862
+ if ( ( $output[ $optionname ] < 0 ) || ( $output[ $optionname ] > 3 ) ) {
863
+ $output[ $optionname ] = 0;
864
+ }
865
+
866
+ // scroll tracking content ID
867
+ } elseif ( $optionname == GTM4WP_OPTION_SCROLLER_CONTENTID ) {
868
+ $output[ $optionname ] = trim( str_replace( '#', '', $newoptionvalue ) );
869
+
870
+ // anything else
871
+ } else {
872
+ switch ( gettype( $optionvalue ) ) {
873
+ case 'boolean': {
874
+ $output[ $optionname ] = (bool) $newoptionvalue;
875
+
876
+ break;
877
+ }
878
+
879
+ case 'integer': {
880
+ $output[ $optionname ] = (int) $newoptionvalue;
881
+
882
+ break;
883
+ }
884
+
885
+ default: {
886
+ $output[ $optionname ] = $newoptionvalue;
887
+ }
888
+ } // end switch
889
+ }
890
+ }
891
+
892
+ return $output;
893
+ }
894
+
895
+ function gtm4wp_admin_init() {
896
+ global $gtm4wp_includefieldtexts, $gtm4wp_eventfieldtexts, $gtm4wp_integratefieldtexts, $gtm4wp_scrollerfieldtexts,
897
+ $gtm4wp_advancedfieldtexts, $gtm4wp_entity_ids;
898
+
899
+ register_setting( GTM4WP_ADMIN_GROUP, GTM4WP_OPTIONS, 'gtm4wp_sanitize_options' );
900
+
901
+ add_settings_section(
902
+ GTM4WP_ADMIN_GROUP_GENERAL,
903
+ __( 'General', 'duracelltomi-google-tag-manager' ),
904
+ 'gtm4wp_admin_output_section',
905
+ GTM4WP_ADMINSLUG
906
+ );
907
+
908
+ add_settings_field(
909
+ GTM4WP_ADMIN_GROUP_GTMID,
910
+ __( 'Google Tag Manager ID', 'duracelltomi-google-tag-manager' ),
911
+ 'gtm4wp_admin_output_field',
912
+ GTM4WP_ADMINSLUG,
913
+ GTM4WP_ADMIN_GROUP_GENERAL,
914
+ array(
915
+ 'label_for' => GTM4WP_ADMIN_GROUP_GTMID,
916
+ 'description' => __( 'Enter your Google Tag Manager ID here. Use comma without space (,) to enter multiple IDs.', 'duracelltomi-google-tag-manager' ),
917
+ )
918
+ );
919
+
920
+ add_settings_field(
921
+ GTM4WP_ADMIN_GROUP_PLACEMENT,
922
+ __( 'Container code <code>&lt;noscript&gt;</code> part placement', 'duracelltomi-google-tag-manager' ),
923
+ 'gtm4wp_admin_output_field',
924
+ GTM4WP_ADMINSLUG,
925
+ GTM4WP_ADMIN_GROUP_GENERAL,
926
+ array(
927
+ 'label_for' => GTM4WP_ADMIN_GROUP_PLACEMENT,
928
+ 'description' => __( "Code placement decides where to put the second, so called noscript part of the GTM container code.<br />This code is usually only executed if your visitor has for some reason disabled JavaScript.<br/>The main GTM container code will be placed into the <code>&lt;head&gt;</code> section of your webpages anyway (where it belongs to).<br />If you select 'Custom' you need to edit your template file and add the following line just after the opening <code>&lt;body&gt;</code> tag:<br /><code>&lt;?php if ( function_exists( 'gtm4wp_the_gtm_tag' ) ) { gtm4wp_the_gtm_tag(); } ?&gt;</code>", 'duracelltomi-google-tag-manager' ),
929
+ )
930
+ );
931
+
932
+ add_settings_section(
933
+ GTM4WP_ADMIN_GROUP_INCLUDES,
934
+ __( 'Basic data', 'duracelltomi-google-tag-manager' ),
935
+ 'gtm4wp_admin_output_section',
936
+ GTM4WP_ADMINSLUG
937
+ );
938
+
939
+ foreach ( $gtm4wp_includefieldtexts as $fieldid => $fielddata ) {
940
+ $phase = isset( $fielddata['phase'] ) ? $fielddata['phase'] : GTM4WP_PHASE_STABLE;
941
+
942
+ add_settings_field(
943
+ 'gtm4wp-admin-' . $fieldid . '-id',
944
+ $fielddata['label'] . '<span class="' . $phase . '"></span>',
945
+ 'gtm4wp_admin_output_field',
946
+ GTM4WP_ADMINSLUG,
947
+ GTM4WP_ADMIN_GROUP_INCLUDES,
948
+ array(
949
+ 'label_for' => 'gtm4wp-options[' . $fieldid . ']',
950
+ 'description' => $fielddata['description'],
951
+ 'optionfieldid' => $fieldid,
952
+ )
953
+ );
954
+ }
955
+
956
+ add_settings_section(
957
+ GTM4WP_ADMIN_GROUP_EVENTS,
958
+ __( 'Events', 'duracelltomi-google-tag-manager' ),
959
+ 'gtm4wp_admin_output_section',
960
+ GTM4WP_ADMINSLUG
961
+ );
962
+
963
+ foreach ( $gtm4wp_eventfieldtexts as $fieldid => $fielddata ) {
964
+ $phase = isset( $fielddata['phase'] ) ? $fielddata['phase'] : GTM4WP_PHASE_STABLE;
965
+
966
+ add_settings_field(
967
+ 'gtm4wp-admin-' . $fieldid . '-id',
968
+ $fielddata['label'] . '<span class="' . $phase . '"></span>',
969
+ 'gtm4wp_admin_output_field',
970
+ GTM4WP_ADMINSLUG,
971
+ GTM4WP_ADMIN_GROUP_EVENTS,
972
+ array(
973
+ 'label_for' => 'gtm4wp-options[' . $fieldid . ']',
974
+ 'description' => $fielddata['description'],
975
+ 'optionfieldid' => $fieldid,
976
+ )
977
+ );
978
+ }
979
+
980
+ add_settings_section(
981
+ GTM4WP_ADMIN_GROUP_SCROLLER,
982
+ __( 'Scroll tracking', 'duracelltomi-google-tag-manager' ),
983
+ 'gtm4wp_admin_output_section',
984
+ GTM4WP_ADMINSLUG
985
+ );
986
+
987
+ foreach ( $gtm4wp_scrollerfieldtexts as $fieldid => $fielddata ) {
988
+ $phase = isset( $fielddata['phase'] ) ? $fielddata['phase'] : GTM4WP_PHASE_STABLE;
989
+
990
+ add_settings_field(
991
+ 'gtm4wp-admin-' . $fieldid . '-id',
992
+ $fielddata['label'] . '<span class="' . $phase . '"></span>',
993
+ 'gtm4wp_admin_output_field',
994
+ GTM4WP_ADMINSLUG,
995
+ GTM4WP_ADMIN_GROUP_SCROLLER,
996
+ array(
997
+ 'label_for' => 'gtm4wp-options[' . $fieldid . ']',
998
+ 'description' => $fielddata['description'],
999
+ 'optionfieldid' => $fieldid,
1000
+ )
1001
+ );
1002
+ }
1003
+
1004
+ add_settings_section(
1005
+ GTM4WP_ADMIN_GROUP_BLACKLIST,
1006
+ __( 'Security', 'duracelltomi-google-tag-manager' ),
1007
+ 'gtm4wp_admin_output_section',
1008
+ GTM4WP_ADMINSLUG
1009
+ );
1010
+
1011
+ add_settings_field(
1012
+ GTM4WP_OPTION_BLACKLIST_ENABLE,
1013
+ __( 'Enable blacklist/whitelist', 'duracelltomi-google-tag-manager' ),
1014
+ 'gtm4wp_admin_output_field',
1015
+ GTM4WP_ADMINSLUG,
1016
+ GTM4WP_ADMIN_GROUP_BLACKLIST,
1017
+ array(
1018
+ 'label_for' => GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_BLACKLIST_ENABLE . ']',
1019
+ 'description' => '',
1020
+ 'optionsfieldid' => GTM4WP_OPTION_BLACKLIST_ENABLE
1021
+ )
1022
+ );
1023
+
1024
+ add_settings_field(
1025
+ GTM4WP_OPTION_BLACKLIST_SANDBOXED,
1026
+ __( 'Custom tag/variable templates', 'duracelltomi-google-tag-manager' ),
1027
+ 'gtm4wp_admin_output_field',
1028
+ GTM4WP_ADMINSLUG,
1029
+ GTM4WP_ADMIN_GROUP_BLACKLIST,
1030
+ array(
1031
+ 'label_for' => GTM4WP_OPTIONS . '[' . GTM4WP_OPTION_BLACKLIST_SANDBOXED . ']',
1032
+ 'description' => '',
1033
+ 'entityid' => GTM4WP_OPTION_BLACKLIST_SANDBOXED
1034
+ )
1035
+ );
1036
+
1037
+ foreach( $gtm4wp_entity_ids as $gtm_entity_group_id => $gtm_entity_group_list ) {
1038
+ foreach( $gtm_entity_group_list as $gtm_entity_id => $gtm_entity_label ) {
1039
+ add_settings_field(
1040
+ 'gtm4wp-admin-blacklist-' . $gtm_entity_group_id . '-' . $gtm_entity_id . '-id',
1041
+ $gtm_entity_label,
1042
+ 'gtm4wp_admin_output_field',
1043
+ GTM4WP_ADMINSLUG,
1044
+ GTM4WP_ADMIN_GROUP_BLACKLIST,
1045
+ array(
1046
+ 'label_for' => 'gtm4wp-options[blacklist-' . $gtm_entity_group_id . '-' . $gtm_entity_id . ']',
1047
+ 'description' => '',
1048
+ 'entityid' => $gtm_entity_id,
1049
+ )
1050
+ );
1051
+ }
1052
+ }
1053
+
1054
+ add_settings_section(
1055
+ GTM4WP_ADMIN_GROUP_INTEGRATION,
1056
+ __( 'Integration', 'duracelltomi-google-tag-manager' ),
1057
+ 'gtm4wp_admin_output_section',
1058
+ GTM4WP_ADMINSLUG
1059
+ );
1060
+
1061
+ foreach ( $gtm4wp_integratefieldtexts as $fieldid => $fielddata ) {
1062
+ $phase = isset( $fielddata['phase'] ) ? $fielddata['phase'] : GTM4WP_PHASE_STABLE;
1063
+
1064
+ add_settings_field(
1065
+ 'gtm4wp-admin-' . $fieldid . '-id',
1066
+ $fielddata['label'] . '<span class="' . $phase . '"></span>',
1067
+ 'gtm4wp_admin_output_field',
1068
+ GTM4WP_ADMINSLUG,
1069
+ GTM4WP_ADMIN_GROUP_INTEGRATION,
1070
+ array(
1071
+ 'label_for' => 'gtm4wp-options[' . $fieldid . ']',
1072
+ 'description' => $fielddata['description'],
1073
+ 'optionfieldid' => $fieldid,
1074
+ 'plugintocheck' => isset( $fielddata['plugintocheck'] ) ? $fielddata['plugintocheck'] : '',
1075
+ )
1076
+ );
1077
+ }
1078
+
1079
+ add_settings_section(
1080
+ GTM4WP_ADMIN_GROUP_ADVANCED,
1081
+ __( 'Advanced', 'duracelltomi-google-tag-manager' ),
1082
+ 'gtm4wp_admin_output_section',
1083
+ GTM4WP_ADMINSLUG
1084
+ );
1085
+
1086
+ foreach ( $gtm4wp_advancedfieldtexts as $fieldid => $fielddata ) {
1087
+ $phase = isset( $fielddata['phase'] ) ? $fielddata['phase'] : GTM4WP_PHASE_STABLE;
1088
+
1089
+ add_settings_field(
1090
+ 'gtm4wp-admin-' . $fieldid . '-id',
1091
+ $fielddata['label'] . '<span class="' . $phase . '"></span>',
1092
+ 'gtm4wp_admin_output_field',
1093
+ GTM4WP_ADMINSLUG,
1094
+ GTM4WP_ADMIN_GROUP_ADVANCED,
1095
+ array(
1096
+ 'label_for' => 'gtm4wp-options[' . $fieldid . ']',
1097
+ 'description' => $fielddata['description'],
1098
+ 'optionfieldid' => $fieldid,
1099
+ 'plugintocheck' => isset( $fielddata['plugintocheck'] ) ? $fielddata['plugintocheck'] : '',
1100
+ )
1101
+ );
1102
+ }
1103
+
1104
+ add_settings_section(
1105
+ GTM4WP_ADMIN_GROUP_CREDITS,
1106
+ __( 'Credits', 'duracelltomi-google-tag-manager' ),
1107
+ 'gtm4wp_admin_output_section',
1108
+ GTM4WP_ADMINSLUG
1109
+ );
1110
+
1111
+ add_settings_field(
1112
+ GTM4WP_ADMIN_GROUP_INFO,
1113
+ __( 'Author', 'duracelltomi-google-tag-manager' ),
1114
+ 'gtm4wp_admin_output_field',
1115
+ GTM4WP_ADMINSLUG,
1116
+ GTM4WP_ADMIN_GROUP_CREDITS,
1117
+ array(
1118
+ 'label_for' => GTM4WP_ADMIN_GROUP_INFO,
1119
+ 'description' => '<strong>Thomas Geiger</strong><br />
1120
+ Website: <a href="https://gtm4wp.com/" target="_blank">gtm4wp.com</a><br />
1121
+ <a href="https://www.linkedin.com/in/duracelltomi" target="_blank">Me on LinkedIn</a><br />
1122
+ <a href="http://www.linkedin.com/company/jabjab-online-marketing-ltd" target="_blank">JabJab Online Marketing on LinkedIn</a>',
1123
+ )
1124
+ );
1125
+
1126
+ // apply oembed code changes on the admin as well since the oembed call on the admin is cached by WordPress into a transient
1127
+ // that is applied on the frontend later
1128
+ require_once dirname( __FILE__ ) . '/../integration/youtube.php';
1129
+ require_once dirname( __FILE__ ) . '/../integration/vimeo.php';
1130
+ require_once dirname( __FILE__ ) . '/../integration/soundcloud.php';
1131
+ }
1132
+
1133
+ function gtm4wp_show_admin_page() {
1134
+ global $gtp4wp_plugin_url;
1135
+ ?>
1136
+ <div class="wrap">
1137
+ <div id="gtm4wp-icon" class="icon32" style="background-image: url(<?php echo $gtp4wp_plugin_url; ?>admin/images/tag_manager-32.png);"><br /></div>
1138
+ <h2><?php _e( 'Google Tag Manager for WordPress options', 'duracelltomi-google-tag-manager' ); ?></h2>
1139
+ <form action="options.php" method="post">
1140
+ <?php settings_fields( GTM4WP_ADMIN_GROUP ); ?>
1141
+ <?php do_settings_sections( GTM4WP_ADMINSLUG ); ?>
1142
+ <?php submit_button(); ?>
1143
+
1144
+ </form>
1145
+ </div>
1146
+ <?php
1147
+ }
1148
+
1149
+ function gtm4wp_add_admin_page() {
1150
+ add_options_page(
1151
+ __( 'Google Tag Manager for WordPress settings', 'duracelltomi-google-tag-manager' ),
1152
+ __( 'Google Tag Manager', 'duracelltomi-google-tag-manager' ),
1153
+ 'manage_options',
1154
+ GTM4WP_ADMINSLUG,
1155
+ 'gtm4wp_show_admin_page'
1156
+ );
1157
+ }
1158
+
1159
+ function gtm4wp_add_admin_js( $hook ) {
1160
+ global $gtp4wp_plugin_url;
1161
+
1162
+ if ( $hook == 'settings_page_' . GTM4WP_ADMINSLUG ) {
1163
+ wp_register_script( 'admin-subtabs', $gtp4wp_plugin_url . 'js/admin-subtabs.js', array(), GTM4WP_VERSION );
1164
+
1165
+ $subtabtexts = array(
1166
+ 'posttabtitle' => __( 'Posts', 'duracelltomi-google-tag-manager' ),
1167
+ 'searchtabtitle' => __( 'Search', 'duracelltomi-google-tag-manager' ),
1168
+ 'visitortabtitle' => __( 'Visitors', 'duracelltomi-google-tag-manager' ),
1169
+ 'adwordstabtitle' => __( 'Google Ads', 'duracelltomi-google-tag-manager' ),
1170
+ 'browsertabtitle' => __( 'Browser/OS/Device', 'duracelltomi-google-tag-manager' ),
1171
+ 'blocktagstabtitle' => __( 'Blacklist tags', 'duracelltomi-google-tag-manager' ),
1172
+ 'blocktriggerstabtitle' => __( 'Blacklist triggers', 'duracelltomi-google-tag-manager' ),
1173
+ 'blockmacrostabtitle' => __( 'Blacklist variables', 'duracelltomi-google-tag-manager' ),
1174
+ 'wpcf7tabtitle' => __( 'Contact Form 7', 'duracelltomi-google-tag-manager' ),
1175
+ 'wctabtitle' => __( 'WooCommerce', 'duracelltomi-google-tag-manager' ),
1176
+ 'gotabtitle' => __( 'Google Optimize', 'duracelltomi-google-tag-manager' ),
1177
+ 'amptabtitle' => __( 'Accelerated Mobile Pages', 'duracelltomi-google-tag-manager' ),
1178
+ 'cookiebottabtitle' => __( 'Cookiebot', 'duracelltomi-google-tag-manager' ),
1179
+ 'weathertabtitle' => __( 'Weather & geo data', 'duracelltomi-google-tag-manager' ),
1180
+ 'generaleventstabtitle' => __( 'General events', 'duracelltomi-google-tag-manager' ),
1181
+ 'mediaeventstabtitle' => __( 'Media events', 'duracelltomi-google-tag-manager' ),
1182
+ 'depecratedeventstabtitle' => __( 'Deprecated', 'duracelltomi-google-tag-manager' ),
1183
+ 'sitetabtitle' => __( 'Site', 'duracelltomi-google-tag-manager' ),
1184
+ 'misctabtitle' => __( 'Misc', 'duracelltomi-google-tag-manager' ),
1185
+ );
1186
+ wp_localize_script( 'admin-subtabs', 'gtm4wp', $subtabtexts );
1187
+
1188
+ wp_enqueue_script( 'admin-subtabs' );
1189
+ wp_enqueue_script( 'admin-tabcreator', $gtp4wp_plugin_url . 'js/admin-tabcreator.js', array( 'jquery-core' ), GTM4WP_VERSION );
1190
+
1191
+ wp_enqueue_style( 'gtm4wp-validate', $gtp4wp_plugin_url . 'css/admin-gtm4wp.css', array(), GTM4WP_VERSION );
1192
+ }
1193
+ }
1194
+
1195
+ function gtm4wp_admin_head() {
1196
+ echo '
1197
+ <style type="text/css">
1198
+ .gtmid_validation_error,
1199
+ .goid_validation_error,
1200
+ .goid_ga_validation_error,
1201
+ .ampid_validation_error,
1202
+ .datalayername_validation_error,
1203
+ .gtmauth_validation_error,
1204
+ .gtmpreview_validation_error,
1205
+ .gtm_wpconfig_set {
1206
+ color: #c00;
1207
+ font-weight: bold;
1208
+ }
1209
+ .gtmid_validation_error,
1210
+ .goid_validation_error,
1211
+ .goid_ga_validation_error,
1212
+ .ampid_validation_error,
1213
+ .datalayername_validation_error,
1214
+ .gtmauth_validation_error,
1215
+ .gtmpreview_validation_error {
1216
+ display: none;
1217
+ }
1218
+ </style>
1219
+ <script type="text/javascript">
1220
+ jQuery(function() {
1221
+ jQuery( "#gtm4wp-options\\\\[gtm-code\\\\]" )
1222
+ .bind( "blur", function() {
1223
+ var gtmid_regex = /^GTM-[A-Z0-9]+$/;
1224
+ var gtmid_list = jQuery( this ).val().trim().split( "," );
1225
+
1226
+ var gtmid_haserror = false;
1227
+ for( var i=0; i<gtmid_list.length; i++ ) {
1228
+ gtmid_haserror = gtmid_haserror || !gtmid_regex.test( gtmid_list[ i ] );
1229
+ }
1230
+
1231
+ if ( gtmid_haserror ) {
1232
+ jQuery( ".gtmid_validation_error" )
1233
+ .show();
1234
+ } else {
1235
+ jQuery( ".gtmid_validation_error" )
1236
+ .hide();
1237
+ }
1238
+ });
1239
+
1240
+ jQuery( "#gtm4wp-options\\\\[integrate-google-optimize-idlist\\\\]" )
1241
+ .bind( "blur", function() {
1242
+ var goid_regex = /^(GTM|OPT)-[A-Z0-9]+$/;
1243
+ var goid_val = jQuery( this ).val().trim();
1244
+ if ( "" == goid_val ) {
1245
+ goid_list = [];
1246
+ } else {
1247
+ var goid_list = goid_val.split( "," );
1248
+ }
1249
+
1250
+ var goid_haserror = false;
1251
+ for( var i=0; i<goid_list.length; i++ ) {
1252
+ goid_haserror = goid_haserror || !goid_regex.test( goid_list[ i ] );
1253
+ }
1254
+
1255
+ if ( goid_haserror && (goid_list.length > 0) ) {
1256
+ jQuery( ".goid_validation_error" )
1257
+ .show();
1258
+ } else {
1259
+ jQuery( ".goid_validation_error" )
1260
+ .hide();
1261
+ }
1262
+ });
1263
+
1264
+ jQuery( "#gtm4wp-options\\\\[integrate-google-optimize-gaid\\\\]" )
1265
+ .bind( "blur", function() {
1266
+ var gogaid_regex = /^UA-[0-9]+-[0-9]+$/;
1267
+ var gogaid_val = jQuery( this ).val().trim();
1268
+ if ( "" == gogaid_val ) {
1269
+ gogaid_list = [];
1270
+ } else {
1271
+ var gogaid_list = gogaid_val.split( "," );
1272
+ }
1273
+
1274
+ var gogaid_haserror = false;
1275
+ for( var i=0; i<gogaid_list.length; i++ ) {
1276
+ gogaid_haserror = gogaid_haserror || !gogaid_regex.test( gogaid_list[ i ] );
1277
+ }
1278
+
1279
+ if ( gogaid_haserror && (gogaid_list.length > 0) ) {
1280
+ jQuery( ".goid_ga_validation_error" )
1281
+ .show();
1282
+ } else {
1283
+ jQuery( ".goid_ga_validation_error" )
1284
+ .hide();
1285
+ }
1286
+ });
1287
+
1288
+ jQuery( "#gtm4wp-options\\\\[integrate-amp-gtm\\\\]" )
1289
+ .bind( "blur", function() {
1290
+ var ampid_regex = /^GTM-[A-Z0-9]+$/;
1291
+ var ampid_val = jQuery( this ).val().trim();
1292
+ if ( "" == ampid_val ) {
1293
+ ampid_list = [];
1294
+ } else {
1295
+ var ampid_list = ampid_val.split( "," );
1296
+ }
1297
+
1298
+ var ampid_haserror = false;
1299
+ for( var i=0; i<ampid_list.length; i++ ) {
1300
+ ampid_haserror = ampid_haserror || !ampid_regex.test( gogaid_list[ i ] );
1301
+ }
1302
+
1303
+ if ( ampid_haserror && (ampid_list.length > 0) ) {
1304
+ jQuery( ".ampid_validation_error" )
1305
+ .show();
1306
+ } else {
1307
+ jQuery( ".ampid_validation_error" )
1308
+ .hide();
1309
+ }
1310
+ });
1311
+
1312
+ jQuery( "#gtm4wp-options\\\\[gtm-datalayer-variable-name\\\\]" )
1313
+ .bind( "blur", function() {
1314
+ var currentval = jQuery( this ).val();
1315
+
1316
+ jQuery( ".datalayername_validation_error" )
1317
+ .hide();
1318
+
1319
+ if ( currentval != "" ) {
1320
+ // I know this is not the exact definition for a variable name but I think other kind of variable names should not be used.
1321
+ var gtmvarname_regex = /^[a-zA-Z][a-zA-Z0-9_-]*$/;
1322
+ if ( ! gtmvarname_regex.test( currentval ) ) {
1323
+ jQuery( ".datalayername_validation_error" )
1324
+ .show();
1325
+ }
1326
+ }
1327
+ });
1328
+
1329
+ jQuery( "#gtm4wp-options\\\\[gtm-env-gtm-auth\\\\]" )
1330
+ .bind( "blur", function() {
1331
+ var currentval = jQuery( this ).val();
1332
+
1333
+ jQuery( ".gtmauth_validation_error" )
1334
+ .hide();
1335
+
1336
+ if ( currentval != "" ) {
1337
+ var gtmauth_regex = /^[a-zA-Z0-9-_]+$/;
1338
+ if ( ! gtmauth_regex.test( currentval ) ) {
1339
+ jQuery( ".gtmauth_validation_error" )
1340
+ .show();
1341
+ }
1342
+ }
1343
+ });
1344
+
1345
+ jQuery( "#gtm4wp-options\\\\[gtm-env-gtm-preview\\\\]" )
1346
+ .bind( "blur", function() {
1347
+ var currentval = jQuery( this ).val();
1348
+
1349
+ jQuery( ".gtmpreview_validation_error" )
1350
+ .hide();
1351
+
1352
+ if ( currentval != "" ) {
1353
+ var gtmpreview_regex = /^env-[0-9]+$/;
1354
+ if ( ! gtmpreview_regex.test( currentval ) ) {
1355
+ jQuery( ".gtmpreview_validation_error" )
1356
+ .show();
1357
+ }
1358
+ }
1359
+ });
1360
+
1361
+ jQuery( document )
1362
+ .on( "click", ".gtm4wp-notice .notice-dismiss", function( e ) {
1363
+ jQuery.post(ajaxurl, {
1364
+ action: "gtm4wp_dismiss_notice",
1365
+ noticeid: jQuery( this ).closest(".gtm4wp-notice")
1366
+ .attr( "data-href" )
1367
+ .substring( 1 )
1368
+ });
1369
+ });
1370
+ });
1371
+ </script>';
1372
+ }
1373
+
1374
+ function gtm4wp_show_warning() {
1375
+ global $gtm4wp_options, $gtp4wp_plugin_url, $gtm4wp_integratefieldtexts, $current_user,
1376
+ $gtm4wp_def_user_notices_dismisses;
1377
+
1378
+ $woo_plugin_active = is_plugin_active( $gtm4wp_integratefieldtexts[ GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC ]['plugintocheck'] );
1379
+ if ( $woo_plugin_active && function_exists( 'WC' ) ) {
1380
+ $woo = WC();
1381
+ } else {
1382
+ $woo = null;
1383
+ }
1384
+
1385
+ $gtm4wp_user_notices_dismisses = get_user_meta( $current_user->ID, GTM4WP_USER_NOTICES_KEY, true );
1386
+ if ( $gtm4wp_user_notices_dismisses === '' ) {
1387
+ if ( is_array( $gtm4wp_def_user_notices_dismisses ) ) {
1388
+ $gtm4wp_user_notices_dismisses = $gtm4wp_def_user_notices_dismisses;
1389
+ } else {
1390
+ $gtm4wp_user_notices_dismisses = array();
1391
+ }
1392
+ } else {
1393
+ $gtm4wp_user_notices_dismisses = @unserialize( $gtm4wp_user_notices_dismisses );
1394
+ if ( false === $gtm4wp_user_notices_dismisses || !is_array( $gtm4wp_user_notices_dismisses ) ) {
1395
+ $gtm4wp_user_notices_dismisses = array();
1396
+ }
1397
+ }
1398
+ $gtm4wp_user_notices_dismisses = array_merge( $gtm4wp_def_user_notices_dismisses, $gtm4wp_user_notices_dismisses );
1399
+
1400
+ if ( ( trim( $gtm4wp_options[ GTM4WP_OPTION_GTM_CODE ] ) == '' ) && ( false === $gtm4wp_user_notices_dismisses['enter-gtm-code'] ) ) {
1401
+ echo '<div class="gtm4wp-notice notice notice-error is-dismissible" data-href="?enter-gtm-code"><p><strong>' . sprintf( __( 'To start using Google Tag Manager for WordPress, please <a href="%s">enter your GTM ID</a>', 'duracelltomi-google-tag-manager' ), 'options-general.php?page=' . GTM4WP_ADMINSLUG ) . '</strong></p></div>';
1402
+ }
1403
+
1404
+ if ( (
1405
+ ( '' != $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_AUTH ] ) && ( '' == $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_PREVIEW ] )
1406
+ ) || (
1407
+ ( '' == $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_AUTH ] ) && ( '' != $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_PREVIEW ] )
1408
+ ) ) {
1409
+ echo '<div class="gtm4wp-notice notice notice-error" data-href="?incomplete-gtm-env-config"><p><strong>' . sprintf( __( 'Incomplete Google Tag Manager environment configuration: either gtm_preview or gtm_auth parameter value is missing!', 'duracelltomi-google-tag-manager' ), 'options-general.php?page=' . GTM4WP_ADMINSLUG ) . '</strong></p></div>';
1410
+ }
1411
+
1412
+ if ( ( false === $gtm4wp_user_notices_dismisses['wc-ga-plugin-warning'] ) || ( false === $gtm4wp_user_notices_dismisses['wc-gayoast-plugin-warning'] ) ) {
1413
+ $is_wc_active = $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC ] ||
1414
+ $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ||
1415
+ $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ];
1416
+
1417
+ if ( ( false === $gtm4wp_user_notices_dismisses['wc-ga-plugin-warning'] ) && $is_wc_active && is_plugin_active( 'woocommerce-google-analytics-integration/woocommerce-google-analytics-integration.php' ) ) {
1418
+ echo '<div class="gtm4wp-notice notice notice-warning is-dismissible" data-href="?wc-ga-plugin-warning"><p><strong>' . __( 'Notice: you should deactivate the plugin "WooCommerce Google Analytics Integration" if you are using Google Analytics tags inside Google Tag Manager!', 'duracelltomi-google-tag-manager' ) . '</strong></p></div>';
1419
+ }
1420
+
1421
+ if ( ( false === $gtm4wp_user_notices_dismisses['wc-gayoast-plugin-warning'] ) && $is_wc_active && is_plugin_active( 'google-analytics-for-wordpress/googleanalytics.php' ) ) {
1422
+ echo '<div class="gtm4wp-notice notice notice-warning is-dismissible" data-href="?wc-gayoast-plugin-warning"><p><strong>' . __( 'Notice: you should deactivate the plugin "Google Analytics for WordPress by MonsterInsights" if you are using Google Analytics tags inside Google Tag Manager!', 'duracelltomi-google-tag-manager' ) . '</strong></p></div>';
1423
+ }
1424
+ }
1425
+
1426
+ if ( ( false === $gtm4wp_user_notices_dismisses['php72-warning'] ) && ( version_compare( PHP_VERSION, '7.2.0' ) < 0 ) ) {
1427
+ echo '<div class="gtm4wp-notice notice notice-warning is-dismissible" data-href="?php72-warning"><p><strong>' . __( 'Warning: You are using an outdated version of PHP (v' . PHP_VERSION . ') that might be not compatible with future versions of the plugin Google Tag Manager for WordPress (GTM4WP). Please consider to upgrade your PHP.', 'duracelltomi-google-tag-manager' ) . '</strong></p></div>';
1428
+ }
1429
+ }
1430
+
1431
+ function gtm4wp_dismiss_notice() {
1432
+ global $gtm4wp_def_user_notices_dismisses, $current_user;
1433
+
1434
+ $gtm4wp_user_notices_dismisses = get_user_meta( $current_user->ID, GTM4WP_USER_NOTICES_KEY, true );
1435
+ if ( $gtm4wp_user_notices_dismisses === '' ) {
1436
+ if ( is_array( $gtm4wp_def_user_notices_dismisses ) ) {
1437
+ $gtm4wp_user_notices_dismisses = $gtm4wp_def_user_notices_dismisses;
1438
+ } else {
1439
+ $gtm4wp_user_notices_dismisses = array();
1440
+ }
1441
+ } else {
1442
+ $gtm4wp_user_notices_dismisses = @unserialize( $gtm4wp_user_notices_dismisses );
1443
+ if ( false === $gtm4wp_user_notices_dismisses || !is_array( $gtm4wp_user_notices_dismisses ) ) {
1444
+ $gtm4wp_user_notices_dismisses = array();
1445
+ }
1446
+ }
1447
+ $gtm4wp_user_notices_dismisses = array_merge( $gtm4wp_def_user_notices_dismisses, $gtm4wp_user_notices_dismisses );
1448
+
1449
+ $noticeid = trim( basename( $_POST['noticeid'] ) );
1450
+ if ( array_key_exists( $noticeid, $gtm4wp_user_notices_dismisses ) ) {
1451
+ $gtm4wp_user_notices_dismisses[ $noticeid ] = true;
1452
+ update_user_meta( $current_user->ID, GTM4WP_USER_NOTICES_KEY, serialize( $gtm4wp_user_notices_dismisses ) );
1453
+ }
1454
+ }
1455
+
1456
+ function gtm4wp_add_plugin_action_links( $links, $file ) {
1457
+ global $gtp4wp_plugin_basename;
1458
+
1459
+ if ( $file != $gtp4wp_plugin_basename ) {
1460
+ return $links;
1461
+ }
1462
+
1463
+ $settings_link = '<a href="' . menu_page_url( GTM4WP_ADMINSLUG, false ) . '">' . esc_html( __( 'Settings' ) ) . '</a>';
1464
+
1465
+ array_unshift( $links, $settings_link );
1466
+
1467
+ return $links;
1468
+ }
1469
+
1470
+ function gtm4wp_show_upgrade_notification( $current_plugin_metadata, $new_plugin_metadata ) {
1471
+ if ( isset( $new_plugin_metadata->upgrade_notice ) && strlen( trim( $new_plugin_metadata->upgrade_notice ) ) > 0 ) {
1472
+ echo '<p style="background-color: #d54e21; padding: 10px; color: #f9f9f9; margin-top: 10px"><strong>Important Upgrade Notice:</strong> ';
1473
+ echo esc_html( $new_plugin_metadata->upgrade_notice ), '</p>';
1474
+ }
1475
+ }
1476
+
1477
+ add_action( 'admin_init', 'gtm4wp_admin_init' );
1478
+ add_action( 'admin_menu', 'gtm4wp_add_admin_page' );
1479
+ add_action( 'admin_enqueue_scripts', 'gtm4wp_add_admin_js' );
1480
+ add_action( 'admin_notices', 'gtm4wp_show_warning' );
1481
+ add_action( 'admin_head', 'gtm4wp_admin_head' );
1482
+ add_filter( 'plugin_action_links', 'gtm4wp_add_plugin_action_links', 10, 2 );
1483
+ add_action( 'wp_ajax_gtm4wp_dismiss_notice', 'gtm4wp_dismiss_notice' );
1484
+ add_action( 'in_plugin_update_message-duracelltomi-google-tag-manager-for-wordpress/duracelltomi-google-tag-manager-for-wordpress.php', 'gtm4wp_show_upgrade_notification', 10, 2 );
common/readoptions.php CHANGED
@@ -1,434 +1,465 @@
1
- <?php
2
- define( 'GTM4WP_OPTIONS', 'gtm4wp-options' );
3
- define( 'GTM4WP_OPTION_GTM_CODE', 'gtm-code' );
4
- define( 'GTM4WP_OPTION_GTM_PLACEMENT', 'gtm-code-placement' );
5
- define( 'GTM4WP_OPTION_DATALAYER_NAME', 'gtm-datalayer-variable-name' );
6
- define( 'GTM4WP_OPTION_ENV_GTM_AUTH', 'gtm-env-gtm-auth' );
7
- define( 'GTM4WP_OPTION_ENV_GTM_PREVIEW', 'gtm-env-gtm-preview' );
8
- define( 'GTM4WP_OPTION_DONOTTRACK', 'gtm-browser-do-not-track' );
9
- define( 'GTM4WP_OPTION_LOADEARLY', 'gtm-load-gtm-early' );
10
-
11
- define( 'GTM4WP_OPTION_INCLUDE_REMARKETING', 'include-remarketing' );
12
- define( 'GTM4WP_OPTION_INCLUDE_LOGGEDIN', 'include-loggedin' );
13
- define( 'GTM4WP_OPTION_INCLUDE_USERROLE', 'include-userrole' );
14
- define( 'GTM4WP_OPTION_INCLUDE_USERID', 'include-userid' );
15
- define( 'GTM4WP_OPTION_INCLUDE_USEREMAIL', 'include-useremail' );
16
- define( 'GTM4WP_OPTION_INCLUDE_USERREGDATE', 'include-userregdate' );
17
- define( 'GTM4WP_OPTION_INCLUDE_USERNAME', 'include-username' );
18
- define( 'GTM4WP_OPTION_INCLUDE_VISITOR_IP', 'include-visitor-ip' );
19
- define( 'GTM4WP_OPTION_INCLUDE_POSTTYPE', 'include-posttype' );
20
- define( 'GTM4WP_OPTION_INCLUDE_CATEGORIES', 'include-categories' );
21
- define( 'GTM4WP_OPTION_INCLUDE_TAGS', 'include-tags' );
22
- define( 'GTM4WP_OPTION_INCLUDE_AUTHORID', 'include-authorid' );
23
- define( 'GTM4WP_OPTION_INCLUDE_AUTHOR', 'include-author' );
24
- define( 'GTM4WP_OPTION_INCLUDE_POSTDATE', 'include-postdate' );
25
- define( 'GTM4WP_OPTION_INCLUDE_POSTTITLE', 'include-posttitle' );
26
- define( 'GTM4WP_OPTION_INCLUDE_POSTCOUNT', 'include-postcount' );
27
- define( 'GTM4WP_OPTION_INCLUDE_POSTID', 'include-postid' );
28
- define( 'GTM4WP_OPTION_INCLUDE_POSTFORMAT', 'include-postformat' );
29
- define( 'GTM4WP_OPTION_INCLUDE_POSTTERMLIST', 'include-postterms' );
30
- define( 'GTM4WP_OPTION_INCLUDE_SEARCHDATA', 'include-searchdata' );
31
- define( 'GTM4WP_OPTION_INCLUDE_BROWSERDATA', 'include-browserdata' );
32
- define( 'GTM4WP_OPTION_INCLUDE_OSDATA', 'include-osdata' );
33
- define( 'GTM4WP_OPTION_INCLUDE_DEVICEDATA', 'include-devicedata' );
34
- define( 'GTM4WP_OPTION_INCLUDE_MISCGEO', 'include-miscgeo' );
35
- define( 'GTM4WP_OPTION_INCLUDE_MISCGEOAPI', 'geo-apikey' );
36
- define( 'GTM4WP_OPTION_INCLUDE_MISCGEOCF', 'include-miscgeo-cloudflare' );
37
- define( 'GTM4WP_OPTION_INCLUDE_WEATHER', 'include-weather' );
38
- define( 'GTM4WP_OPTION_INCLUDE_WEATHERUNITS', 'weather-weatherunits' );
39
- define( 'GTM4WP_OPTION_INCLUDE_WEATHEROWMAPI', 'weather-openweathermap-apikey' );
40
- define( 'GTM4WP_OPTION_INCLUDE_SITEID', 'include-siteid' );
41
- define( 'GTM4WP_OPTION_INCLUDE_SITENAME', 'include-sitename' );
42
-
43
- define( 'GTM4WP_OPTION_EVENTS_FORMMOVE', 'event-form-move' );
44
- define( 'GTM4WP_OPTION_EVENTS_NEWUSERREG', 'event-new-user-registration' );
45
- define( 'GTM4WP_OPTION_EVENTS_USERLOGIN', 'event-user-logged-in' );
46
-
47
- define( 'GTM4WP_OPTION_EVENTS_YOUTUBE', 'event-youtube' );
48
- define( 'GTM4WP_OPTION_EVENTS_VIMEO', 'event-vimeo' );
49
- define( 'GTM4WP_OPTION_EVENTS_SOUNDCLOUD', 'event-soundcloud' );
50
-
51
- define( 'GTM4WP_OPTION_SCROLLER_ENABLED', 'scroller-enabled' );
52
- define( 'GTM4WP_OPTION_SCROLLER_DEBUGMODE', 'scroller-debug-mode' );
53
- define( 'GTM4WP_OPTION_SCROLLER_CALLBACKTIME', 'scroller-callback-time' );
54
- define( 'GTM4WP_OPTION_SCROLLER_DISTANCE', 'scroller-distance' );
55
- define( 'GTM4WP_OPTION_SCROLLER_CONTENTID', 'scroller-contentid' );
56
- define( 'GTM4WP_OPTION_SCROLLER_READERTIME', 'scroller-readertime' );
57
-
58
- define( 'GTM4WP_OPTION_BLACKLIST_ENABLE', 'blacklist-enable' );
59
- define( 'GTM4WP_OPTION_BLACKLIST_SANDBOXED', 'blacklist-sandboxed' );
60
- define( 'GTM4WP_OPTION_BLACKLIST_STATUS', 'blacklist-status' );
61
-
62
- // deprecated options BEGIN
63
- define( 'GTM4WP_OPTION_BLACKLIST_ADADVISOR', 'blacklist-adadvisor' );
64
- define( 'GTM4WP_OPTION_BLACKLIST_ADROLL', 'blacklist-adroll' );
65
- define( 'GTM4WP_OPTION_BLACKLIST_AWCONV', 'blacklist-adwords-conversion' );
66
- define( 'GTM4WP_OPTION_BLACKLIST_AWREMARKET', 'blacklist-adwords-remarketing' );
67
- define( 'GTM4WP_OPTION_BLACKLIST_BIZO', 'blacklist-bizo' );
68
- define( 'GTM4WP_OPTION_BLACKLIST_CLICKTALE', 'blacklist-clicktale' );
69
- define( 'GTM4WP_OPTION_BLACKLIST_COMSCORE', 'blacklist-comscore' );
70
- define( 'GTM4WP_OPTION_BLACKLIST_CUSTOMHTML', 'blacklist-custom-html' );
71
- define( 'GTM4WP_OPTION_BLACKLIST_CUSTOMIMG', 'blacklist-custom-img-tag' );
72
- define( 'GTM4WP_OPTION_BLACKLIST_DBLCLKCOUNT', 'blacklist-doubleclick-counter' );
73
- define( 'GTM4WP_OPTION_BLACKLIST_DBLCLKSALES', 'blacklist-doubleclick-sales' );
74
- define( 'GTM4WP_OPTION_BLACKLIST_GACLASSIC', 'blacklist-google-analytics' );
75
- define( 'GTM4WP_OPTION_BLACKLIST_MARIN', 'blacklist-marin' );
76
- define( 'GTM4WP_OPTION_BLACKLIST_MPLEXIFRAME', 'blacklist-mediaplex-iframe' );
77
- define( 'GTM4WP_OPTION_BLACKLIST_MPLEXROI', 'blacklist-mediaplex-roi' );
78
- define( 'GTM4WP_OPTION_BLACKLIST_MEDIA6DEG', 'blacklist-media6degrees' );
79
- define( 'GTM4WP_OPTION_BLACKLIST_TURNCONV', 'blacklist-turn-conversion' );
80
- define( 'GTM4WP_OPTION_BLACKLIST_TURNDATA', 'blacklist-turn-data' );
81
- define( 'GTM4WP_OPTION_BLACKLIST_UA', 'blacklist-universal-analytics' );
82
-
83
- define( 'GTM4WP_OPTION_BLACKLIST_MACRO_DOMELEMENT', 'blacklist-macro-dom-element' );
84
- define( 'GTM4WP_OPTION_BLACKLIST_MACRO_CUSTOMJS', 'blacklist-macro-custom-js' );
85
- define( 'GTM4WP_OPTION_BLACKLIST_MACRO_CONSTANT', 'blacklist-macro-constant-string' );
86
- define( 'GTM4WP_OPTION_BLACKLIST_MACRO_1STCOOKIE', 'blacklist-macro-1st-party-cookie' );
87
- define( 'GTM4WP_OPTION_BLACKLIST_MACRO_EVENTNAME', 'blacklist-macro-event-name' );
88
- define( 'GTM4WP_OPTION_BLACKLIST_MACRO_JSVAR', 'blacklist-macro-javascript-variable' );
89
- define( 'GTM4WP_OPTION_BLACKLIST_MACRO_DLAYERVAR', 'blacklist-macro-datalayer-variable' );
90
- define( 'GTM4WP_OPTION_BLACKLIST_MACRO_RANDOMNUM', 'blacklist-macro-random-number' );
91
- define( 'GTM4WP_OPTION_BLACKLIST_MACRO_REFERRER', 'blacklist-macro-referrer' );
92
- define( 'GTM4WP_OPTION_BLACKLIST_MACRO_URL', 'blacklist-macro-url' );
93
- define( 'GTM4WP_OPTION_BLACKLIST_MACRO_AUTOEVENT', 'blacklist-macro-autoevent-variable' );
94
- // deprecated options END
95
-
96
- define( 'GTM4WP_OPTION_INTEGRATE_WPCF7', 'integrate-wpcf7' );
97
-
98
- define( 'GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC', 'integrate-woocommerce-track-classic-ecommerce' );
99
- define( 'GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC', 'integrate-woocommerce-track-enhanced-ecommerce' );
100
- define( 'GTM4WP_OPTION_INTEGRATE_WCPRODPERIMPRESSION', 'integrate-woocommerce-product-per-impression' );
101
- define( 'GTM4WP_OPTION_INTEGRATE_WCEECCARTASFIRSTSTEP', 'integrate-woocommerce-cart-as-first-step' );
102
- define( 'GTM4WP_OPTION_INTEGRATE_WCEINCLUDECARTINDL', 'integrate-woocommerce-cart-content-in-datalayer' );
103
- define( 'GTM4WP_OPTION_INTEGRATE_WCEECBRANDTAXONOMY', 'integrate-woocommerce-brand-taxonomy' );
104
- define( 'GTM4WP_OPTION_INTEGRATE_WCREMARKETING', 'integrate-woocommerce-remarketing' );
105
- define( 'GTM4WP_OPTION_INTEGRATE_WCUSESKU', 'integrate-woocommerce-remarketing-usesku' );
106
- define( 'GTM4WP_OPTION_INTEGRATE_WCUSEFULLCATEGORYPATH', 'integrate-woocommerce-use-full-category-path' );
107
- define( 'GTM4WP_OPTION_INTEGRATE_WCREMPRODIDPREFIX', 'integrate-woocommerce-remarketing-productidprefix' );
108
- define( 'GTM4WP_OPTION_INTEGRATE_WCCUSTOMERDATA', 'integrate-woocommerce-customer-data' );
109
- define( 'GTM4WP_OPTION_INTEGRATE_WCORDERDATA', 'integrate-woocommerce-order-data' );
110
- define( 'GTM4WP_OPTION_INTEGRATE_WCEXCLUDETAX', 'integrate-woocommerce-exclude-tax' );
111
- define( 'GTM4WP_OPTION_INTEGRATE_WCEXCLUDESHIPPING', 'integrate-woocommerce-exclude-shipping' );
112
- define( 'GTM4WP_OPTION_INTEGRATE_WCNOORDERTRACKEDFLAG', 'integrate-woocommerce-do-not-use-order-tracked-flag' );
113
-
114
- define( 'GTM4WP_OPTION_INTEGRATE_GOOGLEOPTIMIZEIDS', 'integrate-google-optimize-idlist' );
115
- define( 'GTM4WP_OPTION_INTEGRATE_GOOGLEOPTIMIZETIMEOUT', 'integrate-google-optimize-timeout' );
116
-
117
- define( 'GTM4WP_OPTION_INTEGRATE_WPECOMMERCE', 'integrate-wp-e-commerce' );
118
-
119
- define( 'GTM4WP_OPTION_INTEGRATE_AMPID', 'integrate-amp-id' );
120
-
121
- define( 'GTM4WP_PLACEMENT_FOOTER', 0 );
122
- define( 'GTM4WP_PLACEMENT_BODYOPEN', 1 );
123
- define( 'GTM4WP_PLACEMENT_BODYOPEN_AUTO', 2 );
124
- define( 'GTM4WP_PLACEMENT_OFF', 3 );
125
-
126
- global $gtm4wp_options, $gtm4wp_defaultoptions, $gtm4wp_entity_ids;
127
-
128
- $gtm4wp_options = array();
129
-
130
- $gtm4wp_defaultoptions = array(
131
- GTM4WP_OPTION_GTM_CODE => '',
132
- GTM4WP_OPTION_DATALAYER_NAME => '',
133
- GTM4WP_OPTION_GTM_PLACEMENT => GTM4WP_PLACEMENT_FOOTER,
134
- GTM4WP_OPTION_ENV_GTM_AUTH => '',
135
- GTM4WP_OPTION_ENV_GTM_PREVIEW => '',
136
- GTM4WP_OPTION_DONOTTRACK => false,
137
- GTM4WP_OPTION_LOADEARLY => false,
138
-
139
- GTM4WP_OPTION_INCLUDE_REMARKETING => false,
140
- GTM4WP_OPTION_INCLUDE_LOGGEDIN => false,
141
- GTM4WP_OPTION_INCLUDE_USERROLE => false,
142
- GTM4WP_OPTION_INCLUDE_USERID => false,
143
- GTM4WP_OPTION_INCLUDE_USEREMAIL => false,
144
- GTM4WP_OPTION_INCLUDE_USERREGDATE => false,
145
- GTM4WP_OPTION_INCLUDE_USERNAME => false,
146
- GTM4WP_OPTION_INCLUDE_VISITOR_IP => false,
147
- GTM4WP_OPTION_INCLUDE_POSTTYPE => true,
148
- GTM4WP_OPTION_INCLUDE_CATEGORIES => true,
149
- GTM4WP_OPTION_INCLUDE_TAGS => true,
150
- GTM4WP_OPTION_INCLUDE_AUTHOR => true,
151
- GTM4WP_OPTION_INCLUDE_AUTHORID => false,
152
- GTM4WP_OPTION_INCLUDE_POSTDATE => false,
153
- GTM4WP_OPTION_INCLUDE_POSTTITLE => false,
154
- GTM4WP_OPTION_INCLUDE_POSTCOUNT => false,
155
- GTM4WP_OPTION_INCLUDE_POSTID => false,
156
- GTM4WP_OPTION_INCLUDE_POSTFORMAT => false,
157
- GTM4WP_OPTION_INCLUDE_POSTTERMLIST => false,
158
- GTM4WP_OPTION_INCLUDE_SEARCHDATA => false,
159
- GTM4WP_OPTION_INCLUDE_BROWSERDATA => false,
160
- GTM4WP_OPTION_INCLUDE_OSDATA => false,
161
- GTM4WP_OPTION_INCLUDE_DEVICEDATA => false,
162
- GTM4WP_OPTION_INCLUDE_MISCGEO => false,
163
- GTM4WP_OPTION_INCLUDE_MISCGEOAPI => '',
164
- GTM4WP_OPTION_INCLUDE_MISCGEOCF => false,
165
- GTM4WP_OPTION_INCLUDE_WEATHER => false,
166
- GTM4WP_OPTION_INCLUDE_WEATHERUNITS => 0,
167
- GTM4WP_OPTION_INCLUDE_WEATHEROWMAPI => '',
168
- GTM4WP_OPTION_INCLUDE_SITEID => false,
169
- GTM4WP_OPTION_INCLUDE_SITENAME => false,
170
-
171
- GTM4WP_OPTION_EVENTS_FORMMOVE => false,
172
- GTM4WP_OPTION_EVENTS_NEWUSERREG => false,
173
- GTM4WP_OPTION_EVENTS_USERLOGIN => false,
174
-
175
- GTM4WP_OPTION_EVENTS_YOUTUBE => false,
176
- GTM4WP_OPTION_EVENTS_VIMEO => false,
177
- GTM4WP_OPTION_EVENTS_SOUNDCLOUD => false,
178
-
179
- GTM4WP_OPTION_SCROLLER_ENABLED => false,
180
- GTM4WP_OPTION_SCROLLER_DEBUGMODE => false,
181
- GTM4WP_OPTION_SCROLLER_CALLBACKTIME => 100,
182
- GTM4WP_OPTION_SCROLLER_DISTANCE => 150,
183
- GTM4WP_OPTION_SCROLLER_CONTENTID => 'content',
184
- GTM4WP_OPTION_SCROLLER_READERTIME => 60,
185
-
186
- GTM4WP_OPTION_BLACKLIST_ENABLE => 0,
187
- GTM4WP_OPTION_BLACKLIST_SANDBOXED => false,
188
- GTM4WP_OPTION_BLACKLIST_STATUS => '',
189
-
190
- GTM4WP_OPTION_INTEGRATE_WPCF7 => false,
191
-
192
- GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC => false,
193
- GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC => false,
194
- GTM4WP_OPTION_INTEGRATE_WCPRODPERIMPRESSION => 0,
195
- GTM4WP_OPTION_INTEGRATE_WCEECCARTASFIRSTSTEP => false,
196
- GTM4WP_OPTION_INTEGRATE_WCEINCLUDECARTINDL => false,
197
- GTM4WP_OPTION_INTEGRATE_WCEECBRANDTAXONOMY => '',
198
- GTM4WP_OPTION_INTEGRATE_WCREMARKETING => false,
199
- GTM4WP_OPTION_INTEGRATE_WCUSESKU => false,
200
- GTM4WP_OPTION_INTEGRATE_WCUSEFULLCATEGORYPATH => false,
201
- GTM4WP_OPTION_INTEGRATE_WCREMPRODIDPREFIX => '',
202
- GTM4WP_OPTION_INTEGRATE_WCCUSTOMERDATA => false,
203
- GTM4WP_OPTION_INTEGRATE_WCORDERDATA => false,
204
- GTM4WP_OPTION_INTEGRATE_WCEXCLUDETAX => false,
205
- GTM4WP_OPTION_INTEGRATE_WCEXCLUDESHIPPING => false,
206
- GTM4WP_OPTION_INTEGRATE_WCNOORDERTRACKEDFLAG => false,
207
-
208
- GTM4WP_OPTION_INTEGRATE_GOOGLEOPTIMIZEIDS => '',
209
- GTM4WP_OPTION_INTEGRATE_GOOGLEOPTIMIZETIMEOUT => 4000,
210
-
211
- GTM4WP_OPTION_INTEGRATE_WPECOMMERCE => false,
212
-
213
- GTM4WP_OPTION_INTEGRATE_AMPID => ''
214
- );
215
-
216
- $gtm4wp_entity_ids = array(
217
- 'tags' => array(
218
- 'abtGeneric' => 'AB TASTY Generic Tag',
219
- 'ta' => 'AdAdvisor Tag',
220
- 'adm' => 'Adometry Tag',
221
- 'asp' => 'AdRoll Smart Pixel Tag',
222
- 'awct' => 'Google Ads Conversion Tracking Tag',
223
- 'sp' => 'Google Ads Remarketing Tag',
224
- 'awc' => 'Affiliate Window Conversion Tag',
225
- 'awj' => 'Affiliate Window Journey Tag',
226
- 'baut' => 'Bing Ads Universal Event Tracking',
227
- 'bb' => 'Bizrate Insights Buyer Survey Solution',
228
- 'bsa' => 'Bizrate Insights Site Abandonment Survey Solution',
229
- 'cts' => 'ClickTale Standard Tracking Tag',
230
- 'csm' => 'comScore Unified Digital Measurement Tag',
231
- 'mpm' => 'Conversant Mediaplex - IFRAME MCT Tag',
232
- 'mpr' => 'Conversant Mediaplex - Standard IMG ROI Tag',
233
- 'gclidw' => 'Conversion Linker',
234
- 'cegg' => 'Crazy Egg Tag',
235
- 'crto' => 'Criteo OneTag',
236
- 'html' => 'Custom HTML Tag',
237
- 'img' => 'Custom Image Tag',
238
- 'dstag' => 'DistroScale Tag',
239
- 'flc' => 'Floodlight Counter Tag',
240
- 'fls' => 'Floodlight Sales Tag',
241
- 'm6d' => 'Dstillery Universal Pixel Tag',
242
- 'ela' => 'Eulerian Analytics Tag',
243
- 'ga' => 'Google Analytics Tag (classic, legacy)',
244
- 'ua' => 'Google Analytics Tag (universal, latest)',
245
- 'gcs' => 'Google Consumer Surveys Website Satisfaction',
246
- 'opt' => 'Google Optimize',
247
- 'ts' => 'Google Trusted Stores Tag',
248
- 'hjtc' => 'Hotjar Tracking Code',
249
- 'infinity' => 'Infinity Call Tracking Tag',
250
- 'sca' => 'Intent Media - Search Compare Ads',
251
- 'k50Init' => 'K50 tracking tag',
252
- 'll' => 'LeadLab',
253
- 'bzi' => 'LinkedIn Tag',
254
- 'ljs' => 'Lytics JS Tag',
255
- 'ms' => 'Marin Software Tag',
256
- 'mpm' => 'Mediaplex - IFRAME MCT Tag',
257
- 'mpr' => 'Mediaplex - Standard IMG ROI Tag',
258
- 'messagemate' => 'Message Mate',
259
- 'mf' => 'Mouseflow Tag',
260
- 'ta' => 'Neustar Pixel',
261
- 'ndcr' => 'Nielsen DCR Static Lite Tag',
262
- 'nudge' => 'Nudge Content Analytics Tag',
263
- 'okt' => 'Oktopost Tracking Code',
264
- 'omc' => 'Optimise Conversion Tag',
265
- 'messagemate' => 'OwnerListens Message Mate',
266
- 'pa' => 'Perfect Audience Pixel',
267
- 'pc' => 'Personali Canvas',
268
- 'pntr' => 'Pinterest',
269
- 'placedPixel' => 'Placed',
270
- 'pijs' => 'Pulse Insights Voice of Customer Platform',
271
- 'qcm' => 'Quantcast Audience Measurement',
272
- 'qpx' => 'Quora Pixel',
273
- 'fxm' => 'Rawsoft FoxMetrics',
274
- 'scjs' => 'SaleCycle JavaScript Tag',
275
- 'scp' => 'SaleCycle Pixel Tag',
276
- 'sfc' => 'SearchForce JavaScript Tracking for Conversion Page',
277
- 'sfl' => 'SearchForce JavaScript Tracking for Landing Page',
278
- 'sfr' => 'SearchForce Redirection Tracking Tag',
279
- 'shareaholic' => 'Shareaholic',
280
- 'svw' => 'Survicate Widget',
281
- 'tdlc' => 'Tradedoubler Lead Conversion Tag',
282
- 'tdsc' => 'Tradedoubler Sale Conversion Tag',
283
- 'tc' => 'Turn Conversion Tracking Tag',
284
- 'tdc' => 'Turn Data Collection Tag',
285
- 'twitter_website_tag' => 'Twitter Universal Website Tag',
286
- 'uslt' => 'Upsellit Global Footer Tag',
287
- 'uspt' => 'Upsellit Confirmation Tag',
288
- 'vei' => 'Ve Interactive JavaScript Tag',
289
- 'veip' => 'Ve Interactive Pixel',
290
- 'vdc' => 'VisualDNA Conversion Tag',
291
- 'xpsh' => 'Xtremepush',
292
- 'yieldify' => 'Yieldify',
293
- 'zone' => 'Zones'
294
- ),
295
- 'triggers' => array(
296
- 'evl' => 'Element Visibility Listener/Trigger',
297
- 'cl' => 'Click Listener/Trigger',
298
- 'fsl' => 'Form Submit Listener/Trigger',
299
- 'hl' => 'History Listener/Trigger',
300
- 'jel' => 'JavaScript Error Listener/Trigger',
301
- 'lcl' => 'Link Click Listener/Trigger',
302
- 'sdl' => 'Scroll Depth Listener/Trigger',
303
- 'tl' => 'Timer Listener/Trigger',
304
- 'ytl' => 'YouTube Video Listener/Trigger'
305
- ),
306
- 'variables' => array(
307
- 'k' => '1st Party Cookie',
308
- 'c' => 'Constant',
309
- 'ctv' => 'Container Version Number',
310
- 'e' => 'Custom Event',
311
- 'jsm' => 'Custom JavaScript Variable',
312
- 'v' => 'Data Layer Variable',
313
- 'dbg' => 'Debug Mode',
314
- 'd' => 'DOM Element',
315
- 'vis' => 'Element Visibility',
316
- 'f' => 'HTTP Referrer',
317
- 'j' => 'JavaScript Variable',
318
- 'smm' => 'Lookup Table',
319
- 'r' => 'Random Number',
320
- 'remm' => 'RegEx Table',
321
- 'u' => 'URL'
322
- )
323
- );
324
-
325
- function gtm4wp_migrate_blacklist_whitelist( $current_options ) {
326
- if ( ( array_key_exists( GTM4WP_OPTION_BLACKLIST_ENABLE, $current_options ) )
327
- && ( $current_options[ GTM4WP_OPTION_BLACKLIST_ENABLE ] > 0 )
328
- ) {
329
- $_gtmrestrictlistitems = array();
330
-
331
- // IDs from https://developers.google.com/tag-manager/devguide#security
332
- if ( $current_options[ GTM4WP_OPTION_BLACKLIST_ADADVISOR ] ) {
333
- $_gtmrestrictlistitems[] = 'ta';
334
- }
335
- if ( $current_options[ GTM4WP_OPTION_BLACKLIST_ADROLL ] ) {
336
- $_gtmrestrictlistitems[] = 'asp';
337
- }
338
- if ( $current_options[ GTM4WP_OPTION_BLACKLIST_AWCONV ] ) {
339
- $_gtmrestrictlistitems[] = 'awct';
340
- }
341
- if ( $current_options[ GTM4WP_OPTION_BLACKLIST_AWREMARKET ] ) {
342
- $_gtmrestrictlistitems[] = 'sp';
343
- }
344
- if ( $current_options[ GTM4WP_OPTION_BLACKLIST_BIZO ] ) {
345
- $_gtmrestrictlistitems[] = 'bzi';
346
- }
347
- if ( $current_options[ GTM4WP_OPTION_BLACKLIST_CLICKTALE ] ) {
348
- $_gtmrestrictlistitems[] = 'cts';
349
- }
350
- if ( $current_options[ GTM4WP_OPTION_BLACKLIST_COMSCORE ] ) {
351
- $_gtmrestrictlistitems[] = 'csm';
352
- }
353
- if ( $current_options[ GTM4WP_OPTION_BLACKLIST_CUSTOMHTML ] ) {
354
- $_gtmrestrictlistitems[] = 'html';
355
- }
356
- if ( $current_options[ GTM4WP_OPTION_BLACKLIST_CUSTOMIMG ] ) {
357
- $_gtmrestrictlistitems[] = 'img';
358
- }
359
- if ( $current_options[ GTM4WP_OPTION_BLACKLIST_DBLCLKCOUNT ] ) {
360
- $_gtmrestrictlistitems[] = 'flc';
361
- }
362
- if ( $current_options[ GTM4WP_OPTION_BLACKLIST_DBLCLKSALES ] ) {
363
- $_gtmrestrictlistitems[] = 'fls';
364
- }
365
- if ( $current_options[ GTM4WP_OPTION_BLACKLIST_GACLASSIC ] ) {
366
- $_gtmrestrictlistitems[] = 'ga';
367
- }
368
- if ( $current_options[ GTM4WP_OPTION_BLACKLIST_MARIN ] ) {
369
- $_gtmrestrictlistitems[] = 'ms';
370
- }
371
- if ( $current_options[ GTM4WP_OPTION_BLACKLIST_MPLEXIFRAME ] ) {
372
- $_gtmrestrictlistitems[] = 'mpm';
373
- }
374
- if ( $current_options[ GTM4WP_OPTION_BLACKLIST_MPLEXROI ] ) {
375
- $_gtmrestrictlistitems[] = 'mpr';
376
- }
377
- if ( $current_options[ GTM4WP_OPTION_BLACKLIST_MEDIA6DEG ] ) {
378
- $_gtmrestrictlistitems[] = 'm6d';
379
- }
380
- if ( $current_options[ GTM4WP_OPTION_BLACKLIST_TURNCONV ] ) {
381
- $_gtmrestrictlistitems[] = 'tc';
382
- }
383
- if ( $current_options[ GTM4WP_OPTION_BLACKLIST_TURNDATA ] ) {
384
- $_gtmrestrictlistitems[] = 'tdc';
385
- }
386
- if ( $current_options[ GTM4WP_OPTION_BLACKLIST_UA ] ) {
387
- $_gtmrestrictlistitems[] = 'ua';
388
- }
389
-
390
- $current_options[ GTM4WP_OPTION_BLACKLIST_STATUS ] = implode( ',', $_gtmrestrictlistitems );
391
- }
392
-
393
- return $current_options;
394
- }
395
-
396
- function gtm4wp_reload_options() {
397
- global $gtm4wp_defaultoptions;
398
-
399
- $storedoptions = (array) get_option( GTM4WP_OPTIONS );
400
- if ( ! is_array( $gtm4wp_defaultoptions ) ) {
401
- $gtm4wp_defaultoptions = array();
402
- }
403
-
404
- if ( !isset( $storedoptions[ GTM4WP_OPTION_BLACKLIST_STATUS ] ) ) {
405
- $storedoptions = gtm4wp_migrate_blacklist_whitelist( $storedoptions );
406
- }
407
-
408
- $return_options = array_merge( $gtm4wp_defaultoptions, $storedoptions );
409
- $return_options[ GTM4WP_OPTION_BLACKLIST_STATUS ] = explode( ',', $return_options[ GTM4WP_OPTION_BLACKLIST_STATUS ] );
410
-
411
- if ( defined( 'GTM4WP_HARDCODED_GTM_ID' ) ) {
412
- $return_options[ GTM4WP_OPTION_GTM_CODE ] = GTM4WP_HARDCODED_GTM_ID;
413
- }
414
-
415
- if ( defined( 'GTM4WP_HARDCODED_GTM_ENV_AUTH' ) ) {
416
- $return_options[ GTM4WP_OPTION_ENV_GTM_AUTH ] = GTM4WP_HARDCODED_GTM_ENV_AUTH;
417
- }
418
-
419
- if ( defined( 'GTM4WP_HARDCODED_GTM_ENV_PREVIEW' ) ) {
420
- $return_options[ GTM4WP_OPTION_ENV_GTM_PREVIEW ] = GTM4WP_HARDCODED_GTM_ENV_PREVIEW;
421
- }
422
-
423
- return $return_options;
424
- }
425
-
426
- function gtp4wp_debug_file( $debug_data ) {
427
- $fp = fopen( dirname( __FILE__ ) . '/' . date( 'Y-m-d-H-i-s-u' ) . '.txt', 'w' );
428
- if ( $fp ) {
429
- fwrite( $fp, $debug_data );
430
- fclose( $fp );
431
- }
432
- }
433
-
434
- $gtm4wp_options = gtm4wp_reload_options();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ define( 'GTM4WP_OPTIONS', 'gtm4wp-options' );
3
+ define( 'GTM4WP_OPTION_GTM_CODE', 'gtm-code' );
4
+ define( 'GTM4WP_OPTION_GTM_PLACEMENT', 'gtm-code-placement' );
5
+ define( 'GTM4WP_OPTION_DATALAYER_NAME', 'gtm-datalayer-variable-name' );
6
+ define( 'GTM4WP_OPTION_ENV_GTM_AUTH', 'gtm-env-gtm-auth' );
7
+ define( 'GTM4WP_OPTION_ENV_GTM_PREVIEW', 'gtm-env-gtm-preview' );
8
+ define( 'GTM4WP_OPTION_DONOTTRACK', 'gtm-browser-do-not-track' );
9
+ define( 'GTM4WP_OPTION_LOADEARLY', 'gtm-load-gtm-early' );
10
+ define( 'GTM4WP_OPTION_GTMDOMAIN', 'gtm-domain-name' );
11
+
12
+ define( 'GTM4WP_OPTION_INCLUDE_REMARKETING', 'include-remarketing' );
13
+ define( 'GTM4WP_OPTION_INCLUDE_LOGGEDIN', 'include-loggedin' );
14
+ define( 'GTM4WP_OPTION_INCLUDE_USERROLE', 'include-userrole' );
15
+ define( 'GTM4WP_OPTION_INCLUDE_USERID', 'include-userid' );
16
+ define( 'GTM4WP_OPTION_INCLUDE_USEREMAIL', 'include-useremail' );
17
+ define( 'GTM4WP_OPTION_INCLUDE_USERREGDATE', 'include-userregdate' );
18
+ define( 'GTM4WP_OPTION_INCLUDE_USERNAME', 'include-username' );
19
+ define( 'GTM4WP_OPTION_INCLUDE_VISITOR_IP', 'include-visitor-ip' );
20
+ define( 'GTM4WP_OPTION_INCLUDE_POSTTYPE', 'include-posttype' );
21
+ define( 'GTM4WP_OPTION_INCLUDE_CATEGORIES', 'include-categories' );
22
+ define( 'GTM4WP_OPTION_INCLUDE_TAGS', 'include-tags' );
23
+ define( 'GTM4WP_OPTION_INCLUDE_AUTHORID', 'include-authorid' );
24
+ define( 'GTM4WP_OPTION_INCLUDE_AUTHOR', 'include-author' );
25
+ define( 'GTM4WP_OPTION_INCLUDE_POSTDATE', 'include-postdate' );
26
+ define( 'GTM4WP_OPTION_INCLUDE_POSTTITLE', 'include-posttitle' );
27
+ define( 'GTM4WP_OPTION_INCLUDE_POSTCOUNT', 'include-postcount' );
28
+ define( 'GTM4WP_OPTION_INCLUDE_POSTID', 'include-postid' );
29
+ define( 'GTM4WP_OPTION_INCLUDE_POSTFORMAT', 'include-postformat' );
30
+ define( 'GTM4WP_OPTION_INCLUDE_POSTTERMLIST', 'include-postterms' );
31
+ define( 'GTM4WP_OPTION_INCLUDE_SEARCHDATA', 'include-searchdata' );
32
+ define( 'GTM4WP_OPTION_INCLUDE_BROWSERDATA', 'include-browserdata' );
33
+ define( 'GTM4WP_OPTION_INCLUDE_OSDATA', 'include-osdata' );
34
+ define( 'GTM4WP_OPTION_INCLUDE_DEVICEDATA', 'include-devicedata' );
35
+ define( 'GTM4WP_OPTION_INCLUDE_MISCGEO', 'include-miscgeo' );
36
+ define( 'GTM4WP_OPTION_INCLUDE_MISCGEOAPI', 'geo-apikey' );
37
+ define( 'GTM4WP_OPTION_INCLUDE_MISCGEOCF', 'include-miscgeo-cloudflare' );
38
+ define( 'GTM4WP_OPTION_INCLUDE_WEATHER', 'include-weather' );
39
+ define( 'GTM4WP_OPTION_INCLUDE_WEATHERUNITS', 'weather-weatherunits' );
40
+ define( 'GTM4WP_OPTION_INCLUDE_WEATHEROWMAPI', 'weather-openweathermap-apikey' );
41
+ define( 'GTM4WP_OPTION_INCLUDE_SITEID', 'include-siteid' );
42
+ define( 'GTM4WP_OPTION_INCLUDE_SITENAME', 'include-sitename' );
43
+
44
+ define( 'GTM4WP_OPTION_EVENTS_FORMMOVE', 'event-form-move' );
45
+ define( 'GTM4WP_OPTION_EVENTS_NEWUSERREG', 'event-new-user-registration' );
46
+ define( 'GTM4WP_OPTION_EVENTS_USERLOGIN', 'event-user-logged-in' );
47
+
48
+ define( 'GTM4WP_OPTION_EVENTS_YOUTUBE', 'event-youtube' );
49
+ define( 'GTM4WP_OPTION_EVENTS_VIMEO', 'event-vimeo' );
50
+ define( 'GTM4WP_OPTION_EVENTS_SOUNDCLOUD', 'event-soundcloud' );
51
+
52
+ define( 'GTM4WP_OPTION_SCROLLER_ENABLED', 'scroller-enabled' );
53
+ define( 'GTM4WP_OPTION_SCROLLER_DEBUGMODE', 'scroller-debug-mode' );
54
+ define( 'GTM4WP_OPTION_SCROLLER_CALLBACKTIME', 'scroller-callback-time' );
55
+ define( 'GTM4WP_OPTION_SCROLLER_DISTANCE', 'scroller-distance' );
56
+ define( 'GTM4WP_OPTION_SCROLLER_CONTENTID', 'scroller-contentid' );
57
+ define( 'GTM4WP_OPTION_SCROLLER_READERTIME', 'scroller-readertime' );
58
+
59
+ define( 'GTM4WP_OPTION_BLACKLIST_ENABLE', 'blacklist-enable' );
60
+ define( 'GTM4WP_OPTION_BLACKLIST_SANDBOXED', 'blacklist-sandboxed' );
61
+ define( 'GTM4WP_OPTION_BLACKLIST_STATUS', 'blacklist-status' );
62
+
63
+ // deprecated options BEGIN
64
+ define( 'GTM4WP_OPTION_BLACKLIST_ADADVISOR', 'blacklist-adadvisor' );
65
+ define( 'GTM4WP_OPTION_BLACKLIST_ADROLL', 'blacklist-adroll' );
66
+ define( 'GTM4WP_OPTION_BLACKLIST_AWCONV', 'blacklist-adwords-conversion' );
67
+ define( 'GTM4WP_OPTION_BLACKLIST_AWREMARKET', 'blacklist-adwords-remarketing' );
68
+ define( 'GTM4WP_OPTION_BLACKLIST_BIZO', 'blacklist-bizo' );
69
+ define( 'GTM4WP_OPTION_BLACKLIST_CLICKTALE', 'blacklist-clicktale' );
70
+ define( 'GTM4WP_OPTION_BLACKLIST_COMSCORE', 'blacklist-comscore' );
71
+ define( 'GTM4WP_OPTION_BLACKLIST_CUSTOMHTML', 'blacklist-custom-html' );
72
+ define( 'GTM4WP_OPTION_BLACKLIST_CUSTOMIMG', 'blacklist-custom-img-tag' );
73
+ define( 'GTM4WP_OPTION_BLACKLIST_DBLCLKCOUNT', 'blacklist-doubleclick-counter' );
74
+ define( 'GTM4WP_OPTION_BLACKLIST_DBLCLKSALES', 'blacklist-doubleclick-sales' );
75
+ define( 'GTM4WP_OPTION_BLACKLIST_GACLASSIC', 'blacklist-google-analytics' );
76
+ define( 'GTM4WP_OPTION_BLACKLIST_MARIN', 'blacklist-marin' );
77
+ define( 'GTM4WP_OPTION_BLACKLIST_MPLEXIFRAME', 'blacklist-mediaplex-iframe' );
78
+ define( 'GTM4WP_OPTION_BLACKLIST_MPLEXROI', 'blacklist-mediaplex-roi' );
79
+ define( 'GTM4WP_OPTION_BLACKLIST_MEDIA6DEG', 'blacklist-media6degrees' );
80
+ define( 'GTM4WP_OPTION_BLACKLIST_TURNCONV', 'blacklist-turn-conversion' );
81
+ define( 'GTM4WP_OPTION_BLACKLIST_TURNDATA', 'blacklist-turn-data' );
82
+ define( 'GTM4WP_OPTION_BLACKLIST_UA', 'blacklist-universal-analytics' );
83
+
84
+ define( 'GTM4WP_OPTION_BLACKLIST_MACRO_DOMELEMENT', 'blacklist-macro-dom-element' );
85
+ define( 'GTM4WP_OPTION_BLACKLIST_MACRO_CUSTOMJS', 'blacklist-macro-custom-js' );
86
+ define( 'GTM4WP_OPTION_BLACKLIST_MACRO_CONSTANT', 'blacklist-macro-constant-string' );
87
+ define( 'GTM4WP_OPTION_BLACKLIST_MACRO_1STCOOKIE', 'blacklist-macro-1st-party-cookie' );
88
+ define( 'GTM4WP_OPTION_BLACKLIST_MACRO_EVENTNAME', 'blacklist-macro-event-name' );
89
+ define( 'GTM4WP_OPTION_BLACKLIST_MACRO_JSVAR', 'blacklist-macro-javascript-variable' );
90
+ define( 'GTM4WP_OPTION_BLACKLIST_MACRO_DLAYERVAR', 'blacklist-macro-datalayer-variable' );
91
+ define( 'GTM4WP_OPTION_BLACKLIST_MACRO_RANDOMNUM', 'blacklist-macro-random-number' );
92
+ define( 'GTM4WP_OPTION_BLACKLIST_MACRO_REFERRER', 'blacklist-macro-referrer' );
93
+ define( 'GTM4WP_OPTION_BLACKLIST_MACRO_URL', 'blacklist-macro-url' );
94
+ define( 'GTM4WP_OPTION_BLACKLIST_MACRO_AUTOEVENT', 'blacklist-macro-autoevent-variable' );
95
+ // deprecated options END
96
+
97
+ define( 'GTM4WP_OPTION_INTEGRATE_WPCF7', 'integrate-wpcf7' );
98
+
99
+ define( 'GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC', 'integrate-woocommerce-track-classic-ecommerce' );
100
+ define( 'GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC', 'integrate-woocommerce-track-enhanced-ecommerce' );
101
+ define( 'GTM4WP_OPTION_INTEGRATE_WCPRODPERIMPRESSION', 'integrate-woocommerce-product-per-impression' );
102
+ define( 'GTM4WP_OPTION_INTEGRATE_WCEECCARTASFIRSTSTEP', 'integrate-woocommerce-cart-as-first-step' );
103
+ define( 'GTM4WP_OPTION_INTEGRATE_WCEINCLUDECARTINDL', 'integrate-woocommerce-cart-content-in-datalayer' );
104
+ define( 'GTM4WP_OPTION_INTEGRATE_WCEECBRANDTAXONOMY', 'integrate-woocommerce-brand-taxonomy' );
105
+ define( 'GTM4WP_OPTION_INTEGRATE_WCREMARKETING', 'integrate-woocommerce-remarketing' );
106
+ define( 'GTM4WP_OPTION_INTEGRATE_WCBUSINESSVERTICAL', 'integrate-woocommerce-business-vertical' );
107
+ define( 'GTM4WP_OPTION_INTEGRATE_WCUSESKU', 'integrate-woocommerce-remarketing-usesku' );
108
+ define( 'GTM4WP_OPTION_INTEGRATE_WCUSEFULLCATEGORYPATH', 'integrate-woocommerce-use-full-category-path' );
109
+ define( 'GTM4WP_OPTION_INTEGRATE_WCREMPRODIDPREFIX', 'integrate-woocommerce-remarketing-productidprefix' );
110
+ define( 'GTM4WP_OPTION_INTEGRATE_WCCUSTOMERDATA', 'integrate-woocommerce-customer-data' );
111
+ define( 'GTM4WP_OPTION_INTEGRATE_WCORDERDATA', 'integrate-woocommerce-order-data' );
112
+ define( 'GTM4WP_OPTION_INTEGRATE_WCORDERMAXAGE', 'integrate-woocommerce-order-max-age' );
113
+ define( 'GTM4WP_OPTION_INTEGRATE_WCEXCLUDETAX', 'integrate-woocommerce-exclude-tax' );
114
+ define( 'GTM4WP_OPTION_INTEGRATE_WCEXCLUDESHIPPING', 'integrate-woocommerce-exclude-shipping' );
115
+ define( 'GTM4WP_OPTION_INTEGRATE_WCNOORDERTRACKEDFLAG', 'integrate-woocommerce-do-not-use-order-tracked-flag' );
116
+
117
+ define( 'GTM4WP_OPTION_INTEGRATE_GOOGLEOPTIMIZEIDS', 'integrate-google-optimize-idlist' );
118
+ define( 'GTM4WP_OPTION_INTEGRATE_GOOGLEOPTIMIZETIMEOUT', 'integrate-google-optimize-timeout' );
119
+
120
+ define( 'GTM4WP_OPTION_INTEGRATE_WPECOMMERCE', 'integrate-wp-e-commerce' );
121
+
122
+ define( 'GTM4WP_OPTION_INTEGRATE_AMPID', 'integrate-amp-id' );
123
+
124
+ define( 'GTM4WP_OPTION_INTEGRATE_COOKIEBOT', 'integrate-cookiebot' );
125
+
126
+ define( 'GTM4WP_PLACEMENT_FOOTER', 0 );
127
+ define( 'GTM4WP_PLACEMENT_BODYOPEN', 1 );
128
+ define( 'GTM4WP_PLACEMENT_BODYOPEN_AUTO', 2 );
129
+ define( 'GTM4WP_PLACEMENT_OFF', 3 );
130
+
131
+ global $gtm4wp_options, $gtm4wp_defaultoptions, $gtm4wp_entity_ids;
132
+
133
+ $gtm4wp_options = array();
134
+
135
+ $gtm4wp_defaultoptions = array(
136
+ GTM4WP_OPTION_GTM_CODE => '',
137
+ GTM4WP_OPTION_DATALAYER_NAME => '',
138
+ GTM4WP_OPTION_GTM_PLACEMENT => GTM4WP_PLACEMENT_FOOTER,
139
+ GTM4WP_OPTION_ENV_GTM_AUTH => '',
140
+ GTM4WP_OPTION_ENV_GTM_PREVIEW => '',
141
+ GTM4WP_OPTION_DONOTTRACK => false,
142
+ GTM4WP_OPTION_LOADEARLY => false,
143
+ GTM4WP_OPTION_GTMDOMAIN => '',
144
+
145
+ GTM4WP_OPTION_INCLUDE_REMARKETING => false,
146
+ GTM4WP_OPTION_INCLUDE_LOGGEDIN => false,
147
+ GTM4WP_OPTION_INCLUDE_USERROLE => false,
148
+ GTM4WP_OPTION_INCLUDE_USERID => false,
149
+ GTM4WP_OPTION_INCLUDE_USEREMAIL => false,
150
+ GTM4WP_OPTION_INCLUDE_USERREGDATE => false,
151
+ GTM4WP_OPTION_INCLUDE_USERNAME => false,
152
+ GTM4WP_OPTION_INCLUDE_VISITOR_IP => false,
153
+ GTM4WP_OPTION_INCLUDE_POSTTYPE => true,
154
+ GTM4WP_OPTION_INCLUDE_CATEGORIES => true,
155
+ GTM4WP_OPTION_INCLUDE_TAGS => true,
156
+ GTM4WP_OPTION_INCLUDE_AUTHOR => true,
157
+ GTM4WP_OPTION_INCLUDE_AUTHORID => false,
158
+ GTM4WP_OPTION_INCLUDE_POSTDATE => false,
159
+ GTM4WP_OPTION_INCLUDE_POSTTITLE => false,
160
+ GTM4WP_OPTION_INCLUDE_POSTCOUNT => false,
161
+ GTM4WP_OPTION_INCLUDE_POSTID => false,
162
+ GTM4WP_OPTION_INCLUDE_POSTFORMAT => false,
163
+ GTM4WP_OPTION_INCLUDE_POSTTERMLIST => false,
164
+ GTM4WP_OPTION_INCLUDE_SEARCHDATA => false,
165
+ GTM4WP_OPTION_INCLUDE_BROWSERDATA => false,
166
+ GTM4WP_OPTION_INCLUDE_OSDATA => false,
167
+ GTM4WP_OPTION_INCLUDE_DEVICEDATA => false,
168
+ GTM4WP_OPTION_INCLUDE_MISCGEO => false,
169
+ GTM4WP_OPTION_INCLUDE_MISCGEOAPI => '',
170
+ GTM4WP_OPTION_INCLUDE_MISCGEOCF => false,
171
+ GTM4WP_OPTION_INCLUDE_WEATHER => false,
172
+ GTM4WP_OPTION_INCLUDE_WEATHERUNITS => 0,
173
+ GTM4WP_OPTION_INCLUDE_WEATHEROWMAPI => '',
174
+ GTM4WP_OPTION_INCLUDE_SITEID => false,
175
+ GTM4WP_OPTION_INCLUDE_SITENAME => false,
176
+
177
+ GTM4WP_OPTION_EVENTS_FORMMOVE => false,
178
+ GTM4WP_OPTION_EVENTS_NEWUSERREG => false,
179
+ GTM4WP_OPTION_EVENTS_USERLOGIN => false,
180
+
181
+ GTM4WP_OPTION_EVENTS_YOUTUBE => false,
182
+ GTM4WP_OPTION_EVENTS_VIMEO => false,
183
+ GTM4WP_OPTION_EVENTS_SOUNDCLOUD => false,
184
+
185
+ GTM4WP_OPTION_SCROLLER_ENABLED => false,
186
+ GTM4WP_OPTION_SCROLLER_DEBUGMODE => false,
187
+ GTM4WP_OPTION_SCROLLER_CALLBACKTIME => 100,
188
+ GTM4WP_OPTION_SCROLLER_DISTANCE => 150,
189
+ GTM4WP_OPTION_SCROLLER_CONTENTID => 'content',
190
+ GTM4WP_OPTION_SCROLLER_READERTIME => 60,
191
+
192
+ GTM4WP_OPTION_BLACKLIST_ENABLE => 0,
193
+ GTM4WP_OPTION_BLACKLIST_SANDBOXED => false,
194
+ GTM4WP_OPTION_BLACKLIST_STATUS => '',
195
+
196
+ GTM4WP_OPTION_INTEGRATE_WPCF7 => false,
197
+
198
+ GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC => false,
199
+ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC => false,
200
+ GTM4WP_OPTION_INTEGRATE_WCPRODPERIMPRESSION => 0,
201
+ GTM4WP_OPTION_INTEGRATE_WCEECCARTASFIRSTSTEP => false,
202
+ GTM4WP_OPTION_INTEGRATE_WCEINCLUDECARTINDL => false,
203
+ GTM4WP_OPTION_INTEGRATE_WCEECBRANDTAXONOMY => '',
204
+ GTM4WP_OPTION_INTEGRATE_WCREMARKETING => false,
205
+ GTM4WP_OPTION_INTEGRATE_WCBUSINESSVERTICAL => 'retail',
206
+ GTM4WP_OPTION_INTEGRATE_WCUSESKU => false,
207
+ GTM4WP_OPTION_INTEGRATE_WCUSEFULLCATEGORYPATH => false,
208
+ GTM4WP_OPTION_INTEGRATE_WCREMPRODIDPREFIX => '',
209
+ GTM4WP_OPTION_INTEGRATE_WCCUSTOMERDATA => false,
210
+ GTM4WP_OPTION_INTEGRATE_WCORDERDATA => false,
211
+ GTM4WP_OPTION_INTEGRATE_WCORDERMAXAGE => 30,
212
+ GTM4WP_OPTION_INTEGRATE_WCEXCLUDETAX => false,
213
+ GTM4WP_OPTION_INTEGRATE_WCEXCLUDESHIPPING => false,
214
+ GTM4WP_OPTION_INTEGRATE_WCNOORDERTRACKEDFLAG => false,
215
+
216
+ GTM4WP_OPTION_INTEGRATE_GOOGLEOPTIMIZEIDS => '',
217
+ GTM4WP_OPTION_INTEGRATE_GOOGLEOPTIMIZETIMEOUT => 4000,
218
+
219
+ GTM4WP_OPTION_INTEGRATE_WPECOMMERCE => false,
220
+
221
+ GTM4WP_OPTION_INTEGRATE_AMPID => '',
222
+
223
+ GTM4WP_OPTION_INTEGRATE_COOKIEBOT => false
224
+ );
225
+
226
+ $gtm4wp_business_verticals = array(
227
+ 'retail' => 'Retail',
228
+ 'education' => 'Education',
229
+ 'flights' => 'Flights',
230
+ 'hotel_rental' => 'Hotel rental',
231
+ 'jobs' => 'Jobs',
232
+ 'local' => 'Local deals',
233
+ 'real_estate' => 'Real estate',
234
+ 'travel' => 'Travel',
235
+ 'custom' => 'Custom'
236
+ );
237
+
238
+ $gtm4wp_business_verticals_ids = array(
239
+ 'flights' => 'destination',
240
+ 'travel' => 'destination'
241
+ );
242
+
243
+ $gtm4wp_entity_ids = array(
244
+ 'tags' => array(
245
+ 'abtGeneric' => 'AB TASTY Generic Tag',
246
+ 'ta' => 'AdAdvisor Tag',
247
+ 'adm' => 'Adometry Tag',
248
+ 'asp' => 'AdRoll Smart Pixel Tag',
249
+ 'awct' => 'Google Ads Conversion Tracking Tag',
250
+ 'sp' => 'Google Ads Remarketing Tag',
251
+ 'awc' => 'Affiliate Window Conversion Tag',
252
+ 'awj' => 'Affiliate Window Journey Tag',
253
+ 'baut' => 'Bing Ads Universal Event Tracking',
254
+ 'bb' => 'Bizrate Insights Buyer Survey Solution',
255
+ 'bsa' => 'Bizrate Insights Site Abandonment Survey Solution',
256
+ 'cts' => 'ClickTale Standard Tracking Tag',
257
+ 'csm' => 'comScore Unified Digital Measurement Tag',
258
+ 'mpm' => 'Conversant Mediaplex - IFRAME MCT Tag',
259
+ 'mpr' => 'Conversant Mediaplex - Standard IMG ROI Tag',
260
+ 'gclidw' => 'Conversion Linker',
261
+ 'cegg' => 'Crazy Egg Tag',
262
+ 'crto' => 'Criteo OneTag',
263
+ 'html' => 'Custom HTML Tag',
264
+ 'img' => 'Custom Image Tag',
265
+ 'dstag' => 'DistroScale Tag',
266
+ 'flc' => 'Floodlight Counter Tag',
267
+ 'fls' => 'Floodlight Sales Tag',
268
+ 'm6d' => 'Dstillery Universal Pixel Tag',
269
+ 'ela' => 'Eulerian Analytics Tag',
270
+ 'ga' => 'Google Analytics Tag (classic, legacy)',
271
+ 'ua' => 'Google Analytics Tag (universal, latest)',
272
+ 'gcs' => 'Google Consumer Surveys Website Satisfaction',
273
+ 'opt' => 'Google Optimize',
274
+ 'ts' => 'Google Trusted Stores Tag',
275
+ 'hjtc' => 'Hotjar Tracking Code',
276
+ 'infinity' => 'Infinity Call Tracking Tag',
277
+ 'sca' => 'Intent Media - Search Compare Ads',
278
+ 'k50Init' => 'K50 tracking tag',
279
+ 'll' => 'LeadLab',
280
+ 'bzi' => 'LinkedIn Tag',
281
+ 'ljs' => 'Lytics JS Tag',
282
+ 'ms' => 'Marin Software Tag',
283
+ 'mpm' => 'Mediaplex - IFRAME MCT Tag',
284
+ 'mpr' => 'Mediaplex - Standard IMG ROI Tag',
285
+ 'messagemate' => 'Message Mate',
286
+ 'mf' => 'Mouseflow Tag',
287
+ 'ta' => 'Neustar Pixel',
288
+ 'ndcr' => 'Nielsen DCR Static Lite Tag',
289
+ 'nudge' => 'Nudge Content Analytics Tag',
290
+ 'okt' => 'Oktopost Tracking Code',
291
+ 'omc' => 'Optimise Conversion Tag',
292
+ 'messagemate' => 'OwnerListens Message Mate',
293
+ 'pa' => 'Perfect Audience Pixel',
294
+ 'pc' => 'Personali Canvas',
295
+ 'pntr' => 'Pinterest',
296
+ 'placedPixel' => 'Placed',
297
+ 'pijs' => 'Pulse Insights Voice of Customer Platform',
298
+ 'qcm' => 'Quantcast Audience Measurement',
299
+ 'qpx' => 'Quora Pixel',
300
+ 'fxm' => 'Rawsoft FoxMetrics',
301
+ 'scjs' => 'SaleCycle JavaScript Tag',
302
+ 'scp' => 'SaleCycle Pixel Tag',
303
+ 'sfc' => 'SearchForce JavaScript Tracking for Conversion Page',
304
+ 'sfl' => 'SearchForce JavaScript Tracking for Landing Page',
305
+ 'sfr' => 'SearchForce Redirection Tracking Tag',
306
+ 'shareaholic' => 'Shareaholic',
307
+ 'svw' => 'Survicate Widget',
308
+ 'tdlc' => 'Tradedoubler Lead Conversion Tag',
309
+ 'tdsc' => 'Tradedoubler Sale Conversion Tag',
310
+ 'tc' => 'Turn Conversion Tracking Tag',
311
+ 'tdc' => 'Turn Data Collection Tag',
312
+ 'twitter_website_tag' => 'Twitter Universal Website Tag',
313
+ 'uslt' => 'Upsellit Global Footer Tag',
314
+ 'uspt' => 'Upsellit Confirmation Tag',
315
+ 'vei' => 'Ve Interactive JavaScript Tag',
316
+ 'veip' => 'Ve Interactive Pixel',
317
+ 'vdc' => 'VisualDNA Conversion Tag',
318
+ 'xpsh' => 'Xtremepush',
319
+ 'yieldify' => 'Yieldify',
320
+ 'zone' => 'Zones'
321
+ ),
322
+ 'triggers' => array(
323
+ 'evl' => 'Element Visibility Listener/Trigger',
324
+ 'cl' => 'Click Listener/Trigger',
325
+ 'fsl' => 'Form Submit Listener/Trigger',
326
+ 'hl' => 'History Listener/Trigger',
327
+ 'jel' => 'JavaScript Error Listener/Trigger',
328
+ 'lcl' => 'Link Click Listener/Trigger',
329
+ 'sdl' => 'Scroll Depth Listener/Trigger',
330
+ 'tl' => 'Timer Listener/Trigger',
331
+ 'ytl' => 'YouTube Video Listener/Trigger'
332
+ ),
333
+ 'variables' => array(
334
+ 'k' => '1st Party Cookie',
335
+ 'c' => 'Constant',
336
+ 'ctv' => 'Container Version Number',
337
+ 'e' => 'Custom Event',
338
+ 'jsm' => 'Custom JavaScript Variable',
339
+ 'v' => 'Data Layer Variable',
340
+ 'dbg' => 'Debug Mode',
341
+ 'd' => 'DOM Element',
342
+ 'vis' => 'Element Visibility',
343
+ 'f' => 'HTTP Referrer',
344
+ 'j' => 'JavaScript Variable',
345
+ 'smm' => 'Lookup Table',
346
+ 'r' => 'Random Number',
347
+ 'remm' => 'RegEx Table',
348
+ 'u' => 'URL'
349
+ )
350
+ );
351
+
352
+ function gtm4wp_migrate_blacklist_whitelist( $current_options ) {
353
+ if ( ( array_key_exists( GTM4WP_OPTION_BLACKLIST_ENABLE, $current_options ) )
354
+ && ( $current_options[ GTM4WP_OPTION_BLACKLIST_ENABLE ] > 0 )
355
+ ) {
356
+ $_gtmrestrictlistitems = array();
357
+
358
+ // IDs from https://developers.google.com/tag-manager/devguide#security
359
+ if ( $current_options[ GTM4WP_OPTION_BLACKLIST_ADADVISOR ] ) {
360
+ $_gtmrestrictlistitems[] = 'ta';
361
+ }
362
+ if ( $current_options[ GTM4WP_OPTION_BLACKLIST_ADROLL ] ) {
363
+ $_gtmrestrictlistitems[] = 'asp';
364
+ }
365
+ if ( $current_options[ GTM4WP_OPTION_BLACKLIST_AWCONV ] ) {
366
+ $_gtmrestrictlistitems[] = 'awct';
367
+ }
368
+ if ( $current_options[ GTM4WP_OPTION_BLACKLIST_AWREMARKET ] ) {
369
+ $_gtmrestrictlistitems[] = 'sp';
370
+ }
371
+ if ( $current_options[ GTM4WP_OPTION_BLACKLIST_BIZO ] ) {
372
+ $_gtmrestrictlistitems[] = 'bzi';
373
+ }
374
+ if ( $current_options[ GTM4WP_OPTION_BLACKLIST_CLICKTALE ] ) {
375
+ $_gtmrestrictlistitems[] = 'cts';
376
+ }
377
+ if ( $current_options[ GTM4WP_OPTION_BLACKLIST_COMSCORE ] ) {
378
+ $_gtmrestrictlistitems[] = 'csm';
379
+ }
380
+ if ( $current_options[ GTM4WP_OPTION_BLACKLIST_CUSTOMHTML ] ) {
381
+ $_gtmrestrictlistitems[] = 'html';
382
+ }
383
+ if ( $current_options[ GTM4WP_OPTION_BLACKLIST_CUSTOMIMG ] ) {
384
+ $_gtmrestrictlistitems[] = 'img';
385
+ }
386
+ if ( $current_options[ GTM4WP_OPTION_BLACKLIST_DBLCLKCOUNT ] ) {
387
+ $_gtmrestrictlistitems[] = 'flc';
388
+ }
389
+ if ( $current_options[ GTM4WP_OPTION_BLACKLIST_DBLCLKSALES ] ) {
390
+ $_gtmrestrictlistitems[] = 'fls';
391
+ }
392
+ if ( $current_options[ GTM4WP_OPTION_BLACKLIST_GACLASSIC ] ) {
393
+ $_gtmrestrictlistitems[] = 'ga';
394
+ }
395
+ if ( $current_options[ GTM4WP_OPTION_BLACKLIST_MARIN ] ) {
396
+ $_gtmrestrictlistitems[] = 'ms';
397
+ }
398
+ if ( $current_options[ GTM4WP_OPTION_BLACKLIST_MPLEXIFRAME ] ) {
399
+ $_gtmrestrictlistitems[] = 'mpm';
400
+ }
401
+ if ( $current_options[ GTM4WP_OPTION_BLACKLIST_MPLEXROI ] ) {
402
+ $_gtmrestrictlistitems[] = 'mpr';
403
+ }
404
+ if ( $current_options[ GTM4WP_OPTION_BLACKLIST_MEDIA6DEG ] ) {
405
+ $_gtmrestrictlistitems[] = 'm6d';
406
+ }
407
+ if ( $current_options[ GTM4WP_OPTION_BLACKLIST_TURNCONV ] ) {
408
+ $_gtmrestrictlistitems[] = 'tc';
409
+ }
410
+ if ( $current_options[ GTM4WP_OPTION_BLACKLIST_TURNDATA ] ) {
411
+ $_gtmrestrictlistitems[] = 'tdc';
412
+ }
413
+ if ( $current_options[ GTM4WP_OPTION_BLACKLIST_UA ] ) {
414
+ $_gtmrestrictlistitems[] = 'ua';
415
+ }
416
+
417
+ $current_options[ GTM4WP_OPTION_BLACKLIST_STATUS ] = implode( ',', $_gtmrestrictlistitems );
418
+ }
419
+
420
+ return $current_options;
421
+ }
422
+
423
+ function gtm4wp_reload_options() {
424
+ global $gtm4wp_defaultoptions, $gtm4wp_business_verticals;
425
+
426
+ $storedoptions = (array) get_option( GTM4WP_OPTIONS );
427
+ if ( ! is_array( $gtm4wp_defaultoptions ) ) {
428
+ $gtm4wp_defaultoptions = array();
429
+ }
430
+
431
+ if ( !isset( $storedoptions[ GTM4WP_OPTION_BLACKLIST_STATUS ] ) ) {
432
+ $storedoptions = gtm4wp_migrate_blacklist_whitelist( $storedoptions );
433
+ }
434
+
435
+ $return_options = array_merge( $gtm4wp_defaultoptions, $storedoptions );
436
+ $return_options[ GTM4WP_OPTION_BLACKLIST_STATUS ] = explode( ',', $return_options[ GTM4WP_OPTION_BLACKLIST_STATUS ] );
437
+
438
+ if ( defined( 'GTM4WP_HARDCODED_GTM_ID' ) ) {
439
+ $return_options[ GTM4WP_OPTION_GTM_CODE ] = GTM4WP_HARDCODED_GTM_ID;
440
+ }
441
+
442
+ if ( defined( 'GTM4WP_HARDCODED_GTM_ENV_AUTH' ) ) {
443
+ $return_options[ GTM4WP_OPTION_ENV_GTM_AUTH ] = GTM4WP_HARDCODED_GTM_ENV_AUTH;
444
+ }
445
+
446
+ if ( defined( 'GTM4WP_HARDCODED_GTM_ENV_PREVIEW' ) ) {
447
+ $return_options[ GTM4WP_OPTION_ENV_GTM_PREVIEW ] = GTM4WP_HARDCODED_GTM_ENV_PREVIEW;
448
+ }
449
+
450
+ if ( !array_key_exists( $return_options[ GTM4WP_OPTION_INTEGRATE_WCBUSINESSVERTICAL ], $gtm4wp_business_verticals ) ) {
451
+ $return_options[ GTM4WP_OPTION_INTEGRATE_WCBUSINESSVERTICAL ] = $gtm4wp_defaultoptions[ GTM4WP_OPTION_INTEGRATE_WCBUSINESSVERTICAL ];
452
+ }
453
+
454
+ return $return_options;
455
+ }
456
+
457
+ function gtp4wp_debug_file( $debug_data ) {
458
+ $fp = fopen( dirname( __FILE__ ) . '/' . date( 'Y-m-d-H-i-s-u' ) . '.txt', 'w' );
459
+ if ( $fp ) {
460
+ fwrite( $fp, $debug_data );
461
+ fclose( $fp );
462
+ }
463
+ }
464
+
465
+ $gtm4wp_options = gtm4wp_reload_options();
duracelltomi-google-tag-manager-for-wordpress.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
  Plugin Name: Google Tag Manager for Wordpress
4
- Version: 1.12.3
5
  Plugin URI: https://gtm4wp.com/
6
  Description: The first Google Tag Manager plugin for WordPress with business goals in mind
7
  Author: Thomas Geiger
@@ -10,10 +10,10 @@ Text Domain: duracelltomi-google-tag-manager
10
  Domain Path: /languages
11
 
12
  WC requires at least: 3.2
13
- WC tested up to: 5.2.2
14
  */
15
 
16
- define( 'GTM4WP_VERSION', '1.12.3' );
17
  define( 'GTM4WP_PATH', plugin_dir_path( __FILE__ ) );
18
 
19
  global $gtp4wp_plugin_url, $gtp4wp_plugin_basename;
1
  <?php
2
  /*
3
  Plugin Name: Google Tag Manager for Wordpress
4
+ Version: 1.13
5
  Plugin URI: https://gtm4wp.com/
6
  Description: The first Google Tag Manager plugin for WordPress with business goals in mind
7
  Author: Thomas Geiger
10
  Domain Path: /languages
11
 
12
  WC requires at least: 3.2
13
+ WC tested up to: 5.3.0
14
  */
15
 
16
+ define( 'GTM4WP_VERSION', '1.13' );
17
  define( 'GTM4WP_PATH', plugin_dir_path( __FILE__ ) );
18
 
19
  global $gtp4wp_plugin_url, $gtp4wp_plugin_basename;
integration/whichbrowser/bootstrap.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ spl_autoload_register(function ($class) {
4
+
5
+ // project-specific namespace prefix
6
+ $prefix = 'WhichBrowser\\';
7
+
8
+ // base directory for the namespace prefix
9
+ $base_dir = __DIR__ . '/src/';
10
+
11
+ // does the class use the namespace prefix?
12
+ $len = strlen($prefix);
13
+ if (strncmp($prefix, $class, $len) !== 0) {
14
+ // no, move to the next registered autoloader
15
+ return;
16
+ }
17
+
18
+ // get the relative class name
19
+ $relative_class = substr($class, $len);
20
+
21
+ // replace the namespace prefix with the base directory, replace namespace
22
+ // separators with directory separators in the relative class name, append
23
+ // with .php
24
+ $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
25
+
26
+ // if the file exists, require it
27
+ if (file_exists($file)) {
28
+ require $file;
29
+ }
30
+ });
integration/whichbrowser/data/applications-bots.php CHANGED
@@ -12,13 +12,19 @@ Applications::$BOTS = [
12
  [ 'name' => 'Adaxas', 'id' => 'adaxas', 'regexp' => '/Adaxas Spider/u' ],
13
  [ 'name' => 'AddThis.com', 'id' => 'addthis', 'regexp' => '/AddThis.com/u' ],
14
  [ 'name' => 'ADmantX', 'id' => 'admantx', 'regexp' => '/ADmantX Platform Semantic Analyzer/u' ],
15
- [ 'name' => 'AhrefsBot', 'id' => 'ahrefsbot', 'regexp' => '/AhrefsBot.Feeds v([0-9.]*)/u' ],
16
- [ 'name' => 'AhrefsBot', 'id' => 'ahrefsbot', 'regexp' => '/AhrefsBot\/([0-9.]*)/u' ],
 
 
 
 
17
  [ 'name' => 'Alexa', 'id' => 'archiver', 'regexp' => '/ia_archiver/u' ],
18
  [ 'name' => 'AltaVista', 'id' => 'altavista', 'regexp' => '/AltaVista Intranet V([0-9.]*)/u' ],
19
  [ 'name' => 'Analytics SEO', 'id' => 'curious', 'regexp' => '/Curious George - www.analyticsseo.com\/crawler/u' ],
20
  [ 'name' => 'Amazon CloudFront', 'id' => 'cloudfront', 'regexp' => '/Amazon CloudFront/u' ],
21
  [ 'name' => 'Amorank Spider', 'id' => 'amorank', 'regexp' => '/AmorankSpider\/([0-9.]*)/u' ],
 
 
22
  [ 'name' => 'ArchiveBot', 'id' => 'archive', 'regexp' => '/ArchiveTeam ArchiveBot/u' ],
23
  [ 'name' => 'Archive.org', 'id' => 'archive', 'regexp' => '/archive.org_bot(?:\/([0-9.]*))?/u' ],
24
  [ 'name' => 'Archive.org', 'id' => 'archive', 'regexp' => '/special_archiver(?:\/([0-9.]*))?/u' ],
@@ -32,6 +38,7 @@ Applications::$BOTS = [
32
  [ 'name' => 'Baiduspider', 'id' => 'baidu', 'regexp' => '/baiduspider-mobile-gate/u' ],
33
  [ 'name' => 'Baiduspider', 'id' => 'baidu', 'regexp' => '/\+http:\/\/www.baidu.com\/search\/spider.html/u' ],
34
  [ 'name' => 'Baiduspider', 'id' => 'baidu', 'regexp' => '/BaiduImagespider/u' ],
 
35
  [ 'name' => 'BazQux', 'id' => 'bazqux', 'regexp' => '/BazQux\/([0-9.]*)/u' ],
36
  [ 'name' => 'Bing', 'id' => 'bingbot', 'regexp' => '/bingbot\/([0-9.]*)/u' ],
37
  [ 'name' => 'Bing', 'id' => 'msnbot', 'regexp' => '/msnbot\/([0-9.]*)/u' ],
@@ -42,7 +49,10 @@ Applications::$BOTS = [
42
  [ 'name' => 'Bing', 'id' => 'msnbot', 'regexp' => '/MSNBOT_Mobile/u' ],
43
  [ 'name' => 'Bing', 'id' => 'msmobot', 'regexp' => '/MSMOBOT/u' ],
44
  [ 'name' => 'Bing Preview', 'id' => 'bing', 'regexp' => '/BingPreview\/([0-9.]*)/u' ],
 
 
45
  [ 'name' => 'BlogBridge', 'id' => 'blogbridge', 'regexp' => '/BlogBridge ([0-9.]*)/u' ],
 
46
  [ 'name' => 'Bloglines', 'id' => 'bloglines', 'regexp' => '/Bloglines\/([0-9.]*)/u' ],
47
  [ 'name' => 'Bloglovin', 'id' => 'bloglovin', 'regexp' => '/Bloglovin\/([0-9.]*)/u' ],
48
  [ 'name' => 'BlogPulse', 'id' => 'blogpulse', 'regexp' => '/BlogPulse \(ISSpider-([0-9.]*)/u' ],
@@ -50,21 +60,46 @@ Applications::$BOTS = [
50
  [ 'name' => 'Blogtrottr', 'id' => 'blogtrot', 'regexp' => '/Blogtrottr\/([0-9.]*)/u' ],
51
  [ 'name' => 'Blogshares', 'id' => 'blogshares', 'regexp' => '/Blogshares/u' ],
52
  [ 'name' => 'BoardReader', 'id' => 'boardreader', 'regexp' => '/BoardReader\/([0-9.]*)/u' ],
 
53
  [ 'name' => 'Browsershots', 'id' => 'browsershots', 'regexp' => '/Browsershots/u' ],
54
  [ 'name' => 'BUbiNG', 'id' => 'bubing', 'regexp' => '/BUbiNG/u' ],
 
 
55
  [ 'name' => 'Butterfly', 'id' => 'butterfly', 'regexp' => '/Butterfly\/([0-9.]*)/u' ],
 
 
56
  [ 'name' => 'CiteSeerX', 'id' => 'heritrix', 'regexp' => '/heritrix\/([0-9.]*)/u' ],
 
57
  [ 'name' => 'Cliqzbot', 'id' => 'cliqz', 'regexp' => '/Cliqzbot\/([0-9.]*)/u' ],
58
- [ 'name' => 'CloudFare Always Online', 'id' => 'cloudflare', 'regexp' => '/CloudFlare-AlwaysOnline\/([0-9.]*)/u' ],
 
 
 
 
 
 
59
  [ 'name' => 'Comodo', 'id' => 'comodo', 'regexp' => '/Comodo Spider ([0-9.]*)/u' ],
60
  [ 'name' => 'CommaFeed', 'id' => 'commafeed', 'regexp' => '/CommaFeed\/([0-9.]*)/u' ],
61
- [ 'name' => 'CommonCrawl', 'id' => 'cbot', 'regexp' => '/CCBot\/([0-9.]*)/u' ],
 
62
  [ 'name' => 'Data Hotel Watchdog', 'id' => 'watchdog', 'regexp' => '/Data-Hotel-Watchdog\/([0-9.]*)/u' ],
 
63
  [ 'name' => 'DataparkSearch', 'id' => 'datasearch', 'regexp' => '/DataparkSearch\/([0-9.]*)/u' ],
 
 
64
  [ 'name' => 'Daumoa', 'id' => 'daumoa', 'regexp' => '/Daumoa ([0-9.]*)/u' ],
65
  [ 'name' => 'Digg', 'id' => 'digg', 'regexp' => '/Digg Deeper\/v([0-9.]*)/u' ],
66
  [ 'name' => 'Digg', 'id' => 'digg', 'regexp' => '/Digg\/([0-9.]*)/u' ],
 
 
 
67
  [ 'name' => 'Domain Re-Animator', 'id' => 'domain', 'regexp' => '/Domain Re-Animator Bot/u' ],
 
 
 
 
 
 
68
  [ 'name' => 'Exabot Thumbnails', 'id' => 'exabot', 'regexp' => '/Exabot-Thumbnails/u' ],
69
  [ 'name' => 'ExactSeek', 'id' => 'exactseek', 'regexp' => '/ExactSeek Crawler/u' ],
70
  [ 'name' => 'Ezooms Crawler', 'id' => 'ezooms', 'regexp' => '/Ezooms\/([0-9.]*)/u' ],
@@ -91,11 +126,13 @@ Applications::$BOTS = [
91
  [ 'name' => 'FeedValidator', 'id' => 'validator', 'regexp' => '/FeedValidator\/([0-9.]*)/u' ],
92
  [ 'name' => 'FeedZirra', 'id' => 'feed', 'regexp' => '/feedzirra/u' ],
93
  [ 'name' => 'Fever', 'id' => 'fever', 'regexp' => '/Fever\/([0-9.]*)/u' ],
 
94
  [ 'name' => 'Friendica', 'id' => 'friendica', 'regexp' => '/Friendica/u' ],
95
  [ 'name' => 'FTRF: Friendly Robot', 'id' => 'robot', 'regexp' => '/FTRF: Friendly robot\/([0-9.]*)/u' ],
96
  [ 'name' => 'Genieo Web Filter', 'id' => 'genieo', 'regexp' => '/Genieo\/([0-9.]*)/u' ],
97
  [ 'name' => 'GNIP', 'id' => 'fetchor', 'regexp' => '/UnwindFetchor\/([0-9.]*)/u' ],
98
  [ 'name' => 'Gocrawl', 'id' => 'google', 'regexp' => '/Googlebot \(gocrawl v([0-9.]*)\)/u' ],
 
99
  [ 'name' => 'GomezAgent', 'id' => 'gomez', 'regexp' => '/GomezAgent ([0-9.]+)/u' ],
100
  [ 'name' => 'Goo', 'id' => 'ichiro', 'regexp' => '/ichiro\/mobile goo/u' ],
101
  [ 'name' => 'Goo Blog Search', 'id' => 'gooblog', 'regexp' => '/gooblog\/([0-9.]*)/u' ],
@@ -110,6 +147,7 @@ Applications::$BOTS = [
110
  [ 'name' => 'Google App Engine', 'id' => 'google', 'regexp' => '/AppEngine-Google/u' ],
111
  [ 'name' => 'Google Web Preview', 'id' => 'google', 'regexp' => '/Google Web Preview/u' ],
112
  [ 'name' => 'Google Page Speed', 'id' => 'google', 'regexp' => '/Google Page Speed Insights/u' ],
 
113
  [ 'name' => 'Google FeedBurner', 'id' => 'feed', 'regexp' => '/FeedBurner\/([0-9.]*)/u' ],
114
  [ 'name' => 'Google Feedfetcher', 'id' => 'google', 'regexp' => '/Feedfetcher-Google/iu' ],
115
  [ 'name' => 'Google Font Analysis', 'id' => 'google', 'regexp' => '/Google-FontAnalysis\/([0-9.]*)/u' ],
@@ -122,36 +160,65 @@ Applications::$BOTS = [
122
  [ 'name' => 'Google Wireless Transcoder', 'id' => 'google', 'regexp' => '/Google Wireless Transcoder/u' ],
123
  [ 'name' => 'Google Play Newsstand', 'id' => 'google', 'regexp' => '/GoogleProducer/u' ],
124
  [ 'name' => 'Google YouTube Sample', 'id' => 'google', 'regexp' => '/Google-YouTubeSample\/([0-9.]*)/u' ],
 
125
  [ 'name' => 'Grammarly', 'id' => 'grammarly', 'regexp' => '/Grammarly\/([0-9.]*)/u' ],
126
  [ 'name' => 'Grub', 'id' => 'grub', 'regexp' => '/grub-client-([0-9.]*)/u' ],
127
  [ 'name' => 'Hatena Antenna', 'id' => 'hatena', 'regexp' => '/Hatena Antenna\/([0-9.]*)/u' ],
128
  [ 'name' => 'Hatena Diary', 'id' => 'hatena', 'regexp' => '/Hatena Diary RSS Module/u' ],
129
  [ 'name' => 'Hatena Pagetitle', 'id' => 'hatena', 'regexp' => '/Hatena Pagetitle Agent\/([0-9.]*)/u' ],
130
  [ 'name' => 'HeartRails Capture', 'id' => 'capture', 'regexp' => '/HeartRails_Capture\/([0-9.]*)/u' ],
 
 
 
131
  [ 'name' => 'htdig', 'id' => 'htdig', 'regexp' => '/htdig\/([0-9.]*)/u' ],
132
  [ 'name' => 'HTTPMon', 'id' => 'httpmon', 'regexp' => '/HTTPMon\/([0-9.]*)/u' ],
133
  [ 'name' => 'HubPages', 'id' => 'hubpages', 'regexp' => '/HubPages V([0-9.]*)/u' ],
 
134
  [ 'name' => 'iAsk Spider', 'id' => 'spider', 'regexp' => '/iaskspider\/([0-9.]*)/u' ],
135
  [ 'name' => 'iAsk Spider', 'id' => 'spider', 'regexp' => '/iaskspider2/u' ],
136
  [ 'name' => 'Ichiro', 'id' => 'ichiro', 'regexp' => '/ichiro\/([0-9.]*)/u' ],
137
  [ 'name' => 'Internet Archive', 'id' => 'archive', 'regexp' => '/InternetArchive\/([0-9.]*)/u' ],
 
 
 
138
  [ 'name' => 'JamesBOT', 'id' => 'crawler', 'regexp' => '/James BOT - WebCrawler/u' ],
139
  [ 'name' => 'Jayde', 'id' => 'crawler', 'regexp' => '/Jayde Crawler./u' ],
 
140
  [ 'name' => 'Kouio', 'id' => 'kouio', 'regexp' => '/kouio.com/u' ],
141
  [ 'name' => 'Larbin', 'id' => 'larbin', 'regexp' => '/[Ll]arbin[\/_]([0-9.]*)/u' ],
 
 
142
  [ 'name' => 'Linkedin Bot', 'id' => 'linkedin', 'regexp' => '/LinkedInBot\/([0-9.]*)/u' ],
 
143
  [ 'name' => 'Linkdex Bot', 'id' => 'linkdex', 'regexp' => '/linkdexbot-mobile\/([0-9.]*)/u' ],
144
  [ 'name' => 'Linkdex Bot', 'id' => 'linkdex', 'regexp' => '/linkdex.com\/v([0-9.]*)/u' ],
145
  [ 'name' => 'Livedoor', 'id' => 'livedoor', 'regexp' => '/livedoor/u' ],
 
146
  [ 'name' => 'LTX71', 'id' => 'ltx71', 'regexp' => '/ltx71/u' ],
147
  [ 'name' => 'Magpie RSS', 'id' => 'magpie', 'regexp' => '/MagpieRSS\/([0-9.]*)/u' ],
 
 
148
  [ 'name' => 'Mapian News Bot', 'id' => 'mapion', 'regexp' => '/mapion-news-bot\/([0-9.]*)/u' ],
 
 
 
 
 
149
  [ 'name' => 'Microsoft Social Streams', 'id' => 'socialstreams', 'regexp' => '/Microsoft MSN SocialStreams Bot/u' ],
150
  [ 'name' => 'Mixi', 'id' => 'mixi', 'regexp' => '/mixi-check\/([0-9.]*)/u' ],
 
151
  [ 'name' => 'MnoGoSearch', 'id' => 'mnogo', 'regexp' => '/MnoGoSearch\/([0-9.]*)/u' ],
 
152
  [ 'name' => 'Monitor.us', 'id' => 'monitor', 'regexp' => '/monitor.us/u' ],
 
 
153
  [ 'name' => 'Naver Yeti', 'id' => 'yeti', 'regexp' => '/Yeti\/([0-9.]*)/u' ],
154
- [ 'name' => 'Netcraft Survey Bot', 'id' => 'netcraft', 'regexp' => '/Netcraft Web Server Survey/u' ],
 
 
 
 
 
155
  [ 'name' => 'Netvibes', 'id' => 'netvibes', 'regexp' => '/Netvibes/u' ],
156
  [ 'name' => 'NewsBlur', 'id' => 'newsblur', 'regexp' => '/NewsBlur Favicon Fetcher/u' ],
157
  [ 'name' => 'NewsBlur', 'id' => 'newsblur', 'regexp' => '/NewsBlur Feed Fetcher/u' ],
@@ -160,17 +227,27 @@ Applications::$BOTS = [
160
  [ 'name' => 'NewsGator', 'id' => 'newsgator', 'regexp' => '/NewsGator\/([0-9.]*)/u' ],
161
  [ 'name' => 'NewsGator', 'id' => 'newsgator', 'regexp' => '/NewsGatorOnline\/([0-9.]*)/u' ],
162
  [ 'name' => 'NewsGator FetchLinks', 'id' => 'newsgator', 'regexp' => '/NewsGator FetchLinks extension\/([0-9.]*)/u' ],
 
 
163
  [ 'name' => 'OpenWebSpider', 'id' => 'spider', 'regexp' => '/OpenWebSpider v([0-9.]*)/u' ],
164
  [ 'name' => 'OrangeBot', 'id' => 'orange', 'regexp' => '/OrangeBot-Collector\/([0-9.]*)/u' ],
165
  [ 'name' => 'OrangeBot', 'id' => 'orange', 'regexp' => '/OrangeBot-Mobile/u' ],
166
- [ 'name' => 'PagesInventory ', 'id' => 'pages', 'regexp' => '/PagesInventory/u' ],
167
- [ 'name' => 'Picsearch bot', 'id' => 'psbot', 'regexp' => '/psbot-page/u' ],
 
 
 
 
168
  [ 'name' => 'Pingdom', 'id' => 'pingdom', 'regexp' => '/Pingdom.com_bot_version_([0-9.]*)/u' ],
169
  [ 'name' => 'Pinterest', 'id' => 'pinterest', 'regexp' => '/Pinterest\/([0-9.]+)( \(+|$)/u' ],
 
 
 
170
  [ 'name' => 'PostRank', 'id' => 'postrank', 'regexp' => '/PostRank\/([0-9.]*)/u' ],
171
  [ 'name' => 'PowerMapper', 'id' => 'crawler', 'regexp' => '/CrawlerProcess \(http:\/\/www\.PowerMapper\.com\) \/([0-9.]*)/u' ],
172
  [ 'name' => 'Radian 6', 'id' => 'feed', 'regexp' => '/R6_FeedFetcher/u' ],
173
  [ 'name' => 'Radian 6', 'id' => 'comment', 'regexp' => '/R6_CommentReader/u' ],
 
174
  [ 'name' => 'RssBar', 'id' => 'rssbar', 'regexp' => '/RssBar\/([0-9.]*)/u' ],
175
  [ 'name' => 'ROI Hunter', 'id' => 'hunter', 'regexp' => '/ROI Hunter/u' ],
176
  [ 'name' => 'QuerySeekerSpider', 'id' => 'spider', 'regexp' => '/QuerySeekerSpider(?:\/([0-9.]*))?/u' ],
@@ -178,11 +255,21 @@ Applications::$BOTS = [
178
  [ 'name' => 'SafeSearch Microdata', 'id' => 'safesearch', 'regexp' => '/SafeSearch microdata crawler/u' ],
179
  [ 'name' => 'Scrapy', 'id' => 'scrapy', 'regexp' => '/Scrapy\/([0-9.]*)/u' ],
180
  [ 'name' => 'ScreenerBot', 'id' => 'crawler', 'regexp' => '/ScreenerBot Crawler Beta ([0-9.]*)/u' ],
 
 
 
 
 
181
  [ 'name' => 'Server Density', 'id' => 'monitor', 'regexp' => '/Server Density Service Monitoring/u' ],
 
 
 
182
  [ 'name' => 'ShopWiki', 'id' => 'shopwiki', 'regexp' => '/ShopWiki\/([0-9.]*)/u' ],
183
  [ 'name' => 'SilverReader', 'id' => 'reader', 'regexp' => '/SilverReader\/([0-9.]*)/u' ],
184
  [ 'name' => 'SimplePie', 'id' => 'simplepie', 'regexp' => '/SimplePie\/([0-9.]*)/u' ],
185
  [ 'name' => 'Site24x7', 'id' => 'site24', 'regexp' => '/Site24x7/u' ],
 
 
186
  [ 'name' => 'Sogou Web Spider', 'id' => 'sogou', 'regexp' => '/sogou spider/u' ],
187
  [ 'name' => 'Sogou Web Spider', 'id' => 'sogou', 'regexp' => '/Sogou pic spider\/([0-9.]*)/u' ],
188
  [ 'name' => 'Sogou Web Spider', 'id' => 'sogou', 'regexp' => '/Sogou inst spider\/([0-9.]*)/u' ],
@@ -192,21 +279,32 @@ Applications::$BOTS = [
192
  [ 'name' => 'Soso Web Spider', 'id' => 'soso', 'regexp' => '/Sosospider\/([0-9.]*)/u' ],
193
  [ 'name' => 'Soso Web Spider', 'id' => 'soso', 'regexp' => '/Sosospider/u' ],
194
  [ 'name' => 'Soso Image Spider', 'id' => 'soso', 'regexp' => '/Sosoimagespider/u' ],
 
195
  [ 'name' => 'SPDYCheck', 'id' => 'spdycheck', 'regexp' => '/SPDYCheck SPDY Protocol Tester/iu' ],
196
  [ 'name' => 'Spinn3r', 'id' => 'spinn', 'regexp' => '/Spinn3r ([0-9.]*)/iu' ],
197
  [ 'name' => 'Spiderlytics', 'id' => 'spider', 'regexp' => '/Spiderlytics\/([0-9.]*)/iu' ],
 
 
 
198
  [ 'name' => 'StatusCake Error Detector', 'id' => 'detector', 'regexp' => '/StatusCake Error Detector/iu' ],
199
  [ 'name' => 'Summify', 'id' => 'summify', 'regexp' => '/Summify\/([0-9.]*)/u' ],
200
  [ 'name' => 'TelegramBot', 'id' => 'telegram', 'regexp' => '/TelegramBot/u' ],
201
  [ 'name' => 'Twisted PageGetter', 'id' => 'twisted', 'regexp' => '/Twisted PageGetter/u' ],
202
  [ 'name' => 'Twitterbot', 'id' => 'twitter', 'regexp' => '/Twitterbot\/([0-9.]*)/u' ],
203
  [ 'name' => 'Tiny Tiny RSS', 'id' => 'tiny', 'regexp' => '/Tiny Tiny RSS\/([0-9.]*)/u' ],
 
 
204
  [ 'name' => 'TLSProber', 'id' => 'tlsprober', 'regexp' => '/TLSProber\/([0-9.]*)/u' ],
 
205
  [ 'name' => 'Typhoeus', 'id' => 'typhoeus', 'regexp' => '/Typhoeus/u' ],
206
  [ 'name' => 'Vagabondo', 'id' => 'vagabondo', 'regexp' => '/Vagabondo\/([0-9.]*)/u' ],
 
 
 
207
  [ 'name' => 'Voilabot', 'id' => 'voila', 'regexp' => '/Voila[Bb]ot/u' ],
208
  [ 'name' => 'VocusBot', 'id' => 'vocus', 'regexp' => '/VocusBot ([0-9.]*)/u' ],
209
  [ 'name' => 'Vodafone mCrawler', 'id' => 'mcrawler', 'regexp' => '/Vodafone mCrawler/u' ],
 
210
  [ 'name' => 'W3Bot', 'id' => 'w3bot', 'regexp' => '/W3Bot ([0-9.]*)/u' ],
211
  [ 'name' => 'W3C CSS Validator', 'id' => 'jigsaw', 'regexp' => '/Jigsaw\/([0-9.]*)/u' ],
212
  [ 'name' => 'W3C Internationalization Checker', 'id' => 'w3c', 'regexp' => '/W3C_I18n-Checker\/([0-9.]*)/u' ],
@@ -218,6 +316,7 @@ Applications::$BOTS = [
218
  [ 'name' => 'W3C Robot', 'id' => 'w3c', 'regexp' => '/W3CRobot\/([0-9.]*)/u' ],
219
  [ 'name' => 'W3C Unified Validator', 'id' => 'w3c', 'regexp' => '/W3C_Unicorn\/([0-9.]*)/u' ],
220
  [ 'name' => 'W3C Validator.nu', 'id' => 'validator', 'regexp' => '/Validator.nu\//u' ],
 
221
  [ 'name' => 'Wayback Archive', 'id' => 'wayback', 'regexp' => '/waybackarchive.org\/([0-9.]*)/u' ],
222
  [ 'name' => 'WebbCrawler', 'id' => 'crawler', 'regexp' => '/WebbCrawler ([0-9.]*)/u' ],
223
  [ 'name' => 'WebIndexer', 'id' => 'webindexer', 'regexp' => '/WebIndexer\//u' ],
@@ -225,6 +324,7 @@ Applications::$BOTS = [
225
  [ 'name' => 'WordPress.com', 'id' => 'wordpress', 'regexp' => '/WordPress\.com; http/u' ],
226
  [ 'name' => 'WordPress Jetpack', 'id' => 'wordpress', 'regexp' => '/Jetpack by WordPress\.com/u' ],
227
  [ 'name' => 'WWW Mechanize', 'id' => 'mechanize', 'regexp' => '/WWW-Mechanize\/([0-9.]*)/u' ],
 
228
  [ 'name' => 'Xerka WebBot', 'id' => 'xerka', 'regexp' => '/Xerka WebBot v([0-9.]*)/u' ],
229
  [ 'name' => 'XML Sitemaps Generator', 'id' => 'sitemap', 'regexp' => '/XML-Sitemaps\/([0-9.]*)/u' ],
230
  [ 'name' => 'XMLSitemapGenerator', 'id' => 'sitemap', 'regexp' => '/XmlSitemapGenerator/u' ],
@@ -263,6 +363,12 @@ Applications::$BOTS = [
263
 
264
  [ 'name' => 'Inktomi Slurp', 'id' => 'slurp', 'regexp' => '/Slurp\/([0-9.]*)/u' ],
265
  [ 'name' => 'Inktomi Slurp', 'id' => 'slurp', 'regexp' => '/Slurp\.so\/([0-9.]*)/u' ],
 
 
 
 
 
 
266
 
267
  /* Generic bots */
268
  [ 'name' => 'Apache Httpd', 'id' => 'httpclient', 'regexp' => '/Apache-HttpClient(?:\/([0-9.]*))?/u' ],
@@ -271,6 +377,11 @@ Applications::$BOTS = [
271
  [ 'name' => 'Apache Nutch', 'id' => 'nutch', 'regexp' => '/Nutch(?:CVS|Org)\/([0-9.]*)/u' ],
272
  [ 'name' => 'Apache Synapse', 'id' => 'synapse', 'regexp' => '/compatible; Synapse/u' ],
273
  [ 'name' => 'Borland Delphi', 'id' => 'indy', 'regexp' => '/Indy Library/u' ],
 
 
 
 
 
274
  [ 'name' => 'Wget', 'id' => 'wget', 'regexp' => '/Wget\/([0-9.]*)/u' ],
275
  [ 'name' => 'Curl', 'id' => 'curl', 'regexp' => '/^curl\/([0-9.]*)/u' ],
276
 
@@ -279,7 +390,8 @@ Applications::$BOTS = [
279
  [ 'name' => 'Perl', 'id' => 'simple', 'regexp' => '/LWP::Simple\//u' ],
280
  [ 'name' => 'Perl', 'id' => 'libwww', 'regexp' => '/libwww-perl\//u' ],
281
  [ 'name' => 'Perl', 'id' => 'lwp', 'regexp' => '/lwp-trivial\//u' ],
282
- [ 'name' => 'Python', 'id' => 'urllib', 'regexp' => '/Python-urllib/u' ],
 
283
  [ 'name' => 'PHP', 'id' => 'php', 'regexp' => '/ PHP\/([0-9.]*)/u' ],
284
  [ 'name' => 'PHP', 'id' => 'php', 'regexp' => '/^PHP/u' ],
285
  [ 'name' => 'PHP', 'id' => 'pear', 'regexp' => '/PEAR HTTP_Request class/u' ],
12
  [ 'name' => 'Adaxas', 'id' => 'adaxas', 'regexp' => '/Adaxas Spider/u' ],
13
  [ 'name' => 'AddThis.com', 'id' => 'addthis', 'regexp' => '/AddThis.com/u' ],
14
  [ 'name' => 'ADmantX', 'id' => 'admantx', 'regexp' => '/ADmantX Platform Semantic Analyzer/u' ],
15
+ [ 'name' => 'Adsbot', 'id' => 'adsbot', 'regexp' => '/Adsbot\/([0-9.]*)/u' ], // Not to be mixed up with Google Adsbot
16
+ [ 'name' => 'Ahrefs Feeds Bot', 'id' => 'ahrefs', 'regexp' => '/AhrefsBot\.Feeds v([0-9.]*)/u' ],
17
+ [ 'name' => 'Ahrefs Site Audit Bot', 'id' => 'ahrefs', 'regexp' => '/AhrefsSiteAudit\/([0-9.]*)/u' ],
18
+ [ 'name' => 'Ahrefs News Bot', 'id' => 'ahrefs', 'regexp' => '/AhrefsBot\/([0-9.]*)\; News/u' ],
19
+ [ 'name' => 'Ahrefs SA Bot', 'id' => 'ahrefs', 'regexp' => '/AhrefsBot\/([0-9.]*)\; SA/u' ],
20
+ [ 'name' => 'Ahrefs Bot', 'id' => 'ahrefs', 'regexp' => '/AhrefsBot\/([0-9.]*)/u' ],
21
  [ 'name' => 'Alexa', 'id' => 'archiver', 'regexp' => '/ia_archiver/u' ],
22
  [ 'name' => 'AltaVista', 'id' => 'altavista', 'regexp' => '/AltaVista Intranet V([0-9.]*)/u' ],
23
  [ 'name' => 'Analytics SEO', 'id' => 'curious', 'regexp' => '/Curious George - www.analyticsseo.com\/crawler/u' ],
24
  [ 'name' => 'Amazon CloudFront', 'id' => 'cloudfront', 'regexp' => '/Amazon CloudFront/u' ],
25
  [ 'name' => 'Amorank Spider', 'id' => 'amorank', 'regexp' => '/AmorankSpider\/([0-9.]*)/u' ],
26
+ [ 'name' => 'Apple Bot', 'id' => 'apple', 'regexp' => '/Applebot\/([0-9.]*)/u' ],
27
+ [ 'name' => 'Apple News Bot', 'id' => 'apple', 'regexp' => '/AppleNewsBot/u' ],
28
  [ 'name' => 'ArchiveBot', 'id' => 'archive', 'regexp' => '/ArchiveTeam ArchiveBot/u' ],
29
  [ 'name' => 'Archive.org', 'id' => 'archive', 'regexp' => '/archive.org_bot(?:\/([0-9.]*))?/u' ],
30
  [ 'name' => 'Archive.org', 'id' => 'archive', 'regexp' => '/special_archiver(?:\/([0-9.]*))?/u' ],
38
  [ 'name' => 'Baiduspider', 'id' => 'baidu', 'regexp' => '/baiduspider-mobile-gate/u' ],
39
  [ 'name' => 'Baiduspider', 'id' => 'baidu', 'regexp' => '/\+http:\/\/www.baidu.com\/search\/spider.html/u' ],
40
  [ 'name' => 'Baiduspider', 'id' => 'baidu', 'regexp' => '/BaiduImagespider/u' ],
41
+ [ 'name' => 'Barkrowler', 'id' => 'barkrowler', 'regexp' => '/Barkrowler\/([0-9.]*)/u' ],
42
  [ 'name' => 'BazQux', 'id' => 'bazqux', 'regexp' => '/BazQux\/([0-9.]*)/u' ],
43
  [ 'name' => 'Bing', 'id' => 'bingbot', 'regexp' => '/bingbot\/([0-9.]*)/u' ],
44
  [ 'name' => 'Bing', 'id' => 'msnbot', 'regexp' => '/msnbot\/([0-9.]*)/u' ],
49
  [ 'name' => 'Bing', 'id' => 'msnbot', 'regexp' => '/MSNBOT_Mobile/u' ],
50
  [ 'name' => 'Bing', 'id' => 'msmobot', 'regexp' => '/MSMOBOT/u' ],
51
  [ 'name' => 'Bing Preview', 'id' => 'bing', 'regexp' => '/BingPreview\/([0-9.]*)/u' ],
52
+ [ 'name' => 'Blex Bot', 'id' => 'blex', 'regexp' => '/BLEXBot\/([0-9.]*)/u' ],
53
+ [ 'name' => 'Blex Test Bot', 'id' => 'blex', 'regexp' => '/BLEXBotTest\/([0-9.]*)/u' ],
54
  [ 'name' => 'BlogBridge', 'id' => 'blogbridge', 'regexp' => '/BlogBridge ([0-9.]*)/u' ],
55
+ [ 'name' => 'Blogger Bot', 'id' => 'blogger', 'regexp' => '/blogger\.com\)/u' ],
56
  [ 'name' => 'Bloglines', 'id' => 'bloglines', 'regexp' => '/Bloglines\/([0-9.]*)/u' ],
57
  [ 'name' => 'Bloglovin', 'id' => 'bloglovin', 'regexp' => '/Bloglovin\/([0-9.]*)/u' ],
58
  [ 'name' => 'BlogPulse', 'id' => 'blogpulse', 'regexp' => '/BlogPulse \(ISSpider-([0-9.]*)/u' ],
60
  [ 'name' => 'Blogtrottr', 'id' => 'blogtrot', 'regexp' => '/Blogtrottr\/([0-9.]*)/u' ],
61
  [ 'name' => 'Blogshares', 'id' => 'blogshares', 'regexp' => '/Blogshares/u' ],
62
  [ 'name' => 'BoardReader', 'id' => 'boardreader', 'regexp' => '/BoardReader\/([0-9.]*)/u' ],
63
+ [ 'name' => 'British Library', 'id' => 'lddc', 'regexp' => '/uk_lddc_bot\/([0-9.]*)/u' ],
64
  [ 'name' => 'Browsershots', 'id' => 'browsershots', 'regexp' => '/Browsershots/u' ],
65
  [ 'name' => 'BUbiNG', 'id' => 'bubing', 'regexp' => '/BUbiNG/u' ],
66
+ [ 'name' => 'Buck', 'id' => 'buck', 'regexp' => '/Buck\/([0-9.]*)/u' ],
67
+ [ 'name' => 'BuiltWith', 'id' => 'builtwith', 'regexp' => '/BuiltWith\/([0-9.]*)/u' ],
68
  [ 'name' => 'Butterfly', 'id' => 'butterfly', 'regexp' => '/Butterfly\/([0-9.]*)/u' ],
69
+ [ 'name' => 'BuzzSumo', 'id' => 'buzzsumo', 'regexp' => '/buzzsumo\.com/u' ],
70
+ [ 'name' => 'Bytespider', 'id' => 'bytespider', 'regexp' => '/Bytespider/u' ],
71
  [ 'name' => 'CiteSeerX', 'id' => 'heritrix', 'regexp' => '/heritrix\/([0-9.]*)/u' ],
72
+ [ 'name' => 'Clarabot', 'id' => 'clarabot', 'regexp' => '/Clarabot\/([0-9.]*)/u' ],
73
  [ 'name' => 'Cliqzbot', 'id' => 'cliqz', 'regexp' => '/Cliqzbot\/([0-9.]*)/u' ],
74
+ [ 'name' => 'Cloudflare Always Online', 'id' => 'cloudflare', 'regexp' => '/CloudFlare-AlwaysOnline\/([0-9.]*)/u' ],
75
+ [ 'name' => 'Cloudflare AMP', 'id' => 'cloudflare', 'regexp' => '/Cloudflare-AMP\/([0-9.]*)/u' ],
76
+ [ 'name' => 'Cloudflare Diagnostics', 'id' => 'cloudflare', 'regexp' => '/Cloudflare Diagnostics/u' ],
77
+ [ 'name' => 'Cloudflare Diagnostics', 'id' => 'cloudflare', 'regexp' => '/Cloudflare-Diagnostics/u' ],
78
+ [ 'name' => 'Cloudflare SpeedTest', 'id' => 'cloudflare', 'regexp' => '/Cloudflare SpeedTest\/([0-9.]*)/u' ],
79
+ [ 'name' => 'Coccocbot Web', 'id' => 'coccoc', 'regexp' => '/coccocbot-web\/([0-9.]*)/u' ],
80
+ [ 'name' => 'Coccocbot Image', 'id' => 'coccoc', 'regexp' => '/coccocbot-image\/([0-9.]*)/u' ],
81
  [ 'name' => 'Comodo', 'id' => 'comodo', 'regexp' => '/Comodo Spider ([0-9.]*)/u' ],
82
  [ 'name' => 'CommaFeed', 'id' => 'commafeed', 'regexp' => '/CommaFeed\/([0-9.]*)/u' ],
83
+ [ 'name' => 'Common Crawl Bot', 'id' => 'cbot', 'regexp' => '/CCBot\/([0-9.]*)/u' ],
84
+ [ 'name' => 'Common Crawl Research Bot', 'id' => 'cresearch', 'regexp' => '/CCResearchBot\/([0-9.]*)/u' ],
85
  [ 'name' => 'Data Hotel Watchdog', 'id' => 'watchdog', 'regexp' => '/Data-Hotel-Watchdog\/([0-9.]*)/u' ],
86
+ [ 'name' => 'Datanyze', 'id' => 'datanyze', 'regexp' => '/Datanyze/u' ],
87
  [ 'name' => 'DataparkSearch', 'id' => 'datasearch', 'regexp' => '/DataparkSearch\/([0-9.]*)/u' ],
88
+ [ 'name' => 'Dataprovider Bot', 'id' => 'dataprovider', 'regexp' => '/Dataprovider/u' ],
89
+ [ 'name' => 'Daum', 'id' => 'daum', 'regexp' => '/Daum\/([0-9.]*)/u' ],
90
  [ 'name' => 'Daumoa', 'id' => 'daumoa', 'regexp' => '/Daumoa ([0-9.]*)/u' ],
91
  [ 'name' => 'Digg', 'id' => 'digg', 'regexp' => '/Digg Deeper\/v([0-9.]*)/u' ],
92
  [ 'name' => 'Digg', 'id' => 'digg', 'regexp' => '/Digg\/([0-9.]*)/u' ],
93
+ [ 'name' => 'DomainCrawler', 'id' => 'domaincrawl', 'regexp' => '/DomainCrawler\/([0-9.]*)/u' ],
94
+ [ 'name' => 'Domain Stats Bot', 'id' => 'domainstats', 'regexp' => '/DomainStatsBot\/([0-9.]*)/u' ],
95
+ [ 'name' => 'Discord', 'id' => 'discord', 'regexp' => '/Discordbot\/([0-9.]*)/u' ],
96
  [ 'name' => 'Domain Re-Animator', 'id' => 'domain', 'regexp' => '/Domain Re-Animator Bot/u' ],
97
+ [ 'name' => 'DMCA', 'id' => 'dmca', 'regexp' => '/DMCA\.com Page Protection Crawling Service/u' ],
98
+ [ 'name' => 'DuckDuckGo Bot', 'id' => 'duckduck', 'regexp' => '/DuckDuckBot\/([0-9.]*)/u' ],
99
+ [ 'name' => 'DuckDuckGo Https Bot', 'id' => 'duckduck', 'regexp' => '/DuckDuckBot-Https\/([0-9.]*)/u' ],
100
+ [ 'name' => 'DuckDuckGo Favicons Bot', 'id' => 'duckduck', 'regexp' => '/DuckDuckGo-Favicons-Bot\/([0-9.]*)/u' ],
101
+ [ 'name' => 'Embed PHP Library', 'id' => 'embed', 'regexp' => '/Embed PHP library/iu' ],
102
+ [ 'name' => 'Evc-batch', 'id' => 'evc', 'regexp' => '/evc-batch\/([0-9.]*)/u' ],
103
  [ 'name' => 'Exabot Thumbnails', 'id' => 'exabot', 'regexp' => '/Exabot-Thumbnails/u' ],
104
  [ 'name' => 'ExactSeek', 'id' => 'exactseek', 'regexp' => '/ExactSeek Crawler/u' ],
105
  [ 'name' => 'Ezooms Crawler', 'id' => 'ezooms', 'regexp' => '/Ezooms\/([0-9.]*)/u' ],
126
  [ 'name' => 'FeedValidator', 'id' => 'validator', 'regexp' => '/FeedValidator\/([0-9.]*)/u' ],
127
  [ 'name' => 'FeedZirra', 'id' => 'feed', 'regexp' => '/feedzirra/u' ],
128
  [ 'name' => 'Fever', 'id' => 'fever', 'regexp' => '/Fever\/([0-9.]*)/u' ],
129
+ [ 'name' => 'Florienzh', 'id' => 'florienzh', 'regexp' => '/Florienzh\/([0-9.]*)/u' ],
130
  [ 'name' => 'Friendica', 'id' => 'friendica', 'regexp' => '/Friendica/u' ],
131
  [ 'name' => 'FTRF: Friendly Robot', 'id' => 'robot', 'regexp' => '/FTRF: Friendly robot\/([0-9.]*)/u' ],
132
  [ 'name' => 'Genieo Web Filter', 'id' => 'genieo', 'regexp' => '/Genieo\/([0-9.]*)/u' ],
133
  [ 'name' => 'GNIP', 'id' => 'fetchor', 'regexp' => '/UnwindFetchor\/([0-9.]*)/u' ],
134
  [ 'name' => 'Gocrawl', 'id' => 'google', 'regexp' => '/Googlebot \(gocrawl v([0-9.]*)\)/u' ],
135
+ [ 'name' => 'Gofeed', 'id' => 'gofeed', 'regexp' => '/Gofeed\/([0-9.]+)/u' ],
136
  [ 'name' => 'GomezAgent', 'id' => 'gomez', 'regexp' => '/GomezAgent ([0-9.]+)/u' ],
137
  [ 'name' => 'Goo', 'id' => 'ichiro', 'regexp' => '/ichiro\/mobile goo/u' ],
138
  [ 'name' => 'Goo Blog Search', 'id' => 'gooblog', 'regexp' => '/gooblog\/([0-9.]*)/u' ],
147
  [ 'name' => 'Google App Engine', 'id' => 'google', 'regexp' => '/AppEngine-Google/u' ],
148
  [ 'name' => 'Google Web Preview', 'id' => 'google', 'regexp' => '/Google Web Preview/u' ],
149
  [ 'name' => 'Google Page Speed', 'id' => 'google', 'regexp' => '/Google Page Speed Insights/u' ],
150
+ [ 'name' => 'Google Favicon', 'id' => 'google', 'regexp' => '/Google Favicon/u' ],
151
  [ 'name' => 'Google FeedBurner', 'id' => 'feed', 'regexp' => '/FeedBurner\/([0-9.]*)/u' ],
152
  [ 'name' => 'Google Feedfetcher', 'id' => 'google', 'regexp' => '/Feedfetcher-Google/iu' ],
153
  [ 'name' => 'Google Font Analysis', 'id' => 'google', 'regexp' => '/Google-FontAnalysis\/([0-9.]*)/u' ],
160
  [ 'name' => 'Google Wireless Transcoder', 'id' => 'google', 'regexp' => '/Google Wireless Transcoder/u' ],
161
  [ 'name' => 'Google Play Newsstand', 'id' => 'google', 'regexp' => '/GoogleProducer/u' ],
162
  [ 'name' => 'Google YouTube Sample', 'id' => 'google', 'regexp' => '/Google-YouTubeSample\/([0-9.]*)/u' ],
163
+ [ 'name' => 'Gowikibot', 'id' => 'gowiki', 'regexp' => '/Gowikibot\/([0-9.]*)/u' ],
164
  [ 'name' => 'Grammarly', 'id' => 'grammarly', 'regexp' => '/Grammarly\/([0-9.]*)/u' ],
165
  [ 'name' => 'Grub', 'id' => 'grub', 'regexp' => '/grub-client-([0-9.]*)/u' ],
166
  [ 'name' => 'Hatena Antenna', 'id' => 'hatena', 'regexp' => '/Hatena Antenna\/([0-9.]*)/u' ],
167
  [ 'name' => 'Hatena Diary', 'id' => 'hatena', 'regexp' => '/Hatena Diary RSS Module/u' ],
168
  [ 'name' => 'Hatena Pagetitle', 'id' => 'hatena', 'regexp' => '/Hatena Pagetitle Agent\/([0-9.]*)/u' ],
169
  [ 'name' => 'HeartRails Capture', 'id' => 'capture', 'regexp' => '/HeartRails_Capture\/([0-9.]*)/u' ],
170
+ [ 'name' => 'Heureka Feed', 'id' => 'heureka', 'regexp' => '/Heurekabot-Feed/u' ],
171
+ [ 'name' => 'HootSuite', 'id' => 'hootsuite', 'regexp' => '/Hootsuite-WebFeed\/([0-9\.]*)/u' ],
172
+ [ 'name' => 'HootSuite', 'id' => 'hootsuite', 'regexp' => '/HootSuite Image proxy/u' ],
173
  [ 'name' => 'htdig', 'id' => 'htdig', 'regexp' => '/htdig\/([0-9.]*)/u' ],
174
  [ 'name' => 'HTTPMon', 'id' => 'httpmon', 'regexp' => '/HTTPMon\/([0-9.]*)/u' ],
175
  [ 'name' => 'HubPages', 'id' => 'hubpages', 'regexp' => '/HubPages V([0-9.]*)/u' ],
176
+ [ 'name' => 'HubSpot Crawler', 'id' => 'hubspot', 'regexp' => '/hubspot\.com/u' ],
177
  [ 'name' => 'iAsk Spider', 'id' => 'spider', 'regexp' => '/iaskspider\/([0-9.]*)/u' ],
178
  [ 'name' => 'iAsk Spider', 'id' => 'spider', 'regexp' => '/iaskspider2/u' ],
179
  [ 'name' => 'Ichiro', 'id' => 'ichiro', 'regexp' => '/ichiro\/([0-9.]*)/u' ],
180
  [ 'name' => 'Internet Archive', 'id' => 'archive', 'regexp' => '/InternetArchive\/([0-9.]*)/u' ],
181
+ [ 'name' => 'IndeedBot', 'id' => 'indeed', 'regexp' => '/IndeedBot ([0-9.]*)/u' ],
182
+ [ 'name' => 'Iodc', 'id' => 'iodc', 'regexp' => '/iodc\.co\.uk/u' ],
183
+ [ 'name' => 'Istellabot', 'id' => 'istellabot', 'regexp' => '/istellabot\/t\.([0-9.]*)/u' ],
184
  [ 'name' => 'JamesBOT', 'id' => 'crawler', 'regexp' => '/James BOT - WebCrawler/u' ],
185
  [ 'name' => 'Jayde', 'id' => 'crawler', 'regexp' => '/Jayde Crawler./u' ],
186
+ [ 'name' => 'KakaoTalk Bot', 'id' => 'kakao', 'regexp' => '/kakaotalk-scrap\/([0-9.]*)/u' ],
187
  [ 'name' => 'Kouio', 'id' => 'kouio', 'regexp' => '/kouio.com/u' ],
188
  [ 'name' => 'Larbin', 'id' => 'larbin', 'regexp' => '/[Ll]arbin[\/_]([0-9.]*)/u' ],
189
+ [ 'name' => 'LetsearchBot', 'id' => 'letsearch', 'regexp' => '/LetsearchBot\/([0-9.]*)/u' ],
190
+ [ 'name' => 'Line Bot', 'id' => 'line', 'regexp' => '/Linespider\/([0-9.]*)/u' ],
191
  [ 'name' => 'Linkedin Bot', 'id' => 'linkedin', 'regexp' => '/LinkedInBot\/([0-9.]*)/u' ],
192
+ [ 'name' => 'Linkpad Bot', 'id' => 'linkpad', 'regexp' => '/LinkpadBot\/([0-9.]*)/u' ],
193
  [ 'name' => 'Linkdex Bot', 'id' => 'linkdex', 'regexp' => '/linkdexbot-mobile\/([0-9.]*)/u' ],
194
  [ 'name' => 'Linkdex Bot', 'id' => 'linkdex', 'regexp' => '/linkdex.com\/v([0-9.]*)/u' ],
195
  [ 'name' => 'Livedoor', 'id' => 'livedoor', 'regexp' => '/livedoor/u' ],
196
+ [ 'name' => 'LookSeek', 'id' => 'seeker', 'regexp' => '/Seeker v\.([0-9.]*)/u' ],
197
  [ 'name' => 'LTX71', 'id' => 'ltx71', 'regexp' => '/ltx71/u' ],
198
  [ 'name' => 'Magpie RSS', 'id' => 'magpie', 'regexp' => '/MagpieRSS\/([0-9.]*)/u' ],
199
+ [ 'name' => 'Majestic MJ12 Bot', 'id' => 'mj12bot', 'regexp' => '/MJ12bot\/v([0-9.]*)/u' ],
200
+ [ 'name' => 'Majestic MJ12 Bot', 'id' => 'mj12bot', 'regexp' => '/mj12bot/u' ],
201
  [ 'name' => 'Mapian News Bot', 'id' => 'mapion', 'regexp' => '/mapion-news-bot\/([0-9.]*)/u' ],
202
+ [ 'name' => 'Mail.ru Bot', 'id' => 'mail\.ru', 'regexp' => '/Mail\.RU_Bot\/Img\/([0-9.]*)/i' ],
203
+ [ 'name' => 'Mail.ru Bot', 'id' => 'mail\.ru', 'regexp' => '/Mail\.RU_Bot\/([0-9.]*)/i' ],
204
+ [ 'name' => 'Medium Bot', 'id' => 'medium', 'regexp' => '/Mediumbot-MetaTagFetcher\/([0-9.]*)/u' ],
205
+ [ 'name' => 'Medium Bot', 'id' => 'medium', 'regexp' => '/Mediumbot-ProxyFetcher\/([0-9.]*)/u' ],
206
+ [ 'name' => 'Mega Index Bot', 'id' => 'megaindex', 'regexp' => '/MegaIndex\.ru\/([0-9.]*)/u' ],
207
  [ 'name' => 'Microsoft Social Streams', 'id' => 'socialstreams', 'regexp' => '/Microsoft MSN SocialStreams Bot/u' ],
208
  [ 'name' => 'Mixi', 'id' => 'mixi', 'regexp' => '/mixi-check\/([0-9.]*)/u' ],
209
+ [ 'name' => 'Minds', 'id' => 'minds', 'regexp' => '/MindsMediaProxy\/([0-9\.]*)/u' ],
210
  [ 'name' => 'MnoGoSearch', 'id' => 'mnogo', 'regexp' => '/MnoGoSearch\/([0-9.]*)/u' ],
211
+ [ 'name' => 'MojeekBot', 'id' => 'mojeek', 'regexp' => '/MojeekBot\/([0-9.]*)/u' ],
212
  [ 'name' => 'Monitor.us', 'id' => 'monitor', 'regexp' => '/monitor.us/u' ],
213
+ [ 'name' => 'Moz', 'id' => 'dotbot', 'regexp' => '/DotBot\/([0-9.]*)/i' ],
214
+ [ 'name' => 'Moz', 'id' => 'rogerbot', 'regexp' => '/rogerbot\/([0-9.]*)/i' ],
215
  [ 'name' => 'Naver Yeti', 'id' => 'yeti', 'regexp' => '/Yeti\/([0-9.]*)/u' ],
216
+ [ 'name' => 'MxToolbox', 'id' => 'mxtoolbox', 'regexp' => '/MxToolbox\/([a-zA-Z0-9.]*)/u' ],
217
+ [ 'name' => 'Netcraft Survey Agent Bot', 'id' => 'netcraft', 'regexp' => '/NetcraftSurveyAgent\/([0-9.]*)/u' ],
218
+ [ 'name' => 'Netcraft Web Server Survey Bot', 'id' => 'netcraft', 'regexp' => '/Netcraft Web Server Survey/u' ],
219
+ [ 'name' => 'Netcraft SSL Server Survey Bot', 'id' => 'netcraft', 'regexp' => '/Netcraft SSL Server Survey/u' ],
220
+ [ 'name' => 'Netcraft Bot', 'id' => 'netcraft', 'regexp' => '/Netcraft/iu' ],
221
+ [ 'name' => 'netEstate NE Crawler', 'id' => 'netestate', 'regexp' => '/netEstate NE Crawler/u' ],
222
  [ 'name' => 'Netvibes', 'id' => 'netvibes', 'regexp' => '/Netvibes/u' ],
223
  [ 'name' => 'NewsBlur', 'id' => 'newsblur', 'regexp' => '/NewsBlur Favicon Fetcher/u' ],
224
  [ 'name' => 'NewsBlur', 'id' => 'newsblur', 'regexp' => '/NewsBlur Feed Fetcher/u' ],
227
  [ 'name' => 'NewsGator', 'id' => 'newsgator', 'regexp' => '/NewsGator\/([0-9.]*)/u' ],
228
  [ 'name' => 'NewsGator', 'id' => 'newsgator', 'regexp' => '/NewsGatorOnline\/([0-9.]*)/u' ],
229
  [ 'name' => 'NewsGator FetchLinks', 'id' => 'newsgator', 'regexp' => '/NewsGator FetchLinks extension\/([0-9.]*)/u' ],
230
+ [ 'name' => 'Nimbostratus', 'id' => 'nimbostratus', 'regexp' => '/Nimbostratus-Bot\/v([0-9.]*)/u' ],
231
+ [ 'name' => 'OdklBot', 'id' => 'odklbot', 'regexp' => '/OdklBot\/([0-9.]*)/u' ],
232
  [ 'name' => 'OpenWebSpider', 'id' => 'spider', 'regexp' => '/OpenWebSpider v([0-9.]*)/u' ],
233
  [ 'name' => 'OrangeBot', 'id' => 'orange', 'regexp' => '/OrangeBot-Collector\/([0-9.]*)/u' ],
234
  [ 'name' => 'OrangeBot', 'id' => 'orange', 'regexp' => '/OrangeBot-Mobile/u' ],
235
+ [ 'name' => 'PagesInventory', 'id' => 'pages', 'regexp' => '/PagesInventory/u' ],
236
+ [ 'name' => 'Petal Bot', 'id' => 'petal', 'regexp' => '/PetalBot/u' ],
237
+ [ 'name' => 'Petal Bot', 'id' => 'aspiegel', 'regexp' => '/Aspiegel/u' ],
238
+ [ 'name' => 'Picsearch Bot', 'id' => 'psbot', 'regexp' => '/psbot\/([0-9.]*)/u' ],
239
+ [ 'name' => 'Picsearch Bot', 'id' => 'psbot', 'regexp' => '/psbot-page/u' ],
240
+ [ 'name' => 'Picsearch Bot', 'id' => 'psbot', 'regexp' => '/psbot-image/u' ],
241
  [ 'name' => 'Pingdom', 'id' => 'pingdom', 'regexp' => '/Pingdom.com_bot_version_([0-9.]*)/u' ],
242
  [ 'name' => 'Pinterest', 'id' => 'pinterest', 'regexp' => '/Pinterest\/([0-9.]+)( \(+|$)/u' ],
243
+ [ 'name' => 'Plurk Bot', 'id' => 'plurk', 'regexp' => '/PlurkBot\/([0-9\.]*)/u' ],
244
+ [ 'name' => 'Pocket', 'id' => 'pocket', 'regexp' => '/PocketImageCache\/([0-9.]+)/u' ],
245
+ [ 'name' => 'Pocket', 'id' => 'pocket', 'regexp' => '/PocketParser\/([0-9.]+)/u' ],
246
  [ 'name' => 'PostRank', 'id' => 'postrank', 'regexp' => '/PostRank\/([0-9.]*)/u' ],
247
  [ 'name' => 'PowerMapper', 'id' => 'crawler', 'regexp' => '/CrawlerProcess \(http:\/\/www\.PowerMapper\.com\) \/([0-9.]*)/u' ],
248
  [ 'name' => 'Radian 6', 'id' => 'feed', 'regexp' => '/R6_FeedFetcher/u' ],
249
  [ 'name' => 'Radian 6', 'id' => 'comment', 'regexp' => '/R6_CommentReader/u' ],
250
+ [ 'name' => 'Reddit Bot', 'id' => 'reddit', 'regexp' => '/redditbot\/([0-9.]*)/u' ],
251
  [ 'name' => 'RssBar', 'id' => 'rssbar', 'regexp' => '/RssBar\/([0-9.]*)/u' ],
252
  [ 'name' => 'ROI Hunter', 'id' => 'hunter', 'regexp' => '/ROI Hunter/u' ],
253
  [ 'name' => 'QuerySeekerSpider', 'id' => 'spider', 'regexp' => '/QuerySeekerSpider(?:\/([0-9.]*))?/u' ],
255
  [ 'name' => 'SafeSearch Microdata', 'id' => 'safesearch', 'regexp' => '/SafeSearch microdata crawler/u' ],
256
  [ 'name' => 'Scrapy', 'id' => 'scrapy', 'regexp' => '/Scrapy\/([0-9.]*)/u' ],
257
  [ 'name' => 'ScreenerBot', 'id' => 'crawler', 'regexp' => '/ScreenerBot Crawler Beta ([0-9.]*)/u' ],
258
+ [ 'name' => 'Search Atlas Bot', 'id' => 'searchatlas', 'regexp' => '/SearchAtlas/iu' ],
259
+ [ 'name' => 'Seekport Crawler', 'id' => 'seekport', 'regexp' => '/Seekport Crawler/u' ],
260
+ [ 'name' => 'Semrush', 'id' => 'semrush', 'regexp' => '/SemrushBot\/([0-9.]*)/u' ],
261
+ [ 'name' => 'Serp Stat', 'id' => 'serpstat', 'regexp' => '/serpstatbot\/([0-9.]*)/u' ],
262
+ [ 'name' => 'SEOkicks Bot', 'id' => 'seokicks', 'regexp' => '/SEOkicks/u' ],
263
  [ 'name' => 'Server Density', 'id' => 'monitor', 'regexp' => '/Server Density Service Monitoring/u' ],
264
+ [ 'name' => 'Seznam bot', 'id' => 'seznam', 'regexp' => '/SeznamBot|SklikBot|Seznam screenshot-generator/u' ],
265
+ [ 'name' => 'Seznam Email Proxy', 'id' => 'seznam', 'regexp' => '/SeznamEmailProxy/u' ],
266
+ [ 'name' => 'Seznam Zbozi.cz', 'id' => 'seznam', 'regexp' => '/Seznam-Zbozi-robot/u' ],
267
  [ 'name' => 'ShopWiki', 'id' => 'shopwiki', 'regexp' => '/ShopWiki\/([0-9.]*)/u' ],
268
  [ 'name' => 'SilverReader', 'id' => 'reader', 'regexp' => '/SilverReader\/([0-9.]*)/u' ],
269
  [ 'name' => 'SimplePie', 'id' => 'simplepie', 'regexp' => '/SimplePie\/([0-9.]*)/u' ],
270
  [ 'name' => 'Site24x7', 'id' => 'site24', 'regexp' => '/Site24x7/u' ],
271
+ [ 'name' => 'Skype Url Preview', 'id' => 'skype', 'regexp' => '/SkypeUriPreview Preview\/([0-9.]*)/u' ],
272
+ [ 'name' => 'Slackbot Link Checker', 'id' => 'slack', 'regexp' => '/Slackbot-LinkExpanding ([0-9.]*)/u' ],
273
  [ 'name' => 'Sogou Web Spider', 'id' => 'sogou', 'regexp' => '/sogou spider/u' ],
274
  [ 'name' => 'Sogou Web Spider', 'id' => 'sogou', 'regexp' => '/Sogou pic spider\/([0-9.]*)/u' ],
275
  [ 'name' => 'Sogou Web Spider', 'id' => 'sogou', 'regexp' => '/Sogou inst spider\/([0-9.]*)/u' ],
279
  [ 'name' => 'Soso Web Spider', 'id' => 'soso', 'regexp' => '/Sosospider\/([0-9.]*)/u' ],
280
  [ 'name' => 'Soso Web Spider', 'id' => 'soso', 'regexp' => '/Sosospider/u' ],
281
  [ 'name' => 'Soso Image Spider', 'id' => 'soso', 'regexp' => '/Sosoimagespider/u' ],
282
+ [ 'name' => 'SpazioDati', 'id' => 'spaziodati', 'regexp' => '/spaziodati/u' ],
283
  [ 'name' => 'SPDYCheck', 'id' => 'spdycheck', 'regexp' => '/SPDYCheck SPDY Protocol Tester/iu' ],
284
  [ 'name' => 'Spinn3r', 'id' => 'spinn', 'regexp' => '/Spinn3r ([0-9.]*)/iu' ],
285
  [ 'name' => 'Spiderlytics', 'id' => 'spider', 'regexp' => '/Spiderlytics\/([0-9.]*)/iu' ],
286
+ [ 'name' => 'Sputnik Favicon Bot', 'id' => 'sputnik', 'regexp' => '/SputnikFaviconBot\/([0-9.]*)/iu' ],
287
+ [ 'name' => 'Sputnik Image Bot', 'id' => 'sputnik', 'regexp' => '/SputnikImageBot\/([0-9.]*)/iu' ],
288
+ [ 'name' => 'Sputnik Bot', 'id' => 'sputnik', 'regexp' => '/SputnikBot\/([0-9.]*)/iu' ],
289
  [ 'name' => 'StatusCake Error Detector', 'id' => 'detector', 'regexp' => '/StatusCake Error Detector/iu' ],
290
  [ 'name' => 'Summify', 'id' => 'summify', 'regexp' => '/Summify\/([0-9.]*)/u' ],
291
  [ 'name' => 'TelegramBot', 'id' => 'telegram', 'regexp' => '/TelegramBot/u' ],
292
  [ 'name' => 'Twisted PageGetter', 'id' => 'twisted', 'regexp' => '/Twisted PageGetter/u' ],
293
  [ 'name' => 'Twitterbot', 'id' => 'twitter', 'regexp' => '/Twitterbot\/([0-9.]*)/u' ],
294
  [ 'name' => 'Tiny Tiny RSS', 'id' => 'tiny', 'regexp' => '/Tiny Tiny RSS\/([0-9.]*)/u' ],
295
+ [ 'name' => 'TinEye Bot', 'id' => 'tineye', 'regexp' => '/TinEye\/([0-9.]*)/u' ],
296
+ [ 'name' => 'TinEye Bot', 'id' => 'tineye', 'regexp' => '/TinEye-bot\/([0-9.]*)/u' ],
297
  [ 'name' => 'TLSProber', 'id' => 'tlsprober', 'regexp' => '/TLSProber\/([0-9.]*)/u' ],
298
+ [ 'name' => 'TrustedSite', 'id' => 'trustedsite', 'regexp' => '/TrustedSite/u' ],
299
  [ 'name' => 'Typhoeus', 'id' => 'typhoeus', 'regexp' => '/Typhoeus/u' ],
300
  [ 'name' => 'Vagabondo', 'id' => 'vagabondo', 'regexp' => '/Vagabondo\/([0-9.]*)/u' ],
301
+ [ 'name' => 'VelenPublicWebCrawler', 'id' => 'velen', 'regexp' => '/VelenPublicWebCrawler\/([0-9.]*)/u' ],
302
+ [ 'name' => 'vkShare', 'id' => 'vkshare', 'regexp' => '/vkShare/u' ],
303
+ [ 'name' => 'Voat', 'id' => 'voat', 'regexp' => '/Voat\.co OpenGraph Parser/u' ],
304
  [ 'name' => 'Voilabot', 'id' => 'voila', 'regexp' => '/Voila[Bb]ot/u' ],
305
  [ 'name' => 'VocusBot', 'id' => 'vocus', 'regexp' => '/VocusBot ([0-9.]*)/u' ],
306
  [ 'name' => 'Vodafone mCrawler', 'id' => 'mcrawler', 'regexp' => '/Vodafone mCrawler/u' ],
307
+ [ 'name' => 'VuhuvBot', 'id' => 'vuhuv', 'regexp' => '/vuhuvBot\/([0-9.]*)/u' ],
308
  [ 'name' => 'W3Bot', 'id' => 'w3bot', 'regexp' => '/W3Bot ([0-9.]*)/u' ],
309
  [ 'name' => 'W3C CSS Validator', 'id' => 'jigsaw', 'regexp' => '/Jigsaw\/([0-9.]*)/u' ],
310
  [ 'name' => 'W3C Internationalization Checker', 'id' => 'w3c', 'regexp' => '/W3C_I18n-Checker\/([0-9.]*)/u' ],
316
  [ 'name' => 'W3C Robot', 'id' => 'w3c', 'regexp' => '/W3CRobot\/([0-9.]*)/u' ],
317
  [ 'name' => 'W3C Unified Validator', 'id' => 'w3c', 'regexp' => '/W3C_Unicorn\/([0-9.]*)/u' ],
318
  [ 'name' => 'W3C Validator.nu', 'id' => 'validator', 'regexp' => '/Validator.nu\//u' ],
319
+ [ 'name' => 'Wappalyzer', 'id' => 'wappalyzer', 'regexp' => '/Wappalyzer/u' ],
320
  [ 'name' => 'Wayback Archive', 'id' => 'wayback', 'regexp' => '/waybackarchive.org\/([0-9.]*)/u' ],
321
  [ 'name' => 'WebbCrawler', 'id' => 'crawler', 'regexp' => '/WebbCrawler ([0-9.]*)/u' ],
322
  [ 'name' => 'WebIndexer', 'id' => 'webindexer', 'regexp' => '/WebIndexer\//u' ],
324
  [ 'name' => 'WordPress.com', 'id' => 'wordpress', 'regexp' => '/WordPress\.com; http/u' ],
325
  [ 'name' => 'WordPress Jetpack', 'id' => 'wordpress', 'regexp' => '/Jetpack by WordPress\.com/u' ],
326
  [ 'name' => 'WWW Mechanize', 'id' => 'mechanize', 'regexp' => '/WWW-Mechanize\/([0-9.]*)/u' ],
327
+ [ 'name' => 'Xenu Link Sleuth', 'id' => 'xenu', 'regexp' => '/Xenu Link Sleuth\/([0-9.]*)/u' ],
328
  [ 'name' => 'Xerka WebBot', 'id' => 'xerka', 'regexp' => '/Xerka WebBot v([0-9.]*)/u' ],
329
  [ 'name' => 'XML Sitemaps Generator', 'id' => 'sitemap', 'regexp' => '/XML-Sitemaps\/([0-9.]*)/u' ],
330
  [ 'name' => 'XMLSitemapGenerator', 'id' => 'sitemap', 'regexp' => '/XmlSitemapGenerator/u' ],
363
 
364
  [ 'name' => 'Inktomi Slurp', 'id' => 'slurp', 'regexp' => '/Slurp\/([0-9.]*)/u' ],
365
  [ 'name' => 'Inktomi Slurp', 'id' => 'slurp', 'regexp' => '/Slurp\.so\/([0-9.]*)/u' ],
366
+
367
+ [ 'name' => 'Yelp Spider', 'id' => 'yelp', 'regexp' => '/yelpspider\-([0-9.]*)/u' ],
368
+ [ 'name' => 'Yioop Bot', 'id' => 'yioop', 'regexp' => '/YioopBot/u' ],
369
+ [ 'name' => 'Yisou Spider', 'id' => 'yisou', 'regexp' => '/YisouSpider\/?([0-9.]*)/u' ],
370
+ [ 'name' => 'Zgrab', 'id' => 'zgrab', 'regexp' => '/zgrab\//u' ],
371
+ [ 'name' => 'ZmEu', 'id' => 'zmeu', 'regexp' => '/ZmEu/u' ],
372
 
373
  /* Generic bots */
374
  [ 'name' => 'Apache Httpd', 'id' => 'httpclient', 'regexp' => '/Apache-HttpClient(?:\/([0-9.]*))?/u' ],
377
  [ 'name' => 'Apache Nutch', 'id' => 'nutch', 'regexp' => '/Nutch(?:CVS|Org)\/([0-9.]*)/u' ],
378
  [ 'name' => 'Apache Synapse', 'id' => 'synapse', 'regexp' => '/compatible; Synapse/u' ],
379
  [ 'name' => 'Borland Delphi', 'id' => 'indy', 'regexp' => '/Indy Library/u' ],
380
+ [ 'name' => 'Go Http Client', 'id' => 'go', 'regexp' => '/Go-http-client\/([0-9.]*)/u' ],
381
+ [ 'name' => 'Go Http Client', 'id' => 'go', 'regexp' => '/go-httpclient v([0-9.]*)/u' ],
382
+ [ 'name' => 'HttpUnit', 'id' => 'httpunit', 'regexp' => '/httpunit\/([0-9.]*)/u' ],
383
+ [ 'name' => 'OkHttp', 'id' => 'okhttp', 'regexp' => '/okhttp\/([0-9.]*)/u' ],
384
+ [ 'name' => 'Node Fetch', 'id' => 'node', 'regexp' => '/node-fetch\/([0-9.]*)/u' ],
385
  [ 'name' => 'Wget', 'id' => 'wget', 'regexp' => '/Wget\/([0-9.]*)/u' ],
386
  [ 'name' => 'Curl', 'id' => 'curl', 'regexp' => '/^curl\/([0-9.]*)/u' ],
387
 
390
  [ 'name' => 'Perl', 'id' => 'simple', 'regexp' => '/LWP::Simple\//u' ],
391
  [ 'name' => 'Perl', 'id' => 'libwww', 'regexp' => '/libwww-perl\//u' ],
392
  [ 'name' => 'Perl', 'id' => 'lwp', 'regexp' => '/lwp-trivial\//u' ],
393
+ [ 'name' => 'Python', 'id' => 'urllib', 'regexp' => '/Python-urllib\/([0-9.]*)/u' ],
394
+ [ 'name' => 'Python', 'id' => 'requests', 'regexp' => '/python-requests\/([0-9.]*)/u' ],
395
  [ 'name' => 'PHP', 'id' => 'php', 'regexp' => '/ PHP\/([0-9.]*)/u' ],
396
  [ 'name' => 'PHP', 'id' => 'php', 'regexp' => '/^PHP/u' ],
397
  [ 'name' => 'PHP', 'id' => 'pear', 'regexp' => '/PEAR HTTP_Request class/u' ],
integration/whichbrowser/data/applications-browsers.php CHANGED
@@ -15,7 +15,9 @@ Applications::$BROWSERS = [
15
  [ 'name' => '2345 Explorer', 'id' => '2345', 'regexp' =>'/2345Explorer\/([0-9.]*)/u', 'details' => 3 ],
16
  [ 'name' => '2345 Explorer', 'id' => '2345', 'regexp' =>'/2345Explorer v([0-9.]*)/u', 'details' => 3 ],
17
  [ 'name' => '2345 Chrome', 'id' => '2345', 'regexp' =>'/2345chrome v([0-9.]*)/u', 'details' => 3 ],
 
18
  [ 'name' => '360 Extreme Explorer', 'id' => 'qihu', 'regexp' =>'/QIHU 360EE/u', 'type' => Constants\DeviceType::DESKTOP ],
 
19
  [ 'name' => '360 Safe Explorer', 'id' => 'qihu', 'regexp' =>'/QIHU 360SE/u', 'type' => Constants\DeviceType::DESKTOP ],
20
  [ 'name' => '7Star', 'id' => '7star', 'regexp' =>'/7Star\/([0-9.]*)/u' ], // see: http://www.qixing123.com
21
  [ 'name' => 'ABrowse', 'id' => 'abrowse', 'regexp' =>'/A[Bb]rowse ([0-9.]*)/u' ], // browser for the Syllable OS
@@ -23,8 +25,10 @@ Applications::$BROWSERS = [
23
  [ 'name' => 'Acorn Browse', 'id' => 'acorn', 'regexp' =>'/Acorn Browse ([0-9.]+)/u' ],
24
  [ 'name' => 'Acorn Browse', 'id' => 'acorn', 'regexp' =>'/Acorn Phoenix ([0-9.]+)/u' ],
25
  [ 'name' => 'Acoo Browser', 'id' => 'acoo', 'regexp' =>'/Acoo Browser/u' ],
 
26
  [ 'name' => 'AOL Desktop', 'id' => 'aol', 'regexp' =>'/AOL ([0-9.]*); AOLBuild/i' ],
27
  [ 'name' => 'AOL Browser', 'id' => 'america', 'regexp' =>'/America Online Browser (?:[0-9.]*); rev([0-9.]*);/i' ],
 
28
  [ 'name' => 'Arachne', 'id' => 'arachne', 'regexp' =>'/xChaos_Arachne\/[0-9]\.([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: www.glennmcc.org
29
  [ 'name' => 'Arora', 'id' => 'arora', 'regexp' =>'/[Aa]rora\/([0-9.]*)/u' ], // see: www.arora-browser.org
30
  [ 'name' => 'AWeb', 'id' => 'aweb', 'regexp' =>'/Amiga-AWeb(?:\/([0-9.]*))?/u' ],
@@ -32,85 +36,180 @@ Applications::$BROWSERS = [
32
  [ 'name' => 'Avant Browser', 'id' => 'avant', 'regexp' =>'/Avant Browser/u' ],
33
  [ 'name' => 'Avant Browser', 'id' => 'avant', 'regexp' =>'/Avant TriCore/u' ],
34
  [ 'name' => 'Avast SafeZone', 'id' => 'asw', 'regexp' =>'/ASW\/([0-9.]*)/u', 'details' => 2 ],
 
35
  [ 'name' => 'Aviator', 'id' => 'aviator', 'regexp' =>'/Aviator\/([0-9.]*)/u', 'details' => 1 ], // see: https://github.com/WhiteHatSecurity/Aviator
 
36
  [ 'name' => 'Baidu Browser', 'id' => 'flyflow', 'regexp' =>'/FlyFlow\/([0-9.]*)/u', 'details' => 2 ],
37
  [ 'name' => 'Baidu Browser', 'id' => 'bdbrowser', 'regexp' =>'/bdbrowser\/([0-9.]*)/i' ],
38
  [ 'name' => 'Baidu Browser', 'id' => 'bdbrowser', 'regexp' =>'/bdbrowser_i18n\/([0-9.]*)/i' ],
39
  [ 'name' => 'Baidu Spark', 'id' => 'bdspark', 'regexp' =>'/BDSpark\/([0-9.]*)/u', 'details' => 2 ],
 
40
  [ 'name' => 'Beamrise', 'id' => 'beamrise', 'regexp' =>'/Beamrise\/([0-9.]*)/u' ], // see: http://beamrise.com
 
41
  [ 'name' => 'Black Wren', 'id' => 'blackwren', 'regexp' =>'/BlackWren\/([0-9.]*)/u', 'details' => 2 ], // see: https://github.com/conmarap/jetbrowser
 
 
 
42
  [ 'name' => 'Brave', 'id' => 'brave', 'regexp' =>'/brave\/([0-9.]*)/u' ],
 
 
 
43
  [ 'name' => 'Byffox', 'id' => 'byffox', 'regexp' =>'/Byffox\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
44
  [ 'name' => 'Camino', 'id' => 'camino', 'regexp' =>'/Camino\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
45
  [ 'name' => 'Canure', 'id' => 'canure', 'regexp' =>'/Canure\/([0-9.]*)/u', 'details' => 3 ], // see: http://canure.weebly.com/index.html
 
 
46
  [ 'name' => 'Charon', 'id' => 'charon', 'regexp' =>'/Charon/' ], // see: http://www.vitanuova.com/inferno/man/1/charon.html
 
 
 
 
47
  [ 'name' => 'ChromePlus', 'id' => 'chromeplus', 'regexp' =>'/ChromePlus(?:\/([0-9.]*))?$/u', 'details' => 3, 'type' => Constants\DeviceType::DESKTOP ],
 
 
48
  [ 'name' => 'CometBird', 'id' => 'cometbird', 'regexp' =>'/CometBird\/([0-9.]*)/u' ], // see: http://www.cometbird.com
49
  [ 'name' => 'Comodo Dragon', 'id' => 'comodo', 'regexp' =>'/Comodo_Dragon\/([0-9.]*)/u', 'details' => 2 ],
50
  [ 'name' => 'Comodo Dragon', 'id' => 'dragon', 'regexp' =>'/Dragon\/([0-9.]*)/u', 'details' => 2 ],
51
  [ 'name' => 'Comodo IceDragon', 'id' => 'dragon', 'regexp' =>'/IceDragon\/([0-9.]*)/u', 'details' => 2, 'type' => Constants\DeviceType::DESKTOP ],
52
  [ 'name' => 'Conkeror', 'id' => 'conkeror', 'regexp' =>'/[Cc]onkeror\/([0-9.]*)/u' ],
 
53
  [ 'name' => 'CoolNovo', 'id' => 'coolnovo', 'regexp' =>'/(?:CoolNovo|CoolNovoChromePlus)\/([0-9.]*)/u', 'details' => 3, 'type' => Constants\DeviceType::DESKTOP ],
 
 
 
54
  [ 'name' => 'Cunaguaro', 'id' => 'cunaguaro', 'regexp' =>'/Cunaguaro\/([0-9.]*)/u', 'details' => 3, 'type' => Constants\DeviceType::DESKTOP ],
 
55
  [ 'name' => 'Cyberfox', 'id' => 'cyberfox', 'regexp' =>'/Cyberfox\/([0-9.]*)/u', 'details' => 2 ], // see: https://cyberfox.8pecxstudios.com
56
  [ 'name' => 'Daedalus', 'id' => 'daedalus', 'regexp' =>'/Daedalus ([0-9.]*)/u', 'details' => 2 ],
 
 
 
 
57
  [ 'name' => 'Dillo', 'id' => 'dillo', 'regexp' =>'/Dillo\/([0-9.]*)/u' ], // see: http://www.dillo.org
 
58
  [ 'name' => 'Doga Rhodonit', 'id' => 'rhodonit', 'regexp' =>'/DogaRhodonit/u' ],
 
 
59
  [ 'name' => 'EudoraWeb', 'id' => 'eudoraweb', 'regexp' =>'/EudoraWeb ([0-9.]*)/u' ],
 
 
60
  [ 'name' => 'Flock', 'id' => 'flock', 'regexp' =>'/Flock\/([0-9.]*)/u', 'details' => 3, 'type' => Constants\DeviceType::DESKTOP ],
 
 
61
  [ 'name' => 'Galeon', 'id' => 'galeon', 'regexp' =>'/Galeon\/([0-9.]*)/u', 'details' => 3 ],
 
62
  [ 'name' => 'GNOME Web', 'id' => 'epiphany', 'regexp' =>'/Epiphany\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
 
 
 
63
  [ 'name' => 'IBrowse', 'id' => 'ibrowse', 'regexp' =>'/IBrowse[\/ ]([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
64
  [ 'name' => 'iCab', 'id' => 'icab', 'regexp' =>'/iCab(?: J)?[\/ ](?:Pre)?([0-9.]*)/u' ],
65
  [ 'name' => 'Iceape', 'id' => 'iceape', 'regexp' =>'/Iceape\/([0-9.]*)/u' ],
66
  [ 'name' => 'IceCat', 'id' => 'icecat', 'regexp' =>'/IceCat[ \/]([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://www.gnu.org/software/gnuzilla/
 
67
  [ 'name' => 'Iceweasel', 'id' => 'iceweasel', 'regexp' =>'/Iceweasel\/([0-9.]*)/iu', 'type' => Constants\DeviceType::DESKTOP ],
 
68
  [ 'name' => 'Iridium', 'id' => 'iridium', 'regexp' =>'/Iridium\/([0-9.]*)/u', 'details' => 2 ], // see: http://www.srware.net/en/software_srware_iron.php
69
  [ 'name' => 'Iron', 'id' => 'iron', 'regexp' =>'/Iron\/([0-9.]*)/u', 'details' => 2 ], // see: http://www.srware.net/en/software_srware_iron.php
 
70
  [ 'name' => 'Kazehakase', 'id' => 'kazehakase', 'regexp' =>'/Kazehakase\/([0-9.]*)/u' ], // see: http://kazehakase.osdn.jp
71
  [ 'name' => 'KChrome', 'id' => 'kchrome', 'regexp' =>'/KChrome\/([0-9.]*)/u', 'details' => 3 ], // see: http://www.kchrome.com
 
 
 
 
72
  [ 'name' => 'K-Meleon', 'id' => 'meleon', 'regexp' =>'/K-Meleon\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: http://kmeleonbrowser.org
 
73
  [ 'name' => 'LieBao', 'id' => 'lbbrowser', 'regexp' =>'/LBBROWSER/u' ], // see: http://www.liebao.cn
 
74
  [ 'name' => 'Lobo', 'id' => 'lobo', 'regexp' =>'/Lobo\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: http://sourceforge.net/projects/xamj/files/Lobo%20Browser/
 
 
75
  [ 'name' => 'Lunascape', 'id' => 'lunascape', 'regexp' =>'/ Lunascape[\/| ]([0-9.]*)/u', 'details' => 3 ], // see: http://www.lunascape.tv
76
  [ 'name' => 'Naenara', 'id' => 'naenara', 'regexp' =>'/NaenaraBrowser\/([0-9.]*)/u', 'details' => 2 ], // Firefox based browser used with Red Star OS
 
 
77
  [ 'name' => 'Maxthon', 'id' => 'mxbrowser', 'regexp' =>'/MxBrowser\/([0-9.]*)/u' ],
78
  [ 'name' => 'Maxthon', 'id' => 'mxbrowser', 'regexp' =>'/MxBrowser-iPhone\/([0-9.]*)/u' ],
 
 
79
  [ 'name' => 'MixShark', 'id' => 'mixshark', 'regexp' =>'/MixShark\/([0-9.]*)/u' ], // see: http://terbaddo.free.fr/mixshark.php
80
  [ 'name' => 'mlbrowser', 'id' => 'mlbrowser', 'regexp' =>'/mlbrowser/u' ], // see: https://github.com/Topguy/mlbrowser
 
 
81
  [ 'name' => 'NetPositive', 'id' => 'netpositive', 'regexp' =>'/NetPositive\/([0-9.]*)/u' ],
 
82
  [ 'name' => 'Origyn', 'id' => 'origyn', 'regexp' =>'/Origyn Web Browser/u' ],
83
  [ 'name' => 'Odyssey', 'id' => 'owb', 'regexp' =>'/OWB\/([0-9.]*)/u' ],
 
 
84
  [ 'name' => 'Orca', 'id' => 'orca', 'regexp' =>'/Orca\/([0-9.]*)/u' ],
85
  [ 'name' => 'Oregano', 'id' => 'oregano', 'regexp' =>'/Oregano ([0-9.]*)/u' ], // see: http://www.xat.nl/en/riscos/sw/oregano/
86
  [ 'name' => 'Otter', 'id' => 'otter', 'regexp' =>'/Otter(?: Browser)?\/([0-9.]*)/u' ], // see: https://otter-browser.org
87
  [ 'name' => 'Pale Moon', 'id' => 'palemoon', 'regexp' =>'/Pale[mM]oon\/([0-9.]*)/u' ], // see: https://www.palemoon.org
 
 
 
 
88
  [ 'name' => 'Qihoo 360', 'id' => 'qihu', 'regexp' =>'/QIHU THEWORLD/u' ],
 
89
  [ 'name' => 'QtWeb', 'id' => 'qtweb', 'regexp' =>'/QtWeb Internet Browser\/([0-9.]*)/u' ],
 
90
  [ 'name' => 'QupZilla', 'id' => 'qupzilla', 'regexp' =>'/QupZilla\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
 
91
  [ 'name' => 'rekonq', 'id' => 'rekonq', 'regexp' =>'/rekonq(?:\/([0-9.]*))?/u', 'type' => Constants\DeviceType::DESKTOP ],
92
  [ 'name' => 'Ryouko', 'id' => 'ryouko', 'regexp' =>'/Ryouko\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://github.com/foxhead128/ryouko
 
93
  [ 'name' => 'SaaYaa Explorer', 'id' => 'saayaa', 'regexp' =>'/SaaYaa/u', 'type' => Constants\DeviceType::DESKTOP ],
 
 
 
 
 
94
  [ 'name' => 'Sleipnir', 'id' => 'sleipnir', 'regexp' =>'/Sleipnir\/([0-9.]*)/u', 'details' => 3 ],
 
95
  [ 'name' => 'Sogou Explorer', 'id' => 'metasr', 'regexp' =>'/SE 2.X MetaSr/u', 'type' => Constants\DeviceType::DESKTOP ],
 
 
96
  [ 'name' => 'Stainless', 'id' => 'stainless', 'regexp' =>'/Stainless\/([0-9.]*)/u' ], // see: http://www.stainlessapp.com
 
97
  [ 'name' => 'SunChrome', 'id' => 'sunchrome', 'regexp' =>'/SunChrome\/([0-9.]*)/u' ],
 
 
98
  [ 'name' => 'Superbird', 'id' => 'superbird', 'regexp' =>'/Super[Bb]ird\/([0-9.]*)/u', 'details' => 2 ],
 
 
99
  [ 'name' => 'Swing Browser', 'id' => 'swing', 'regexp' =>'/Swing(?:\(And\))?\/([0-9.]*)/u', 'details' => 3 ], // see: http://swing-browser.com
 
 
100
  [ 'name' => 'Tencent Traveler', 'id' => 'tencent', 'regexp' =>'/TencentTraveler ([0-9.]*)/u', 'details' => 2 ],
101
  [ 'name' => 'TenFourFox', 'id' => 'tenfourfox', 'regexp' =>'/TenFourFox\//u' ],
102
  [ 'name' => 'The World', 'id' => 'theworld', 'regexp' =>'/TheWorld(?: ([0-9.]*))?/u' ],
 
103
  [ 'name' => 'Tungsten Browser', 'id' => 'tungsten', 'regexp' =>'/TungstenBrowser\/([0-9.]*)/u' ],
 
 
 
104
  [ 'name' => 'Vivaldi', 'id' => 'vivaldi', 'regexp' =>'/Vivaldi\/([0-9.]*)/u', 'details' => 2 ],
 
 
105
  [ 'name' => 'Voyager', 'id' => 'voyager', 'regexp' =>'/AmigaVoyager\/([0-9.]*)/u' ],
106
  [ 'name' => 'Waterfox', 'id' => 'waterfox', 'regexp' =>'/Waterfox\/([0-9.]*)/u', 'details' => 2, 'type' => Constants\DeviceType::DESKTOP ],
 
 
 
 
107
  [ 'name' => 'Yandex Browser', 'id' => 'yabrowser', 'regexp' =>'/YaBrowser\/([0-9.]*)/u', 'details' => 2 ],
 
 
 
108
 
109
  /* Mobile browsers */
110
  [ 'name' => '1Browser', 'id' => '1password', 'regexp' =>'/1Password\/([0-9.]*)/u' ],
111
  [ 'name' => '2345 Browser', 'id' => '2345', 'regexp' =>'/Mb2345Browser\/([0-9.]*)/u' ],
112
  [ 'name' => '3G Explorer', 'id' => '3g explorer', 'regexp' =>'/3G Explorer\/([0-9.]*)/u', 'details' => 3 ],
113
  [ 'name' => '4G Explorer', 'id' => '4g explorer', 'regexp' =>'/4G Explorer\/([0-9.]*)/u', 'details' => 3 ],
 
114
  [ 'name' => 'Atomic', 'id' => 'atomiclite', 'regexp' =>'/AtomicLite\/([0-9.]*)/u' ], // see: http://atomicwebbrowser.com
115
  [ 'name' => 'AU', 'id' => 'au', 'regexp' =>'/(?:^| )AU(?:.Browser)?\/([0-9.]+)/u' ],
116
  [ 'name' => 'Awakening', 'id' => 'awakening', 'regexp' =>'/Awakening Browser\/([0-9.]*)/u', 'details' => 2 ],
@@ -128,10 +227,14 @@ Applications::$BROWSERS = [
128
  [ 'name' => 'Digia @Web', 'id' => 'digia', 'regexp' =>'/Digia @Web\/([0-9.]*)/u' ],
129
  [ 'name' => 'Doris', 'id' => 'doris', 'regexp' =>'/Doris\/([0-9.]*)/u' ],
130
  [ 'name' => 'Dorothy', 'id' => 'doroty', 'regexp' =>'/Dorothy$/u' ],
 
 
131
  [ 'name' => 'EMOBILE Browser', 'id' => 'www browser', 'regexp' =>'/WWW Browser\/ver([0-9.]*)/u' ],
 
132
  [ 'name' => 'EUI Browser', 'id' => 'eui', 'regexp' =>'/EUI Browser\/[^0-9\s]*([0-9.]*)/u', 'details' => 2 ],
133
  [ 'name' => 'Go.Web', 'id' => 'go\.web', 'regexp' =>'/Go\.Web\/([0-9.]*)/u' ], // used on early Blackberry, by GoAmerica
134
  [ 'name' => 'Helium', 'id' => 'helium', 'regexp' =>'/HeliumMobileBrowser\/([0-9.]*)/u' ],
 
135
  [ 'name' => 'Huohou Browser', 'id' => 'huohoubrowser', 'regexp' =>'/HuohouBrowser\/([0-9.]*)/u' ],
136
  [ 'name' => 'iCab', 'id' => 'icab', 'regexp' =>'/iCabMobile\/([0-9.]*)/u' ],
137
  [ 'name' => 'iLunascape', 'id' => 'lunascape', 'regexp' =>'/iLunascape\/([0-9.]*)/u', 'details' => 3 ], // see: http://www.lunascape.tv
@@ -139,35 +242,49 @@ Applications::$BROWSERS = [
139
  [ 'name' => 'iSurf', 'id' => 'isurf', 'regexp' =>'/iSurf version \/v([0-9.]*)/u', 'details' => 2 ],
140
  [ 'name' => 'Jig Browser', 'id' => 'jig browser', 'regexp' =>'/jig browser(?: web| core|9i?)?;? ?([0-9.]+)?/u', 'type' => Constants\DeviceType::MOBILE ],
141
  [ 'name' => 'Jumanji', 'id' => 'jumanji', 'regexp' =>'/jumanji/u' ], // see: jumanji browser ubuntu
 
142
  [ 'name' => 'Kiosk', 'id' => 'kiosk', 'regexp' =>'/Kiosk\/([0-9.]*)/u' ], // see: http://www.kioskbrowser.net
 
143
  [ 'name' => 'LeBrowser', 'id' => 'lebrowser', 'regexp' =>'/LeBrowser\/([0-9.]*)/u', 'details' => 2 ],
144
  [ 'name' => 'LieBaoFast', 'id' => 'liebao', 'regexp' =>'/LieBaoFast\/([0-9.]*)/u' ], // see: http://www.liebao.cn
145
  [ 'name' => 'MaCross Mobile', 'id' => 'macross', 'regexp' =>'/MaCross\/([0-9.]*)/u' ],
146
  [ 'name' => 'Mammoth', 'id' => 'mammoth', 'regexp' =>'/Mammoth\/([0-9.]*)/u' ], // see: https://itunes.apple.com/cn/app/meng-ma-liu-lan-qi/id403760998?mt=8
147
  [ 'name' => 'mCent Browser', 'id' => 'mcent', 'regexp' =>'/mCent\/([0-9.]*)/u' ],
 
 
148
  [ 'name' => 'Motorola Internet Browser', 'id' => 'mib', 'regexp' =>'/MIB\/([0-9.]*)/u' ],
149
  [ 'name' => 'Motorola Internet Browser', 'id' => 'mib', 'regexp' =>'/MIB([0-9.]+)\//u' ],
150
  [ 'name' => 'Motorola Internet Browser', 'id' => 'cmcs', 'regexp' =>'/Browser\/CMCS([0-9.]*)/u' ],
151
  [ 'name' => 'Motorola WebKit', 'id' => 'motorola', 'regexp' =>'/MotorolaWebKit(?:\/([0-9.]*))?/u', 'details' => 3 ],
 
152
  [ 'name' => 'NetFront Life Browser', 'id' => 'netfrontlife', 'regexp' =>'/NetFrontLifeBrowser\/([0-9.]*)/u' ],
153
  [ 'name' => 'OneBrowser', 'id' => 'onebrowser', 'regexp' =>'/OneBrowser\/([0-9.]*)/u' ],
 
154
  [ 'name' => 'PocketLink', 'id' => 'plink', 'regexp' =>'/PLink ([0-9.]+)/iu', 'details' => 2 ],
155
  [ 'name' => 'Polaris', 'id' => 'polaris', 'regexp' =>'/Polaris[\/ ]v?([0-9.]*)/iu', 'details' => 2 ],
156
  [ 'name' => 'Polaris', 'id' => 'polaris', 'regexp' =>'/POLARIS([0-9.]+)/u', 'details' => 2 ],
 
157
  [ 'name' => 'Openwave', 'id' => 'openwave', 'regexp' =>'/Open[Ww]ave\/([0-9.]*)/u', 'details' => 2, 'type' => Constants\DeviceType::MOBILE ],
158
  [ 'name' => 'Openwave', 'id' => 'openwave', 'regexp' =>'/Openwave Mobile Browser ([0-9.]*)/u', 'details' => 2, 'type' => Constants\DeviceType::MOBILE ],
159
  [ 'name' => 'Openwave', 'id' => 'openwave', 'regexp' =>'/Browser\/OpenWave([0-9.]*)/u', 'details' => 2, 'type' => Constants\DeviceType::MOBILE ],
160
  [ 'name' => 'Openwave', 'id' => 'up', 'regexp' =>'/UP\. ?Browser(?:\/([a-z0-9.]*))?/iu', 'details' => 2, 'type' => Constants\DeviceType::MOBILE ],
161
  [ 'name' => 'Openwave', 'id' => 'km', 'regexp' =>'/KM\.Browser\/([0-9.]+)/iu', 'details' => 2, 'type' => Constants\DeviceType::MOBILE ],
162
  [ 'name' => 'Openwave', 'id' => 'up', 'regexp' =>'/UP\/([0-9.]+)/u', 'details' => 2, 'type' => Constants\DeviceType::MOBILE ],
163
- [ 'name' => 'Quark Browser', 'id' => 'quark', 'regexp' =>'/Quark\/([0-9.]*)/u', 'details' => 3 ],
 
 
 
164
  [ 'name' => 'SEMC Browser', 'id' => 'semc', 'regexp' =>'/SEMC-Browser\/([0-9.]*)/u' ],
165
  [ 'name' => 'STNC HitchHiker' , 'id' => 'stnc', 'regexp' =>'/STNC-WTL\/[0-9.]*/u' ],
166
  [ 'name' => 'Sogou Mobile', 'id' => 'sogou', 'regexp' =>'/SogouMobileBrowser\/([0-9.]*)/u', 'details' => 2 ],
167
  [ 'name' => 'Swing Browser', 'id' => 'swing', 'regexp' =>'/Swing\(And\)\/([0-9.]*)/u', 'details' => 3 ],
168
  [ 'name' => 'Symphony', 'id' => 'symphony', 'regexp' =>'/Symphony ([0-9.]+)$/u' ],
 
169
  [ 'name' => 'TinY', 'id' => 'ucpro', 'regexp' =>'/ucpro\/([0-9.]+)/iu' ],
 
170
  [ 'name' => 'WebLite', 'id' => 'weblite', 'regexp' =>'/WebLite\/([0-9.]*)/u', 'type' => Constants\DeviceType::MOBILE ],
 
 
171
 
172
  /* Television browsers */
173
  [ 'name' => 'AltiBrowser', 'id' => 'alti', 'regexp' =>'/AltiBrowser\/([0-9.]*)/i' ],
@@ -175,6 +292,7 @@ Applications::$BROWSERS = [
175
  [ 'name' => 'AwoX', 'id' => 'awox', 'regexp' =>'/AwoX(?:\/([0-9.]*))? Browser/i' ],
176
  [ 'name' => 'Isis', 'id' => 'browserserver', 'regexp' =>'/BrowserServer/u' ],
177
  [ 'name' => 'Isis', 'id' => 'isis', 'regexp' =>'/ISIS\/([0-9.]*)/u', 'details' => 2 ],
 
178
  [ 'name' => 'Spyglass', 'id' => 'spyglass', 'regexp' =>'/Spyglass ([0-9.]+); OpenTV/u' ],
179
  [ 'name' => 'Oregan Browser', 'id' => 'oregan', 'regexp' =>'/OreganMediaBrowser(?:\/([0-9.]*))?/u', 'details' => 2 ],
180
  [ 'name' => 'Viera Browser', 'id' => 'viera', 'regexp' =>'/Viera\/([0-9.]*)/u' ],
@@ -216,7 +334,7 @@ Applications::$BROWSERS = [
216
  [ 'name' => 'Snowshoe', 'id' => 'snowshoe', 'regexp' =>'/Snowshoe\/([0-9.]*)/u', 'details' => 2 ],
217
  [ 'name' => 'Sputnik', 'id' => 'sputnik', 'regexp' =>'/Sputnik\/([0-9.]*)/iu', 'details' => 3 ],
218
  [ 'name' => 'Surf', 'id' => 'surf', 'regexp' =>'/Surf\/([0-9.]*)/u' ],
219
- [ 'name' => 'TaoBrowser', 'id' => 'tao', 'regexp' =>'/TaoBrowser\/([0-9.]*)/u', 'details' => 2 ],
220
  [ 'name' => 'TaomeeBrowser', 'id' => 'tao', 'regexp' =>'/TaomeeBrowser\/([0-9.]*)/u', 'details' => 2 ],
221
  [ 'name' => 'TazWeb', 'id' => 'taz', 'regexp' =>'/TazWeb/u' ],
222
  [ 'name' => 'Uzbl', 'id' => 'uzbl', 'regexp' =>'/^Uzbl/u' ],
@@ -250,4 +368,4 @@ Applications::$BROWSERS = [
250
  [ 'name' => 'BrightSign', 'id' => 'brightsign', 'regexp' =>'/BrightSign\/([0-9.]*)/u', 'type' => Constants\DeviceType::SIGNAGE ],
251
  [ 'name' => 'Coship MMCP', 'id' => 'coship', 'regexp' =>'/Coship_MMCP_([0-9.]*)/u', 'type' => Constants\DeviceType::SIGNAGE ],
252
  ]
253
- ];
15
  [ 'name' => '2345 Explorer', 'id' => '2345', 'regexp' =>'/2345Explorer\/([0-9.]*)/u', 'details' => 3 ],
16
  [ 'name' => '2345 Explorer', 'id' => '2345', 'regexp' =>'/2345Explorer v([0-9.]*)/u', 'details' => 3 ],
17
  [ 'name' => '2345 Chrome', 'id' => '2345', 'regexp' =>'/2345chrome v([0-9.]*)/u', 'details' => 3 ],
18
+ [ 'name' => '37abc Browser', 'id' => '37abc', 'regexp' => '/ 37abc\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
19
  [ 'name' => '360 Extreme Explorer', 'id' => 'qihu', 'regexp' =>'/QIHU 360EE/u', 'type' => Constants\DeviceType::DESKTOP ],
20
+ [ 'name' => '1st Browser', 'id' => '1stbrowser', 'regexp' => '/1stBrowser\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
21
  [ 'name' => '360 Safe Explorer', 'id' => 'qihu', 'regexp' =>'/QIHU 360SE/u', 'type' => Constants\DeviceType::DESKTOP ],
22
  [ 'name' => '7Star', 'id' => '7star', 'regexp' =>'/7Star\/([0-9.]*)/u' ], // see: http://www.qixing123.com
23
  [ 'name' => 'ABrowse', 'id' => 'abrowse', 'regexp' =>'/A[Bb]rowse ([0-9.]*)/u' ], // browser for the Syllable OS
25
  [ 'name' => 'Acorn Browse', 'id' => 'acorn', 'regexp' =>'/Acorn Browse ([0-9.]+)/u' ],
26
  [ 'name' => 'Acorn Browse', 'id' => 'acorn', 'regexp' =>'/Acorn Phoenix ([0-9.]+)/u' ],
27
  [ 'name' => 'Acoo Browser', 'id' => 'acoo', 'regexp' =>'/Acoo Browser/u' ],
28
+ [ 'name' => 'Amigo Browser', 'id' => 'amigo', 'regexp' => '/ Amigo\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://amigo.mail.ru/
29
  [ 'name' => 'AOL Desktop', 'id' => 'aol', 'regexp' =>'/AOL ([0-9.]*); AOLBuild/i' ],
30
  [ 'name' => 'AOL Browser', 'id' => 'america', 'regexp' =>'/America Online Browser (?:[0-9.]*); rev([0-9.]*);/i' ],
31
+ [ 'name' => 'APUS Browser', 'id' => 'apus', 'regexp' => '/APUSBrowser\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://www.apusapps.com/en/browser/
32
  [ 'name' => 'Arachne', 'id' => 'arachne', 'regexp' =>'/xChaos_Arachne\/[0-9]\.([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: www.glennmcc.org
33
  [ 'name' => 'Arora', 'id' => 'arora', 'regexp' =>'/[Aa]rora\/([0-9.]*)/u' ], // see: www.arora-browser.org
34
  [ 'name' => 'AWeb', 'id' => 'aweb', 'regexp' =>'/Amiga-AWeb(?:\/([0-9.]*))?/u' ],
36
  [ 'name' => 'Avant Browser', 'id' => 'avant', 'regexp' =>'/Avant Browser/u' ],
37
  [ 'name' => 'Avant Browser', 'id' => 'avant', 'regexp' =>'/Avant TriCore/u' ],
38
  [ 'name' => 'Avast SafeZone', 'id' => 'asw', 'regexp' =>'/ASW\/([0-9.]*)/u', 'details' => 2 ],
39
+ [ 'name' => 'AVG Secure Browser', 'id' => 'avg', 'regexp' =>'/ AVG\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://www.avg.com/secure-browser
40
  [ 'name' => 'Aviator', 'id' => 'aviator', 'regexp' =>'/Aviator\/([0-9.]*)/u', 'details' => 1 ], // see: https://github.com/WhiteHatSecurity/Aviator
41
+ [ 'name' => 'Avira Scout', 'id' => 'avira', 'regexp' => '/AviraScout\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://www.avira.com/en/avira-scout
42
  [ 'name' => 'Baidu Browser', 'id' => 'flyflow', 'regexp' =>'/FlyFlow\/([0-9.]*)/u', 'details' => 2 ],
43
  [ 'name' => 'Baidu Browser', 'id' => 'bdbrowser', 'regexp' =>'/bdbrowser\/([0-9.]*)/i' ],
44
  [ 'name' => 'Baidu Browser', 'id' => 'bdbrowser', 'regexp' =>'/bdbrowser_i18n\/([0-9.]*)/i' ],
45
  [ 'name' => 'Baidu Spark', 'id' => 'bdspark', 'regexp' =>'/BDSpark\/([0-9.]*)/u', 'details' => 2 ],
46
+ [ 'name' => 'Basilisk', 'id' => 'basilisk', 'regexp' => '/ Basilisk\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://basilisk-browser.org/
47
  [ 'name' => 'Beamrise', 'id' => 'beamrise', 'regexp' =>'/Beamrise\/([0-9.]*)/u' ], // see: http://beamrise.com
48
+ [ 'name' => 'Beonex', 'id' => 'beonex', 'regexp' =>'/Beonex\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://www.beonex.com/
49
  [ 'name' => 'Black Wren', 'id' => 'blackwren', 'regexp' =>'/BlackWren\/([0-9.]*)/u', 'details' => 2 ], // see: https://github.com/conmarap/jetbrowser
50
+ [ 'name' => 'Black Hawk', 'id' => 'blackhawk', 'regexp' => '/BlackHawk\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: http://www.netgate.sk/blackhawk/help/welcome-to-blackhawk-web-browser.html
51
+ [ 'name' => 'Bolt Browser', 'id' => 'bolt', 'regexp' => '/ Bolt\/([0-9.]*)/i', 'type' => Constants\DeviceType::DESKTOP ], // see: http://www.boltbrowser.com/
52
+ [ 'name' => 'Blackbird', 'id' => 'blackbird', 'regexp' =>'/Blackbird\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: http://www.blackbirdbrowser.com/
53
  [ 'name' => 'Brave', 'id' => 'brave', 'regexp' =>'/brave\/([0-9.]*)/u' ],
54
+ [ 'name' => 'Brisk Bard', 'id' => 'brisk', 'regexp' => '/BriskBard\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://www.briskbard.com/index.php?lang=en
55
+ [ 'name' => 'BrowseX', 'id' => 'browsex', 'regexp' => '/BrowseX \(([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://dev.pdqi.com/fossil/browsex/doc/tip/index.html
56
+ [ 'name' => 'Browzar', 'id' => 'browzar', 'regexp' => '/Browzar/u', 'type' => Constants\DeviceType::DESKTOP ], // see: http://browzar.com/
57
  [ 'name' => 'Byffox', 'id' => 'byffox', 'regexp' =>'/Byffox\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
58
  [ 'name' => 'Camino', 'id' => 'camino', 'regexp' =>'/Camino\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
59
  [ 'name' => 'Canure', 'id' => 'canure', 'regexp' =>'/Canure\/([0-9.]*)/u', 'details' => 3 ], // see: http://canure.weebly.com/index.html
60
+ [ 'name' => 'CCleaner Browser', 'id' => 'ccleaner', 'regexp' => '/CCleaner\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://www.ccleaner.com/ccleaner/browser
61
+ [ 'name' => 'Cent Browser', 'id' => 'cent', 'regexp' => '/ Cent\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://www.centbrowser.com/
62
  [ 'name' => 'Charon', 'id' => 'charon', 'regexp' =>'/Charon/' ], // see: http://www.vitanuova.com/inferno/man/1/charon.html
63
+ [ 'name' => 'Chedot', 'id' => 'chedot', 'regexp' => '/ Chedot\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: http://landing.chedot.com/
64
+ [ 'name' => 'Cheshire', 'id' => 'cheshire', 'regexp' => '/ Cheshire\/([0-9.A-Z]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
65
+ [ 'name' => 'Chim Lac', 'id' => 'chimlac', 'regexp' => '/chimlac_browser\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://chimlac.com.vn/
66
+ [ 'name' => 'Chimera', 'id' => 'chimera', 'regexp' => '/ Chimera\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
67
  [ 'name' => 'ChromePlus', 'id' => 'chromeplus', 'regexp' =>'/ChromePlus(?:\/([0-9.]*))?$/u', 'details' => 3, 'type' => Constants\DeviceType::DESKTOP ],
68
+ [ 'name' => 'Colibri', 'id' => 'colibri', 'regexp' => '/Colibri\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://colibri.opqr.co/
69
+ [ 'name' => 'Columbus', 'id' => 'columbus', 'regexp' =>'/Columbus\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
70
  [ 'name' => 'CometBird', 'id' => 'cometbird', 'regexp' =>'/CometBird\/([0-9.]*)/u' ], // see: http://www.cometbird.com
71
  [ 'name' => 'Comodo Dragon', 'id' => 'comodo', 'regexp' =>'/Comodo_Dragon\/([0-9.]*)/u', 'details' => 2 ],
72
  [ 'name' => 'Comodo Dragon', 'id' => 'dragon', 'regexp' =>'/Dragon\/([0-9.]*)/u', 'details' => 2 ],
73
  [ 'name' => 'Comodo IceDragon', 'id' => 'dragon', 'regexp' =>'/IceDragon\/([0-9.]*)/u', 'details' => 2, 'type' => Constants\DeviceType::DESKTOP ],
74
  [ 'name' => 'Conkeror', 'id' => 'conkeror', 'regexp' =>'/[Cc]onkeror\/([0-9.]*)/u' ],
75
+ [ 'name' => 'Coc Coc', 'id' => 'coc', 'regexp' => '/coc_coc_browser\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://coccoc.com/en/
76
  [ 'name' => 'CoolNovo', 'id' => 'coolnovo', 'regexp' =>'/(?:CoolNovo|CoolNovoChromePlus)\/([0-9.]*)/u', 'details' => 3, 'type' => Constants\DeviceType::DESKTOP ],
77
+ [ 'name' => 'Corom Browser', 'id' => 'corom', 'regexp' => '/ CoRom\/([0-9.]*)/u', 'type' => Constants\DeviceType::MOBILE ], // see: https://apkpure.com/corom-browser-for-android/com.coccoc.corom
78
+ [ 'name' => 'Crazy Browser', 'id' => 'crazy', 'regexp' => '/Crazy Browser ([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
79
+ [ 'name' => 'Crusta', 'id' => 'crusta', 'regexp' => '/ Crusta\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://github.com/Tarptaeya/Crusta
80
  [ 'name' => 'Cunaguaro', 'id' => 'cunaguaro', 'regexp' =>'/Cunaguaro\/([0-9.]*)/u', 'details' => 3, 'type' => Constants\DeviceType::DESKTOP ],
81
+ [ 'name' => 'Cyberdog', 'id' => 'cyberdog', 'regexp' =>'/Cyberdog\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
82
  [ 'name' => 'Cyberfox', 'id' => 'cyberfox', 'regexp' =>'/Cyberfox\/([0-9.]*)/u', 'details' => 2 ], // see: https://cyberfox.8pecxstudios.com
83
  [ 'name' => 'Daedalus', 'id' => 'daedalus', 'regexp' =>'/Daedalus ([0-9.]*)/u', 'details' => 2 ],
84
+ [ 'name' => 'Deg-degan', 'id' => 'degan', 'regexp' => '/Degdegan\/([0-9.]*)/u', 'details' => 3, 'type' => Constants\DeviceType::DESKTOP ],
85
+ [ 'name' => 'Demeter', 'id' => 'demeter', 'regexp' =>'/Demeter\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
86
+ [ 'name' => 'DeskBrowse', 'id' => 'deskbrowse', 'regexp' =>'/DeskBrowse\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
87
+ [ 'name' => 'Diigo Browser', 'id' => 'diigo', 'regexp' => '/DiigoBrowser/u', 'type' => Constants\DeviceType::MOBILE ], // see: https://apps.apple.com/us/app/diigo-annotator-for-safari/id933773981
88
  [ 'name' => 'Dillo', 'id' => 'dillo', 'regexp' =>'/Dillo\/([0-9.]*)/u' ], // see: http://www.dillo.org
89
+ [ 'name' => 'DocZilla', 'id' => 'doczilla', 'regexp' =>'/DocZilla\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
90
  [ 'name' => 'Doga Rhodonit', 'id' => 'rhodonit', 'regexp' =>'/DogaRhodonit/u' ],
91
+ [ 'name' => 'DPlus Browser', 'id' => 'dplus', 'regexp' =>'/ DPlus ([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
92
+ [ 'name' => 'Elements Browser', 'id' => 'elements', 'regexp' => '/Elements Browser\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
93
  [ 'name' => 'EudoraWeb', 'id' => 'eudoraweb', 'regexp' =>'/EudoraWeb ([0-9.]*)/u' ],
94
+ [ 'name' => 'Falkon', 'id' => 'falkon', 'regexp' => '/ Falkon\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://www.falkon.org/
95
+ [ 'name' => 'FlameSky', 'id' => 'flamesky', 'regexp' => '/FlameSky\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://github.com/flameskyofficial/flamesky
96
  [ 'name' => 'Flock', 'id' => 'flock', 'regexp' =>'/Flock\/([0-9.]*)/u', 'details' => 3, 'type' => Constants\DeviceType::DESKTOP ],
97
+ [ 'name' => 'Framafox', 'id' => 'framafox', 'regexp' => '/Framafox\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://framakey.org/telecharger/applications-portables-libres#internet
98
+ [ 'name' => 'Freeu Browser', 'id' => 'freeu', 'regexp' => '/ Free[Uu]\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://play.google.com/store/apps/details?id=com.freeuvpn.android&hl=en
99
  [ 'name' => 'Galeon', 'id' => 'galeon', 'regexp' =>'/Galeon\/([0-9.]*)/u', 'details' => 3 ],
100
+ [ 'name' => 'GlobalMojo', 'id' => 'globalmojo', 'regexp' =>'/GlobalMojo\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
101
  [ 'name' => 'GNOME Web', 'id' => 'epiphany', 'regexp' =>'/Epiphany\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
102
+ [ 'name' => 'GreenBrowser', 'id' => 'greenbrowser', 'regexp' =>'/GreenBrowser/u', 'type' => Constants\DeviceType::DESKTOP ],
103
+ [ 'name' => 'Hola Browser', 'id' => 'hola', 'regexp' => '/ Hola\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://play.google.com/store/apps/details?id=org.hola&hl=en
104
+ [ 'name' => 'Hydra Browser', 'id' => 'hydra', 'regexp' =>'/Hydra Browser/u', 'type' => Constants\DeviceType::DESKTOP ],
105
  [ 'name' => 'IBrowse', 'id' => 'ibrowse', 'regexp' =>'/IBrowse[\/ ]([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
106
  [ 'name' => 'iCab', 'id' => 'icab', 'regexp' =>'/iCab(?: J)?[\/ ](?:Pre)?([0-9.]*)/u' ],
107
  [ 'name' => 'Iceape', 'id' => 'iceape', 'regexp' =>'/Iceape\/([0-9.]*)/u' ],
108
  [ 'name' => 'IceCat', 'id' => 'icecat', 'regexp' =>'/IceCat[ \/]([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://www.gnu.org/software/gnuzilla/
109
+ [ 'name' => 'Icedove', 'id' => 'icedove', 'regexp' => '/ Icedove\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://wiki.debian.org/Icedove
110
  [ 'name' => 'Iceweasel', 'id' => 'iceweasel', 'regexp' =>'/Iceweasel\/([0-9.]*)/iu', 'type' => Constants\DeviceType::DESKTOP ],
111
+ [ 'name' => 'iRider Browser', 'id' => 'irider', 'regexp' =>'/iRider ([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
112
  [ 'name' => 'Iridium', 'id' => 'iridium', 'regexp' =>'/Iridium\/([0-9.]*)/u', 'details' => 2 ], // see: http://www.srware.net/en/software_srware_iron.php
113
  [ 'name' => 'Iron', 'id' => 'iron', 'regexp' =>'/Iron\/([0-9.]*)/u', 'details' => 2 ], // see: http://www.srware.net/en/software_srware_iron.php
114
+ [ 'name' => 'Kapiko', 'id' => 'kapiko', 'regexp' => '/ Kapiko\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://sites.google.com/site/kapikoproject/
115
  [ 'name' => 'Kazehakase', 'id' => 'kazehakase', 'regexp' =>'/Kazehakase\/([0-9.]*)/u' ], // see: http://kazehakase.osdn.jp
116
  [ 'name' => 'KChrome', 'id' => 'kchrome', 'regexp' =>'/KChrome\/([0-9.]*)/u', 'details' => 3 ], // see: http://www.kchrome.com
117
+ [ 'name' => 'Kinza', 'id' => 'kinza', 'regexp' => '/ Kinza\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://www.kinza.jp/en/
118
+ [ 'name' => 'KKMAN', 'id' => 'kkman', 'regexp' => '/ KKman([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://www.kkbox.com/kkman/
119
+ [ 'name' => 'Klondike', 'id' => 'klondike', 'regexp' => '/Klondike\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
120
+ [ 'name' => 'Kylo', 'id' => 'kylo', 'regexp' => '/ Kylo\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: http://kylo.tv/
121
  [ 'name' => 'K-Meleon', 'id' => 'meleon', 'regexp' =>'/K-Meleon\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: http://kmeleonbrowser.org
122
+ [ 'name' => 'LBrowser', 'id' => 'lbrowser', 'regexp' =>'/LBrowser\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
123
  [ 'name' => 'LieBao', 'id' => 'lbbrowser', 'regexp' =>'/LBBROWSER/u' ], // see: http://www.liebao.cn
124
+ [ 'name' => 'Light', 'id' => 'light', 'regexp' => '/ Light\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://en.wikipedia.org/wiki/Light_(web_browser)
125
  [ 'name' => 'Lobo', 'id' => 'lobo', 'regexp' =>'/Lobo\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: http://sourceforge.net/projects/xamj/files/Lobo%20Browser/
126
+ [ 'name' => 'Lolifox', 'id' => 'lolifox', 'regexp' => '/lolifox\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://ja.wikipedia.org/wiki/Lolifox
127
+ [ 'name' => 'Lovense', 'id' => 'lovense', 'regexp' => '/Lovense\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://www.lovense.com/cam-model/guides/pc-phone
128
  [ 'name' => 'Lunascape', 'id' => 'lunascape', 'regexp' =>'/ Lunascape[\/| ]([0-9.]*)/u', 'details' => 3 ], // see: http://www.lunascape.tv
129
  [ 'name' => 'Naenara', 'id' => 'naenara', 'regexp' =>'/NaenaraBrowser\/([0-9.]*)/u', 'details' => 2 ], // Firefox based browser used with Red Star OS
130
+ [ 'name' => 'NetCaptor', 'id' => 'netcaptor', 'regexp' =>'/NetCaptor ([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://en.wikipedia.org/wiki/NetCaptor
131
+ [ 'name' => 'Madfox', 'id' => 'madfox', 'regexp' =>'/Madfox\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
132
  [ 'name' => 'Maxthon', 'id' => 'mxbrowser', 'regexp' =>'/MxBrowser\/([0-9.]*)/u' ],
133
  [ 'name' => 'Maxthon', 'id' => 'mxbrowser', 'regexp' =>'/MxBrowser-iPhone\/([0-9.]*)/u' ],
134
+ [ 'name' => 'Min Browser', 'id' => 'min', 'regexp' => '/ min\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://minbrowser.github.io/min/
135
+ [ 'name' => 'Mini Browser', 'id' => 'mini', 'regexp' => '/ MiniBrowser\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: http://dmkho.tripod.com/mb/index.html
136
  [ 'name' => 'MixShark', 'id' => 'mixshark', 'regexp' =>'/MixShark\/([0-9.]*)/u' ], // see: http://terbaddo.free.fr/mixshark.php
137
  [ 'name' => 'mlbrowser', 'id' => 'mlbrowser', 'regexp' =>'/mlbrowser/u' ], // see: https://github.com/Topguy/mlbrowser
138
+ [ 'name' => 'Mypal Browser', 'id' => 'mypal', 'regexp' => '/ Mypal\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://github.com/Feodor2/Mypal
139
+ [ 'name' => 'Multi-Browser XP', 'id' => 'multixp', 'regexp' =>'/Multi-Browser ([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
140
  [ 'name' => 'NetPositive', 'id' => 'netpositive', 'regexp' =>'/NetPositive\/([0-9.]*)/u' ],
141
+ [ 'name' => 'Nichrome', 'id' => 'nichrome', 'regexp' => '/Nichrome\/self\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
142
  [ 'name' => 'Origyn', 'id' => 'origyn', 'regexp' =>'/Origyn Web Browser/u' ],
143
  [ 'name' => 'Odyssey', 'id' => 'owb', 'regexp' =>'/OWB\/([0-9.]*)/u' ],
144
+ [ 'name' => 'Open Live Writer', 'id' => 'live', 'regexp' =>'/Open Live Writer ([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: http://openlivewriter.org/
145
+ [ 'name' => 'Orange Browser', 'id' => 'juzi', 'regexp' =>'/JuziBrowser/u', 'type' => Constants\DeviceType::DESKTOP ], // see: http://www.123juzi.com/
146
  [ 'name' => 'Orca', 'id' => 'orca', 'regexp' =>'/Orca\/([0-9.]*)/u' ],
147
  [ 'name' => 'Oregano', 'id' => 'oregano', 'regexp' =>'/Oregano ([0-9.]*)/u' ], // see: http://www.xat.nl/en/riscos/sw/oregano/
148
  [ 'name' => 'Otter', 'id' => 'otter', 'regexp' =>'/Otter(?: Browser)?\/([0-9.]*)/u' ], // see: https://otter-browser.org
149
  [ 'name' => 'Pale Moon', 'id' => 'palemoon', 'regexp' =>'/Pale[mM]oon\/([0-9.]*)/u' ], // see: https://www.palemoon.org
150
+ [ 'name' => 'Patriott Browser', 'id' => 'patriott', 'regexp' =>'/Patriott\:\:Browser\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: http://madgroup.x10.mx/patriott1.php
151
+ [ 'name' => 'Perk', 'id' => 'perk', 'regexp' =>'/ Perk\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: http://www.perk.com/
152
+ [ 'name' => 'Polarity', 'id' => 'polarity', 'regexp' =>'/Polarity\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
153
+ [ 'name' => 'Privacy Browser', 'id' => 'privacy', 'regexp' => '/PrivacyBrowser\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://www.stoutner.com/privacy-browser/
154
  [ 'name' => 'Qihoo 360', 'id' => 'qihu', 'regexp' =>'/QIHU THEWORLD/u' ],
155
+ [ 'name' => 'Qiyu Browser', 'id' => 'qiyu', 'regexp' => '/Qiyu\/([0-9.]*)/i', 'type' => Constants\DeviceType::DESKTOP ], // see: https://apps.apple.com/cn/app/qi-yu-liu-lan-qi/id959447103
156
  [ 'name' => 'QtWeb', 'id' => 'qtweb', 'regexp' =>'/QtWeb Internet Browser\/([0-9.]*)/u' ],
157
+ [ 'name' => 'Quick Look', 'id' => 'quicklook', 'regexp' => '/QuickLook\/([0-9.]*)/u' ], // see: https://en.wikipedia.org/wiki/Quick_Look
158
  [ 'name' => 'QupZilla', 'id' => 'qupzilla', 'regexp' =>'/QupZilla\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
159
+ [ 'name' => 'Qute Browser', 'id' => 'qute', 'regexp' => '/qutebrowser\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://github.com/qutebrowser/qutebrowser
160
  [ 'name' => 'rekonq', 'id' => 'rekonq', 'regexp' =>'/rekonq(?:\/([0-9.]*))?/u', 'type' => Constants\DeviceType::DESKTOP ],
161
  [ 'name' => 'Ryouko', 'id' => 'ryouko', 'regexp' =>'/Ryouko\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://github.com/foxhead128/ryouko
162
+ [ 'name' => 'Sylera', 'id' => 'sylera', 'regexp' =>'/Sylera\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // Needs to be discovered before SeaMonkey Browser, see: https://ja.wikipedia.org/wiki/Sylera
163
  [ 'name' => 'SaaYaa Explorer', 'id' => 'saayaa', 'regexp' =>'/SaaYaa/u', 'type' => Constants\DeviceType::DESKTOP ],
164
+ [ 'name' => 'SalamWeb', 'id' => 'salam', 'regexp' => '/SalamWeb\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://salamweb.com/
165
+ [ 'name' => 'SalamWeb', 'id' => 'salam', 'regexp' => '/Salam Browser/u', 'type' => Constants\DeviceType::DESKTOP ],
166
+ [ 'name' => 'Shiira', 'id' => 'shiira', 'regexp' => '/Shiira/u', 'type' => Constants\DeviceType::DESKTOP ],
167
+ [ 'name' => 'Sielo Browser', 'id' => 'sielo', 'regexp' => '/ Sielo\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://github.com/SieloBrowser/sielo-legacy
168
+ [ 'name' => 'SiteKiosk', 'id' => 'sitekiosk', 'regexp' => '/SiteKiosk ([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://www.provisio.com/web/us/products/windows-kiosk-software-sitekiosk
169
  [ 'name' => 'Sleipnir', 'id' => 'sleipnir', 'regexp' =>'/Sleipnir\/([0-9.]*)/u', 'details' => 3 ],
170
+ [ 'name' => 'Slimjet', 'id' => 'slimjet', 'regexp' => '/ Slimjet\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://www.slimjet.com/
171
  [ 'name' => 'Sogou Explorer', 'id' => 'metasr', 'regexp' =>'/SE 2.X MetaSr/u', 'type' => Constants\DeviceType::DESKTOP ],
172
+ [ 'name' => 'Sparrow', 'id' => 'sparrow', 'regexp' =>'/Sparrow\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
173
+ [ 'name' => 'Sputnik', 'id' => 'sputnik', 'regexp' => '/SputnikBrowser\/([0-9.]*)/u' ], // see: https://browser.sputnik.ru/
174
  [ 'name' => 'Stainless', 'id' => 'stainless', 'regexp' =>'/Stainless\/([0-9.]*)/u' ], // see: http://www.stainlessapp.com
175
+ [ 'name' => 'Station Browser', 'id' => 'station', 'regexp' => '/ Station\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://getstation.com/
176
  [ 'name' => 'SunChrome', 'id' => 'sunchrome', 'regexp' =>'/SunChrome\/([0-9.]*)/u' ],
177
+ [ 'name' => 'Sundance', 'id' => 'sundance', 'regexp' =>'/Sundance\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
178
+ [ 'name' => 'Sundial', 'id' => 'sundial', 'regexp' =>'/Sundial\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: http://www.sundialbrowser.com/
179
  [ 'name' => 'Superbird', 'id' => 'superbird', 'regexp' =>'/Super[Bb]ird\/([0-9.]*)/u', 'details' => 2 ],
180
+ [ 'name' => 'Swiftweasel', 'id' => 'swiftweasel', 'regexp' =>'/Swiftweasel\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: http://swiftweasel.tuxfamily.org/
181
+ [ 'name' => 'Swiftfox', 'id' => 'swiftfox', 'regexp' =>'/Swiftfox/u', 'type' => Constants\DeviceType::DESKTOP ],
182
  [ 'name' => 'Swing Browser', 'id' => 'swing', 'regexp' =>'/Swing(?:\(And\))?\/([0-9.]*)/u', 'details' => 3 ], // see: http://swing-browser.com
183
+ [ 'name' => 't-online.de', 'id' => 'to-browser', 'regexp' =>'/TO-Browser\/TOB([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://www.t-online.de/computer/browser/
184
+ [ 'name' => 't-online.de', 'id' => 'to-browser', 'regexp' =>'/TO-Browser/u', 'type' => Constants\DeviceType::DESKTOP ],
185
  [ 'name' => 'Tencent Traveler', 'id' => 'tencent', 'regexp' =>'/TencentTraveler ([0-9.]*)/u', 'details' => 2 ],
186
  [ 'name' => 'TenFourFox', 'id' => 'tenfourfox', 'regexp' =>'/TenFourFox\//u' ],
187
  [ 'name' => 'The World', 'id' => 'theworld', 'regexp' =>'/TheWorld(?: ([0-9.]*))?/u' ],
188
+ [ 'name' => 'Tulip Chain', 'id' => 'tulip', 'regexp' =>'/TulipChain\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: http://ostermiller.org/tulipchain/
189
  [ 'name' => 'Tungsten Browser', 'id' => 'tungsten', 'regexp' =>'/TungstenBrowser\/([0-9.]*)/u' ],
190
+ [ 'name' => 'UltraBrowser', 'id' => 'ultrab', 'regexp' =>'/UltraBrowser ([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: http://www.ultrabrowser.com/
191
+ [ 'name' => 'Usejump', 'id' => 'usejump', 'regexp' =>'/Usejump\/([0-9.]*)/u', 'details' => 2, 'type' => Constants\DeviceType::DESKTOP ],
192
+ [ 'name' => 'Vimprobable', 'id' => 'vimprobable', 'regexp' =>'/Vimprobable\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
193
  [ 'name' => 'Vivaldi', 'id' => 'vivaldi', 'regexp' =>'/Vivaldi\/([0-9.]*)/u', 'details' => 2 ],
194
+ [ 'name' => 'VMware Workspace ONE', 'id' => 'airwatch', 'regexp' => '/Air[Ww]atch Browser v([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
195
+ [ 'name' => 'Vonkeror', 'id' => 'vonkeror', 'regexp' =>'/Vonkeror\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
196
  [ 'name' => 'Voyager', 'id' => 'voyager', 'regexp' =>'/AmigaVoyager\/([0-9.]*)/u' ],
197
  [ 'name' => 'Waterfox', 'id' => 'waterfox', 'regexp' =>'/Waterfox\/([0-9.]*)/u', 'details' => 2, 'type' => Constants\DeviceType::DESKTOP ],
198
+ [ 'name' => 'Whale Browser', 'id' => 'whale', 'regexp' => '/ Whale\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://whale.naver.com/
199
+ [ 'name' => 'WinWAP Browser', 'id' => 'winwap', 'regexp' => '/WinWAP\/([0-9]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://www.winwap.com/mobile_applications/winwap_browser.php
200
+ [ 'name' => 'WinWAP Browser', 'id' => 'winwap', 'regexp' => '/WinWAP-SPBE\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ],
201
+ [ 'name' => 'Xvast', 'id' => 'xvast', 'regexp' =>'/Xvast\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: http://www.xvast.com/
202
  [ 'name' => 'Yandex Browser', 'id' => 'yabrowser', 'regexp' =>'/YaBrowser\/([0-9.]*)/u', 'details' => 2 ],
203
+ [ 'name' => 'Zvu Browser', 'id' => 'zvu', 'regexp' => '/ Zvu\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: http://zvu.com/
204
+ [ 'name' => 'ZipZap', 'id' => 'zipzap', 'regexp' =>'/ZipZap ([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: http://www.zipzaphome.com/
205
+ [ 'name' => 'Zombie.js', 'id' => 'zombie', 'regexp' =>'/Zombie\.js\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: http://zombie.js.org/
206
 
207
  /* Mobile browsers */
208
  [ 'name' => '1Browser', 'id' => '1password', 'regexp' =>'/1Password\/([0-9.]*)/u' ],
209
  [ 'name' => '2345 Browser', 'id' => '2345', 'regexp' =>'/Mb2345Browser\/([0-9.]*)/u' ],
210
  [ 'name' => '3G Explorer', 'id' => '3g explorer', 'regexp' =>'/3G Explorer\/([0-9.]*)/u', 'details' => 3 ],
211
  [ 'name' => '4G Explorer', 'id' => '4g explorer', 'regexp' =>'/4G Explorer\/([0-9.]*)/u', 'details' => 3 ],
212
+ [ 'name' => 'Aloha Browser', 'id' => 'aloha', 'regexp' => '/AlohaBrowser\/([0-9.]*)/u', 'type' => Constants\DeviceType::MOBILE ], // see: https://alohabrowser.com/
213
  [ 'name' => 'Atomic', 'id' => 'atomiclite', 'regexp' =>'/AtomicLite\/([0-9.]*)/u' ], // see: http://atomicwebbrowser.com
214
  [ 'name' => 'AU', 'id' => 'au', 'regexp' =>'/(?:^| )AU(?:.Browser)?\/([0-9.]+)/u' ],
215
  [ 'name' => 'Awakening', 'id' => 'awakening', 'regexp' =>'/Awakening Browser\/([0-9.]*)/u', 'details' => 2 ],
227
  [ 'name' => 'Digia @Web', 'id' => 'digia', 'regexp' =>'/Digia @Web\/([0-9.]*)/u' ],
228
  [ 'name' => 'Doris', 'id' => 'doris', 'regexp' =>'/Doris\/([0-9.]*)/u' ],
229
  [ 'name' => 'Dorothy', 'id' => 'doroty', 'regexp' =>'/Dorothy$/u' ],
230
+ [ 'name' => 'Ecosia Browser', 'id' => 'ecosia', 'regexp' => '/Ecosia\sandroid\@([0-9.]*)/u', 'type' => Constants\DeviceType::MOBILE ], // see: https://play.google.com/store/apps/details?id=com.ecosia.android
231
+ [ 'name' => 'Ecosia Browser', 'id' => 'ecosia', 'regexp' => '/Ecosia\sios\@([0-9.]*)/u', 'type' => Constants\DeviceType::MOBILE ], // see: https://apps.apple.com/us/app/ecosia/id670881887
232
  [ 'name' => 'EMOBILE Browser', 'id' => 'www browser', 'regexp' =>'/WWW Browser\/ver([0-9.]*)/u' ],
233
+ [ 'name' => 'Epic Browser', 'id' => 'epic', 'regexp' => '/ Epic\/([0-9.]*)/u', 'type' => Constants\DeviceType::MOBILE ], // see: https://en.wikipedia.org/wiki/Epic_(web_browser)
234
  [ 'name' => 'EUI Browser', 'id' => 'eui', 'regexp' =>'/EUI Browser\/[^0-9\s]*([0-9.]*)/u', 'details' => 2 ],
235
  [ 'name' => 'Go.Web', 'id' => 'go\.web', 'regexp' =>'/Go\.Web\/([0-9.]*)/u' ], // used on early Blackberry, by GoAmerica
236
  [ 'name' => 'Helium', 'id' => 'helium', 'regexp' =>'/HeliumMobileBrowser\/([0-9.]*)/u' ],
237
+ [ 'name' => 'HeyTap Browser', 'id' => 'heytap', 'regexp' => '/HeyTapBrowser\/([0-9.]*)/u', 'type' => Constants\DeviceType::MOBILE ],
238
  [ 'name' => 'Huohou Browser', 'id' => 'huohoubrowser', 'regexp' =>'/HuohouBrowser\/([0-9.]*)/u' ],
239
  [ 'name' => 'iCab', 'id' => 'icab', 'regexp' =>'/iCabMobile\/([0-9.]*)/u' ],
240
  [ 'name' => 'iLunascape', 'id' => 'lunascape', 'regexp' =>'/iLunascape\/([0-9.]*)/u', 'details' => 3 ], // see: http://www.lunascape.tv
242
  [ 'name' => 'iSurf', 'id' => 'isurf', 'regexp' =>'/iSurf version \/v([0-9.]*)/u', 'details' => 2 ],
243
  [ 'name' => 'Jig Browser', 'id' => 'jig browser', 'regexp' =>'/jig browser(?: web| core|9i?)?;? ?([0-9.]+)?/u', 'type' => Constants\DeviceType::MOBILE ],
244
  [ 'name' => 'Jumanji', 'id' => 'jumanji', 'regexp' =>'/jumanji/u' ], // see: jumanji browser ubuntu
245
+ [ 'name' => 'K.Browser', 'id' => 'tnsbrowser', 'regexp' => '/TNSBrowser\/([0-9.]*)/u', 'type' => Constants\DeviceType::MOBILE ], // see: https://play.google.com/store/apps/details?id=com.tnsua.browser
246
  [ 'name' => 'Kiosk', 'id' => 'kiosk', 'regexp' =>'/Kiosk\/([0-9.]*)/u' ], // see: http://www.kioskbrowser.net
247
+ [ 'name' => 'Kiwi Browser', 'id' => 'kiwi', 'regexp' => '/Kiwi Chrome\/([0-9.A-Z]*)/u' ], // see: https://kiwibrowser.com
248
  [ 'name' => 'LeBrowser', 'id' => 'lebrowser', 'regexp' =>'/LeBrowser\/([0-9.]*)/u', 'details' => 2 ],
249
  [ 'name' => 'LieBaoFast', 'id' => 'liebao', 'regexp' =>'/LieBaoFast\/([0-9.]*)/u' ], // see: http://www.liebao.cn
250
  [ 'name' => 'MaCross Mobile', 'id' => 'macross', 'regexp' =>'/MaCross\/([0-9.]*)/u' ],
251
  [ 'name' => 'Mammoth', 'id' => 'mammoth', 'regexp' =>'/Mammoth\/([0-9.]*)/u' ], // see: https://itunes.apple.com/cn/app/meng-ma-liu-lan-qi/id403760998?mt=8
252
  [ 'name' => 'mCent Browser', 'id' => 'mcent', 'regexp' =>'/mCent\/([0-9.]*)/u' ],
253
+ [ 'name' => 'Mint Browser', 'id' => 'mint', 'regexp' => '/XiaoMi\/Mint Browser\/([0-9.]*)/u', 'type' => Constants\DeviceType::MOBILE ], // see: http://www.mintbrowser.com/
254
+ [ 'name' => 'Mobicip', 'id' => 'mobicip', 'regexp' => '/ Mobicip\//u', 'type' => Constants\DeviceType::MOBILE ], // see: https://www.mobicip.com/
255
  [ 'name' => 'Motorola Internet Browser', 'id' => 'mib', 'regexp' =>'/MIB\/([0-9.]*)/u' ],
256
  [ 'name' => 'Motorola Internet Browser', 'id' => 'mib', 'regexp' =>'/MIB([0-9.]+)\//u' ],
257
  [ 'name' => 'Motorola Internet Browser', 'id' => 'cmcs', 'regexp' =>'/Browser\/CMCS([0-9.]*)/u' ],
258
  [ 'name' => 'Motorola WebKit', 'id' => 'motorola', 'regexp' =>'/MotorolaWebKit(?:\/([0-9.]*))?/u', 'details' => 3 ],
259
+ [ 'name' => 'MultiZilla', 'id' => 'multizilla', 'regexp' => '/MultiZilla\/([0-9.]*)/u', 'type' => Constants\DeviceType::DESKTOP ], // see: https://sourceforge.net/projects/multizilla/
260
  [ 'name' => 'NetFront Life Browser', 'id' => 'netfrontlife', 'regexp' =>'/NetFrontLifeBrowser\/([0-9.]*)/u' ],
261
  [ 'name' => 'OneBrowser', 'id' => 'onebrowser', 'regexp' =>'/OneBrowser\/([0-9.]*)/u' ],
262
+ [ 'name' => 'OnePlus Browser', 'id' => 'oneplus', 'regexp' => '/OnePlusBrowser\/([0-9.]*)/u', 'type' => Constants\DeviceType::MOBILE ], // see: https://www.oneplus.com/
263
  [ 'name' => 'PocketLink', 'id' => 'plink', 'regexp' =>'/PLink ([0-9.]+)/iu', 'details' => 2 ],
264
  [ 'name' => 'Polaris', 'id' => 'polaris', 'regexp' =>'/Polaris[\/ ]v?([0-9.]*)/iu', 'details' => 2 ],
265
  [ 'name' => 'Polaris', 'id' => 'polaris', 'regexp' =>'/POLARIS([0-9.]+)/u', 'details' => 2 ],
266
+ [ 'name' => 'Pure Browser', 'id' => 'pure', 'regexp' =>'/PureBrowser\/([0-9.]*)/u', 'details' => 2 ],
267
  [ 'name' => 'Openwave', 'id' => 'openwave', 'regexp' =>'/Open[Ww]ave\/([0-9.]*)/u', 'details' => 2, 'type' => Constants\DeviceType::MOBILE ],
268
  [ 'name' => 'Openwave', 'id' => 'openwave', 'regexp' =>'/Openwave Mobile Browser ([0-9.]*)/u', 'details' => 2, 'type' => Constants\DeviceType::MOBILE ],
269
  [ 'name' => 'Openwave', 'id' => 'openwave', 'regexp' =>'/Browser\/OpenWave([0-9.]*)/u', 'details' => 2, 'type' => Constants\DeviceType::MOBILE ],
270
  [ 'name' => 'Openwave', 'id' => 'up', 'regexp' =>'/UP\. ?Browser(?:\/([a-z0-9.]*))?/iu', 'details' => 2, 'type' => Constants\DeviceType::MOBILE ],
271
  [ 'name' => 'Openwave', 'id' => 'km', 'regexp' =>'/KM\.Browser\/([0-9.]+)/iu', 'details' => 2, 'type' => Constants\DeviceType::MOBILE ],
272
  [ 'name' => 'Openwave', 'id' => 'up', 'regexp' =>'/UP\/([0-9.]+)/u', 'details' => 2, 'type' => Constants\DeviceType::MOBILE ],
273
+ [ 'name' => 'Oppo Browser', 'id' => 'oppo', 'regexp' =>'/OppoBrowser\/([0-9.]+)/iu' ],
274
+ [ 'name' => 'Quark Browser', 'id' => 'quark', 'regexp' =>'/Quark\/([0-9.]*)/u', 'details' => 3 ],
275
+ [ 'name' => 'Realme Browser', 'id' => 'realme', 'regexp' =>'/RealmeBrowser\/([0-9.]*)/u', 'type' => Constants\DeviceType::MOBILE ],
276
+
277
  [ 'name' => 'SEMC Browser', 'id' => 'semc', 'regexp' =>'/SEMC-Browser\/([0-9.]*)/u' ],
278
  [ 'name' => 'STNC HitchHiker' , 'id' => 'stnc', 'regexp' =>'/STNC-WTL\/[0-9.]*/u' ],
279
  [ 'name' => 'Sogou Mobile', 'id' => 'sogou', 'regexp' =>'/SogouMobileBrowser\/([0-9.]*)/u', 'details' => 2 ],
280
  [ 'name' => 'Swing Browser', 'id' => 'swing', 'regexp' =>'/Swing\(And\)\/([0-9.]*)/u', 'details' => 3 ],
281
  [ 'name' => 'Symphony', 'id' => 'symphony', 'regexp' =>'/Symphony ([0-9.]+)$/u' ],
282
+ [ 'name' => 'Tenta Browser', 'id' => 'tenta', 'regexp' => '/ Tenta\/([0-9.]*)/u', 'type' => Constants\DeviceType::MOBILE ], // see: https://play.google.com/store/apps/details?id=com.tenta.android&hl=en
283
  [ 'name' => 'TinY', 'id' => 'ucpro', 'regexp' =>'/ucpro\/([0-9.]+)/iu' ],
284
+ [ 'name' => 'Vivo Browser', 'id' => 'vivo', 'regexp' =>'/VivoBrowser\/([0-9.]+)/iu' ],
285
  [ 'name' => 'WebLite', 'id' => 'weblite', 'regexp' =>'/WebLite\/([0-9.]*)/u', 'type' => Constants\DeviceType::MOBILE ],
286
+ [ 'name' => 'WK Browser', 'id' => 'wk', 'regexp' => '/wkbrowser ([0-9.]*)/u', 'type' => Constants\DeviceType::MOBILE ], // see: https://github.com/keanulee/WKBrowser
287
+ [ 'name' => 'Yaani Browser', 'id' => 'yaani', 'regexp' => '/YaaniBrowser\/([0-9.]*)/u', 'type' => Constants\DeviceType::MOBILE ], // see: https://www.yaani.com.tr/
288
 
289
  /* Television browsers */
290
  [ 'name' => 'AltiBrowser', 'id' => 'alti', 'regexp' =>'/AltiBrowser\/([0-9.]*)/i' ],
292
  [ 'name' => 'AwoX', 'id' => 'awox', 'regexp' =>'/AwoX(?:\/([0-9.]*))? Browser/i' ],
293
  [ 'name' => 'Isis', 'id' => 'browserserver', 'regexp' =>'/BrowserServer/u' ],
294
  [ 'name' => 'Isis', 'id' => 'isis', 'regexp' =>'/ISIS\/([0-9.]*)/u', 'details' => 2 ],
295
+ [ 'name' => 'Netbox', 'id' => 'netbox', 'regexp' =>'/Netbox\/([0-9.]*)/u', 'type' => Constants\DeviceType::TELEVISION ],
296
  [ 'name' => 'Spyglass', 'id' => 'spyglass', 'regexp' =>'/Spyglass ([0-9.]+); OpenTV/u' ],
297
  [ 'name' => 'Oregan Browser', 'id' => 'oregan', 'regexp' =>'/OreganMediaBrowser(?:\/([0-9.]*))?/u', 'details' => 2 ],
298
  [ 'name' => 'Viera Browser', 'id' => 'viera', 'regexp' =>'/Viera\/([0-9.]*)/u' ],
334
  [ 'name' => 'Snowshoe', 'id' => 'snowshoe', 'regexp' =>'/Snowshoe\/([0-9.]*)/u', 'details' => 2 ],
335
  [ 'name' => 'Sputnik', 'id' => 'sputnik', 'regexp' =>'/Sputnik\/([0-9.]*)/iu', 'details' => 3 ],
336
  [ 'name' => 'Surf', 'id' => 'surf', 'regexp' =>'/Surf\/([0-9.]*)/u' ],
337
+ [ 'name' => 'Taobao Browser', 'id' => 'tao', 'regexp' =>'/TaoBrowser\/([0-9.]*)/u', 'details' => 2 ],
338
  [ 'name' => 'TaomeeBrowser', 'id' => 'tao', 'regexp' =>'/TaomeeBrowser\/([0-9.]*)/u', 'details' => 2 ],
339
  [ 'name' => 'TazWeb', 'id' => 'taz', 'regexp' =>'/TazWeb/u' ],
340
  [ 'name' => 'Uzbl', 'id' => 'uzbl', 'regexp' =>'/^Uzbl/u' ],
368
  [ 'name' => 'BrightSign', 'id' => 'brightsign', 'regexp' =>'/BrightSign\/([0-9.]*)/u', 'type' => Constants\DeviceType::SIGNAGE ],
369
  [ 'name' => 'Coship MMCP', 'id' => 'coship', 'regexp' =>'/Coship_MMCP_([0-9.]*)/u', 'type' => Constants\DeviceType::SIGNAGE ],
370
  ]
371
+ ];
integration/whichbrowser/data/applications-others.php CHANGED
@@ -71,11 +71,20 @@ Applications::$OTHERS = [
71
  Constants\BrowserType::APP_CHAT => [
72
  [ 'name' => 'Facebook Messenger', 'id' => 'messenger', 'regexp' =>'/FBAN\/MessengerForiOS/u' ],
73
  [ 'name' => 'Facebook Messenger', 'id' => 'messenger', 'regexp' =>'/FB_IAB\/MESSENGER/u' ],
 
 
74
  [ 'name' => 'Kik', 'id' => 'kik', 'regexp' =>'/Kik\/([0-9.]*?)(\.0)?\.[0-9]{3,4}/u' ],
 
 
 
 
75
  [ 'name' => 'WeChat', 'id' => 'messenger', 'regexp' =>'/MicroMessenger\/([0-9.]*)/u' ],
 
76
  [ 'name' => 'Wire', 'id' => 'wire', 'regexp' =>'/Wire\/([0-9.]*)/u' ],
77
  [ 'name' => 'Yahoo Messenger', 'id' => 'yahoo', 'regexp' =>'/YahooMobile\/1.0 \(im; ([0-9.]+)\)/u', 'details' => 3 ],
78
  [ 'name' => 'Yammer', 'id' => 'yammer', 'regexp' =>'/Yammer\/([0-9.]*)/u', 'details' => 2 ],
 
 
79
  ],
80
 
81
  Constants\BrowserType::APP_SOCIAL => [
@@ -91,6 +100,7 @@ Applications::$OTHERS = [
91
  [ 'name' => 'Twitter', 'id' => 'twitter', 'regexp' =>'/TwitterAndroid/u' ],
92
  [ 'name' => 'Twitter', 'id' => 'twitter', 'regexp' =>'/Twitter for iPhone/u' ],
93
  [ 'name' => 'WordPress', 'id' => 'wp-android', 'regexp' =>'/wp-android\/([0-9.]*)/u' ],
 
94
  ],
95
 
96
  Constants\BrowserType::APP_OFFICE => [
71
  Constants\BrowserType::APP_CHAT => [
72
  [ 'name' => 'Facebook Messenger', 'id' => 'messenger', 'regexp' =>'/FBAN\/MessengerForiOS/u' ],
73
  [ 'name' => 'Facebook Messenger', 'id' => 'messenger', 'regexp' =>'/FB_IAB\/MESSENGER/u' ],
74
+ [ 'name' => 'KakaoTalk', 'id' => 'kakao', 'regexp' => '/KAKAOTALK ([0-9.]*)/u' ],
75
+ [ 'name' => 'KakaoTalk', 'id' => 'kakao', 'regexp' => '/KAKAOTALK/u' ],
76
  [ 'name' => 'Kik', 'id' => 'kik', 'regexp' =>'/Kik\/([0-9.]*?)(\.0)?\.[0-9]{3,4}/u' ],
77
+ [ 'name' => 'Line', 'id' => 'line', 'regexp' => '/ Line\/([0-9.]*)/u' ],
78
+ [ 'name' => 'Slack', 'id' => 'slack', 'regexp' => '/ Slack_SSB\/([0-9.]*)/u' ],
79
+ [ 'name' => 'Viber', 'id' => 'viber', 'regexp' => '/ Viber/u' ],
80
+ [ 'name' => 'Viber', 'id' => 'viber', 'regexp' => '/Viber\/([0-9.]*)/u' ],
81
  [ 'name' => 'WeChat', 'id' => 'messenger', 'regexp' =>'/MicroMessenger\/([0-9.]*)/u' ],
82
+ [ 'name' => 'WhatsApp', 'id' => 'whatsapp', 'regexp' =>'/WhatsApp\/([0-9.]*)/u' ],
83
  [ 'name' => 'Wire', 'id' => 'wire', 'regexp' =>'/Wire\/([0-9.]*)/u' ],
84
  [ 'name' => 'Yahoo Messenger', 'id' => 'yahoo', 'regexp' =>'/YahooMobile\/1.0 \(im; ([0-9.]+)\)/u', 'details' => 3 ],
85
  [ 'name' => 'Yammer', 'id' => 'yammer', 'regexp' =>'/Yammer\/([0-9.]*)/u', 'details' => 2 ],
86
+ [ 'name' => 'Zalo', 'id' => 'zalo', 'regexp' => '/Zalo\-win32\-([0-9.]*)/u' ],
87
+ [ 'name' => 'Zalo', 'id' => 'zalo', 'regexp' => '/ Zalo\/([0-9.]*)/u' ],
88
  ],
89
 
90
  Constants\BrowserType::APP_SOCIAL => [
100
  [ 'name' => 'Twitter', 'id' => 'twitter', 'regexp' =>'/TwitterAndroid/u' ],
101
  [ 'name' => 'Twitter', 'id' => 'twitter', 'regexp' =>'/Twitter for iPhone/u' ],
102
  [ 'name' => 'WordPress', 'id' => 'wp-android', 'regexp' =>'/wp-android\/([0-9.]*)/u' ],
103
+ [ 'name' => 'Yelp', 'id' => 'yelp', 'regexp' =>'/YelpApp\/([0-9.]*)/u' ],
104
  ],
105
 
106
  Constants\BrowserType::APP_OFFICE => [
integration/whichbrowser/data/browsers-chrome.php CHANGED
@@ -71,6 +71,26 @@ Chrome::$DESKTOP = [
71
  '62.0.3202' => 'stable',
72
  '63.0.3239' => 'stable',
73
  '64.0.3282' => 'stable',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  ];
75
 
76
  Chrome::$MOBILE = [
@@ -114,4 +134,25 @@ Chrome::$MOBILE = [
114
  '62.0.3202' => 'stable',
115
  '63.0.3239' => 'stable',
116
  '64.0.3282' => 'stable',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  ];
71
  '62.0.3202' => 'stable',
72
  '63.0.3239' => 'stable',
73
  '64.0.3282' => 'stable',
74
+ '65.0.3325' => 'stable',
75
+ '66.0.3359' => 'stable',
76
+ '67.0.3396' => 'stable',
77
+ '68.0.3440' => 'stable',
78
+ '69.0.3497' => 'stable',
79
+ '72.0.3626' => 'stable',
80
+ '73.0.3683' => 'stable',
81
+ '74.0.3729' => 'stable',
82
+ '75.0.3770' => 'stable',
83
+ '76.0.3809' => 'stable',
84
+ '77.0.3865' => 'stable',
85
+ '78.0.3904' => 'stable',
86
+ '79.0.3945' => 'stable',
87
+ '80.0.3987' => 'stable',
88
+ '81.0.4044' => 'stable',
89
+ '83.0.4103' => 'stable',
90
+ '84.0.4147' => 'stable',
91
+ '85.0.4183' => 'stable',
92
+ '86.0.4240' => 'stable',
93
+ '87.0.4280' => 'stable',
94
  ];
95
 
96
  Chrome::$MOBILE = [
134
  '62.0.3202' => 'stable',
135
  '63.0.3239' => 'stable',
136
  '64.0.3282' => 'stable',
137
+ '65.0.3325' => 'stable',
138
+ '66.0.3359' => 'stable',
139
+ '67.0.3396' => 'stable',
140
+ '68.0.3440' => 'stable',
141
+ '69.0.3497' => 'stable',
142
+ '70.0.3538' => 'stable',
143
+ '71.0.3578' => 'stable',
144
+ '72.0.3626' => 'stable',
145
+ '73.0.3683' => 'stable',
146
+ '74.0.3729' => 'stable',
147
+ '75.0.3770' => 'stable',
148
+ '76.0.3809' => 'stable',
149
+ '77.0.3865' => 'stable',
150
+ '78.0.3904' => 'stable',
151
+ '79.0.3945' => 'stable',
152
+ '80.0.3987' => 'stable',
153
+ '83.0.4103' => 'stable',
154
+ '84.0.4147' => 'stable',
155
+ '85.0.4183' => 'stable',
156
+ '86.0.4240' => 'stable',
157
+ '87.0.4280' => 'stable',
158
  ];
integration/whichbrowser/data/indices/models-android.php CHANGED
@@ -13,48 +13,50 @@ DeviceModels::$ANDROID_INDEX = array (
13
  5 => '[0-9]0[0-9]F!!',
14
  6 => '(Haier[- ])?H[ETW]- ?[A-Z][0-9]!!',
15
  7 => '(Hisense )?(LED[0-9]{2,2}(G|K|L|EC|XT)[0-9]{2,3})!',
16
- 8 => '[SX0][0-9]{2,2}HT!!',
17
  9 => '(Huawei )?[MSTX](1|2|7|8|10)\\-[A-Z0-9][0-9]{2,2}!!',
18
- 10 => 'G[0-9]{3,3}!!',
19
- 11 => 'Y[0-9]{3,3}!!',
20
- 12 => '[0-9AS][0-9]{2,2}HW!!',
21
- 13 => '(USCC-|KYOCERA-)?E[0-9]{4,4}!!',
22
- 14 => '(USCC-|KYOCERA-)?C[0-9]{4,4}!!',
23
- 15 => '[0-9]0[0-9]KC?!!',
24
- 16 => 'K\\-?Touch!!',
25
- 17 => '(Lenovo ?)?(IdeaTab ?)?[AB][0-9]{4,4}!!',
26
- 18 => '(Lenovo )?(Tab ?)?(2 ?)?[AS](7|8|10)!!',
27
- 19 => '(Lenovo ?)?(IdeaTab ?)?[KSV][0-9]{4,4}!!',
28
- 20 => '[0-9]0[0-9]LG!!',
29
- 21 => 'M\\-PP!!',
30
- 22 => 'M\\-MP!!',
31
- 23 => 'M\\-IPRO!!',
32
- 24 => '(MEDION|(MD )?LIFETAB)!!',
33
- 25 => 'M\\.T\\.T\\.!!',
34
- 26 => 'O\\+!!',
35
- 27 => '[0-9]{2,2}PFH6[0-9]{3,3}!',
36
- 28 => '(?:RIVO )?RHYTHM RX ?([0-9]+)!',
37
- 29 => '[456A]0[0-9]SH!!',
38
- 30 => '(3|5|6)0[0-9]SH!!',
39
- 31 => 'C[0-9]{4,4}!!',
40
- 32 => 'D[0-9]{4,4}!!',
41
- 33 => 'E[0-9]{4,4}!!',
42
- 34 => 'F[0-9]{4,4}!!',
43
- 35 => 'G[0-9]{4,4}!!',
44
- 36 => 'H[0-9]{4,4}!!',
45
- 37 => 'E[0-9]{2,2}[a-z]!!',
46
- 38 => 'L[0-9]{2,2}[a-z]!!',
47
- 39 => '(SNM\\-)?M[0-9]{2,2}[a-z]!!',
48
- 40 => 'S[0-9]{2,2}[a-z]!!',
49
- 41 => '(XOLO )?[ABQX][0-9]{3,4}!!',
50
- 42 => '(ZTE ?)?N[0-9]{3,3}!!',
51
- 43 => '(ZXY-)?(ZTE )?N[0-9]{4,4}!!',
52
- 44 => '(ZTE ?)?U[0-9]{3,3}!!',
53
- 45 => '(ZTE ?)?V[0-9]{3,3}[A-Z]!!',
54
- 46 => '(ZTE ?)?V ?[0-9]{3,3}!!',
55
- 47 => '(ZTE ?)?X[0-9]{3,3}!!',
56
- 48 => '(ZTE )?Z[0-9]!!',
57
- 49 => '[a-z][a-z](?:-[a-z][a-z])?, SmartTabII7!',
 
 
58
  ),
59
  '@00' =>
60
  array (
@@ -131,7 +133,11 @@ DeviceModels::$ANDROID_INDEX = array (
131
  ),
132
  '@3' =>
133
  array (
134
- 0 => '(3|5|6)0[0-9]SH!!',
 
 
 
 
135
  ),
136
  '@36' =>
137
  array (
@@ -162,20 +168,22 @@ DeviceModels::$ANDROID_INDEX = array (
162
  13 => '4027[ADNX]!',
163
  14 => '4028[AEJS]!',
164
  15 => '4032[ADEX]!',
165
- 16 => '4033[AL]!',
166
  17 => '4034[ADEFGX]!',
167
  18 => '4035[ADYX]!',
168
  19 => '4036[E]!',
169
  20 => '4037[AX]!',
170
  21 => '4037[T]!',
171
  22 => '4037[V]!',
172
- 23 => '4045[ADELOX]!',
173
- 24 => '4055[JU]!',
174
- 25 => '4060[A]!',
175
- 26 => '4060[W]!',
176
- 27 => '40[0-9]SC!!',
177
- 28 => '40[0-9]SO!!',
178
- 29 => '402ZT',
 
 
179
  ),
180
  '@48' =>
181
  array (
@@ -183,50 +191,67 @@ DeviceModels::$ANDROID_INDEX = array (
183
  ),
184
  '@5' =>
185
  array (
186
- 0 => '(3|5|6)0[0-9]SH!!',
187
  ),
188
  '@50' =>
189
  array (
190
  0 => '5010[DEGSUX]!',
191
- 1 => '5012[G]!',
192
- 2 => '5015[ADEX]!',
193
- 3 => '5016[AJ]!',
194
- 4 => '5017[B]!',
195
- 5 => '5017[ADEOX]!',
196
- 6 => '5019[D]!',
197
- 7 => '5020[A]!',
198
- 8 => '5022[DEX]!',
199
- 9 => '5023[F]!',
200
- 10 => '5025[DEGX]!',
201
- 11 => '5027[B]!',
202
- 12 => '5036[D]!',
203
- 13 => '5038[ADEX]!',
204
- 14 => '5042[ADEFGTWXY]!',
205
- 15 => '5044[ADOY]!',
206
- 16 => '5045[ADGJTX]!',
207
- 17 => '5046[Y]!',
208
- 18 => '5050[ASYX]!',
209
- 19 => '5051[ADJMX]!',
210
- 20 => '5054[ADOSTX]!',
211
- 21 => '5054[NW]!',
212
- 22 => '5056[ADENUWX]!',
213
- 23 => '5056[O]!',
214
- 24 => '5057[M]!',
215
- 25 => '5065[ADJNWX]!',
216
- 26 => '5070[DJX]!',
217
- 27 => '5080[DX]!',
218
- 28 => '5085[CD]!',
219
- 29 => '5095[BIKY]!',
220
- 30 => '5096[A]!',
221
- 31 => '5098[OS]!',
222
- 32 => '504Q',
223
- 33 => '504Q+',
224
- 34 => '504QP',
225
- 35 => '501LV',
226
- 36 => '(48|50|55)AX600C!',
227
- 37 => '5080C Pro',
228
- 38 => '50[0-9]SO!!',
229
- 39 => '502ZT',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
  ),
231
  '@55' =>
232
  array (
@@ -243,6 +268,10 @@ DeviceModels::$ANDROID_INDEX = array (
243
  5 => '5860S',
244
  6 => 5870,
245
  ),
 
 
 
 
246
  '@60' =>
247
  array (
248
  0 => '6014[DX]!',
@@ -257,14 +286,23 @@ DeviceModels::$ANDROID_INDEX = array (
257
  9 => '6045[BFGIKOXY]!',
258
  10 => '6050[AFWY]!',
259
  11 => '6055[ABDHIKPUY]!',
260
- 12 => '6070[KOY]!',
261
- 13 => '60[0-9]SO!!',
262
- 14 => '6034R ORANGE Niva',
 
 
 
 
 
 
 
 
 
263
  ),
264
  '@70' =>
265
  array (
266
  0 => '7030[L]!',
267
- 1 => '7040[NR]!',
268
  2 => '7040[T]!',
269
  3 => '7043[AEKY]!',
270
  4 => '7044[AXY]!',
@@ -275,6 +313,8 @@ DeviceModels::$ANDROID_INDEX = array (
275
  9 => '7051[X]!',
276
  10 => '7053[D]!',
277
  11 => '7055[AW]!',
 
 
278
  ),
279
  '@71' =>
280
  array (
@@ -341,19 +381,19 @@ DeviceModels::$ANDROID_INDEX = array (
341
  ),
342
  '@90' =>
343
  array (
344
- 0 => '9001[DX]!',
345
  1 => '9002[AWX]!',
346
  2 => '9003[AX]!',
347
  3 => '9005[X]!',
348
  4 => '9006[W]!',
349
  5 => '9007[ATX]!',
350
- 6 => '9008[AIJTUX]!',
351
  7 => '9010[X]!',
352
- 8 => '9015[BJW]!',
353
  9 => '9022[SX]!',
354
- 10 => '9024[W]!',
355
  11 => '9025[MQ]!',
356
- 12 => '9021A',
357
  13 => '909d',
358
  14 => 9088,
359
  15 => '9020[A]!',
@@ -429,11 +469,12 @@ DeviceModels::$ANDROID_INDEX = array (
429
  7 => 'A31',
430
  8 => 'A31c',
431
  9 => 'A31t',
432
- 10 => 'A33f',
433
- 11 => 'A33w',
434
- 12 => 'A37f',
435
- 13 => 'A37fw',
436
- 14 => 'A3',
 
437
  ),
438
  '@A4' =>
439
  array (
@@ -474,10 +515,11 @@ DeviceModels::$ANDROID_INDEX = array (
474
  17 => 'A500CG',
475
  18 => 'A55i',
476
  19 => 'A52',
477
- 20 => 'A51f',
478
- 21 => 'A51w',
479
- 22 => 'A5000',
480
- 23 => 'a5',
 
481
  ),
482
  '@A6' =>
483
  array (
@@ -512,9 +554,10 @@ DeviceModels::$ANDROID_INDEX = array (
512
  16 => 'A750',
513
  17 => 'A7000-a',
514
  18 => 'A7010a48',
515
- 19 => 'A7272+',
516
- 20 => 'A70(CY6T)',
517
- 21 => 'A78h四核(C1V3)',
 
518
  ),
519
  '@A8' =>
520
  array (
@@ -720,8 +763,8 @@ DeviceModels::$ANDROID_INDEX = array (
720
  33 => '(Allview|Alldro)!!',
721
  34 => 'Allwinner A10',
722
  35 => '(Highscreen|Alpha|Bay|Boost|Cosmo|Explosion|Power|Prime|Zera)!!',
723
- 36 => '(HUAWEI )?(ALP|BLA|CRR|LON|MATE|MHA|MT1|MT2|MT7|M200|NXT|Z100)!!',
724
- 37 => '(HW-|HUAWEI )?(ALE|D2|DAV|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|VIE|VKY|VNS|VTR|WAS)!!',
725
  38 => 'Alfa A93 POP',
726
  39 => 'Alfa L',
727
  40 => 'Ally',
@@ -806,18 +849,19 @@ DeviceModels::$ANDROID_INDEX = array (
806
  41 => 'AN10G2-LZ',
807
  42 => 'AN10BG3-LZ',
808
  43 => 'AN7DG3C',
809
- 44 => '(iBall )?Andi!!',
810
- 45 => 'AND1',
811
- 46 => 'AND1E',
812
- 47 => 'AND1E TV',
813
- 48 => 'Android edition by sfr STARADDICT',
814
- 49 => 'Android Edition Starnaute',
815
- 50 => 'Android Edition StarText',
816
- 51 => 'Android Edition StarTrail',
817
- 52 => '(Smartfren|Andromax)!!',
818
- 53 => 'Androtab 7',
819
- 54 => '(Starway )?Andromeda!!',
820
- 55 => '(Andy|Yezz)!!',
 
821
  ),
822
  '@AO' =>
823
  array (
@@ -951,43 +995,44 @@ DeviceModels::$ANDROID_INDEX = array (
951
  13 => 'AT1G*',
952
  14 => 'AT7E',
953
  15 => 'ATP515CKIT',
954
- 16 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
955
- 17 => 'aTab9.7 IPS',
956
- 18 => 'AT735',
957
- 19 => 'Atrix 2',
958
- 20 => 'Atrix 2 WeifanZ',
959
- 21 => 'Atrix 4G',
960
- 22 => 'Atrix 4G ME860',
961
- 23 => 'Atrix 4G MB860',
962
- 24 => 'Atrix HD',
963
- 25 => 'AtrixHD',
964
- 26 => 'ATLANTIS',
965
- 27 => 'ATP7526',
966
- 28 => 'ATP7683',
967
- 29 => 'AT1S0',
968
- 30 => 'AT7-A',
969
- 31 => 'AT7-B',
970
- 32 => 'AT7-C',
971
- 33 => 'AT10-A',
972
- 34 => 'AT10LE-A',
973
- 35 => 'AT10PE-A',
974
- 36 => 'AT100',
975
- 37 => 'AT200',
976
- 38 => 'AT270',
977
- 39 => 'AT300',
978
- 40 => 'AT300SE',
979
- 41 => 'AT330',
980
- 42 => 'AT374',
981
- 43 => 'AT400',
982
- 44 => 'AT470',
983
- 45 => 'AT500',
984
- 46 => 'AT500a',
985
- 47 => 'AT503',
986
- 48 => 'AT570',
987
- 49 => 'AT703',
988
- 50 => 'AT830',
989
- 51 => 'AT-A[QS][0-9]{2,2}!!',
990
- 52 => 'ATLAS W',
 
991
  ),
992
  '@AU' =>
993
  array (
@@ -1047,12 +1092,13 @@ DeviceModels::$ANDROID_INDEX = array (
1047
  5 => 'Barnes & Noble Nook HD+',
1048
  6 => '(Highscreen|Alpha|Bay|Boost|Cosmo|Explosion|Power|Prime|Zera)!!',
1049
  7 => 'BAH-(W09|AL00|L09)!',
1050
- 8 => '(HW-|HUAWEI )?BAC-(AL00|L03|L21|L22)!',
1051
- 9 => 'Backflip',
1052
- 10 => 'Backflip Me600',
1053
- 11 => 'Bambook S1',
1054
- 12 => 'BARRY',
1055
- 13 => 'BASE!!',
 
1056
  ),
1057
  '@BB' =>
1058
  array (
@@ -1066,8 +1112,10 @@ DeviceModels::$ANDROID_INDEX = array (
1066
  7 => 'BBB100-[0-9]!',
1067
  8 => 'BBC100-[0-9]!',
1068
  9 => 'BBD100-[0-9]!',
1069
- 10 => '(BBG-|VIV-)?vivo!!',
1070
- 11 => 'Bbox Miami',
 
 
1071
  ),
1072
  '@BC' =>
1073
  array (
@@ -1145,7 +1193,7 @@ DeviceModels::$ANDROID_INDEX = array (
1145
  '@BK' =>
1146
  array (
1147
  0 => '(BDS|BHX|BKO)\\-!!',
1148
- 1 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
1149
  ),
1150
  '@BL' =>
1151
  array (
@@ -1158,8 +1206,8 @@ DeviceModels::$ANDROID_INDEX = array (
1158
  6 => 'Bluboo S1',
1159
  7 => 'Blaze S180',
1160
  8 => 'BLADE LE 70',
1161
- 9 => '(HUAWEI )?(ALP|BLA|CRR|LON|MATE|MHA|MT1|MT2|MT7|M200|NXT|Z100)!!',
1162
- 10 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
1163
  11 => '(HW-|HUAWEI )?(BLL|CHC|TAG|KII)!!',
1164
  12 => '(BLF-)?lephone!!',
1165
  13 => 'Blackphone 2',
@@ -1180,11 +1228,12 @@ DeviceModels::$ANDROID_INDEX = array (
1180
  1 => '(NOOK )?BNTV250!',
1181
  2 => '(NOOK )?BNRV350!',
1182
  3 => '(NOOK )?BNTV(400)!',
1183
- 4 => '(NOOK )?BNTV(600)!',
1184
- 5 => '(NOOK )?BNTV(800)!',
1185
- 6 => 'BN Nook HD',
1186
- 7 => 'BN NookHD+',
1187
- 8 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
 
1188
  ),
1189
  '@BO' =>
1190
  array (
@@ -1339,8 +1388,8 @@ DeviceModels::$ANDROID_INDEX = array (
1339
  9 => 'Casper VIA!!',
1340
  10 => 'CAT!!',
1341
  11 => 'Candy TV',
1342
- 12 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
1343
- 13 => '(HW-|HUAWEI )?(CRO|LUA|CUN|SCC|SCU|CAM|LYO|MYA)!!',
1344
  14 => '(HW-|HUAWEI )?CAZ-(AL10|TL10|TL20)!',
1345
  15 => '(HW-|HUAWEI )?CAN-(L01|L11|L12)!',
1346
  16 => 'calgary',
@@ -1374,7 +1423,7 @@ DeviceModels::$ANDROID_INDEX = array (
1374
  11 => 'Cherry w500',
1375
  12 => 'CHUWI!!',
1376
  13 => 'CHONG!!',
1377
- 14 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
1378
  15 => '(HW-|HUAWEI )?(BLL|CHC|TAG|KII)!!',
1379
  16 => 'chagall',
1380
  17 => 'chiron',
@@ -1409,17 +1458,19 @@ DeviceModels::$ANDROID_INDEX = array (
1409
  4 => 'Clanga SE 097-1008',
1410
  5 => 'CLP281X',
1411
  6 => 'Click',
1412
- 7 => '(Intex )?Cloud!!',
1413
- 8 => 'CLIQ',
1414
- 9 => 'CLIQ XT',
1415
- 10 => 'CLIQ2',
 
1416
  ),
1417
  '@CM' =>
1418
  array (
1419
  0 => 'CMP!!',
1420
  1 => '(cm|aokp) tenderloin!',
1421
- 2 => 'CM980',
1422
- 3 => 'CM990',
 
1423
  ),
1424
  '@CN' =>
1425
  array (
@@ -1446,11 +1497,12 @@ DeviceModels::$ANDROID_INDEX = array (
1446
  15 => 'Connect-2G-2.0',
1447
  16 => '(Highscreen|Alpha|Bay|Boost|Cosmo|Explosion|Power|Prime|Zera)!!',
1448
  17 => 'Coquettish Red',
1449
- 18 => 'Comet',
1450
- 19 => 'Corvair',
1451
- 20 => 'COOLPIX S800c',
1452
- 21 => 'COOLPIX S810c',
1453
- 22 => 'Constellation V',
 
1454
  ),
1455
  '@CP' =>
1456
  array (
@@ -1459,13 +1511,32 @@ DeviceModels::$ANDROID_INDEX = array (
1459
  2 => 'CP8676!',
1460
  3 => 'CP8298!',
1461
  4 => 'CPN-(W09|AL00|L09)!',
1462
- 5 => 'CPH1605',
1463
- 6 => 'CPH1701',
1464
- 7 => 'CPH1717',
1465
- 8 => 'CPH1609',
1466
- 9 => 'CPH1613',
1467
- 10 => 'CPH1723',
1468
- 11 => 'CPH1611',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1469
  ),
1470
  '@CR' =>
1471
  array (
@@ -1473,8 +1544,8 @@ DeviceModels::$ANDROID_INDEX = array (
1473
  1 => 'CRESTA.CTP888',
1474
  2 => 'Cross!!',
1475
  3 => 'Crosscall!!',
1476
- 4 => '(HUAWEI )?(ALP|BLA|CRR|LON|MATE|MHA|MT1|MT2|MT7|M200|NXT|Z100)!!',
1477
- 5 => '(HW-|HUAWEI )?(CRO|LUA|CUN|SCC|SCU|CAM|LYO|MYA)!!',
1478
  6 => 'CRONO 22',
1479
  7 => 'Crescent',
1480
  ),
@@ -1507,7 +1578,7 @@ DeviceModels::$ANDROID_INDEX = array (
1507
  0 => 'CUBOT!!',
1508
  1 => '(CUBE ?)?(K8|U1|U2|U3|U5|U6|U8|U9)[0-9]?GT!!',
1509
  2 => 'CUBE!!',
1510
- 3 => '(HW-|HUAWEI )?(CRO|LUA|CUN|SCC|SCU|CAM|LYO|MYA)!!',
1511
  ),
1512
  '@CW' =>
1513
  array (
@@ -1546,7 +1617,7 @@ DeviceModels::$ANDROID_INDEX = array (
1546
  '@D2' =>
1547
  array (
1548
  0 => 'D2-[0-9]{3,3}!!',
1549
- 1 => '(HW-|HUAWEI )?(ALE|D2|DAV|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|VIE|VKY|VNS|VTR|WAS)!!',
1550
  ),
1551
  '@D5' =>
1552
  array (
@@ -1579,7 +1650,7 @@ DeviceModels::$ANDROID_INDEX = array (
1579
  1 => '(BLU|DASH|LIFE|NEO|STUDIO|VIVO)!!',
1580
  2 => 'Dakele A380',
1581
  3 => 'DAKELE MC001',
1582
- 4 => '(HW-|HUAWEI )?(ALE|D2|DAV|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|VIE|VKY|VNS|VTR|WAS)!!',
1583
  5 => 'DATAM803HC',
1584
  6 => 'DATAM805HC',
1585
  7 => 'DATAM819HD!',
@@ -1662,17 +1733,21 @@ DeviceModels::$ANDROID_INDEX = array (
1662
  1 => 'DL8006',
1663
  2 => 'DLX',
1664
  3 => 'DLXU',
1665
- 4 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
1666
  5 => 'dL1',
1667
  ),
1668
  '@DM' =>
1669
  array (
1670
  0 => 'DM0[0-9]{2,2}(K|SH)!!',
1671
- 1 => 'DM-01G',
1672
- 2 => 'DM-02H',
1673
- 3 => 'DMC-CM1',
1674
- 4 => 'DM-01H',
1675
- 5 => 'DM-01J',
 
 
 
 
1676
  ),
1677
  '@DN' =>
1678
  array (
@@ -1708,37 +1783,38 @@ DeviceModels::$ANDROID_INDEX = array (
1708
  0 => 'Dream',
1709
  1 => '(GIO-)?(GiONEE[- ])?Dream D1!',
1710
  2 => 'Droid Incredible',
1711
- 3 => 'DroniX-0.5',
1712
- 4 => 'Droid',
1713
- 5 => 'DROID',
1714
- 6 => 'DROID ?2!',
1715
- 7 => 'DROID ?3!',
1716
- 8 => 'DROID ?4!',
1717
- 9 => 'DroidPro',
1718
- 10 => 'DROID Pro',
1719
- 11 => 'DROID HD',
1720
- 12 => 'DROID BIONIC!',
1721
- 13 => 'DROID RAZR HD!',
1722
- 14 => 'DROID ?RAZR!',
1723
- 15 => 'DROID SPYDER',
1724
- 16 => 'DROID ?X2!',
1725
- 17 => 'DROID ?X!',
1726
- 18 => 'DROIDZ Duo',
1727
- 19 => 'DROIDZ Active 3G',
1728
- 20 => 'DROIDZ ATOM S',
1729
- 21 => 'DROIDZ Beat TV',
1730
- 22 => 'DROIDZ Drive+',
1731
- 23 => 'DROIDZ Excel',
1732
- 24 => 'DROIDZ Excite',
1733
- 25 => 'DROIDZ Force',
1734
- 26 => 'DROIDZ Match TV',
1735
- 27 => 'DROIDZ Mini Q',
1736
- 28 => 'DROIDZ Portal X',
1737
- 29 => 'DROIDZ Quad',
1738
- 30 => 'DROIDZ Race',
1739
- 31 => 'DROIDZ Race X',
1740
- 32 => 'DROIDZ Sport',
1741
- 33 => 'DROIDZ Ultimate',
 
1742
  ),
1743
  '@DS' =>
1744
  array (
@@ -1751,7 +1827,7 @@ DeviceModels::$ANDROID_INDEX = array (
1751
  ),
1752
  '@DU' =>
1753
  array (
1754
- 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
1755
  ),
1756
  '@DW' =>
1757
  array (
@@ -1874,7 +1950,7 @@ DeviceModels::$ANDROID_INDEX = array (
1874
  array (
1875
  0 => '(bq|Aquaris|Edison|Maxwell)!!',
1876
  1 => 'edgejr',
1877
- 2 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
1878
  3 => 'edenTAB ET-701',
1879
  ),
1880
  '@EE' =>
@@ -1910,38 +1986,40 @@ DeviceModels::$ANDROID_INDEX = array (
1910
  4 => 'ELIFE-E3',
1911
  5 => 'Elife E5',
1912
  6 => 'ElifeE6',
1913
- 7 => 'Elektra L',
1914
- 8 => 'Elektra XL',
1915
- 9 => 'Electrify',
1916
- 10 => 'Eluga A2',
1917
- 11 => 'ELUGA A3',
1918
- 12 => 'ELUGA A3 Pro',
1919
- 13 => 'ELUGA I2',
1920
- 14 => 'ELUGA I2 Activ',
1921
- 15 => 'ELUGA I4',
1922
- 16 => 'Eluga Arc 2',
1923
- 17 => 'Eluga Mark 2',
1924
- 18 => 'ELUGA Note',
1925
- 19 => 'ELUGA Prim',
1926
- 20 => 'ELUGA Pulse X',
1927
- 21 => 'ELUGA Ray',
1928
- 22 => 'ELUGA Ray Max',
1929
- 23 => 'ELUGA Ray X',
1930
- 24 => 'Eluga Ray 700',
1931
- 25 => 'ELUGA Turbo',
1932
- 26 => 'Elite',
1933
- 27 => 'Elite 11',
1934
- 28 => '(SENCOR )?ELEMENT!!',
1935
- 29 => 'Elite 5.5L+',
1936
- 30 => 'Elite 6.0L',
 
1937
  ),
1938
  '@EM' =>
1939
  array (
1940
  0 => 'EMBT3C',
1941
  1 => 'EM63',
1942
  2 => 'EM01F',
1943
- 3 => 'eMAX mini',
1944
- 4 => 'EMR1879',
 
1945
  ),
1946
  '@EN' =>
1947
  array (
@@ -2002,10 +2080,11 @@ DeviceModels::$ANDROID_INDEX = array (
2002
  8 => 'EVO ?3D!',
2003
  9 => 'EVO 4G',
2004
  10 => 'Evo V 4G',
2005
- 11 => '(HW-|HUAWEI )?(ALE|D2|DAV|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|VIE|VKY|VNS|VTR|WAS)!!',
2006
- 12 => '(EV|KM)-[ES][0-9]{3,3}!!',
2007
- 13 => 'Event',
2008
- 14 => 'EVERY35',
 
2009
  ),
2010
  '@EX' =>
2011
  array (
@@ -2081,7 +2160,7 @@ DeviceModels::$ANDROID_INDEX = array (
2081
  array (
2082
  0 => 'FIH-FB0',
2083
  1 => 'FIH-!!',
2084
- 2 => '(HW-|HUAWEI )?(ALE|D2|DAV|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|VIE|VKY|VNS|VTR|WAS)!!',
2085
  3 => 'Find 5',
2086
  4 => 'FIND7',
2087
  ),
@@ -2120,14 +2199,15 @@ DeviceModels::$ANDROID_INDEX = array (
2120
  25 => 'Flylife!!',
2121
  26 => 'Fly Flylife Web 7.85 Slim',
2122
  27 => 'Flyer',
2123
- 28 => 'Flair E1',
2124
- 29 => 'Flair E2',
2125
- 30 => 'FlairE3',
2126
- 31 => 'Flair P1',
2127
- 32 => 'Flair P1i',
2128
- 33 => 'Flair P8',
2129
- 34 => 'Flair S1',
2130
- 35 => 'Flair Z1',
 
2131
  ),
2132
  '@FN' =>
2133
  array (
@@ -2165,7 +2245,7 @@ DeviceModels::$ANDROID_INDEX = array (
2165
  '@FR' =>
2166
  array (
2167
  0 => 'Freelander I20',
2168
- 1 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
2169
  2 => '(MODECOM )?FreeTAB!!',
2170
  ),
2171
  '@FS' =>
@@ -2173,6 +2253,7 @@ DeviceModels::$ANDROID_INDEX = array (
2173
  0 => 'FS403',
2174
  1 => 'FS407',
2175
  2 => 'FS451',
 
2176
  ),
2177
  '@FT' =>
2178
  array (
@@ -2197,7 +2278,8 @@ DeviceModels::$ANDROID_INDEX = array (
2197
  1 => 'FZ-A2A',
2198
  2 => 'FZ-B2(B|D)!',
2199
  3 => 'FZ-N1',
2200
- 4 => 'FZ-X1',
 
2201
  ),
2202
  '@G ' =>
2203
  array (
@@ -2244,11 +2326,11 @@ DeviceModels::$ANDROID_INDEX = array (
2244
  ),
2245
  '@G6' =>
2246
  array (
2247
- 0 => '(HW-|HUAWEI )?(ALE|D2|DAV|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|VIE|VKY|VNS|VTR|WAS)!!',
2248
  ),
2249
  '@G7' =>
2250
  array (
2251
- 0 => '(HW-|HUAWEI )?(ALE|D2|DAV|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|VIE|VKY|VNS|VTR|WAS)!!',
2252
  ),
2253
  '@G9' =>
2254
  array (
@@ -2415,18 +2497,21 @@ DeviceModels::$ANDROID_INDEX = array (
2415
  ),
2416
  '@GM' =>
2417
  array (
2418
- 0 => 'Gm Discovery',
2419
- 1 => 'GM Discovery II',
2420
- 2 => 'GM Discovery II+',
2421
- 3 => 'GM FOX',
2422
- 4 => 'GM Ultimate Slim',
2423
- 5 => 'GM 5',
2424
- 6 => 'GM 5 d',
2425
- 7 => 'GM 5 Plus',
2426
- 8 => 'GM 5 Plus d',
2427
- 9 => 'GM 6',
2428
- 10 => 'GM 6 d',
2429
- 11 => 'GM Discovery tab 8',
 
 
 
2430
  ),
2431
  '@GN' =>
2432
  array (
@@ -2502,23 +2587,22 @@ DeviceModels::$ANDROID_INDEX = array (
2502
  10 => '(Google )?Nexus ?9!',
2503
  11 => '(Google )?Nexus ?10!',
2504
  12 => 'Google Pixel',
2505
- 13 => 'Google Pixel XL',
2506
- 14 => 'Google Pixel 2',
2507
- 15 => 'Google Pixel 2XL',
2508
- 16 => 'Google Chromebook Pixel (2015)',
2509
- 17 => 'google cube',
2510
- 18 => 'GOCL!!',
2511
- 19 => 'GO Live!!',
2512
- 20 => 'GOOPHONE!!',
2513
- 21 => 'GO !!',
2514
- 22 => 'GOA',
2515
- 23 => 'GO504',
2516
- 24 => 'GO778',
2517
- 25 => 'GO960',
2518
- 26 => 'GO963',
2519
- 27 => 'GO980',
2520
- 28 => 'GO984',
2521
- 29 => 'Gomobile GO1001',
2522
  ),
2523
  '@GP' =>
2524
  array (
@@ -2536,7 +2620,7 @@ DeviceModels::$ANDROID_INDEX = array (
2536
  array (
2537
  0 => 'Grouper',
2538
  1 => 'GR-TB!!',
2539
- 2 => '(HW-|HUAWEI )?(ALE|D2|DAV|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|VIE|VKY|VNS|VTR|WAS)!!',
2540
  3 => 'greenridge',
2541
  4 => 'Graphos A10',
2542
  5 => '(ZTE )?(Grand|Mimosa)!!',
@@ -2598,11 +2682,11 @@ DeviceModels::$ANDROID_INDEX = array (
2598
  ),
2599
  '@H3' =>
2600
  array (
2601
- 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
2602
  ),
2603
  '@H6' =>
2604
  array (
2605
- 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
2606
  ),
2607
  '@H7' =>
2608
  array (
@@ -2610,6 +2694,7 @@ DeviceModels::$ANDROID_INDEX = array (
2610
  1 => 'H7100',
2611
  2 => 'H7500+',
2612
  3 => 'H710VL',
 
2613
  ),
2614
  '@H8' =>
2615
  array (
@@ -2647,6 +2732,9 @@ DeviceModels::$ANDROID_INDEX = array (
2647
  0 => 'HD2',
2648
  1 => 'HD2 LEO',
2649
  2 => 'HD7 Pro',
 
 
 
2650
  ),
2651
  '@HE' =>
2652
  array (
@@ -2682,23 +2770,25 @@ DeviceModels::$ANDROID_INDEX = array (
2682
  '@HL' =>
2683
  array (
2684
  0 => 'HLV-T!!',
 
2685
  ),
2686
  '@HM' =>
2687
  array (
2688
- 0 => 'HMP8100 ATV 93',
2689
- 1 => 'HMP8100 ATV INT',
2690
- 2 => '(Xiaomi )?(Redmi|RedRice|HM)!!',
2691
- 3 => '(Xiaomi )?(Redmi|HM)[ \\-]?Note!!',
2692
- 4 => '(Xiaomi |HM)?20!!',
 
2693
  ),
2694
  '@HN' =>
2695
  array (
2696
- 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
2697
  ),
2698
  '@HO' =>
2699
  array (
2700
  0 => 'HOSIN!!',
2701
- 1 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
2702
  2 => 'Honor3c2G-T',
2703
  3 => 'Honor Bee',
2704
  4 => 'HOMESYNCT2WIFI',
@@ -2755,49 +2845,59 @@ DeviceModels::$ANDROID_INDEX = array (
2755
  6 => 'Huawei MediaPad T1 10 4G',
2756
  7 => '(Huawei )?[MSTX](1|2|7|8|10)\\-[A-Z0-9][0-9]{2,2}!!',
2757
  8 => 'HUAWEI GEM-703L',
2758
- 9 => '(HUAWEI )?(ALP|BLA|CRR|LON|MATE|MHA|MT1|MT2|MT7|M200|NXT|Z100)!!',
2759
- 10 => '(HW-|HUAWEI )?(TIT|TAG|NCE|TRT|SLA)!!',
2760
- 11 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
2761
  12 => '(HW-|HUAWEI )?(BLL|CHC|TAG|KII)!!',
2762
- 13 => '(HW-|HUAWEI )?(ALE|D2|DAV|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|VIE|VKY|VNS|VTR|WAS)!!',
2763
  14 => 'HUAWEI A168-(AL10|DL09|L09|L29)!',
2764
- 15 => '(HW-|HUAWEI )?(CRO|LUA|CUN|SCC|SCU|CAM|LYO|MYA)!!',
2765
  16 => '(HW-|HUAWEI )?CAZ-(AL10|TL10|TL20)!',
2766
  17 => '(HW-|HUAWEI )?CAN-(L01|L11|L12)!',
2767
  18 => '(HW-|HUAWEI )?MLA-(L01|L03|L11|L12|L13)!',
2768
  19 => '(HW-|HUAWEI )?DIG-(AL00|L01|L03|L21|TL10)!',
2769
- 20 => '(HW-|HUAWEI )?BAC-(AL00|L03|L21|L22)!',
2770
- 21 => '(HW-|HUAWEI )?MLA-(AL00|AL10)!',
2771
- 22 => '(HW-|HUAWEI )?MLA-(TL00|TL10|UL00)!',
2772
- 23 => 'Huawei P7 mini',
2773
- 24 => 'Huawei P8max',
2774
- 25 => '(Huawei|Ascend|HW-)!!',
2775
- 26 => 'HUAWEI Honor 3c w',
2776
- 27 => 'Huawei S7',
2777
- 28 => 'Hudl HT7S3',
2778
- 29 => 'Hudl 2',
2779
- 30 => 'HUAWEI U8686',
2780
- 31 => 'Huawei 858',
 
 
 
 
2781
  ),
2782
  '@HW' =>
2783
  array (
2784
- 0 => '(HW-|HUAWEI )?(TIT|TAG|NCE|TRT|SLA)!!',
2785
- 1 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
2786
  2 => '(HW-|HUAWEI )?(BLL|CHC|TAG|KII)!!',
2787
- 3 => '(HW-|HUAWEI )?(ALE|D2|DAV|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|VIE|VKY|VNS|VTR|WAS)!!',
2788
- 4 => '(HW-|HUAWEI )?(CRO|LUA|CUN|SCC|SCU|CAM|LYO|MYA)!!',
2789
  5 => '(HW-|HUAWEI )?CAZ-(AL10|TL10|TL20)!',
2790
  6 => '(HW-|HUAWEI )?CAN-(L01|L11|L12)!',
2791
  7 => '(HW-|HUAWEI )?MLA-(L01|L03|L11|L12|L13)!',
2792
  8 => '(HW-|HUAWEI )?DIG-(AL00|L01|L03|L21|TL10)!',
2793
- 9 => '(HW-|HUAWEI )?BAC-(AL00|L03|L21|L22)!',
2794
- 10 => '(HW-|HUAWEI )?MLA-(AL00|AL10)!',
2795
- 11 => '(HW-|HUAWEI )?MLA-(TL00|TL10|UL00)!',
2796
- 12 => '(Huawei|Ascend|HW-)!!',
2797
- 13 => 'hwu8812D',
2798
- 14 => 'HW-01E',
2799
- 15 => 'HW-03E',
2800
- 16 => 'HWT31',
 
 
 
 
 
 
2801
  ),
2802
  '@HY' =>
2803
  array (
@@ -2921,22 +3021,23 @@ DeviceModels::$ANDROID_INDEX = array (
2921
  7 => 'Incredible ?2!',
2922
  8 => 'Incredible 4G LTE',
2923
  9 => 'Inspire 4G',
2924
- 10 => 'INFOBAR!!',
2925
- 11 => 'Infinix!!',
2926
- 12 => 'IN[0-9]{3,3}!!',
2927
- 13 => 'Infocus!!',
2928
- 14 => 'INHON PAPILIO G1',
2929
- 15 => 'intki E86',
2930
- 16 => 'Innos!!',
2931
- 17 => '(Intex )?Aqua!!',
2932
- 18 => '(Intex )?Cloud!!',
2933
- 19 => 'INTEX IRIS-II',
2934
- 20 => 'INQ Cloud Touch',
2935
- 21 => 'INQ Mayfair (EU)',
2936
- 22 => '(iNote|itel)!!',
2937
- 23 => 'Infinity',
2938
- 24 => 'Internet TV',
2939
- 25 => 'Internet TV Box',
 
2940
  ),
2941
  '@IO' =>
2942
  array (
@@ -3018,6 +3119,8 @@ DeviceModels::$ANDROID_INDEX = array (
3018
  '@JD' =>
3019
  array (
3020
  0 => 'JDN-W09',
 
 
3021
  ),
3022
  '@JI' =>
3023
  array (
@@ -3028,12 +3131,24 @@ DeviceModels::$ANDROID_INDEX = array (
3028
  array (
3029
  0 => 'JJ5S+',
3030
  ),
 
 
 
 
 
 
 
 
3031
  '@JO' =>
3032
  array (
3033
  0 => 'Jolla',
3034
  1 => 'Joy',
3035
  2 => 'JOIN',
3036
  ),
 
 
 
 
3037
  '@JT' =>
3038
  array (
3039
  0 => 'JT SmartPC02',
@@ -3152,11 +3267,13 @@ DeviceModels::$ANDROID_INDEX = array (
3152
  14 => 'KFGIWI',
3153
  15 => 'KFDOWI',
3154
  16 => 'KFSUWI',
 
 
3155
  ),
3156
  '@KI' =>
3157
  array (
3158
  0 => 'Kindle Fire',
3159
- 1 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
3160
  2 => '(HW-|HUAWEI )?(BLL|CHC|TAG|KII)!!',
3161
  3 => 'KIOTO 793',
3162
  4 => 'KITE',
@@ -3168,7 +3285,7 @@ DeviceModels::$ANDROID_INDEX = array (
3168
  ),
3169
  '@KN' =>
3170
  array (
3171
- 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
3172
  ),
3173
  '@KO' =>
3174
  array (
@@ -3267,7 +3384,7 @@ DeviceModels::$ANDROID_INDEX = array (
3267
  ),
3268
  '@LD' =>
3269
  array (
3270
- 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
3271
  1 => 'LDK-ICK v1.4',
3272
  ),
3273
  '@LE' =>
@@ -3407,80 +3524,123 @@ DeviceModels::$ANDROID_INDEX = array (
3407
  12 => 'LG-DS1203',
3408
  13 => 'LG-?E[0-9]{3,3}!!',
3409
  14 => 'LG-F[0-9]{3,3}!!',
3410
- 15 => 'LG-GT540!',
3411
- 16 => 'LG-GW620!',
3412
- 17 => 'LG-H[0-9]{3,3}!!',
3413
- 18 => 'LG-K[0-9]{3,3}!!',
3414
- 19 => 'LG-KH5200',
3415
- 20 => 'LG-KS1024',
3416
- 21 => 'LG-KU[0-9]{4,4}!!',
3417
- 22 => 'LG-?L[0-9]{2,3}[A-Z]!!',
3418
- 23 => 'LG-LG[0-9]{3,3}!!',
3419
- 24 => 'LGLK430',
3420
- 25 => 'LG-LK460',
3421
- 26 => 'LG-?LS[0-9]{3,3}!!',
3422
- 27 => 'LG-LU[0-9]{4,4}!!',
3423
- 28 => 'LG-LW690',
3424
- 29 => 'LG-LW770',
3425
- 30 => 'LG-M[0-9]{3,3}!!',
3426
- 31 => 'LG-?MS[0-9]{3,3}!!',
3427
- 32 => 'LGMP260',
3428
- 33 => 'LG-P[0-9]{3,3}!!',
3429
- 34 => 'LG-SU[0-9]{3,3}!!',
3430
- 35 => 'LG-T480!',
3431
- 36 => 'LG-T540!',
3432
- 37 => 'LG-TP260',
3433
- 38 => 'LG-TP450',
3434
- 39 => 'LG-SU-760',
3435
- 40 => 'LGUK410',
3436
- 41 => 'LG-UK495',
3437
- 42 => 'LGUK750',
3438
- 43 => 'LGUK932',
3439
- 44 => 'LG-UN350',
3440
- 45 => 'LG-?US[0-9]{3,3}!!',
3441
- 46 => 'LG-V[0-9]{3,3}!!',
3442
- 47 => 'LG-VK[0-9]{3,3}!!',
3443
- 48 => 'LG-VN[0-9]{3,3}!!',
3444
- 49 => 'LG-VM[0-9]{3,3}!!',
3445
- 50 => 'LG-VS[0-9]{3,3}!!',
3446
- 51 => 'LG-X[0-9]{3,3}!!',
3447
- 52 => 'LGM-[GKVX][0-9]{3,3}!!',
3448
- 53 => 'lge-F160!',
3449
- 54 => 'LGE-E988!',
3450
- 55 => 'lgp-970',
3451
- 56 => 'LG[LSTV][0-9]{2,2}!!',
3452
- 57 => 'LG!!',
3453
- 58 => 'LG-Google TV!!',
3454
- 59 => 'LG-ANDROID MINI BOX',
3455
- 60 => 'LG-P999',
3456
- 61 => 'LG-E739',
3457
- 62 => 'LG-C800',
 
 
 
 
 
3458
  ),
3459
  '@LI' =>
3460
  array (
3461
  0 => 'Liquid!!',
3462
  1 => '(BLU|DASH|LIFE|NEO|STUDIO|VIVO)!!',
3463
  2 => 'Liberty',
3464
- 3 => '(MEDION|(MD )?LIFETAB)!!',
3465
- 4 => 'Life',
3466
- 5 => 'Liberty Tab G100',
3467
- 6 => 'Live ?With ?Walkman!',
3468
- 7 => 'libra',
3469
- 8 => 'lithium',
3470
- 9 => 'Light Tab',
3471
- 10 => 'Light Tab 2',
3472
- 11 => 'Light Tab 2W',
 
3473
  ),
3474
  '@LL' =>
3475
  array (
3476
- 0 => '(Lanix )?(Ilium|llium)!!',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3477
  ),
3478
  '@LO' =>
3479
  array (
3480
  0 => 'LogicPD Zoom2',
3481
- 1 => '(HUAWEI )?(ALP|BLA|CRR|LON|MATE|MHA|MT1|MT2|MT7|M200|NXT|Z100)!!',
3482
  2 => 'Loox',
3483
  ),
 
 
 
 
3484
  '@LS' =>
3485
  array (
3486
  0 => 'LS670',
@@ -3535,7 +3695,7 @@ DeviceModels::$ANDROID_INDEX = array (
3535
  1 => 'LUXURY 3',
3536
  2 => 'LUXURY 4',
3537
  3 => 'LUXURY 5',
3538
- 4 => '(HW-|HUAWEI )?(CRO|LUA|CUN|SCC|SCU|CAM|LYO|MYA)!!',
3539
  5 => 'Lucky Ultra Sonic U8650',
3540
  6 => 'LU2300',
3541
  7 => 'Lumia800',
@@ -3551,9 +3711,10 @@ DeviceModels::$ANDROID_INDEX = array (
3551
  ),
3552
  '@LY' =>
3553
  array (
3554
- 0 => '(HW-|HUAWEI )?(CRO|LUA|CUN|SCC|SCU|CAM|LYO|MYA)!!',
3555
- 1 => 'LYF LS-4006',
3556
- 2 => 'LYF LS-5009',
 
3557
  ),
3558
  '@M' =>
3559
  array (
@@ -3584,7 +3745,7 @@ DeviceModels::$ANDROID_INDEX = array (
3584
  '@M1' =>
3585
  array (
3586
  0 => 'M19',
3587
- 1 => '(HW-|HUAWEI )?(ALE|D2|DAV|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|VIE|VKY|VNS|VTR|WAS)!!',
3588
  2 => 'M1050S',
3589
  3 => 'M1',
3590
  4 => 'm1 metal',
@@ -3594,7 +3755,7 @@ DeviceModels::$ANDROID_INDEX = array (
3594
  ),
3595
  '@M2' =>
3596
  array (
3597
- 0 => '(HUAWEI )?(ALP|BLA|CRR|LON|MATE|MHA|MT1|MT2|MT7|M200|NXT|Z100)!!',
3598
  1 => 'M210',
3599
  2 => 'm2 note',
3600
  3 => 'm2',
@@ -3682,18 +3843,20 @@ DeviceModels::$ANDROID_INDEX = array (
3682
  2 => 'manta',
3683
  3 => '(bq|Aquaris|Edison|Maxwell)!!',
3684
  4 => '(DNS )?(Airtab )?(E|ES|M|MA|MC|MF|MW|P|PC|PF)[0-9]{2,4}!!',
3685
- 5 => '(HUAWEI )?(ALP|BLA|CRR|LON|MATE|MHA|MT1|MT2|MT7|M200|NXT|Z100)!!',
3686
- 6 => 'MAX FIND 5.0',
3687
- 7 => 'Malata!!',
3688
- 8 => 'Masstel!!',
3689
- 9 => 'MASTONE!!',
3690
- 10 => 'Maxtron!!',
3691
- 11 => 'magi',
3692
- 12 => 'MagicBox',
3693
- 13 => '(Xiaomi )?(MI )?MAX$!',
3694
- 14 => '(Xiaomi )?(MI )?MAX 2$!',
3695
- 15 => 'markf',
3696
- 16 => 'markw',
 
 
3697
  ),
3698
  '@MB' =>
3699
  array (
@@ -3738,22 +3901,24 @@ DeviceModels::$ANDROID_INDEX = array (
3738
  16 => 'Mediacom 810C',
3739
  17 => '(MEDION|(MD )?LIFETAB)!!',
3740
  18 => 'MEEG!!',
3741
- 19 => 'meizu m1note',
3742
- 20 => 'MEIZU M5',
3743
- 21 => 'MEIZU M9',
3744
- 22 => 'MEIZU MX',
3745
- 23 => '(MEO )?Smart A!!',
3746
- 24 => 'MEU AN!!',
3747
- 25 => 'ME[0-9]{3,3}!!',
3748
- 26 => 'MEM02',
3749
- 27 => 'MegaFon SP-AI',
3750
- 28 => 'MegaFon SP-A3',
3751
- 29 => 'MegaFon SP-A5',
3752
- 30 => 'MegaFon SP-A10',
3753
- 31 => 'MegaFon V9',
3754
- 32 => 'MegaFon V9+',
3755
- 33 => 'MegaFon SIM+',
3756
- 34 => 'MegaFon Login 3',
 
 
3757
  ),
3758
  '@MF' =>
3759
  array (
@@ -3765,7 +3930,7 @@ DeviceModels::$ANDROID_INDEX = array (
3765
  '@MH' =>
3766
  array (
3767
  0 => 'MH350',
3768
- 1 => '(HUAWEI )?(ALP|BLA|CRR|LON|MATE|MHA|MT1|MT2|MT7|M200|NXT|Z100)!!',
3769
  ),
3770
  '@MI' =>
3771
  array (
@@ -3805,16 +3970,25 @@ DeviceModels::$ANDROID_INDEX = array (
3805
  33 => '(CSL[- ])?(Spice[- ]?)?Mi(-| )?[0-9]{3,3}!!',
3806
  34 => 'miTab!!',
3807
  35 => '(Xiaomi )?(Xiaomi|Xiaomi M|MI)!!',
3808
- 36 => '(Xiaomi|Xiaomi Mi|MI) Note!!',
3809
- 37 => '(Xiaomi )?(MI )?MAX$!',
3810
- 38 => '(Xiaomi )?(MI )?MAX 2$!',
3811
- 39 => '(Xiaomi )?(MI )?MIX$!',
3812
- 40 => '(Xiaomi )?(MI )?MIX 2$!',
3813
- 41 => 'mido',
3814
- 42 => '(Xiaomi|Xiaomi Mi|MI) Pad!!',
3815
- 43 => '(Xiaomi|Xiaomi Mi|MI)Box!!',
3816
- 44 => '(Xiaomi|Xiaomi Mi|MI)TV!!',
3817
- 45 => '(ZTE )?(Grand|Mimosa)!!',
 
 
 
 
 
 
 
 
 
3818
  ),
3819
  '@MK' =>
3820
  array (
@@ -3857,46 +4031,80 @@ DeviceModels::$ANDROID_INDEX = array (
3857
  13 => 'MOGU!!',
3858
  14 => 'moii!!',
3859
  15 => 'MORAL N01',
3860
- 16 => 'Moto Droid',
3861
- 17 => 'Motorola Pro XT610',
3862
- 18 => 'Motorola Milestone MAXX',
3863
- 19 => 'Motorola Backflip Me600',
3864
- 20 => 'Moto ME860',
3865
- 21 => 'Moto C',
3866
- 22 => 'Moto C Plus',
3867
- 23 => '(Moto)?E2$!',
3868
- 24 => '(Moto)?E2\\(4G-LTE\\)$!',
3869
- 25 => 'Motorola MotoE2!',
3870
- 26 => 'Moto E (4)',
3871
- 27 => 'Moto E (4) Plus',
3872
- 28 => '(Moto)?G3$!',
3873
- 29 => '(Moto)?G3-TE$!',
3874
- 30 => 'MOTOROLA MOTOG',
3875
- 31 => 'Moto G Play',
3876
- 32 => 'Moto G4',
3877
- 33 => 'Moto G (4)',
3878
- 34 => 'Moto G4 Plus',
3879
- 35 => 'Moto G (5)',
3880
- 36 => 'Moto G (5) Plus',
3881
- 37 => 'Moto G (5S) Plus',
3882
- 38 => 'Moto Z (2)',
3883
- 39 => 'Moto Z2 Play',
3884
- 40 => 'Moto X Pro',
3885
- 41 => 'Moto Backflip',
3886
- 42 => 'MOTOROLA XOOM MZ606',
3887
- 43 => 'MOTOROLA RAZR',
3888
- 44 => 'MOTWX435KT',
3889
- 45 => '(PLOYER-)?MOMO!!',
3890
- 46 => 'MOB-5045',
3891
- 47 => 'Mobii 7',
3892
- 48 => 'MoFing',
3893
- 49 => 'mocha',
3894
- 50 => 'MO-01J',
3895
- 51 => 'Movistar Express',
3896
- 52 => 'Movistar Link',
3897
- 53 => 'Movistar Motion',
3898
- 54 => 'Movistar Prime',
3899
- 55 => 'MOVE',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3900
  ),
3901
  '@MP' =>
3902
  array (
@@ -3920,6 +4128,10 @@ DeviceModels::$ANDROID_INDEX = array (
3920
  17 => 'MPQC804HD',
3921
  18 => 'MPQC1010',
3922
  ),
 
 
 
 
3923
  '@MS' =>
3924
  array (
3925
  0 => 'MStar Amber3',
@@ -3976,7 +4188,7 @@ DeviceModels::$ANDROID_INDEX = array (
3976
  28 => 'mt8580!',
3977
  29 => 'mt8658!',
3978
  30 => '(AC|BC|LC|MT|RC|QS|VM|TS|OC)[0-9]{4,4}[A-Z]!!',
3979
- 31 => '(HUAWEI )?(ALP|BLA|CRR|LON|MATE|MHA|MT1|MT2|MT7|M200|NXT|Z100)!!',
3980
  32 => 'MTC Android',
3981
  33 => 'MT791',
3982
  34 => 'MT70[0-9]{2,2}!!',
@@ -4030,7 +4242,7 @@ DeviceModels::$ANDROID_INDEX = array (
4030
  ),
4031
  '@MY' =>
4032
  array (
4033
- 0 => '(HW-|HUAWEI )?(CRO|LUA|CUN|SCC|SCU|CAM|LYO|MYA)!!',
4034
  1 => 'MyPhone A818g Duo',
4035
  2 => 'MyPhone A818 Slim Duo',
4036
  3 => 'MyPhone A848 Duo',
@@ -4095,9 +4307,12 @@ DeviceModels::$ANDROID_INDEX = array (
4095
  0 => 'MZ-m2 note',
4096
  1 => 'MZ-M571C',
4097
  2 => 'MZ-m3 note',
4098
- 3 => 'MZ-MX4',
4099
- 4 => 'MZ-MX4 Pro',
4100
- 5 => 'MZ[0-9]{3,3}!!',
 
 
 
4101
  ),
4102
  '@N-' =>
4103
  array (
@@ -4184,7 +4399,7 @@ DeviceModels::$ANDROID_INDEX = array (
4184
  ),
4185
  '@NC' =>
4186
  array (
4187
- 0 => '(HW-|HUAWEI )?(TIT|TAG|NCE|TRT|SLA)!!',
4188
  ),
4189
  '@NE' =>
4190
  array (
@@ -4221,7 +4436,7 @@ DeviceModels::$ANDROID_INDEX = array (
4221
  30 => '(BLU|DASH|LIFE|NEO|STUDIO|VIVO)!!',
4222
  31 => 'NexusHD2',
4223
  32 => 'Nexus HD2',
4224
- 33 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
4225
  34 => 'Neon7',
4226
  35 => 'Neon9',
4227
  36 => '(NetTab|NT-)!!',
@@ -4312,7 +4527,7 @@ DeviceModels::$ANDROID_INDEX = array (
4312
  ),
4313
  '@NM' =>
4314
  array (
4315
- 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
4316
  1 => '(NMP|MBR|XDK|XDS|XMP)\\-!!',
4317
  ),
4318
  '@NO' =>
@@ -4362,31 +4577,52 @@ DeviceModels::$ANDROID_INDEX = array (
4362
  42 => '(NOOK )?BNTV250!',
4363
  43 => '(NOOK )?BNRV350!',
4364
  44 => '(NOOK )?BNTV(400)!',
4365
- 45 => '(NOOK )?BNTV(600)!',
4366
- 46 => '(NOOK )?BNTV(800)!',
4367
- 47 => 'Nook HD',
4368
- 48 => 'Nook HD+',
4369
- 49 => 'Novapad!!',
4370
- 50 => 'Nova!!',
4371
- 51 => 'Now',
4372
- 52 => 'NO1 S6',
4373
- 53 => 'NOAIN!!',
4374
- 54 => 'Nokia N9',
4375
- 55 => 'Nokia N900',
4376
- 56 => 'Nokia X',
4377
- 57 => 'Nokia X Dual SIM',
4378
- 58 => 'Nokia X+',
4379
- 59 => 'Nokia Xplus',
4380
- 60 => 'Nokia XL 4G',
4381
- 61 => 'Nokia XL',
4382
- 62 => 'Nokia XL Dual SIM',
4383
- 63 => 'Nokia X2',
4384
- 64 => 'NokiaX2DS',
4385
- 65 => 'Notion Ink ADAM',
4386
- 66 => 'Note III',
4387
- 67 => 'Nozomi',
4388
- 68 => 'Noble TAB07-485',
4389
- 69 => '(QMobile|QTab|Q-Smart|Noir)!!',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4390
  ),
4391
  '@NP' =>
4392
  array (
@@ -4420,7 +4656,7 @@ DeviceModels::$ANDROID_INDEX = array (
4420
  ),
4421
  '@NX' =>
4422
  array (
4423
- 0 => '(HUAWEI )?(ALP|BLA|CRR|LON|MATE|MHA|MT1|MT2|MT7|M200|NXT|Z100)!!',
4424
  1 => '(Nexian )?NX-A[0-9]{3,3}!!',
4425
  2 => 'NXA8QC116',
4426
  3 => 'NX16A8116K',
@@ -4454,8 +4690,12 @@ DeviceModels::$ANDROID_INDEX = array (
4454
  '@OB' =>
4455
  array (
4456
  0 => 'OB-OPPO A31c',
4457
- 1 => 'OB-OPPO 3005',
4458
- 2 => 'Obreey SURFpad',
 
 
 
 
4459
  ),
4460
  '@OC' =>
4461
  array (
@@ -4647,17 +4887,21 @@ DeviceModels::$ANDROID_INDEX = array (
4647
  137 => 'ONEPLUS A3010',
4648
  138 => 'ONEPLUS A5000',
4649
  139 => 'ONEPLUS A5010',
4650
- 140 => 'ONE E1000',
4651
- 141 => 'ONE E1001',
4652
- 142 => 'ONE E1003',
4653
- 143 => 'ONE E1005',
4654
- 144 => 'ONDA MID',
4655
- 145 => 'ONDA A9 Core4',
4656
- 146 => 'ONDA VI10',
4657
- 147 => 'Onda V812',
4658
- 148 => 'ONDA v975m',
4659
- 149 => 'ONDA V989',
4660
- 150 => 'ONDA V989 Core8',
 
 
 
 
4661
  ),
4662
  '@OP' =>
4663
  array (
@@ -4666,84 +4910,109 @@ DeviceModels::$ANDROID_INDEX = array (
4666
  2 => 'Opus One',
4667
  3 => 'OPS-DRD Digital Signage Player',
4668
  4 => 'OP110',
4669
- 5 => 'OPPO A30',
4670
- 6 => 'OPPO A31',
4671
- 7 => 'OPPO A31t',
4672
- 8 => 'OPPO A33',
4673
- 9 => 'OPPO A33m',
4674
- 10 => 'OPPO A37m',
4675
- 11 => 'OPPO A53',
4676
- 12 => 'OPPO A53m',
4677
- 13 => 'OPPO A57',
4678
- 14 => 'OPPO A57t',
4679
- 15 => 'OPPO A59m',
4680
- 16 => 'OPPO A59s',
4681
- 17 => 'OPPO A59st',
4682
- 18 => 'OPPO A77',
4683
- 19 => 'OPPO A77t',
4684
- 20 => 'OPPO A800',
4685
- 21 => 'OPPOX905',
4686
- 22 => 'OPPOX907',
4687
- 23 => 'OPPO Find5',
4688
- 24 => 'OPPOX909',
4689
- 25 => 'OPPO X909',
4690
- 26 => 'OPPOX9015',
4691
- 27 => 'OPPOX9017',
4692
- 28 => 'OPPO find7',
4693
- 29 => 'OPPOR601',
4694
- 30 => 'OPPOR801',
4695
- 31 => 'OPPOR803',
4696
- 32 => 'OPPOR805',
4697
- 33 => 'OPPOR807',
4698
- 34 => 'OPPO R811',
4699
- 35 => 'OPPO R813T',
4700
- 36 => 'OPPO R815',
4701
- 37 => 'OPPOR817',
4702
- 38 => 'Oppo R819',
4703
- 39 => 'OPPO R821',
4704
- 40 => 'OPPO R831',
4705
- 41 => 'Oppo R831 Limited Edition',
4706
- 42 => 'OPPO R1001',
4707
- 43 => 'OPPOR8015',
4708
- 44 => 'OPPOR8111',
4709
- 45 => 'OPPOT29',
4710
- 46 => '(OPPO-?)?T703!',
4711
- 47 => 'OPPOU701',
4712
- 48 => 'OPPOU7011',
4713
- 49 => 'OPPOU7015',
4714
- 50 => 'OPPO N1',
4715
- 51 => 'OPPO R7',
4716
- 52 => 'OPPO R7s',
4717
- 53 => 'OPPO R7sm',
4718
- 54 => 'OPPO R7st',
4719
- 55 => 'OPPO R7t',
4720
- 56 => 'OPPO R9m',
4721
- 57 => 'OPPO R9tm',
4722
- 58 => 'OPPO R9km',
4723
- 59 => 'OPPO R9s',
4724
- 60 => 'OPPO R9sk',
4725
- 61 => 'OPPO R9st',
4726
- 62 => 'OPPO R9t',
4727
- 63 => 'OPPO R11',
4728
- 64 => 'OPPO R11t',
4729
- 65 => 'OPPO R7 Plus',
4730
- 66 => 'OPPO R7sPlus',
4731
- 67 => 'OPPO R9 Plusm A',
4732
- 68 => 'OPPO R9 Plustm A',
4733
- 69 => 'OPPO R9s Plus',
4734
- 70 => 'OPPO R11 Plus',
4735
- 71 => 'OPPO R11 Plusk',
4736
- 72 => 'OPPO R11 Pluskt',
4737
- 73 => 'OPPO R11s Plus',
4738
- 74 => 'OPSSON!!',
4739
- 75 => 'OP0118-12',
4740
- 76 => 'Optimus Barcelona',
4741
- 77 => 'Optimus Boston',
4742
- 78 => 'Optimus Madrid',
4743
- 79 => 'Optimus Monte Carlo',
4744
- 80 => 'Optimus San Francisco',
4745
- 81 => 'Optimus San Remo',
4746
- 82 => 'Optimus Zali',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4747
  ),
4748
  '@OR' =>
4749
  array (
@@ -4795,6 +5064,10 @@ DeviceModels::$ANDROID_INDEX = array (
4795
  array (
4796
  0 => '(OV-|Overmax|Vertis)!!',
4797
  ),
 
 
 
 
4798
  '@OY' =>
4799
  array (
4800
  0 => 'Oysters Pacific 800',
@@ -4858,7 +5131,7 @@ DeviceModels::$ANDROID_INDEX = array (
4858
  array (
4859
  0 => 'P2A700',
4860
  1 => 'P2Lite',
4861
- 2 => '(HW-|HUAWEI )?(ALE|D2|DAV|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|VIE|VKY|VNS|VTR|WAS)!!',
4862
  ),
4863
  '@P3' =>
4864
  array (
@@ -4887,11 +5160,11 @@ DeviceModels::$ANDROID_INDEX = array (
4887
  2 => 'P6 Pro',
4888
  3 => 'P6 Qmax',
4889
  4 => 'P6 Quad',
4890
- 5 => '(HW-|HUAWEI )?(ALE|D2|DAV|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|VIE|VKY|VNS|VTR|WAS)!!',
4891
  ),
4892
  '@P7' =>
4893
  array (
4894
- 0 => '(HW-|HUAWEI )?(ALE|D2|DAV|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|VIE|VKY|VNS|VTR|WAS)!!',
4895
  1 => 'P700i',
4896
  2 => 'P701',
4897
  3 => 'P7',
@@ -4995,21 +5268,38 @@ DeviceModels::$ANDROID_INDEX = array (
4995
  15 => 'Patio100',
4996
  16 => 'Patio100 3G',
4997
  17 => 'PAD[0-9]{3,3}!!',
4998
- 18 => 'Panasonic!!',
4999
- 19 => 'pandigital9hr',
5000
- 20 => 'pandigital9hr2',
5001
- 21 => 'pandigitalopc1',
5002
- 22 => 'pandigitalopp1',
5003
- 23 => 'pandigitalp1hr',
5004
- 24 => 'PantechP!!',
5005
- 25 => 'PAT712W',
5006
- 26 => 'PATG7506HD',
5007
- 27 => 'PAP[0-9]{4,4}!!',
5008
- 28 => 'PAD1001',
 
 
 
 
 
 
 
 
 
5009
  ),
5010
  '@PB' =>
5011
  array (
5012
  0 => 'PB99400',
 
 
 
 
 
 
 
 
5013
  ),
5014
  '@PC' =>
5015
  array (
@@ -5017,11 +5307,16 @@ DeviceModels::$ANDROID_INDEX = array (
5017
  1 => '(DNS )?(Airtab )?(E|ES|M|MA|MC|MF|MW|P|PC|PF)[0-9]{2,4}!!',
5018
  2 => '(HTC|PCD|USCC)?ADR[0-9]{4,4}!!',
5019
  3 => 'PC36100!',
5020
- 4 => 'PC-TE307N1W',
5021
- 5 => 'PC-TE508BAW',
5022
- 6 => 'PC-TS508FAM',
5023
- 7 => 'PC-TS508T1W',
5024
- 8 => 'PC-TS708T1W',
 
 
 
 
 
5025
  ),
5026
  '@PD' =>
5027
  array (
@@ -5030,7 +5325,7 @@ DeviceModels::$ANDROID_INDEX = array (
5030
  ),
5031
  '@PE' =>
5032
  array (
5033
- 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
5034
  1 => 'PEDI',
5035
  2 => 'Penta!!',
5036
  3 => 'Pentagram!!',
@@ -5123,34 +5418,40 @@ DeviceModels::$ANDROID_INDEX = array (
5123
  3 => 'Pixel 2',
5124
  4 => 'Pixel 2XL',
5125
  5 => 'Pixel 2 XL',
5126
- 6 => '(Axioo[\\- ])?PICO!!',
5127
- 7 => 'picoBit-L',
5128
- 8 => '(GIO-)?(GiONEE[- ])?Pioneer P1!',
5129
- 9 => '(GIO-)?(GiONEE[- ])?Pioneer P2!',
5130
- 10 => '(GIO-)?(GiONEE[- ])?Pioneer P3!',
5131
- 11 => '(GIO-)?(GiONEE[- ])?Pioneer P4!',
5132
- 12 => 'PixelV1',
5133
- 13 => 'Pixel V2',
5134
- 14 => 'Pixel V2+',
5135
- 15 => 'PI2000',
5136
- 16 => 'PI2010',
5137
- 17 => 'PI2011',
5138
- 18 => 'PI3100',
5139
- 19 => 'PI3100-93',
5140
- 20 => 'PI3100Z3 93',
5141
- 21 => 'PI3105',
5142
- 22 => 'PI3106',
5143
- 23 => 'PI3110',
5144
- 24 => 'PI3205G',
5145
- 25 => 'PI3210G',
5146
- 26 => 'PI3900',
5147
- 27 => 'PI3900-93',
5148
- 28 => 'PI3910',
5149
- 29 => 'PI4010G',
5150
- 30 => 'PI7000',
5151
- 31 => 'PI7100 93',
5152
- 32 => '(PNR-)?Pioneer!!',
5153
- 33 => 'PIRANHA!!',
 
 
 
 
 
 
5154
  ),
5155
  '@PJ' =>
5156
  array (
@@ -5161,7 +5462,7 @@ DeviceModels::$ANDROID_INDEX = array (
5161
  array (
5162
  0 => 'PLE-701L',
5163
  1 => 'PLE-703L',
5164
- 2 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
5165
  3 => 'Planet II v2',
5166
  4 => 'PLANET',
5167
  5 => 'Playboy PB-S3',
@@ -5194,88 +5495,90 @@ DeviceModels::$ANDROID_INDEX = array (
5194
  '@PO' =>
5195
  array (
5196
  0 => '(Highscreen|Alpha|Bay|Boost|Cosmo|Explosion|Power|Prime|Zera)!!',
5197
- 1 => 'PocketBook A7',
5198
- 2 => 'PocketBook A10',
5199
- 3 => 'PocketBook A10 3G',
5200
- 4 => 'PocketBook SURFpad2',
5201
- 5 => 'PocketBook SURFpad 3 (7,85")',
5202
- 6 => 'PocketBook SURFpad 4 S',
5203
- 7 => 'PocketBook SURFpad 4 M',
5204
- 8 => 'PocketBook SURFpad 4 L',
5205
- 9 => 'POV-Mobii-7',
5206
- 10 => 'POV Mobii 7',
5207
- 11 => 'POV TAB-P506!',
5208
- 12 => 'POV TAB-P517!',
5209
- 13 => 'POV TAB-P527!',
5210
- 14 => 'POV TAB-P629!',
5211
- 15 => 'POV TAB-P701!',
5212
- 16 => 'POV TAB-P703!',
5213
- 17 => 'POV TAB-P720!',
5214
- 18 => 'POV TAB-P721A!',
5215
- 19 => 'POV TAB-P721!',
5216
- 20 => 'POV TAB-P722C!',
5217
- 21 => 'POV TAB-P731N!',
5218
- 22 => 'POV TAB-P825!',
5219
- 23 => 'POV TAB-P925!',
5220
- 24 => 'POV TAB-PR945!',
5221
- 25 => 'POV TAB-P1025!',
5222
- 26 => 'POV TAB-P1030!',
5223
- 27 => 'POV TAB-PI1045!',
5224
- 28 => 'POV TAB-P1325!',
5225
- 29 => '(POV )?TAB-PLAYTABPRO!',
5226
- 30 => '(POV )?TAB-PROTAB25!',
5227
- 31 => '(POV )?TAB-PROTAB26!',
5228
- 32 => 'POV TAB-PROTAB27',
5229
- 33 => '(POV )?TAB-PROTAB30!',
5230
- 34 => '(POV )?TAB-PROTAB2XXL(4)!',
5231
- 35 => '(POV )?TAB NAVI7 3G M!',
5232
- 36 => 'POV_TAB-NAVI7-3G-M',
5233
- 37 => 'POV TAB-P547(v1.0)',
5234
- 38 => 'POV TV-HDMI-200BT',
5235
- 39 => 'POV TV-HDMI-200BT(V2.0)',
5236
- 40 => 'POV TV-HDMI-210',
5237
- 41 => 'POV TV-HDMI-KB-01',
5238
- 42 => 'POV TV-SMARTTV-500',
5239
- 43 => 'Polaroid PSPT401',
5240
- 44 => 'Polaroid PSPC505',
5241
- 45 => 'Polaroid PSPC550',
5242
- 46 => 'Polaroid P4005A',
5243
- 47 => 'Polaroid P5005A',
5244
- 48 => 'Polaroid P5046A',
5245
- 49 => 'Polaroid P5525A',
5246
- 50 => 'Polaroid P5526A',
5247
- 51 => 'POLY ?PAD!!',
5248
- 52 => 'POLYTRON!!',
5249
- 53 => 'POMP!!',
5250
- 54 => 'Positivo Mini',
5251
- 55 => 'POSITIVO YPY 07FTB',
5252
- 56 => 'Positivo Ypy AB7E',
5253
- 57 => 'Positivo Ypy AB7EC',
5254
- 58 => 'Positivo Ypy AB7F',
5255
- 59 => 'Positivo AB7F',
5256
- 60 => 'Positivo Ypy AB7H',
5257
- 61 => 'Positivo Ypy AB10E',
5258
- 62 => 'Positivo Ypy AB10EC',
5259
- 63 => 'Positivo Ypy AB10H',
5260
- 64 => 'Positivo BGH Ypy L700',
5261
- 65 => 'Positivo Ypy L700',
5262
- 66 => 'Positivo Ypy L700 Ed. Especial',
5263
- 67 => 'Positivo Ypy L700+',
5264
- 68 => 'Positivo Ypy L700 Kids',
5265
- 69 => 'Positivo BGH Ypy L700 Kids',
5266
- 70 => 'Positivo Ypy L700+ Kids',
5267
- 71 => 'Positivo Ypy L1000',
5268
- 72 => 'Positivo Ypy L1000AB',
5269
- 73 => 'Positivo Ypy L1000F',
5270
- 74 => 'Positivo Ypy L1050',
5271
- 75 => 'Positivo Ypy L1050E',
5272
- 76 => 'Positivo Ypy L1050F',
5273
- 77 => 'Positivo S380',
5274
- 78 => 'Positivo S440',
5275
- 79 => 'Positivo S480',
5276
- 80 => 'Positivo S550',
5277
- 81 => 'Positivo X400',
5278
- 82 => 'Positivo X800',
 
 
5279
  ),
5280
  '@PP' =>
5281
  array (
@@ -5286,7 +5589,7 @@ DeviceModels::$ANDROID_INDEX = array (
5286
  array (
5287
  0 => 'Project Tango Tablet Development Kit',
5288
  1 => '(Highscreen|Alpha|Bay|Boost|Cosmo|Explosion|Power|Prime|Zera)!!',
5289
- 2 => '(HW-|HUAWEI )?(ALE|D2|DAV|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|VIE|VKY|VNS|VTR|WAS)!!',
5290
  3 => 'Pro 10 dual core',
5291
  4 => 'Prada 3.0',
5292
  5 => 'PRO 5',
@@ -5575,9 +5878,10 @@ DeviceModels::$ANDROID_INDEX = array (
5575
  3 => 'R7i',
5576
  4 => 'R7kf',
5577
  5 => 'R7sf',
5578
- 6 => 'R7Plus',
5579
- 7 => 'R7plusf',
5580
- 8 => 'R7Plusm',
 
5581
  ),
5582
  '@R8' =>
5583
  array (
@@ -5724,7 +6028,7 @@ DeviceModels::$ANDROID_INDEX = array (
5724
  2 => 'Rikomagic MK802III',
5725
  3 => 'Rikomagic MK802IIIS',
5726
  4 => '(Gsmart|Gigabyte|Rio)!!',
5727
- 5 => '(HW-|HUAWEI )?(ALE|D2|DAV|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|VIE|VKY|VNS|VTR|WAS)!!',
5728
  6 => 'Rise',
5729
  7 => '(Ritmix )?RM[DP]-?[0-9]{3,3}!!',
5730
  8 => 'RIDGE',
@@ -5774,7 +6078,7 @@ DeviceModels::$ANDROID_INDEX = array (
5774
  ),
5775
  '@RN' =>
5776
  array (
5777
- 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
5778
  ),
5779
  '@RO' =>
5780
  array (
@@ -5897,23 +6201,24 @@ DeviceModels::$ANDROID_INDEX = array (
5897
  ),
5898
  '@SC' =>
5899
  array (
5900
- 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
5901
- 1 => '(HW-|HUAWEI )?(ALE|D2|DAV|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|VIE|VKY|VNS|VTR|WAS)!!',
5902
- 2 => '(HW-|HUAWEI )?(CRO|LUA|CUN|SCC|SCU|CAM|LYO|MYA)!!',
5903
- 3 => 'SCH-[iI][0-9]{3,3}!!',
5904
- 4 => 'SCH-L710!',
5905
- 5 => 'SCH-M828!',
5906
- 6 => 'SCH-N719',
5907
- 7 => 'SCH-P[0-9]{3,3}!!',
5908
- 8 => 'SCH-R[0-9]{3,3}!!',
5909
- 9 => 'SCH-S[0-9]{3,3}!!',
5910
- 10 => 'SCH-V727',
5911
- 11 => 'SCH-W[0-9]{3,4}!!',
5912
- 12 => 'SC-?0[0-9][A-Z]!!',
5913
- 13 => 'SC[LTV][23][0-9]!!',
5914
- 14 => 'Scroll!!',
5915
- 15 => 'SC-!!',
5916
- 16 => 'scorpio',
 
5917
  ),
5918
  '@SD' =>
5919
  array (
@@ -5972,11 +6277,12 @@ DeviceModels::$ANDROID_INDEX = array (
5972
  20 => 'SH-M02',
5973
  21 => 'SH-M02-EVA20',
5974
  22 => 'SH-M03',
5975
- 23 => 'SH-RM02',
5976
- 24 => 'SH-[01][0-9][A-Z]!!',
5977
- 25 => '(SHP-)?(SHARP )?SH[0-9]{2,3}!!',
5978
- 26 => 'SH[FLTV][0-9]{2,2}!!',
5979
- 27 => 'SHARP-ADS1',
 
5980
  ),
5981
  '@SI' =>
5982
  array (
@@ -6000,7 +6306,7 @@ DeviceModels::$ANDROID_INDEX = array (
6000
  0 => 'Slider SL101',
6001
  1 => 'SL930',
6002
  2 => '(HP|Slate)!!',
6003
- 3 => '(HW-|HUAWEI )?(TIT|TAG|NCE|TRT|SLA)!!',
6004
  4 => 'Slidepad!!',
6005
  5 => 'SLIDE',
6006
  ),
@@ -6030,33 +6336,36 @@ DeviceModels::$ANDROID_INDEX = array (
6030
  21 => 'SM-A[0-9]{3,3}!!',
6031
  22 => 'SM-C[0-9]{3,3}!!',
6032
  23 => 'SM-E[0-9]{3,3}!!',
6033
- 24 => 'SM-G[0-9]{3,3}!!',
6034
- 25 => 'SM-I9500',
6035
- 26 => 'SM-J[0-9]{3,3}!!',
6036
- 27 => 'SM-N[0-9]{3,4}!!',
6037
- 28 => 'SM-P[0-9]{3,3}!!',
6038
- 29 => 'SM-S[0-9]{3,3}!!',
6039
- 30 => 'SM-T[0-9]{3,3}!!',
6040
- 31 => 'SM-V700',
6041
- 32 => 'SM-W[0-9]{4,4}!!',
6042
- 33 => 'Smartphone Android by SFR STARADDICT II',
6043
- 34 => '(Smartfren|Andromax)!!',
6044
- 35 => 'Smartfren Tab 7',
6045
- 36 => 'SM919',
6046
- 37 => 'SM701',
6047
- 38 => 'SM801',
6048
- 39 => 'SmartQ!!',
6049
- 40 => 'SMART Sprint',
6050
- 41 => 'SMART Start',
6051
- 42 => 'SMART Surf2 4G',
6052
- 43 => 'SmartTab!!',
 
 
6053
  ),
6054
  '@SN' =>
6055
  array (
6056
  0 => 'SN[0-9]!!',
6057
- 1 => 'Snexian!!',
6058
- 2 => '(SNM\\-)?LT[0-9]{2,2}[a-z]?!!',
6059
- 3 => '(SNM\\-)?M[0-9]{2,2}[a-z]!!',
 
6060
  ),
6061
  '@SO' =>
6062
  array (
@@ -6070,7 +6379,7 @@ DeviceModels::$ANDROID_INDEX = array (
6070
  7 => 'Softwinerf900',
6071
  8 => 'SoftwinerEvbV13',
6072
  9 => 'soho',
6073
- 10 => '(HW-|HUAWEI )?(ALE|D2|DAV|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|VIE|VKY|VNS|VTR|WAS)!!',
6074
  11 => 'SONIC',
6075
  12 => 'Sonim!!',
6076
  13 => 'SO-0[0-9][A-Z]!!',
@@ -6136,63 +6445,64 @@ DeviceModels::$ANDROID_INDEX = array (
6136
  12 => 'ST7001',
6137
  13 => 'ST8000',
6138
  14 => 'ST9001',
6139
- 15 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!',
6140
- 16 => 'ST10',
6141
- 17 => 'ST940I-UP',
6142
- 18 => 'STM[0-9]{3,3}H!!',
6143
- 19 => 'Stylo',
6144
- 20 => 'STARACTIVE',
6145
- 21 => 'STARACTIVE 2',
6146
- 22 => 'STARADDICT II',
6147
- 23 => 'STARADDICT II Plus',
6148
- 24 => 'STARADDICT III',
6149
- 25 => 'STARADDICT 4',
6150
- 26 => 'STARADDICT 5',
6151
- 27 => 'STARADDICT 6',
6152
- 28 => 'STARNAUTE II',
6153
- 29 => 'STARNAUTE 3',
6154
- 30 => 'STARNAUTE3',
6155
- 31 => 'STARNAUTE4',
6156
- 32 => 'Starshine',
6157
- 33 => 'STARSHINE II',
6158
- 34 => 'STARSHINE III',
6159
- 35 => 'STARSHINE 4',
6160
- 36 => 'STARSHINE5',
6161
- 37 => 'STARTEXT II',
6162
- 38 => 'STARTRAIL II',
6163
- 39 => 'StarTrail III',
6164
- 40 => 'STARTRAIL4',
6165
- 41 => 'STARTRAIL 4',
6166
- 42 => 'STARTRAIL5',
6167
- 43 => 'STARTRAIL 6 4G',
6168
- 44 => 'STARTRAIL6',
6169
- 45 => 'STARTRAIL7',
6170
- 46 => 'STARTRAIL 8',
6171
- 47 => 'STARTRAIL 9',
6172
- 48 => 'STARXTREM',
6173
- 49 => 'STARXTREM II',
6174
- 50 => 'STARXTREM3',
6175
- 51 => 'STARXTREM 4',
6176
- 52 => 'STARXTREM5',
6177
- 53 => 'STARXTREM 6',
6178
- 54 => 'STARTAB',
6179
- 55 => 'ST[0-9]{2,2}[a-z]?!!',
6180
- 56 => 'Star N8000',
6181
- 57 => 'Star N9500',
6182
- 58 => 'Star N9589',
6183
- 59 => 'Star Q9000',
6184
- 60 => 'STAR S5',
6185
- 61 => 'STAR S7589',
6186
- 62 => 'Starmobile!!',
6187
- 63 => '(Starway )?Andromeda!!',
6188
- 64 => 'STX!!',
6189
- 65 => 'STOREX LinkBox',
6190
- 66 => 'StarTab 715x',
6191
- 67 => 'ST[0-9]{5,5}-[0-9]!!',
6192
- 68 => 'ST-PAD',
6193
- 69 => 'ST-PAD2',
6194
- 70 => 'STAIRWAY',
6195
- 71 => 'StarTrail TT',
 
6196
  ),
6197
  '@SU' =>
6198
  array (
@@ -6338,73 +6648,81 @@ DeviceModels::$ANDROID_INDEX = array (
6338
  5 => 'Tablet-P27',
6339
  6 => 'TA10CA3',
6340
  7 => '(tablet )?fnac!!',
6341
- 8 => '(HW-|HUAWEI )?(TIT|TAG|NCE|TRT|SLA)!!',
6342
- 9 => '(HW-|HUAWEI )?(BLL|CHC|TAG|KII)!!',
6343
- 10 => 'TA-FONE!!',
6344
- 11 => 'TAB1011',
6345
- 12 => 'TAB-1030',
6346
- 13 => '(Lenovo )?(Tab ?)?(2 ?)?[AS](7|8|10)!!',
6347
- 14 => 'TAB950',
6348
- 15 => 'TAB1062',
6349
- 16 => 'TAB192',
6350
- 17 => 'TA-10(20|28|32|38)!',
6351
- 18 => 'TA-10(24|27|44|53)!',
6352
- 19 => 'TA-10(00|03|21|25|33|39)!',
6353
- 20 => 'TA-10(41)!',
6354
- 21 => 'TA-10(04|12|52)!',
6355
- 22 => '(POV )?TAB-PLAYTABPRO!',
6356
- 23 => '(POV )?TAB-PROTAB25!',
6357
- 24 => '(POV )?TAB-PROTAB26!',
6358
- 25 => '(POV )?TAB-PROTAB30!',
6359
- 26 => 'TAB-PROTAB2-IPS9',
6360
- 27 => 'TAB-PROTAB2-IPS-3G',
6361
- 28 => 'TAB-PROTAB2-IPS-16',
6362
- 29 => 'TAB-PROTAB2.4',
6363
- 30 => 'TAB-PROTAB2XL',
6364
- 31 => 'TAB-PROTAB2.4XL',
6365
- 32 => 'TAB-PROTAB2XXL',
6366
- 33 => 'TAB-PROTAB2XXL(4)',
6367
- 34 => '(POV )?TAB-PROTAB2XXL(4)!',
6368
- 35 => '(POV )?TAB NAVI7 3G M!',
6369
- 36 => 'Tablet P',
6370
- 37 => 'Tablet S',
6371
- 38 => 'Tabra QAV801',
6372
- 39 => 'TAB 7 3G V8',
6373
- 40 => 'TAB 8 3G V8',
6374
- 41 => 'TAB9 3G',
6375
- 42 => 'TAB9 3G V8',
6376
- 43 => 'TAB 10 3G V16',
6377
- 44 => 'TAB 7i 3G',
6378
- 45 => 'TAB 10Q',
6379
- 46 => 'TAB09-410',
6380
- 47 => 'TAB10-410',
6381
- 48 => 'TAB07-485',
6382
- 49 => 'TAB07-200',
6383
- 50 => 'TAB9-200',
6384
- 51 => 'TAB10-201',
6385
- 52 => 'TAB210',
6386
- 53 => 'TAB220',
6387
- 54 => 'TAB224',
6388
- 55 => 'TAB250',
6389
- 56 => 'TAB275',
6390
- 57 => 'TAB260',
6391
- 58 => 'TAB264',
6392
- 59 => 'TAB360',
6393
- 60 => 'TAB364',
6394
- 61 => 'TAB410',
6395
- 62 => 'TAB411',
6396
- 63 => 'TAB420',
6397
- 64 => 'TAB424',
6398
- 65 => 'TAB450',
6399
- 66 => 'TAB460',
6400
- 67 => 'TAB461',
6401
- 68 => 'TAB464',
6402
- 69 => 'TAB465EUK',
6403
- 70 => 'TAB468',
6404
- 71 => 'TAB469',
6405
- 72 => 'TAB466EUK',
6406
- 73 => 'TAB467',
6407
- 74 => 'TAB462',
 
 
 
 
 
 
 
 
6408
  ),
6409
  '@TB' =>
6410
  array (
@@ -6512,7 +6830,7 @@ DeviceModels::$ANDROID_INDEX = array (
6512
  array (
6513
  0 => 'Tilapia',
6514
  1 => 'Titan TV S320',
6515
- 2 => '(HW-|HUAWEI )?(TIT|TAG|NCE|TRT|SLA)!!',
6516
  3 => '(Karbonn|Titanium)!!',
6517
  4 => 'TI320-DU',
6518
  5 => 'TI320-DU TV',
@@ -6577,6 +6895,10 @@ DeviceModels::$ANDROID_INDEX = array (
6577
  49 => 'TM-1058',
6578
  50 => 'tmn!!',
6579
  ),
 
 
 
 
6580
  '@TO' =>
6581
  array (
6582
  0 => 'Toro',
@@ -6630,7 +6952,7 @@ DeviceModels::$ANDROID_INDEX = array (
6630
  14 => 'TR720F',
6631
  15 => 'TR10CS1',
6632
  16 => 'TripNiCE Pyramid',
6633
- 17 => '(HW-|HUAWEI )?(TIT|TAG|NCE|TRT|SLA)!!',
6634
  18 => 'TR10RS1',
6635
  19 => '(KAZAM|Thunder|Tornado|Trooper)!!',
6636
  20 => 'Triumph',
@@ -6980,7 +7302,7 @@ DeviceModels::$ANDROID_INDEX = array (
6980
  20 => 'Vibo-A688',
6981
  21 => 'VitMod ExtraLite 1.6.5.fullodex for HTC HD7 Pro',
6982
  22 => 'Vivid 4G',
6983
- 23 => '(HW-|HUAWEI )?(ALE|D2|DAV|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|VIE|VKY|VNS|VTR|WAS)!!',
6984
  24 => 'Vibe K5 Plus',
6985
  25 => 'VIBE X2 (X2)',
6986
  26 => 'VIBE X3',
@@ -7032,7 +7354,7 @@ DeviceModels::$ANDROID_INDEX = array (
7032
  ),
7033
  '@VK' =>
7034
  array (
7035
- 0 => '(HW-|HUAWEI )?(ALE|D2|DAV|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|VIE|VKY|VNS|VTR|WAS)!!',
7036
  1 => 'VK410',
7037
  2 => 'VK700',
7038
  3 => 'VK810 4G',
@@ -7050,7 +7372,7 @@ DeviceModels::$ANDROID_INDEX = array (
7050
  ),
7051
  '@VN' =>
7052
  array (
7053
- 0 => '(HW-|HUAWEI )?(ALE|D2|DAV|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|VIE|VKY|VNS|VTR|WAS)!!',
7054
  ),
7055
  '@VO' =>
7056
  array (
@@ -7059,24 +7381,25 @@ DeviceModels::$ANDROID_INDEX = array (
7059
  2 => 'Volantisg',
7060
  3 => 'VOYAGER DG300',
7061
  4 => 'VOYAGER2 DG310',
7062
- 5 => 'Vox',
7063
- 6 => 'Vortex',
7064
- 7 => 'vollo Vi86',
7065
- 8 => 'VOTO GT2++',
7066
- 9 => 'VOTO GT7',
7067
- 10 => 'VOTO GT11',
7068
- 11 => 'VOTO GT11 Pro',
7069
- 12 => 'VOTO GT18',
7070
- 13 => 'VOTO V5',
7071
- 14 => 'VOTO VT868',
7072
- 15 => 'VOTO VT888',
7073
- 16 => 'VOTO VT898',
7074
- 17 => 'VOTO VT898S',
7075
- 18 => 'VOTO W5300',
7076
- 19 => 'VOTO X2',
7077
- 20 => 'VOYO A15',
7078
- 21 => 'voyo X6',
7079
- 22 => 'Vodafone!!',
 
7080
  ),
7081
  '@VS' =>
7082
  array (
@@ -7104,7 +7427,7 @@ DeviceModels::$ANDROID_INDEX = array (
7104
  ),
7105
  '@VT' =>
7106
  array (
7107
- 0 => '(HW-|HUAWEI )?(ALE|D2|DAV|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|VIE|VKY|VNS|VTR|WAS)!!',
7108
  1 => 'VT6078',
7109
  2 => 'VT75C',
7110
  3 => 'VT77C',
@@ -7199,7 +7522,7 @@ DeviceModels::$ANDROID_INDEX = array (
7199
  ),
7200
  '@WA' =>
7201
  array (
7202
- 0 => '(HW-|HUAWEI )?(ALE|D2|DAV|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|VIE|VKY|VNS|VTR|WAS)!!',
7203
  1 => 'WA-U420D',
7204
  2 => 'WALSUN S1 Pro',
7205
  3 => 'WALSUN S2',
@@ -7597,19 +7920,21 @@ DeviceModels::$ANDROID_INDEX = array (
7597
  2 => '(Xiaomi|Xiaomi Mi|MI) Note!!',
7598
  3 => '(Xiaomi )?(MI )?MAX$!',
7599
  4 => '(Xiaomi )?(MI )?MAX 2$!',
7600
- 5 => '(Xiaomi )?(MI )?MIX$!',
7601
- 6 => '(Xiaomi )?(MI )?MIX 2$!',
7602
- 7 => '(Xiaomi )?20!!',
7603
- 8 => '(Xiaomi )?(Redmi|RedRice|HM)!!',
7604
- 9 => '(Xiaomi )?(Redmi|HM)[ \\-]?Note!!',
7605
- 10 => '(Xiaomi |HM)?20!!',
7606
- 11 => 'Xiaomi MDT2!',
7607
- 12 => 'Xiaomi MCT1!',
7608
- 13 => 'Xiaomi MAT136!',
7609
- 14 => 'Xiaomi MBT6A5!',
7610
- 15 => '(Xiaomi|Xiaomi Mi|MI) Pad!!',
7611
- 16 => '(Xiaomi|Xiaomi Mi|MI)Box!!',
7612
- 17 => '(Xiaomi|Xiaomi Mi|MI)TV!!',
 
 
7613
  ),
7614
  '@XL' =>
7615
  array (
@@ -7716,6 +8041,10 @@ DeviceModels::$ANDROID_INDEX = array (
7716
  0 => 'Y6 Max',
7717
  1 => 'Y6 Piano',
7718
  ),
 
 
 
 
7719
  '@YD' =>
7720
  array (
7721
  0 => 'YD201',
@@ -7887,18 +8216,19 @@ DeviceModels::$ANDROID_INDEX = array (
7887
  51 => 'Z01BDC',
7888
  52 => 'Z01BS',
7889
  53 => 'Z01FD',
7890
- 54 => 'Z01HD',
7891
- 55 => 'Z01HDA',
7892
- 56 => 'Z01KD',
7893
- 57 => 'Z01KDA',
7894
- 58 => 'Z01MDA',
7895
- 59 => 'Z00YD',
 
7896
  ),
7897
  '@Z1' =>
7898
  array (
7899
  0 => '(BB )?Z10$!',
7900
  1 => 'Z1-H39LW',
7901
- 2 => '(HUAWEI )?(ALP|BLA|CRR|LON|MATE|MHA|MT1|MT2|MT7|M200|NXT|Z100)!!',
7902
  3 => 'Z1i',
7903
  ),
7904
  '@Z2' =>
@@ -8014,17 +8344,18 @@ DeviceModels::$ANDROID_INDEX = array (
8014
  7 => 'ZE550KL',
8015
  8 => 'ZE552KL',
8016
  9 => 'ZE553KL',
8017
- 10 => 'ZEN Touch 2',
8018
- 11 => '(Highscreen|Alpha|Bay|Boost|Cosmo|Explosion|Power|Prime|Zera)!!',
8019
- 12 => 'ZEN 4.5',
8020
- 13 => 'ZEN 4.7',
8021
- 14 => 'ZEN 5+',
8022
- 15 => 'ZENITHINK C94!',
8023
- 16 => 'Zen PO neo',
8024
- 17 => 'ZEN U1',
8025
- 18 => 'ZEN U4',
8026
- 19 => 'ZEN U5',
8027
- 20 => 'ZEN 303 3G',
 
8028
  ),
8029
  '@ZI' =>
8030
  array (
@@ -8155,22 +8486,23 @@ DeviceModels::$ANDROID_INDEX = array (
8155
  98 => 'ZTE B2016',
8156
  99 => 'ZTE B2017',
8157
  100 => 'ZTE B2017G',
8158
- 101 => 'ZTE C2016',
8159
- 102 => 'ZTE C2017',
8160
- 103 => 'ZTE STAR',
8161
- 104 => 'ZTE Star 1',
8162
- 105 => 'ZTE S2004',
8163
- 106 => 'ZTE S2005',
8164
- 107 => 'ZTE S2007',
8165
- 108 => 'ZTE S2010',
8166
- 109 => 'ZTE S2014',
8167
- 110 => 'ZTE U9180',
8168
- 111 => 'ZTE U9370',
8169
- 112 => 'ZTE V6500',
8170
- 113 => 'ZTE V8110',
8171
- 114 => 'ZTE B860A',
8172
- 115 => 'ZTE B860AV1',
8173
- 116 => 'ZTE W1010',
 
8174
  ),
8175
  '@ZU' =>
8176
  array (
13
  5 => '[0-9]0[0-9]F!!',
14
  6 => '(Haier[- ])?H[ETW]- ?[A-Z][0-9]!!',
15
  7 => '(Hisense )?(LED[0-9]{2,2}(G|K|L|EC|XT)[0-9]{2,3})!',
16
+ 8 => '[SX06][0-9]{2,2}HT!!',
17
  9 => '(Huawei )?[MSTX](1|2|7|8|10)\\-[A-Z0-9][0-9]{2,2}!!',
18
+ 10 => '(HW-|HUAWEI )?(ATU|DRA|FLA|JKM|TIT|TAG||MRD|NCE|POT|TRT|SLA)!!',
19
+ 11 => 'G[0-9]{3,3}!!',
20
+ 12 => 'Y[0-9]{3,3}!!',
21
+ 13 => '[0-9AS][0-9]{2,2}HW!!',
22
+ 14 => '(USCC-|KYOCERA-)?E[0-9]{4,4}!!',
23
+ 15 => '(USCC-|KYOCERA-)?C[0-9]{4,4}!!',
24
+ 16 => '[0-9]0[0-9]KC?!!',
25
+ 17 => 'K\\-?Touch!!',
26
+ 18 => '(Lenovo ?)?(IdeaTab ?)?[AB][0-9]{4,4}!!',
27
+ 19 => '(Lenovo )?(Tab ?)?(2 ?)?[AS](7|8|10)!!',
28
+ 20 => '(Lenovo ?)?(IdeaTab ?)?[KSV][0-9]{4,4}!!',
29
+ 21 => '[0-9]0[0-9]LG!!',
30
+ 22 => 'M\\-PP!!',
31
+ 23 => 'M\\-MP!!',
32
+ 24 => 'M\\-IPRO!!',
33
+ 25 => '(MEDION|(MD )?LIFETAB)!!',
34
+ 26 => 'M\\.T\\.T\\.!!',
35
+ 27 => 'O\\+!!',
36
+ 28 => '[0-9]{2,2}PFH6[0-9]{3,3}!',
37
+ 29 => '(?:RIVO )?RHYTHM RX ?([0-9]+)!',
38
+ 30 => '[4567A]0[0-9]SH!!',
39
+ 31 => '(3|5|6|7)0[0-9]SH!!',
40
+ 32 => 'C[0-9]{4,4}!!',
41
+ 33 => 'D[0-9]{4,4}!!',
42
+ 34 => 'E[0-9]{4,4}!!',
43
+ 35 => 'F[0-9]{4,4}!!',
44
+ 36 => 'G[0-9]{4,4}!!',
45
+ 37 => 'H[0-9]{4,4}!!',
46
+ 38 => 'I[0-9]{4,4}!!',
47
+ 39 => 'E[0-9]{2,2}[a-z]!!',
48
+ 40 => 'L[0-9]{2,2}[a-z]!!',
49
+ 41 => '(SNM\\-)?M[0-9]{2,2}[a-z]!!',
50
+ 42 => 'S[0-9]{2,2}[a-z]!!',
51
+ 43 => '(XOLO )?[ABQX][0-9]{3,4}!!',
52
+ 44 => '(ZTE ?)?N[0-9]{3,3}!!',
53
+ 45 => '(ZXY-)?(ZTE )?N[0-9]{4,4}!!',
54
+ 46 => '(ZTE ?)?U[0-9]{3,3}!!',
55
+ 47 => '(ZTE ?)?V[0-9]{3,3}[A-Z]!!',
56
+ 48 => '(ZTE ?)?V ?[0-9]{3,3}!!',
57
+ 49 => '(ZTE ?)?X[0-9]{3,3}!!',
58
+ 50 => '(ZTE )?Z[0-9]!!',
59
+ 51 => '[a-z][a-z](?:-[a-z][a-z])?, SmartTabII7!',
60
  ),
61
  '@00' =>
62
  array (
133
  ),
134
  '@3' =>
135
  array (
136
+ 0 => '(3|5|6|7)0[0-9]SH!!',
137
+ ),
138
+ '@30' =>
139
+ array (
140
+ 0 => 3007,
141
  ),
142
  '@36' =>
143
  array (
168
  13 => '4027[ADNX]!',
169
  14 => '4028[AEJS]!',
170
  15 => '4032[ADEX]!',
171
+ 16 => '4033[ADLX]!',
172
  17 => '4034[ADEFGX]!',
173
  18 => '4035[ADYX]!',
174
  19 => '4036[E]!',
175
  20 => '4037[AX]!',
176
  21 => '4037[T]!',
177
  22 => '4037[V]!',
178
+ 23 => '4045[ADEFLOYX]!',
179
+ 24 => '4047[ADFGX]!',
180
+ 25 => '4049[DG]!',
181
+ 26 => '4055[JU]!',
182
+ 27 => '4060[A]!',
183
+ 28 => '4060[SW]!',
184
+ 29 => '40[0-9]SC!!',
185
+ 30 => '40[0-9]SO!!',
186
+ 31 => '402ZT',
187
  ),
188
  '@48' =>
189
  array (
191
  ),
192
  '@5' =>
193
  array (
194
+ 0 => '(3|5|6|7)0[0-9]SH!!',
195
  ),
196
  '@50' =>
197
  array (
198
  0 => '5010[DEGSUX]!',
199
+ 1 => '5011[A]!',
200
+ 2 => '5012[G]!',
201
+ 3 => '5015[ADEX]!',
202
+ 4 => '5016[AJ]!',
203
+ 5 => '5017[B]!',
204
+ 6 => '5017[ADEOX]!',
205
+ 7 => '5019[D]!',
206
+ 8 => '5020[A]!',
207
+ 9 => '5022[DEX]!',
208
+ 10 => '5023[F]!',
209
+ 11 => '5024[D]!',
210
+ 12 => '5025[DEGX]!',
211
+ 13 => '5027[B]!',
212
+ 14 => '5033[ADJOX]!',
213
+ 15 => '5034[D]!',
214
+ 16 => '5036[D]!',
215
+ 17 => '5038[ADEX]!',
216
+ 18 => '5039[D]!',
217
+ 19 => '5041[C]!',
218
+ 20 => '5042[ADEFGTWXY]!',
219
+ 21 => '5044[ADGIOSTY]!',
220
+ 22 => '5045[ADFGJTXY]!',
221
+ 23 => '5046[DGIJUY]!',
222
+ 24 => '5047[DIUY]!',
223
+ 25 => '5049[EGSWZ]!',
224
+ 26 => '5050[ASYX]!',
225
+ 27 => '5051[ADJMX]!',
226
+ 28 => '5052[DY]!',
227
+ 29 => '5053[D]!',
228
+ 30 => '5054[ADOSTX]!',
229
+ 31 => '5054[NW]!',
230
+ 32 => '5056[ADEINUWX]!',
231
+ 33 => '5056[O]!',
232
+ 34 => '5057[M]!',
233
+ 35 => '5058[I]!',
234
+ 36 => '5059[ADJTXY]!',
235
+ 37 => '5060[D]!',
236
+ 38 => '5065[ADJNWX]!',
237
+ 39 => '5070[DJX]!',
238
+ 40 => '5080[A]!',
239
+ 41 => '5080[DFQX]!',
240
+ 42 => '5085[CDJNOYX]!',
241
+ 43 => '5086[ADY]!',
242
+ 44 => '5090[Y]!',
243
+ 45 => '5095[BIKY]!',
244
+ 46 => '5096[AI]!',
245
+ 47 => '5098[OS]!',
246
+ 48 => '5099[ADY]!',
247
+ 49 => '504Q',
248
+ 50 => '504Q+',
249
+ 51 => '504QP',
250
+ 52 => '501LV',
251
+ 53 => '(48|50|55)AX600C!',
252
+ 54 => '5080C Pro',
253
+ 55 => '50[0-9]SO!!',
254
+ 56 => '502ZT',
255
  ),
256
  '@55' =>
257
  array (
268
  5 => '5860S',
269
  6 => 5870,
270
  ),
271
+ '@6' =>
272
+ array (
273
+ 0 => '(3|5|6|7)0[0-9]SH!!',
274
+ ),
275
  '@60' =>
276
  array (
277
  0 => '6014[DX]!',
286
  9 => '6045[BFGIKOXY]!',
287
  10 => '6050[AFWY]!',
288
  11 => '6055[ABDHIKPUY]!',
289
+ 12 => '6058[D]!',
290
+ 13 => '6060[S]!',
291
+ 14 => '6062[W]!',
292
+ 15 => '6070[KOY]!',
293
+ 16 => '602LV',
294
+ 17 => '60[0-9]SO!!',
295
+ 18 => '602ZT',
296
+ 19 => '6034R ORANGE Niva',
297
+ ),
298
+ '@66' =>
299
+ array (
300
+ 0 => 6607,
301
  ),
302
  '@70' =>
303
  array (
304
  0 => '7030[L]!',
305
+ 1 => '7040[DNR]!',
306
  2 => '7040[T]!',
307
  3 => '7043[AEKY]!',
308
  4 => '7044[AXY]!',
313
  9 => '7051[X]!',
314
  10 => '7053[D]!',
315
  11 => '7055[AW]!',
316
+ 12 => '704DC',
317
+ 13 => '70[0-9]SO!!',
318
  ),
319
  '@71' =>
320
  array (
381
  ),
382
  '@90' =>
383
  array (
384
+ 0 => '9001[DIX]!',
385
  1 => '9002[AWX]!',
386
  2 => '9003[AX]!',
387
  3 => '9005[X]!',
388
  4 => '9006[W]!',
389
  5 => '9007[ATX]!',
390
+ 6 => '9008[ADIJTUX]!',
391
  7 => '9010[X]!',
392
+ 8 => '9015[BJWQ]!',
393
  9 => '9022[SX]!',
394
+ 10 => '9024[OW]!',
395
  11 => '9025[MQ]!',
396
+ 12 => '9021[AM]!',
397
  13 => '909d',
398
  14 => 9088,
399
  15 => '9020[A]!',
469
  7 => 'A31',
470
  8 => 'A31c',
471
  9 => 'A31t',
472
+ 10 => 'A31u',
473
+ 11 => 'A33f',
474
+ 12 => 'A33w',
475
+ 13 => 'A37f',
476
+ 14 => 'A37fw',
477
+ 15 => 'A3',
478
  ),
479
  '@A4' =>
480
  array (
515
  17 => 'A500CG',
516
  18 => 'A55i',
517
  19 => 'A52',
518
+ 20 => 'A51',
519
+ 21 => 'A51f',
520
+ 22 => 'A51w',
521
+ 23 => 'A5000',
522
+ 24 => 'a5',
523
  ),
524
  '@A6' =>
525
  array (
554
  16 => 'A750',
555
  17 => 'A7000-a',
556
  18 => 'A7010a48',
557
+ 19 => 'A73',
558
+ 20 => 'A7272+',
559
+ 21 => 'A70(CY6T)',
560
+ 22 => 'A78h四核(C1V3)',
561
  ),
562
  '@A8' =>
563
  array (
763
  33 => '(Allview|Alldro)!!',
764
  34 => 'Allwinner A10',
765
  35 => '(Highscreen|Alpha|Bay|Boost|Cosmo|Explosion|Power|Prime|Zera)!!',
766
+ 36 => '(HUAWEI )?(ALP|BLA|CRR|EVR|HMA|LIO|LON|LYA|MATE|MHA|MT1|MT2|MT7|M200|NXT|SNE|TAS|Z100)!!',
767
+ 37 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
768
  38 => 'Alfa A93 POP',
769
  39 => 'Alfa L',
770
  40 => 'Ally',
849
  41 => 'AN10G2-LZ',
850
  42 => 'AN10BG3-LZ',
851
  43 => 'AN7DG3C',
852
+ 44 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
853
+ 45 => '(iBall )?Andi!!',
854
+ 46 => 'AND1',
855
+ 47 => 'AND1E',
856
+ 48 => 'AND1E TV',
857
+ 49 => 'Android edition by sfr STARADDICT',
858
+ 50 => 'Android Edition Starnaute',
859
+ 51 => 'Android Edition StarText',
860
+ 52 => 'Android Edition StarTrail',
861
+ 53 => '(Smartfren|Andromax)!!',
862
+ 54 => 'Androtab 7',
863
+ 55 => '(Starway )?Andromeda!!',
864
+ 56 => '(Andy|Yezz)!!',
865
  ),
866
  '@AO' =>
867
  array (
995
  13 => 'AT1G*',
996
  14 => 'AT7E',
997
  15 => 'ATP515CKIT',
998
+ 16 => '(HW-|HUAWEI )?(ATU|DRA|FLA|JKM|TIT|TAG||MRD|NCE|POT|TRT|SLA)!!',
999
+ 17 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
1000
+ 18 => 'aTab9.7 IPS',
1001
+ 19 => 'AT735',
1002
+ 20 => 'Atrix 2',
1003
+ 21 => 'Atrix 2 WeifanZ',
1004
+ 22 => 'Atrix 4G',
1005
+ 23 => 'Atrix 4G ME860',
1006
+ 24 => 'Atrix 4G MB860',
1007
+ 25 => 'Atrix HD',
1008
+ 26 => 'AtrixHD',
1009
+ 27 => 'ATLANTIS',
1010
+ 28 => 'ATP7526',
1011
+ 29 => 'ATP7683',
1012
+ 30 => 'AT1S0',
1013
+ 31 => 'AT7-A',
1014
+ 32 => 'AT7-B',
1015
+ 33 => 'AT7-C',
1016
+ 34 => 'AT10-A',
1017
+ 35 => 'AT10LE-A',
1018
+ 36 => 'AT10PE-A',
1019
+ 37 => 'AT100',
1020
+ 38 => 'AT200',
1021
+ 39 => 'AT270',
1022
+ 40 => 'AT300',
1023
+ 41 => 'AT300SE',
1024
+ 42 => 'AT330',
1025
+ 43 => 'AT374',
1026
+ 44 => 'AT400',
1027
+ 45 => 'AT470',
1028
+ 46 => 'AT500',
1029
+ 47 => 'AT500a',
1030
+ 48 => 'AT503',
1031
+ 49 => 'AT570',
1032
+ 50 => 'AT703',
1033
+ 51 => 'AT830',
1034
+ 52 => 'AT-A[QS][0-9]{2,2}!!',
1035
+ 53 => 'ATLAS W',
1036
  ),
1037
  '@AU' =>
1038
  array (
1092
  5 => 'Barnes & Noble Nook HD+',
1093
  6 => '(Highscreen|Alpha|Bay|Boost|Cosmo|Explosion|Power|Prime|Zera)!!',
1094
  7 => 'BAH-(W09|AL00|L09)!',
1095
+ 8 => 'BAH2-(AL10|L09|W09|W19)!',
1096
+ 9 => '(HW-|HUAWEI )?BAC-(AL00|L03|L21|L22|TL00)!',
1097
+ 10 => 'Backflip',
1098
+ 11 => 'Backflip Me600',
1099
+ 12 => 'Bambook S1',
1100
+ 13 => 'BARRY',
1101
+ 14 => 'BASE!!',
1102
  ),
1103
  '@BB' =>
1104
  array (
1112
  7 => 'BBB100-[0-9]!',
1113
  8 => 'BBC100-[0-9]!',
1114
  9 => 'BBD100-[0-9]!',
1115
+ 10 => 'BBE100-[0-9]!',
1116
+ 11 => 'BBF100-[0-9]!',
1117
+ 12 => '(BBG-|VIV-)?vivo!!',
1118
+ 13 => 'Bbox Miami',
1119
  ),
1120
  '@BC' =>
1121
  array (
1193
  '@BK' =>
1194
  array (
1195
  0 => '(BDS|BHX|BKO)\\-!!',
1196
+ 1 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
1197
  ),
1198
  '@BL' =>
1199
  array (
1206
  6 => 'Bluboo S1',
1207
  7 => 'Blaze S180',
1208
  8 => 'BLADE LE 70',
1209
+ 9 => '(HUAWEI )?(ALP|BLA|CRR|EVR|HMA|LIO|LON|LYA|MATE|MHA|MT1|MT2|MT7|M200|NXT|SNE|TAS|Z100)!!',
1210
+ 10 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
1211
  11 => '(HW-|HUAWEI )?(BLL|CHC|TAG|KII)!!',
1212
  12 => '(BLF-)?lephone!!',
1213
  13 => 'Blackphone 2',
1228
  1 => '(NOOK )?BNTV250!',
1229
  2 => '(NOOK )?BNRV350!',
1230
  3 => '(NOOK )?BNTV(400)!',
1231
+ 4 => '(NOOK )?BNTV(450)!',
1232
+ 5 => '(NOOK )?BNTV(600)!',
1233
+ 6 => '(NOOK )?BNTV(800)!',
1234
+ 7 => 'BN Nook HD',
1235
+ 8 => 'BN NookHD+',
1236
+ 9 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
1237
  ),
1238
  '@BO' =>
1239
  array (
1388
  9 => 'Casper VIA!!',
1389
  10 => 'CAT!!',
1390
  11 => 'Candy TV',
1391
+ 12 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
1392
+ 13 => '(HW-|HUAWEI )?(CRO|LUA|CUN|SCC|SCU|CAM|LDN|LYO|MYA)!!',
1393
  14 => '(HW-|HUAWEI )?CAZ-(AL10|TL10|TL20)!',
1394
  15 => '(HW-|HUAWEI )?CAN-(L01|L11|L12)!',
1395
  16 => 'calgary',
1423
  11 => 'Cherry w500',
1424
  12 => 'CHUWI!!',
1425
  13 => 'CHONG!!',
1426
+ 14 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
1427
  15 => '(HW-|HUAWEI )?(BLL|CHC|TAG|KII)!!',
1428
  16 => 'chagall',
1429
  17 => 'chiron',
1458
  4 => 'Clanga SE 097-1008',
1459
  5 => 'CLP281X',
1460
  6 => 'Click',
1461
+ 7 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
1462
+ 8 => '(Intex )?Cloud!!',
1463
+ 9 => 'CLIQ',
1464
+ 10 => 'CLIQ XT',
1465
+ 11 => 'CLIQ2',
1466
  ),
1467
  '@CM' =>
1468
  array (
1469
  0 => 'CMP!!',
1470
  1 => '(cm|aokp) tenderloin!',
1471
+ 2 => 'CMR-(AL09|AL19|W09|W19)!',
1472
+ 3 => 'CM980',
1473
+ 4 => 'CM990',
1474
  ),
1475
  '@CN' =>
1476
  array (
1497
  15 => 'Connect-2G-2.0',
1498
  16 => '(Highscreen|Alpha|Bay|Boost|Cosmo|Explosion|Power|Prime|Zera)!!',
1499
  17 => 'Coquettish Red',
1500
+ 18 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
1501
+ 19 => 'Comet',
1502
+ 20 => 'Corvair',
1503
+ 21 => 'COOLPIX S800c',
1504
+ 22 => 'COOLPIX S810c',
1505
+ 23 => 'Constellation V',
1506
  ),
1507
  '@CP' =>
1508
  array (
1511
  2 => 'CP8676!',
1512
  3 => 'CP8298!',
1513
  4 => 'CPN-(W09|AL00|L09)!',
1514
+ 5 => 'CPH1803',
1515
+ 6 => 'CPH1809',
1516
+ 7 => 'CPH1901',
1517
+ 8 => 'CPH1937',
1518
+ 9 => 'CPH1941',
1519
+ 10 => 'CPH1605',
1520
+ 11 => 'CPH1701',
1521
+ 12 => 'CPH1717',
1522
+ 13 => 'CPH1801',
1523
+ 14 => 'CPH1729',
1524
+ 15 => 'CPH1827',
1525
+ 16 => 'CPH1609',
1526
+ 17 => 'CPH1613',
1527
+ 18 => 'CPH1723',
1528
+ 19 => 'CPH1727',
1529
+ 20 => 'CPH1819',
1530
+ 21 => 'CPH1821',
1531
+ 22 => 'CPH1859',
1532
+ 23 => 'CPH1881',
1533
+ 24 => 'CPH1823',
1534
+ 25 => 'CPH1969',
1535
+ 26 => 'CPH1721',
1536
+ 27 => 'CPH1611',
1537
+ 28 => 'CPH1879',
1538
+ 29 => 'CPH1861',
1539
+ 30 => 'CPH1979',
1540
  ),
1541
  '@CR' =>
1542
  array (
1544
  1 => 'CRESTA.CTP888',
1545
  2 => 'Cross!!',
1546
  3 => 'Crosscall!!',
1547
+ 4 => '(HUAWEI )?(ALP|BLA|CRR|EVR|HMA|LIO|LON|LYA|MATE|MHA|MT1|MT2|MT7|M200|NXT|SNE|TAS|Z100)!!',
1548
+ 5 => '(HW-|HUAWEI )?(CRO|LUA|CUN|SCC|SCU|CAM|LDN|LYO|MYA)!!',
1549
  6 => 'CRONO 22',
1550
  7 => 'Crescent',
1551
  ),
1578
  0 => 'CUBOT!!',
1579
  1 => '(CUBE ?)?(K8|U1|U2|U3|U5|U6|U8|U9)[0-9]?GT!!',
1580
  2 => 'CUBE!!',
1581
+ 3 => '(HW-|HUAWEI )?(CRO|LUA|CUN|SCC|SCU|CAM|LDN|LYO|MYA)!!',
1582
  ),
1583
  '@CW' =>
1584
  array (
1617
  '@D2' =>
1618
  array (
1619
  0 => 'D2-[0-9]{3,3}!!',
1620
+ 1 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
1621
  ),
1622
  '@D5' =>
1623
  array (
1650
  1 => '(BLU|DASH|LIFE|NEO|STUDIO|VIVO)!!',
1651
  2 => 'Dakele A380',
1652
  3 => 'DAKELE MC001',
1653
+ 4 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
1654
  5 => 'DATAM803HC',
1655
  6 => 'DATAM805HC',
1656
  7 => 'DATAM819HD!',
1733
  1 => 'DL8006',
1734
  2 => 'DLX',
1735
  3 => 'DLXU',
1736
+ 4 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
1737
  5 => 'dL1',
1738
  ),
1739
  '@DM' =>
1740
  array (
1741
  0 => 'DM0[0-9]{2,2}(K|SH)!!',
1742
+ 1 => 'DM001c Frozen',
1743
+ 2 => 'DM001c Mickey',
1744
+ 3 => 'DM001c Princess',
1745
+ 4 => 'DM-01G',
1746
+ 5 => 'DM-01K',
1747
+ 6 => 'DM-02H',
1748
+ 7 => 'DMC-CM1',
1749
+ 8 => 'DM-01H',
1750
+ 9 => 'DM-01J',
1751
  ),
1752
  '@DN' =>
1753
  array (
1783
  0 => 'Dream',
1784
  1 => '(GIO-)?(GiONEE[- ])?Dream D1!',
1785
  2 => 'Droid Incredible',
1786
+ 3 => '(HW-|HUAWEI )?(ATU|DRA|FLA|JKM|TIT|TAG||MRD|NCE|POT|TRT|SLA)!!',
1787
+ 4 => 'DroniX-0.5',
1788
+ 5 => 'Droid',
1789
+ 6 => 'DROID',
1790
+ 7 => 'DROID ?2!',
1791
+ 8 => 'DROID ?3!',
1792
+ 9 => 'DROID ?4!',
1793
+ 10 => 'DroidPro',
1794
+ 11 => 'DROID Pro',
1795
+ 12 => 'DROID HD',
1796
+ 13 => 'DROID BIONIC!',
1797
+ 14 => 'DROID RAZR HD!',
1798
+ 15 => 'DROID ?RAZR!',
1799
+ 16 => 'DROID SPYDER',
1800
+ 17 => 'DROID ?X2!',
1801
+ 18 => 'DROID ?X!',
1802
+ 19 => 'DROIDZ Duo',
1803
+ 20 => 'DROIDZ Active 3G',
1804
+ 21 => 'DROIDZ ATOM S',
1805
+ 22 => 'DROIDZ Beat TV',
1806
+ 23 => 'DROIDZ Drive+',
1807
+ 24 => 'DROIDZ Excel',
1808
+ 25 => 'DROIDZ Excite',
1809
+ 26 => 'DROIDZ Force',
1810
+ 27 => 'DROIDZ Match TV',
1811
+ 28 => 'DROIDZ Mini Q',
1812
+ 29 => 'DROIDZ Portal X',
1813
+ 30 => 'DROIDZ Quad',
1814
+ 31 => 'DROIDZ Race',
1815
+ 32 => 'DROIDZ Race X',
1816
+ 33 => 'DROIDZ Sport',
1817
+ 34 => 'DROIDZ Ultimate',
1818
  ),
1819
  '@DS' =>
1820
  array (
1827
  ),
1828
  '@DU' =>
1829
  array (
1830
+ 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
1831
  ),
1832
  '@DW' =>
1833
  array (
1950
  array (
1951
  0 => '(bq|Aquaris|Edison|Maxwell)!!',
1952
  1 => 'edgejr',
1953
+ 2 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
1954
  3 => 'edenTAB ET-701',
1955
  ),
1956
  '@EE' =>
1986
  4 => 'ELIFE-E3',
1987
  5 => 'Elife E5',
1988
  6 => 'ElifeE6',
1989
+ 7 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
1990
+ 8 => 'Elektra L',
1991
+ 9 => 'Elektra XL',
1992
+ 10 => 'Electrify',
1993
+ 11 => 'Eluga A2',
1994
+ 12 => 'ELUGA A3',
1995
+ 13 => 'ELUGA A3 Pro',
1996
+ 14 => 'ELUGA I2',
1997
+ 15 => 'ELUGA I2 Activ',
1998
+ 16 => 'ELUGA I4',
1999
+ 17 => 'Eluga Arc 2',
2000
+ 18 => 'Eluga Mark 2',
2001
+ 19 => 'ELUGA Note',
2002
+ 20 => 'ELUGA Prim',
2003
+ 21 => 'ELUGA Pulse X',
2004
+ 22 => 'ELUGA Ray',
2005
+ 23 => 'ELUGA Ray Max',
2006
+ 24 => 'ELUGA Ray X',
2007
+ 25 => 'Eluga Ray 700',
2008
+ 26 => 'ELUGA Turbo',
2009
+ 27 => 'Elite',
2010
+ 28 => 'Elite 11',
2011
+ 29 => '(SENCOR )?ELEMENT!!',
2012
+ 30 => 'Elite 5.5L+',
2013
+ 31 => 'Elite 6.0L',
2014
  ),
2015
  '@EM' =>
2016
  array (
2017
  0 => 'EMBT3C',
2018
  1 => 'EM63',
2019
  2 => 'EM01F',
2020
+ 3 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
2021
+ 4 => 'eMAX mini',
2022
+ 5 => 'EMR1879',
2023
  ),
2024
  '@EN' =>
2025
  array (
2080
  8 => 'EVO ?3D!',
2081
  9 => 'EVO 4G',
2082
  10 => 'Evo V 4G',
2083
+ 11 => '(HUAWEI )?(ALP|BLA|CRR|EVR|HMA|LIO|LON|LYA|MATE|MHA|MT1|MT2|MT7|M200|NXT|SNE|TAS|Z100)!!',
2084
+ 12 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
2085
+ 13 => '(EV|KM)-[ES][0-9]{3,3}!!',
2086
+ 14 => 'Event',
2087
+ 15 => 'EVERY35',
2088
  ),
2089
  '@EX' =>
2090
  array (
2160
  array (
2161
  0 => 'FIH-FB0',
2162
  1 => 'FIH-!!',
2163
+ 2 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
2164
  3 => 'Find 5',
2165
  4 => 'FIND7',
2166
  ),
2199
  25 => 'Flylife!!',
2200
  26 => 'Fly Flylife Web 7.85 Slim',
2201
  27 => 'Flyer',
2202
+ 28 => '(HW-|HUAWEI )?(ATU|DRA|FLA|JKM|TIT|TAG||MRD|NCE|POT|TRT|SLA)!!',
2203
+ 29 => 'Flair E1',
2204
+ 30 => 'Flair E2',
2205
+ 31 => 'FlairE3',
2206
+ 32 => 'Flair P1',
2207
+ 33 => 'Flair P1i',
2208
+ 34 => 'Flair P8',
2209
+ 35 => 'Flair S1',
2210
+ 36 => 'Flair Z1',
2211
  ),
2212
  '@FN' =>
2213
  array (
2245
  '@FR' =>
2246
  array (
2247
  0 => 'Freelander I20',
2248
+ 1 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
2249
  2 => '(MODECOM )?FreeTAB!!',
2250
  ),
2251
  '@FS' =>
2253
  0 => 'FS403',
2254
  1 => 'FS407',
2255
  2 => 'FS451',
2256
+ 3 => 'FS514',
2257
  ),
2258
  '@FT' =>
2259
  array (
2278
  1 => 'FZ-A2A',
2279
  2 => 'FZ-B2(B|D)!',
2280
  3 => 'FZ-N1',
2281
+ 4 => 'FZ-T1',
2282
+ 5 => 'FZ-X1',
2283
  ),
2284
  '@G ' =>
2285
  array (
2326
  ),
2327
  '@G6' =>
2328
  array (
2329
+ 0 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
2330
  ),
2331
  '@G7' =>
2332
  array (
2333
+ 0 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
2334
  ),
2335
  '@G9' =>
2336
  array (
2497
  ),
2498
  '@GM' =>
2499
  array (
2500
+ 0 => 'GM190[0135]!',
2501
+ 1 => 'GM191[01357]!',
2502
+ 2 => 'Gm Discovery',
2503
+ 3 => 'GM Discovery II',
2504
+ 4 => 'GM Discovery II+',
2505
+ 5 => 'GM FOX',
2506
+ 6 => 'GM Ultimate Slim',
2507
+ 7 => 'GM 5',
2508
+ 8 => 'GM 5 d',
2509
+ 9 => 'GM 5 Plus',
2510
+ 10 => 'GM 5 Plus d',
2511
+ 11 => 'GM 6',
2512
+ 12 => 'GM 6 d',
2513
+ 13 => 'GM 8 d',
2514
+ 14 => 'GM Discovery tab 8',
2515
  ),
2516
  '@GN' =>
2517
  array (
2587
  10 => '(Google )?Nexus ?9!',
2588
  11 => '(Google )?Nexus ?10!',
2589
  12 => 'Google Pixel',
2590
+ 13 => 'Google Pixel 2',
2591
+ 14 => 'Google Pixel 2XL',
2592
+ 15 => 'Google Chromebook Pixel (2015)',
2593
+ 16 => 'google cube',
2594
+ 17 => 'GOCL!!',
2595
+ 18 => 'GO Live!!',
2596
+ 19 => 'GOOPHONE!!',
2597
+ 20 => 'GO !!',
2598
+ 21 => 'GOA',
2599
+ 22 => 'GO504',
2600
+ 23 => 'GO778',
2601
+ 24 => 'GO960',
2602
+ 25 => 'GO963',
2603
+ 26 => 'GO980',
2604
+ 27 => 'GO984',
2605
+ 28 => 'Gomobile GO1001',
 
2606
  ),
2607
  '@GP' =>
2608
  array (
2620
  array (
2621
  0 => 'Grouper',
2622
  1 => 'GR-TB!!',
2623
+ 2 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
2624
  3 => 'greenridge',
2625
  4 => 'Graphos A10',
2626
  5 => '(ZTE )?(Grand|Mimosa)!!',
2682
  ),
2683
  '@H3' =>
2684
  array (
2685
+ 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
2686
  ),
2687
  '@H6' =>
2688
  array (
2689
+ 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
2690
  ),
2691
  '@H7' =>
2692
  array (
2694
  1 => 'H7100',
2695
  2 => 'H7500+',
2696
  3 => 'H710VL',
2697
+ 4 => 'H715BL',
2698
  ),
2699
  '@H8' =>
2700
  array (
2732
  0 => 'HD2',
2733
  1 => 'HD2 LEO',
2734
  2 => 'HD7 Pro',
2735
+ 3 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
2736
+ 4 => 'HD190[01]!',
2737
+ 5 => 'HD191[03]!',
2738
  ),
2739
  '@HE' =>
2740
  array (
2770
  '@HL' =>
2771
  array (
2772
  0 => 'HLV-T!!',
2773
+ 1 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
2774
  ),
2775
  '@HM' =>
2776
  array (
2777
+ 0 => '(HUAWEI )?(ALP|BLA|CRR|EVR|HMA|LIO|LON|LYA|MATE|MHA|MT1|MT2|MT7|M200|NXT|SNE|TAS|Z100)!!',
2778
+ 1 => 'HMP8100 ATV 93',
2779
+ 2 => 'HMP8100 ATV INT',
2780
+ 3 => '(Xiaomi )?(Redmi|RedRice|HM)!!',
2781
+ 4 => '(Xiaomi )?(Redmi|HM)[ \\-]?Note!!',
2782
+ 5 => '(Xiaomi |HM)?20!!',
2783
  ),
2784
  '@HN' =>
2785
  array (
2786
+ 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
2787
  ),
2788
  '@HO' =>
2789
  array (
2790
  0 => 'HOSIN!!',
2791
+ 1 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
2792
  2 => 'Honor3c2G-T',
2793
  3 => 'Honor Bee',
2794
  4 => 'HOMESYNCT2WIFI',
2845
  6 => 'Huawei MediaPad T1 10 4G',
2846
  7 => '(Huawei )?[MSTX](1|2|7|8|10)\\-[A-Z0-9][0-9]{2,2}!!',
2847
  8 => 'HUAWEI GEM-703L',
2848
+ 9 => '(HUAWEI )?(ALP|BLA|CRR|EVR|HMA|LIO|LON|LYA|MATE|MHA|MT1|MT2|MT7|M200|NXT|SNE|TAS|Z100)!!',
2849
+ 10 => '(HW-|HUAWEI )?(ATU|DRA|FLA|JKM|TIT|TAG||MRD|NCE|POT|TRT|SLA)!!',
2850
+ 11 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
2851
  12 => '(HW-|HUAWEI )?(BLL|CHC|TAG|KII)!!',
2852
+ 13 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
2853
  14 => 'HUAWEI A168-(AL10|DL09|L09|L29)!',
2854
+ 15 => '(HW-|HUAWEI )?(CRO|LUA|CUN|SCC|SCU|CAM|LDN|LYO|MYA)!!',
2855
  16 => '(HW-|HUAWEI )?CAZ-(AL10|TL10|TL20)!',
2856
  17 => '(HW-|HUAWEI )?CAN-(L01|L11|L12)!',
2857
  18 => '(HW-|HUAWEI )?MLA-(L01|L03|L11|L12|L13)!',
2858
  19 => '(HW-|HUAWEI )?DIG-(AL00|L01|L03|L21|TL10)!',
2859
+ 20 => '(HW-|HUAWEI )?BAC-(AL00|L03|L21|L22|TL00)!',
2860
+ 21 => '(HW-|HUAWEI )?HWI-(AL00|TL00)!',
2861
+ 22 => '(HW-|HUAWEI )?PAR-(AL00|LX1|LX1M|LX9|TL00)!',
2862
+ 23 => '(HW-|HUAWEI )?INE-(AL00|LX1|LX1r|LX2||LX2r|TL00)!',
2863
+ 24 => '(HW-|HUAWEI )?MAR-(AL00|LX1A|LX1M|LX2|LX3A|TL00)!',
2864
+ 25 => '(HW-|HUAWEI )?MLA-(AL00|AL10)!',
2865
+ 26 => '(HW-|HUAWEI )?MLA-(TL00|TL10|UL00)!',
2866
+ 27 => 'Huawei P7 mini',
2867
+ 28 => 'Huawei P8max',
2868
+ 29 => '(Huawei|Ascend|HW-)!!',
2869
+ 30 => 'HUAWEI Honor 3c w',
2870
+ 31 => 'Huawei S7',
2871
+ 32 => 'Hudl HT7S3',
2872
+ 33 => 'Hudl 2',
2873
+ 34 => 'HUAWEI U8686',
2874
+ 35 => 'Huawei 858',
2875
  ),
2876
  '@HW' =>
2877
  array (
2878
+ 0 => '(HW-|HUAWEI )?(ATU|DRA|FLA|JKM|TIT|TAG||MRD|NCE|POT|TRT|SLA)!!',
2879
+ 1 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
2880
  2 => '(HW-|HUAWEI )?(BLL|CHC|TAG|KII)!!',
2881
+ 3 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
2882
+ 4 => '(HW-|HUAWEI )?(CRO|LUA|CUN|SCC|SCU|CAM|LDN|LYO|MYA)!!',
2883
  5 => '(HW-|HUAWEI )?CAZ-(AL10|TL10|TL20)!',
2884
  6 => '(HW-|HUAWEI )?CAN-(L01|L11|L12)!',
2885
  7 => '(HW-|HUAWEI )?MLA-(L01|L03|L11|L12|L13)!',
2886
  8 => '(HW-|HUAWEI )?DIG-(AL00|L01|L03|L21|TL10)!',
2887
+ 9 => '(HW-|HUAWEI )?BAC-(AL00|L03|L21|L22|TL00)!',
2888
+ 10 => '(HW-|HUAWEI )?HWI-(AL00|TL00)!',
2889
+ 11 => '(HW-|HUAWEI )?PAR-(AL00|LX1|LX1M|LX9|TL00)!',
2890
+ 12 => '(HW-|HUAWEI )?INE-(AL00|LX1|LX1r|LX2||LX2r|TL00)!',
2891
+ 13 => '(HW-|HUAWEI )?MAR-(AL00|LX1A|LX1M|LX2|LX3A|TL00)!',
2892
+ 14 => '(HW-|HUAWEI )?MLA-(AL00|AL10)!',
2893
+ 15 => '(HW-|HUAWEI )?MLA-(TL00|TL10|UL00)!',
2894
+ 16 => '(Huawei|Ascend|HW-)!!',
2895
+ 17 => 'hwu8812D',
2896
+ 18 => 'HW-01E',
2897
+ 19 => 'HW-01K',
2898
+ 20 => 'HW-03E',
2899
+ 21 => 'HWT31',
2900
+ 22 => 'HWV32',
2901
  ),
2902
  '@HY' =>
2903
  array (
3021
  7 => 'Incredible ?2!',
3022
  8 => 'Incredible 4G LTE',
3023
  9 => 'Inspire 4G',
3024
+ 10 => '(HW-|HUAWEI )?INE-(AL00|LX1|LX1r|LX2||LX2r|TL00)!',
3025
+ 11 => 'INFOBAR!!',
3026
+ 12 => 'Infinix!!',
3027
+ 13 => 'IN[0-9]{3,3}!!',
3028
+ 14 => 'Infocus!!',
3029
+ 15 => 'INHON PAPILIO G1',
3030
+ 16 => 'intki E86',
3031
+ 17 => 'Innos!!',
3032
+ 18 => '(Intex )?Aqua!!',
3033
+ 19 => '(Intex )?Cloud!!',
3034
+ 20 => 'INTEX IRIS-II',
3035
+ 21 => 'INQ Cloud Touch',
3036
+ 22 => 'INQ Mayfair (EU)',
3037
+ 23 => '(iNote|itel)!!',
3038
+ 24 => 'Infinity',
3039
+ 25 => 'Internet TV',
3040
+ 26 => 'Internet TV Box',
3041
  ),
3042
  '@IO' =>
3043
  array (
3119
  '@JD' =>
3120
  array (
3121
  0 => 'JDN-W09',
3122
+ 1 => 'JDN2-AL00HN',
3123
+ 2 => 'JDN2-W09HN',
3124
  ),
3125
  '@JI' =>
3126
  array (
3131
  array (
3132
  0 => 'JJ5S+',
3133
  ),
3134
+ '@JK' =>
3135
+ array (
3136
+ 0 => '(HW-|HUAWEI )?(ATU|DRA|FLA|JKM|TIT|TAG||MRD|NCE|POT|TRT|SLA)!!',
3137
+ ),
3138
+ '@JM' =>
3139
+ array (
3140
+ 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
3141
+ ),
3142
  '@JO' =>
3143
  array (
3144
  0 => 'Jolla',
3145
  1 => 'Joy',
3146
  2 => 'JOIN',
3147
  ),
3148
+ '@JS' =>
3149
+ array (
3150
+ 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
3151
+ ),
3152
  '@JT' =>
3153
  array (
3154
  0 => 'JT SmartPC02',
3267
  14 => 'KFGIWI',
3268
  15 => 'KFDOWI',
3269
  16 => 'KFSUWI',
3270
+ 17 => 'KFMAWI',
3271
+ 18 => 'KFMUWI',
3272
  ),
3273
  '@KI' =>
3274
  array (
3275
  0 => 'Kindle Fire',
3276
+ 1 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
3277
  2 => '(HW-|HUAWEI )?(BLL|CHC|TAG|KII)!!',
3278
  3 => 'KIOTO 793',
3279
  4 => 'KITE',
3285
  ),
3286
  '@KN' =>
3287
  array (
3288
+ 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
3289
  ),
3290
  '@KO' =>
3291
  array (
3384
  ),
3385
  '@LD' =>
3386
  array (
3387
+ 0 => '(HW-|HUAWEI )?(CRO|LUA|CUN|SCC|SCU|CAM|LDN|LYO|MYA)!!',
3388
  1 => 'LDK-ICK v1.4',
3389
  ),
3390
  '@LE' =>
3524
  12 => 'LG-DS1203',
3525
  13 => 'LG-?E[0-9]{3,3}!!',
3526
  14 => 'LG-F[0-9]{3,3}!!',
3527
+ 15 => 'LG-FL40L!',
3528
+ 16 => 'LG-GT540!',
3529
+ 17 => 'LG-GW620!',
3530
+ 18 => 'LG-H[0-9]{3,3}!!',
3531
+ 19 => 'LG-K[0-9]{3,3}!!',
3532
+ 20 => 'LG-KH5200',
3533
+ 21 => 'LG-KS1024',
3534
+ 22 => 'LG-KU[0-9]{4,4}!!',
3535
+ 23 => 'LG-?L[0-9]{2,3}[A-Z]!!',
3536
+ 24 => 'LG-LG[0-9]{3,3}!!',
3537
+ 25 => 'LGLK430',
3538
+ 26 => 'LG-LK460',
3539
+ 27 => 'LG-?LS[0-9]{3,3}!!',
3540
+ 28 => 'LG-LU[0-9]{4,4}!!',
3541
+ 29 => 'LG-LW690',
3542
+ 30 => 'LG-LW770',
3543
+ 31 => 'LG-M[0-9]{3,3}!!',
3544
+ 32 => 'LG-?MS[0-9]{3,3}!!',
3545
+ 33 => 'LGMP260',
3546
+ 34 => 'LG-P[0-9]{3,3}!!',
3547
+ 35 => 'LG-Q710!',
3548
+ 36 => 'LG-RS988!',
3549
+ 37 => 'LG-SP[0-9]{3,3}!!',
3550
+ 38 => 'LG-SU[0-9]{3,3}!!',
3551
+ 39 => 'LG-T480!',
3552
+ 40 => 'LG-T540!',
3553
+ 41 => 'LG-TP260',
3554
+ 42 => 'LG-TP450',
3555
+ 43 => 'LG-SU-760',
3556
+ 44 => 'LGUK410',
3557
+ 45 => 'LG-UK495',
3558
+ 46 => 'LGUK750',
3559
+ 47 => 'LGUK932',
3560
+ 48 => 'LG-UN350',
3561
+ 49 => 'LG-?US[0-9]{3,3}!!',
3562
+ 50 => 'LG-V[0-9]{3,3}!!',
3563
+ 51 => 'LG-VK[0-9]{3,3}!!',
3564
+ 52 => 'LG-VN[0-9]{3,3}!!',
3565
+ 53 => 'LG-VM[0-9]{3,3}!!',
3566
+ 54 => 'LG-VS[0-9]{3,3}!!',
3567
+ 55 => 'LG-X[0-9]{3,3}!!',
3568
+ 56 => 'LGM-[GKVX][0-9]{3,3}!!',
3569
+ 57 => 'LGMP450',
3570
+ 58 => 'lge-F160!',
3571
+ 59 => 'LGE-E988!',
3572
+ 60 => 'lgp-970',
3573
+ 61 => 'LG[LSTV][0-9]{2,2}!!',
3574
+ 62 => 'LG!!',
3575
+ 63 => 'LG-Google TV!!',
3576
+ 64 => 'LG-ANDROID MINI BOX',
3577
+ 65 => 'LG-P999',
3578
+ 66 => 'LG-E739',
3579
+ 67 => 'LG-C800',
3580
  ),
3581
  '@LI' =>
3582
  array (
3583
  0 => 'Liquid!!',
3584
  1 => '(BLU|DASH|LIFE|NEO|STUDIO|VIVO)!!',
3585
  2 => 'Liberty',
3586
+ 3 => '(HUAWEI )?(ALP|BLA|CRR|EVR|HMA|LIO|LON|LYA|MATE|MHA|MT1|MT2|MT7|M200|NXT|SNE|TAS|Z100)!!',
3587
+ 4 => '(MEDION|(MD )?LIFETAB)!!',
3588
+ 5 => 'Life',
3589
+ 6 => 'Liberty Tab G100',
3590
+ 7 => 'Live ?With ?Walkman!',
3591
+ 8 => 'libra',
3592
+ 9 => 'lithium',
3593
+ 10 => 'Light Tab',
3594
+ 11 => 'Light Tab 2',
3595
+ 12 => 'Light Tab 2W',
3596
  ),
3597
  '@LL' =>
3598
  array (
3599
+ 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
3600
+ 1 => '(Lanix )?(Ilium|llium)!!',
3601
+ ),
3602
+ '@LM' =>
3603
+ array (
3604
+ 0 => 'LM-G710!',
3605
+ 1 => 'LM-G715!',
3606
+ 2 => 'LM-G810!',
3607
+ 3 => 'LM-G820!',
3608
+ 4 => 'LM-Q610!',
3609
+ 5 => 'LM-Q617!',
3610
+ 6 => 'LM-Q710!',
3611
+ 7 => 'LM-Q720!',
3612
+ 8 => 'LM-Q725!',
3613
+ 9 => 'LM-Q815!',
3614
+ 10 => 'LM-Q850!',
3615
+ 11 => 'LM-Q910!',
3616
+ 12 => 'LM-Q925!',
3617
+ 13 => 'LM-V350!',
3618
+ 14 => 'LM-V40[59]!',
3619
+ 15 => 'LM-V450!',
3620
+ 16 => 'LM-V500!',
3621
+ 17 => 'LM-X120!',
3622
+ 18 => 'LM-X210!',
3623
+ 19 => 'LM-X212!',
3624
+ 20 => 'LM-X220!',
3625
+ 21 => 'LM-X320!',
3626
+ 22 => 'LM-X410!',
3627
+ 23 => 'LM-X415!',
3628
+ 24 => 'LM-X420!',
3629
+ 25 => 'LM-X510!',
3630
+ 26 => 'LM-X525!',
3631
+ 27 => 'LM-X625!',
3632
+ 28 => 'LM-Y110!',
3633
  ),
3634
  '@LO' =>
3635
  array (
3636
  0 => 'LogicPD Zoom2',
3637
+ 1 => '(HUAWEI )?(ALP|BLA|CRR|EVR|HMA|LIO|LON|LYA|MATE|MHA|MT1|MT2|MT7|M200|NXT|SNE|TAS|Z100)!!',
3638
  2 => 'Loox',
3639
  ),
3640
+ '@LR' =>
3641
+ array (
3642
+ 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
3643
+ ),
3644
  '@LS' =>
3645
  array (
3646
  0 => 'LS670',
3695
  1 => 'LUXURY 3',
3696
  2 => 'LUXURY 4',
3697
  3 => 'LUXURY 5',
3698
+ 4 => '(HW-|HUAWEI )?(CRO|LUA|CUN|SCC|SCU|CAM|LDN|LYO|MYA)!!',
3699
  5 => 'Lucky Ultra Sonic U8650',
3700
  6 => 'LU2300',
3701
  7 => 'Lumia800',
3711
  ),
3712
  '@LY' =>
3713
  array (
3714
+ 0 => '(HUAWEI )?(ALP|BLA|CRR|EVR|HMA|LIO|LON|LYA|MATE|MHA|MT1|MT2|MT7|M200|NXT|SNE|TAS|Z100)!!',
3715
+ 1 => '(HW-|HUAWEI )?(CRO|LUA|CUN|SCC|SCU|CAM|LDN|LYO|MYA)!!',
3716
+ 2 => 'LYF LS-4006',
3717
+ 3 => 'LYF LS-5009',
3718
  ),
3719
  '@M' =>
3720
  array (
3745
  '@M1' =>
3746
  array (
3747
  0 => 'M19',
3748
+ 1 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
3749
  2 => 'M1050S',
3750
  3 => 'M1',
3751
  4 => 'm1 metal',
3755
  ),
3756
  '@M2' =>
3757
  array (
3758
+ 0 => '(HUAWEI )?(ALP|BLA|CRR|EVR|HMA|LIO|LON|LYA|MATE|MHA|MT1|MT2|MT7|M200|NXT|SNE|TAS|Z100)!!',
3759
  1 => 'M210',
3760
  2 => 'm2 note',
3761
  3 => 'm2',
3843
  2 => 'manta',
3844
  3 => '(bq|Aquaris|Edison|Maxwell)!!',
3845
  4 => '(DNS )?(Airtab )?(E|ES|M|MA|MC|MF|MW|P|PC|PF)[0-9]{2,4}!!',
3846
+ 5 => '(HUAWEI )?(ALP|BLA|CRR|EVR|HMA|LIO|LON|LYA|MATE|MHA|MT1|MT2|MT7|M200|NXT|SNE|TAS|Z100)!!',
3847
+ 6 => '(HW-|HUAWEI )?MAR-(AL00|LX1A|LX1M|LX2|LX3A|TL00)!',
3848
+ 7 => 'MAX FIND 5.0',
3849
+ 8 => 'Malata!!',
3850
+ 9 => 'Masstel!!',
3851
+ 10 => 'MASTONE!!',
3852
+ 11 => 'Maxtron!!',
3853
+ 12 => 'magi',
3854
+ 13 => 'MagicBox',
3855
+ 14 => '(Xiaomi )?(MI )?MAX$!',
3856
+ 15 => '(Xiaomi )?(MI )?MAX 2$!',
3857
+ 16 => '(Xiaomi )?(MI )?MAX 3$!',
3858
+ 17 => 'markf',
3859
+ 18 => 'markw',
3860
  ),
3861
  '@MB' =>
3862
  array (
3901
  16 => 'Mediacom 810C',
3902
  17 => '(MEDION|(MD )?LIFETAB)!!',
3903
  18 => 'MEEG!!',
3904
+ 19 => 'MEIZU E3',
3905
+ 20 => 'meizu m1note',
3906
+ 21 => 'MEIZU M5',
3907
+ 22 => 'MEIZU M9',
3908
+ 23 => 'MEIZU MX',
3909
+ 24 => 'Meizu S6',
3910
+ 25 => '(MEO )?Smart A!!',
3911
+ 26 => 'MEU AN!!',
3912
+ 27 => 'ME[0-9]{3,3}!!',
3913
+ 28 => 'MEM02',
3914
+ 29 => 'MegaFon SP-AI',
3915
+ 30 => 'MegaFon SP-A3',
3916
+ 31 => 'MegaFon SP-A5',
3917
+ 32 => 'MegaFon SP-A10',
3918
+ 33 => 'MegaFon V9',
3919
+ 34 => 'MegaFon V9+',
3920
+ 35 => 'MegaFon SIM+',
3921
+ 36 => 'MegaFon Login 3',
3922
  ),
3923
  '@MF' =>
3924
  array (
3930
  '@MH' =>
3931
  array (
3932
  0 => 'MH350',
3933
+ 1 => '(HUAWEI )?(ALP|BLA|CRR|EVR|HMA|LIO|LON|LYA|MATE|MHA|MT1|MT2|MT7|M200|NXT|SNE|TAS|Z100)!!',
3934
  ),
3935
  '@MI' =>
3936
  array (
3970
  33 => '(CSL[- ])?(Spice[- ]?)?Mi(-| )?[0-9]{3,3}!!',
3971
  34 => 'miTab!!',
3972
  35 => '(Xiaomi )?(Xiaomi|Xiaomi M|MI)!!',
3973
+ 36 => 'MI 8',
3974
+ 37 => 'MI 8 SE',
3975
+ 38 => 'MI 8 UD',
3976
+ 39 => 'MI 8 Lite',
3977
+ 40 => 'MI 9',
3978
+ 41 => 'Mi 9T Pro',
3979
+ 42 => 'Mi9 Pro 5G',
3980
+ 43 => '(Xiaomi|Xiaomi Mi|MI) Note!!',
3981
+ 44 => '(Xiaomi )?(MI )?MAX$!',
3982
+ 45 => '(Xiaomi )?(MI )?MAX 2$!',
3983
+ 46 => '(Xiaomi )?(MI )?MAX 3$!',
3984
+ 47 => '(Xiaomi )?(MI )?MIX$!',
3985
+ 48 => '(Xiaomi )?(MI )?MIX 2$!',
3986
+ 49 => '(Xiaomi )?(MI )?MIX 2S$!',
3987
+ 50 => 'mido',
3988
+ 51 => '(Xiaomi|Xiaomi Mi|MI) Pad!!',
3989
+ 52 => '(Xiaomi|Xiaomi Mi|MI)Box!!',
3990
+ 53 => '(Xiaomi|Xiaomi Mi|MI)TV!!',
3991
+ 54 => '(ZTE )?(Grand|Mimosa)!!',
3992
  ),
3993
  '@MK' =>
3994
  array (
4031
  13 => 'MOGU!!',
4032
  14 => 'moii!!',
4033
  15 => 'MORAL N01',
4034
+ 16 => 'motorola one',
4035
+ 17 => 'motorola one action',
4036
+ 18 => 'motorola one macro',
4037
+ 19 => 'motorola one power',
4038
+ 20 => 'motorola one vision',
4039
+ 21 => 'motorola one zoom',
4040
+ 22 => 'Moto Droid',
4041
+ 23 => 'Motorola Pro XT610',
4042
+ 24 => 'Motorola Milestone MAXX',
4043
+ 25 => 'Motorola Backflip Me600',
4044
+ 26 => 'Moto ME860',
4045
+ 27 => 'Moto C',
4046
+ 28 => 'Moto C Plus',
4047
+ 29 => '(Moto)?E2$!',
4048
+ 30 => '(Moto)?E2\\(4G-LTE\\)$!',
4049
+ 31 => 'Motorola MotoE2!',
4050
+ 32 => 'Moto E4',
4051
+ 33 => 'Moto E (4)',
4052
+ 34 => 'Moto E (4) Plus',
4053
+ 35 => 'moto e5 cruise',
4054
+ 36 => 'moto e5 play',
4055
+ 37 => '(Moto)?G3$!',
4056
+ 38 => '(Moto)?G3-TE$!',
4057
+ 39 => 'Moto G 2015',
4058
+ 40 => 'Moto G (2015)',
4059
+ 41 => 'Moto G (2014',
4060
+ 42 => 'MOTOROLA MOTOG',
4061
+ 43 => 'Moto G Play',
4062
+ 44 => 'Moto G Turbo',
4063
+ 45 => 'Moto G4',
4064
+ 46 => 'Moto G (4',
4065
+ 47 => 'Moto G (4)',
4066
+ 48 => 'Moto G4 Plus',
4067
+ 49 => 'Moto G 5',
4068
+ 50 => 'Moto G (5',
4069
+ 51 => 'Moto G (5)',
4070
+ 52 => 'Moto G (5) Plus',
4071
+ 53 => 'Moto G (5S',
4072
+ 54 => 'Moto G (5S)',
4073
+ 55 => 'Moto G (5S) Plus',
4074
+ 56 => 'moto g(6',
4075
+ 57 => 'moto g(6)',
4076
+ 58 => 'moto g(6) (XT1925DL)',
4077
+ 59 => 'moto g(6) forge',
4078
+ 60 => 'moto g(6) play',
4079
+ 61 => 'moto g(6) plus',
4080
+ 62 => 'moto g(7',
4081
+ 63 => 'moto g(7)',
4082
+ 64 => 'moto g(7) optimo (XT1952DL)',
4083
+ 65 => 'moto g(7) play',
4084
+ 66 => 'moto g(7) plus',
4085
+ 67 => 'moto g(7) power',
4086
+ 68 => 'moto g(7) supra',
4087
+ 69 => 'moto g(8',
4088
+ 70 => 'Moto Z (2)',
4089
+ 71 => 'Moto Z2 Play',
4090
+ 72 => 'Moto X Pro',
4091
+ 73 => 'moto x4',
4092
+ 74 => 'Moto Backflip',
4093
+ 75 => 'MOTOROLA XOOM MZ606',
4094
+ 76 => 'MOTOROLA RAZR',
4095
+ 77 => 'MOTWX435KT',
4096
+ 78 => '(PLOYER-)?MOMO!!',
4097
+ 79 => 'MOB-5045',
4098
+ 80 => 'Mobii 7',
4099
+ 81 => 'MoFing',
4100
+ 82 => 'mocha',
4101
+ 83 => 'MO-01J',
4102
+ 84 => 'MO-01K',
4103
+ 85 => 'Movistar Express',
4104
+ 86 => 'Movistar Link',
4105
+ 87 => 'Movistar Motion',
4106
+ 88 => 'Movistar Prime',
4107
+ 89 => 'MOVE',
4108
  ),
4109
  '@MP' =>
4110
  array (
4128
  17 => 'MPQC804HD',
4129
  18 => 'MPQC1010',
4130
  ),
4131
+ '@MR' =>
4132
+ array (
4133
+ 0 => '(HW-|HUAWEI )?(ATU|DRA|FLA|JKM|TIT|TAG||MRD|NCE|POT|TRT|SLA)!!',
4134
+ ),
4135
  '@MS' =>
4136
  array (
4137
  0 => 'MStar Amber3',
4188
  28 => 'mt8580!',
4189
  29 => 'mt8658!',
4190
  30 => '(AC|BC|LC|MT|RC|QS|VM|TS|OC)[0-9]{4,4}[A-Z]!!',
4191
+ 31 => '(HUAWEI )?(ALP|BLA|CRR|EVR|HMA|LIO|LON|LYA|MATE|MHA|MT1|MT2|MT7|M200|NXT|SNE|TAS|Z100)!!',
4192
  32 => 'MTC Android',
4193
  33 => 'MT791',
4194
  34 => 'MT70[0-9]{2,2}!!',
4242
  ),
4243
  '@MY' =>
4244
  array (
4245
+ 0 => '(HW-|HUAWEI )?(CRO|LUA|CUN|SCC|SCU|CAM|LDN|LYO|MYA)!!',
4246
  1 => 'MyPhone A818g Duo',
4247
  2 => 'MyPhone A818 Slim Duo',
4248
  3 => 'MyPhone A848 Duo',
4307
  0 => 'MZ-m2 note',
4308
  1 => 'MZ-M571C',
4309
  2 => 'MZ-m3 note',
4310
+ 3 => 'MZ-M5',
4311
+ 4 => 'MZ-MEIZU M6',
4312
+ 5 => 'MZ-MX4',
4313
+ 6 => 'MZ-MX4 Pro',
4314
+ 7 => 'MZ-MX5',
4315
+ 8 => 'MZ[0-9]{3,3}!!',
4316
  ),
4317
  '@N-' =>
4318
  array (
4399
  ),
4400
  '@NC' =>
4401
  array (
4402
+ 0 => '(HW-|HUAWEI )?(ATU|DRA|FLA|JKM|TIT|TAG||MRD|NCE|POT|TRT|SLA)!!',
4403
  ),
4404
  '@NE' =>
4405
  array (
4436
  30 => '(BLU|DASH|LIFE|NEO|STUDIO|VIVO)!!',
4437
  31 => 'NexusHD2',
4438
  32 => 'Nexus HD2',
4439
+ 33 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
4440
  34 => 'Neon7',
4441
  35 => 'Neon9',
4442
  36 => '(NetTab|NT-)!!',
4527
  ),
4528
  '@NM' =>
4529
  array (
4530
+ 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
4531
  1 => '(NMP|MBR|XDK|XDS|XMP)\\-!!',
4532
  ),
4533
  '@NO' =>
4577
  42 => '(NOOK )?BNTV250!',
4578
  43 => '(NOOK )?BNRV350!',
4579
  44 => '(NOOK )?BNTV(400)!',
4580
+ 45 => '(NOOK )?BNTV(450)!',
4581
+ 46 => '(NOOK )?BNTV(600)!',
4582
+ 47 => '(NOOK )?BNTV(800)!',
4583
+ 48 => 'Nook HD',
4584
+ 49 => 'Nook HD+',
4585
+ 50 => 'Novapad!!',
4586
+ 51 => 'Nova!!',
4587
+ 52 => 'Now',
4588
+ 53 => 'NO1 S6',
4589
+ 54 => 'NOAIN!!',
4590
+ 55 => 'Nokia 1 Plus',
4591
+ 56 => 'Nokia 1',
4592
+ 57 => 'Nokia 2.1',
4593
+ 58 => 'Nokia 2',
4594
+ 59 => 'Nokia 3.1 Plus',
4595
+ 60 => 'Nokia 3.1',
4596
+ 61 => 'Nokia 4.2',
4597
+ 62 => 'Nokia 5.1 Plus',
4598
+ 63 => 'Nokia 5.1',
4599
+ 64 => 'Nokia 6.1 Plus',
4600
+ 65 => 'Nokia 6.1',
4601
+ 66 => 'Nokia 6.2',
4602
+ 67 => 'Nokia 6',
4603
+ 68 => 'Nokia 7.1',
4604
+ 69 => 'Nokia 7 Plus',
4605
+ 70 => 'Nokia 8.1',
4606
+ 71 => 'Nokia 8 Sirocco',
4607
+ 72 => 'Nokia 8',
4608
+ 73 => 'Nokia 9',
4609
+ 74 => 'Nokia 10.1',
4610
+ 75 => 'Nokia N9',
4611
+ 76 => 'Nokia N900',
4612
+ 77 => 'Nokia X',
4613
+ 78 => 'Nokia X Dual SIM',
4614
+ 79 => 'Nokia X+',
4615
+ 80 => 'Nokia Xplus',
4616
+ 81 => 'Nokia XL 4G',
4617
+ 82 => 'Nokia XL',
4618
+ 83 => 'Nokia XL Dual SIM',
4619
+ 84 => 'Nokia X2',
4620
+ 85 => 'NokiaX2DS',
4621
+ 86 => 'Notion Ink ADAM',
4622
+ 87 => 'Note III',
4623
+ 88 => 'Nozomi',
4624
+ 89 => 'Noble TAB07-485',
4625
+ 90 => '(QMobile|QTab|Q-Smart|Noir)!!',
4626
  ),
4627
  '@NP' =>
4628
  array (
4656
  ),
4657
  '@NX' =>
4658
  array (
4659
+ 0 => '(HUAWEI )?(ALP|BLA|CRR|EVR|HMA|LIO|LON|LYA|MATE|MHA|MT1|MT2|MT7|M200|NXT|SNE|TAS|Z100)!!',
4660
  1 => '(Nexian )?NX-A[0-9]{3,3}!!',
4661
  2 => 'NXA8QC116',
4662
  3 => 'NX16A8116K',
4690
  '@OB' =>
4691
  array (
4692
  0 => 'OB-OPPO A31c',
4693
+ 1 => 'OB-OPPO R8205',
4694
+ 2 => 'OB-OPPO R7005',
4695
+ 3 => 'OB-OPPO R7c',
4696
+ 4 => 'OB-OPPO 1105',
4697
+ 5 => 'OB-OPPO 3005',
4698
+ 6 => 'Obreey SURFpad',
4699
  ),
4700
  '@OC' =>
4701
  array (
4887
  137 => 'ONEPLUS A3010',
4888
  138 => 'ONEPLUS A5000',
4889
  139 => 'ONEPLUS A5010',
4890
+ 140 => 'ONEPLUS A6000',
4891
+ 141 => 'ONEPLUS A6003',
4892
+ 142 => 'ONEPLUS A6010',
4893
+ 143 => 'ONEPLUS A6013',
4894
+ 144 => 'ONE E1000',
4895
+ 145 => 'ONE E1001',
4896
+ 146 => 'ONE E1003',
4897
+ 147 => 'ONE E1005',
4898
+ 148 => 'ONDA MID',
4899
+ 149 => 'ONDA A9 Core4',
4900
+ 150 => 'ONDA VI10',
4901
+ 151 => 'Onda V812',
4902
+ 152 => 'ONDA v975m',
4903
+ 153 => 'ONDA V989',
4904
+ 154 => 'ONDA V989 Core8',
4905
  ),
4906
  '@OP' =>
4907
  array (
4910
  2 => 'Opus One',
4911
  3 => 'OPS-DRD Digital Signage Player',
4912
  4 => 'OP110',
4913
+ 5 => 'OPPO PBAM00',
4914
+ 6 => 'OPPO PBFT00',
4915
+ 7 => 'OPPO A30',
4916
+ 8 => 'OPPO A31',
4917
+ 9 => 'OPPO A31t',
4918
+ 10 => 'OPPO A33',
4919
+ 11 => 'OPPO A33m',
4920
+ 12 => 'OPPO A37m',
4921
+ 13 => 'OPPO A53',
4922
+ 14 => 'OPPO A53m',
4923
+ 15 => 'OPPO A53t',
4924
+ 16 => 'OPPO A57',
4925
+ 17 => 'OPPO A57t',
4926
+ 18 => 'OPPO A59m',
4927
+ 19 => 'OPPO A59s',
4928
+ 20 => 'OPPO A59st',
4929
+ 21 => 'OPPO A73',
4930
+ 22 => 'OPPO A73t',
4931
+ 23 => 'OPPO A77',
4932
+ 24 => 'OPPO A77t',
4933
+ 25 => 'OPPO A79',
4934
+ 26 => 'OPPO A79kt',
4935
+ 27 => 'OPPO A79t',
4936
+ 28 => 'OPPO A83',
4937
+ 29 => 'OPPO A83t',
4938
+ 30 => 'OPPO A800',
4939
+ 31 => 'OPPOX905',
4940
+ 32 => 'OPPOX907',
4941
+ 33 => 'OPPO Find5',
4942
+ 34 => 'OPPOX909',
4943
+ 35 => 'OPPO X909',
4944
+ 36 => 'OPPO X9007',
4945
+ 37 => 'OPPOX9015',
4946
+ 38 => 'OPPOX9017',
4947
+ 39 => 'OPPO find7',
4948
+ 40 => 'OPPOR601',
4949
+ 41 => 'OPPOR801',
4950
+ 42 => 'OPPOR803',
4951
+ 43 => 'OPPOR805',
4952
+ 44 => 'OPPOR807',
4953
+ 45 => 'OPPO R811',
4954
+ 46 => 'OPPO R813T',
4955
+ 47 => 'OPPO R815',
4956
+ 48 => 'OPPOR817',
4957
+ 49 => 'Oppo R819',
4958
+ 50 => 'OPPO R821',
4959
+ 51 => 'OPPO R831',
4960
+ 52 => 'Oppo R831 Limited Edition',
4961
+ 53 => 'OPPO R1001',
4962
+ 54 => 'OPPOR8015',
4963
+ 55 => 'OPPOR8111',
4964
+ 56 => 'OPPOT29',
4965
+ 57 => '(OPPO-?)?T703!',
4966
+ 58 => 'OPPOU701',
4967
+ 59 => 'OPPOU7011',
4968
+ 60 => 'OPPOU7015',
4969
+ 61 => 'OPPO PBCM30',
4970
+ 62 => 'OPPO PBCT10',
4971
+ 63 => 'OPPO N1',
4972
+ 64 => 'OPPO R7',
4973
+ 65 => 'OPPO R7Plus',
4974
+ 66 => 'OPPO R7s',
4975
+ 67 => 'OPPO R7sm',
4976
+ 68 => 'OPPO R7st',
4977
+ 69 => 'OPPO R7t',
4978
+ 70 => 'OPPO R9k',
4979
+ 71 => 'OPPO R9m',
4980
+ 72 => 'OPPO R9tm',
4981
+ 73 => 'OPPO R9km',
4982
+ 74 => 'OPPO R9s',
4983
+ 75 => 'OPPO R9sk',
4984
+ 76 => 'OPPO R9st',
4985
+ 77 => 'OPPO R9skt',
4986
+ 78 => 'OPPO R9t',
4987
+ 79 => 'OPPO R11',
4988
+ 80 => 'OPPO R11t',
4989
+ 81 => 'OPPO R7 Plus',
4990
+ 82 => 'OPPO R7sPlus',
4991
+ 83 => 'OPPO R9 Plusm A',
4992
+ 84 => 'OPPO R9 Plustm A',
4993
+ 85 => 'OPPO R9s Plus',
4994
+ 86 => 'OPPO R9s Plust',
4995
+ 87 => 'OPPO R11 Plus',
4996
+ 88 => 'OPPO R11 Plusk',
4997
+ 89 => 'OPPO R11 Pluskt',
4998
+ 90 => 'OPPO R11s',
4999
+ 91 => 'OPPO R11s Plus',
5000
+ 92 => 'OPPO R11st',
5001
+ 93 => 'OPPO R11s Plust',
5002
+ 94 => 'OPPO PAAM00',
5003
+ 95 => 'OPPO PACM00',
5004
+ 96 => 'OPPO PACT00',
5005
+ 97 => 'OPPO PBDM00',
5006
+ 98 => 'OPPO PAFM00',
5007
+ 99 => 'OPSSON!!',
5008
+ 100 => 'OP0118-12',
5009
+ 101 => 'Optimus Barcelona',
5010
+ 102 => 'Optimus Boston',
5011
+ 103 => 'Optimus Madrid',
5012
+ 104 => 'Optimus Monte Carlo',
5013
+ 105 => 'Optimus San Francisco',
5014
+ 106 => 'Optimus San Remo',
5015
+ 107 => 'Optimus Zali',
5016
  ),
5017
  '@OR' =>
5018
  array (
5064
  array (
5065
  0 => '(OV-|Overmax|Vertis)!!',
5066
  ),
5067
+ '@OX' =>
5068
+ array (
5069
+ 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
5070
+ ),
5071
  '@OY' =>
5072
  array (
5073
  0 => 'Oysters Pacific 800',
5131
  array (
5132
  0 => 'P2A700',
5133
  1 => 'P2Lite',
5134
+ 2 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
5135
  ),
5136
  '@P3' =>
5137
  array (
5160
  2 => 'P6 Pro',
5161
  3 => 'P6 Qmax',
5162
  4 => 'P6 Quad',
5163
+ 5 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
5164
  ),
5165
  '@P7' =>
5166
  array (
5167
+ 0 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
5168
  1 => 'P700i',
5169
  2 => 'P701',
5170
  3 => 'P7',
5268
  15 => 'Patio100',
5269
  16 => 'Patio100 3G',
5270
  17 => 'PAD[0-9]{3,3}!!',
5271
+ 18 => '(HW-|HUAWEI )?PAR-(AL00|LX1|LX1M|LX9|TL00)!',
5272
+ 19 => 'PADM00',
5273
+ 20 => 'PADT00',
5274
+ 21 => 'PAAM00',
5275
+ 22 => 'PACM00',
5276
+ 23 => 'PACT00',
5277
+ 24 => 'PAAT00',
5278
+ 25 => 'PAFM00',
5279
+ 26 => 'PAHM00',
5280
+ 27 => 'Panasonic!!',
5281
+ 28 => 'pandigital9hr',
5282
+ 29 => 'pandigital9hr2',
5283
+ 30 => 'pandigitalopc1',
5284
+ 31 => 'pandigitalopp1',
5285
+ 32 => 'pandigitalp1hr',
5286
+ 33 => 'PantechP!!',
5287
+ 34 => 'PAT712W',
5288
+ 35 => 'PATG7506HD',
5289
+ 36 => 'PAP[0-9]{4,4}!!',
5290
+ 37 => 'PAD1001',
5291
  ),
5292
  '@PB' =>
5293
  array (
5294
  0 => 'PB99400',
5295
+ 1 => 'PBAM00',
5296
+ 2 => 'PBAT00',
5297
+ 3 => 'PBFT00',
5298
+ 4 => 'PBBM00',
5299
+ 5 => 'PBCM30',
5300
+ 6 => 'PBEM00',
5301
+ 7 => 'PBET00',
5302
+ 8 => 'PBDM00',
5303
  ),
5304
  '@PC' =>
5305
  array (
5307
  1 => '(DNS )?(Airtab )?(E|ES|M|MA|MC|MF|MW|P|PC|PF)[0-9]{2,4}!!',
5308
  2 => '(HTC|PCD|USCC)?ADR[0-9]{4,4}!!',
5309
  3 => 'PC36100!',
5310
+ 4 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
5311
+ 5 => 'PC-TE307N1W',
5312
+ 6 => 'PC-TE508BAW',
5313
+ 7 => 'PC-TS508FAM',
5314
+ 8 => 'PC-TS508T1W',
5315
+ 9 => 'PC-TS708T1W',
5316
+ 10 => 'PCGM00',
5317
+ 11 => 'PCAM00',
5318
+ 12 => 'PCAM10',
5319
+ 13 => 'PCCM00',
5320
  ),
5321
  '@PD' =>
5322
  array (
5325
  ),
5326
  '@PE' =>
5327
  array (
5328
+ 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
5329
  1 => 'PEDI',
5330
  2 => 'Penta!!',
5331
  3 => 'Pentagram!!',
5418
  3 => 'Pixel 2',
5419
  4 => 'Pixel 2XL',
5420
  5 => 'Pixel 2 XL',
5421
+ 6 => 'Pixel 3',
5422
+ 7 => 'Pixel 3 XL',
5423
+ 8 => 'Pixel 3a',
5424
+ 9 => 'Pixel 3a XL',
5425
+ 10 => 'Pixel 4',
5426
+ 11 => 'Pixel 4 XL',
5427
+ 12 => '(Axioo[\\- ])?PICO!!',
5428
+ 13 => 'picoBit-L',
5429
+ 14 => '(GIO-)?(GiONEE[- ])?Pioneer P1!',
5430
+ 15 => '(GIO-)?(GiONEE[- ])?Pioneer P2!',
5431
+ 16 => '(GIO-)?(GiONEE[- ])?Pioneer P3!',
5432
+ 17 => '(GIO-)?(GiONEE[- ])?Pioneer P4!',
5433
+ 18 => 'PixelV1',
5434
+ 19 => 'Pixel V2',
5435
+ 20 => 'Pixel V2+',
5436
+ 21 => 'PI2000',
5437
+ 22 => 'PI2010',
5438
+ 23 => 'PI2011',
5439
+ 24 => 'PI3100',
5440
+ 25 => 'PI3100-93',
5441
+ 26 => 'PI3100Z3 93',
5442
+ 27 => 'PI3105',
5443
+ 28 => 'PI3106',
5444
+ 29 => 'PI3110',
5445
+ 30 => 'PI3205G',
5446
+ 31 => 'PI3210G',
5447
+ 32 => 'PI3900',
5448
+ 33 => 'PI3900-93',
5449
+ 34 => 'PI3910',
5450
+ 35 => 'PI4010G',
5451
+ 36 => 'PI7000',
5452
+ 37 => 'PI7100 93',
5453
+ 38 => '(PNR-)?Pioneer!!',
5454
+ 39 => 'PIRANHA!!',
5455
  ),
5456
  '@PJ' =>
5457
  array (
5462
  array (
5463
  0 => 'PLE-701L',
5464
  1 => 'PLE-703L',
5465
+ 2 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
5466
  3 => 'Planet II v2',
5467
  4 => 'PLANET',
5468
  5 => 'Playboy PB-S3',
5495
  '@PO' =>
5496
  array (
5497
  0 => '(Highscreen|Alpha|Bay|Boost|Cosmo|Explosion|Power|Prime|Zera)!!',
5498
+ 1 => '(HW-|HUAWEI )?(ATU|DRA|FLA|JKM|TIT|TAG||MRD|NCE|POT|TRT|SLA)!!',
5499
+ 2 => 'PocketBook A7',
5500
+ 3 => 'PocketBook A10',
5501
+ 4 => 'PocketBook A10 3G',
5502
+ 5 => 'PocketBook SURFpad2',
5503
+ 6 => 'PocketBook SURFpad 3 (7,85")',
5504
+ 7 => 'PocketBook SURFpad 4 S',
5505
+ 8 => 'PocketBook SURFpad 4 M',
5506
+ 9 => 'PocketBook SURFpad 4 L',
5507
+ 10 => 'POV-Mobii-7',
5508
+ 11 => 'POV Mobii 7',
5509
+ 12 => 'POV TAB-P506!',
5510
+ 13 => 'POV TAB-P517!',
5511
+ 14 => 'POV TAB-P527!',
5512
+ 15 => 'POV TAB-P629!',
5513
+ 16 => 'POV TAB-P701!',
5514
+ 17 => 'POV TAB-P703!',
5515
+ 18 => 'POV TAB-P720!',
5516
+ 19 => 'POV TAB-P721A!',
5517
+ 20 => 'POV TAB-P721!',
5518
+ 21 => 'POV TAB-P722C!',
5519
+ 22 => 'POV TAB-P731N!',
5520
+ 23 => 'POV TAB-P825!',
5521
+ 24 => 'POV TAB-P925!',
5522
+ 25 => 'POV TAB-PR945!',
5523
+ 26 => 'POV TAB-P1025!',
5524
+ 27 => 'POV TAB-P1030!',
5525
+ 28 => 'POV TAB-PI1045!',
5526
+ 29 => 'POV TAB-P1325!',
5527
+ 30 => '(POV )?TAB-PLAYTABPRO!',
5528
+ 31 => '(POV )?TAB-PROTAB25!',
5529
+ 32 => '(POV )?TAB-PROTAB26!',
5530
+ 33 => 'POV TAB-PROTAB27',
5531
+ 34 => '(POV )?TAB-PROTAB30!',
5532
+ 35 => '(POV )?TAB-PROTAB2XXL(4)!',
5533
+ 36 => '(POV )?TAB NAVI7 3G M!',
5534
+ 37 => 'POV_TAB-NAVI7-3G-M',
5535
+ 38 => 'POV TAB-P547(v1.0)',
5536
+ 39 => 'POV TV-HDMI-200BT',
5537
+ 40 => 'POV TV-HDMI-200BT(V2.0)',
5538
+ 41 => 'POV TV-HDMI-210',
5539
+ 42 => 'POV TV-HDMI-KB-01',
5540
+ 43 => 'POV TV-SMARTTV-500',
5541
+ 44 => 'Polaroid PSPT401',
5542
+ 45 => 'Polaroid PSPC505',
5543
+ 46 => 'Polaroid PSPC550',
5544
+ 47 => 'Polaroid P4005A',
5545
+ 48 => 'Polaroid P5005A',
5546
+ 49 => 'Polaroid P5046A',
5547
+ 50 => 'Polaroid P5525A',
5548
+ 51 => 'Polaroid P5526A',
5549
+ 52 => 'POLY ?PAD!!',
5550
+ 53 => 'POLYTRON!!',
5551
+ 54 => 'POMP!!',
5552
+ 55 => 'Positivo Mini',
5553
+ 56 => 'POSITIVO YPY 07FTB',
5554
+ 57 => 'Positivo Ypy AB7E',
5555
+ 58 => 'Positivo Ypy AB7EC',
5556
+ 59 => 'Positivo Ypy AB7F',
5557
+ 60 => 'Positivo AB7F',
5558
+ 61 => 'Positivo Ypy AB7H',
5559
+ 62 => 'Positivo Ypy AB10E',
5560
+ 63 => 'Positivo Ypy AB10EC',
5561
+ 64 => 'Positivo Ypy AB10H',
5562
+ 65 => 'Positivo BGH Ypy L700',
5563
+ 66 => 'Positivo Ypy L700',
5564
+ 67 => 'Positivo Ypy L700 Ed. Especial',
5565
+ 68 => 'Positivo Ypy L700+',
5566
+ 69 => 'Positivo Ypy L700 Kids',
5567
+ 70 => 'Positivo BGH Ypy L700 Kids',
5568
+ 71 => 'Positivo Ypy L700+ Kids',
5569
+ 72 => 'Positivo Ypy L1000',
5570
+ 73 => 'Positivo Ypy L1000AB',
5571
+ 74 => 'Positivo Ypy L1000F',
5572
+ 75 => 'Positivo Ypy L1050',
5573
+ 76 => 'Positivo Ypy L1050E',
5574
+ 77 => 'Positivo Ypy L1050F',
5575
+ 78 => 'Positivo S380',
5576
+ 79 => 'Positivo S440',
5577
+ 80 => 'Positivo S480',
5578
+ 81 => 'Positivo S550',
5579
+ 82 => 'Positivo X400',
5580
+ 83 => 'Positivo X800',
5581
+ 84 => 'POCOPHONE F1',
5582
  ),
5583
  '@PP' =>
5584
  array (
5589
  array (
5590
  0 => 'Project Tango Tablet Development Kit',
5591
  1 => '(Highscreen|Alpha|Bay|Boost|Cosmo|Explosion|Power|Prime|Zera)!!',
5592
+ 2 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
5593
  3 => 'Pro 10 dual core',
5594
  4 => 'Prada 3.0',
5595
  5 => 'PRO 5',
5878
  3 => 'R7i',
5879
  4 => 'R7kf',
5880
  5 => 'R7sf',
5881
+ 6 => 'R7t',
5882
+ 7 => 'R7Plus',
5883
+ 8 => 'R7plusf',
5884
+ 9 => 'R7Plusm',
5885
  ),
5886
  '@R8' =>
5887
  array (
6028
  2 => 'Rikomagic MK802III',
6029
  3 => 'Rikomagic MK802IIIS',
6030
  4 => '(Gsmart|Gigabyte|Rio)!!',
6031
+ 5 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
6032
  6 => 'Rise',
6033
  7 => '(Ritmix )?RM[DP]-?[0-9]{3,3}!!',
6034
  8 => 'RIDGE',
6078
  ),
6079
  '@RN' =>
6080
  array (
6081
+ 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
6082
  ),
6083
  '@RO' =>
6084
  array (
6201
  ),
6202
  '@SC' =>
6203
  array (
6204
+ 0 => 'SCM-(AL09|W09)!',
6205
+ 1 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
6206
+ 2 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
6207
+ 3 => '(HW-|HUAWEI )?(CRO|LUA|CUN|SCC|SCU|CAM|LDN|LYO|MYA)!!',
6208
+ 4 => 'SCH-[iI][0-9]{3,3}!!',
6209
+ 5 => 'SCH-L710!',
6210
+ 6 => 'SCH-M828!',
6211
+ 7 => 'SCH-N719',
6212
+ 8 => 'SCH-P[0-9]{3,3}!!',
6213
+ 9 => 'SCH-R[0-9]{3,3}!!',
6214
+ 10 => 'SCH-S[0-9]{3,3}!!',
6215
+ 11 => 'SCH-V727',
6216
+ 12 => 'SCH-W[0-9]{3,4}!!',
6217
+ 13 => 'SC-?0[0-9][A-Z]!!',
6218
+ 14 => 'SC[LTV][23][0-9]!!',
6219
+ 15 => 'Scroll!!',
6220
+ 16 => 'SC-!!',
6221
+ 17 => 'scorpio',
6222
  ),
6223
  '@SD' =>
6224
  array (
6277
  20 => 'SH-M02',
6278
  21 => 'SH-M02-EVA20',
6279
  22 => 'SH-M03',
6280
+ 23 => 'SH-M07',
6281
+ 24 => 'SH-RM02',
6282
+ 25 => 'SH-[01][0-9][A-Z]!!',
6283
+ 26 => '(SHP-)?(SHARP )?SH[0-9]{2,3}!!',
6284
+ 27 => 'SH[FLTV][0-9]{2,2}!!',
6285
+ 28 => 'SHARP-ADS1',
6286
  ),
6287
  '@SI' =>
6288
  array (
6306
  0 => 'Slider SL101',
6307
  1 => 'SL930',
6308
  2 => '(HP|Slate)!!',
6309
+ 3 => '(HW-|HUAWEI )?(ATU|DRA|FLA|JKM|TIT|TAG||MRD|NCE|POT|TRT|SLA)!!',
6310
  4 => 'Slidepad!!',
6311
  5 => 'SLIDE',
6312
  ),
6336
  21 => 'SM-A[0-9]{3,3}!!',
6337
  22 => 'SM-C[0-9]{3,3}!!',
6338
  23 => 'SM-E[0-9]{3,3}!!',
6339
+ 24 => 'SM-F[0-9]{3,3}!!',
6340
+ 25 => 'SM-G[0-9]{3,3}!!',
6341
+ 26 => 'SM-I9500',
6342
+ 27 => 'SM-J[0-9]{3,3}!!',
6343
+ 28 => 'SM-M[0-9]{3,4}!!',
6344
+ 29 => 'SM-N[0-9]{3,4}!!',
6345
+ 30 => 'SM-P[0-9]{3,3}!!',
6346
+ 31 => 'SM-S[0-9]{3,3}!!',
6347
+ 32 => 'SM-T[0-9]{3,3}!!',
6348
+ 33 => 'SM-V700',
6349
+ 34 => 'SM-W[0-9]{4,4}!!',
6350
+ 35 => 'Smartphone Android by SFR STARADDICT II',
6351
+ 36 => '(Smartfren|Andromax)!!',
6352
+ 37 => 'Smartfren Tab 7',
6353
+ 38 => 'SM919',
6354
+ 39 => 'SM701',
6355
+ 40 => 'SM801',
6356
+ 41 => 'SmartQ!!',
6357
+ 42 => 'SMART Sprint',
6358
+ 43 => 'SMART Start',
6359
+ 44 => 'SMART Surf2 4G',
6360
+ 45 => 'SmartTab!!',
6361
  ),
6362
  '@SN' =>
6363
  array (
6364
  0 => 'SN[0-9]!!',
6365
+ 1 => '(HUAWEI )?(ALP|BLA|CRR|EVR|HMA|LIO|LON|LYA|MATE|MHA|MT1|MT2|MT7|M200|NXT|SNE|TAS|Z100)!!',
6366
+ 2 => 'Snexian!!',
6367
+ 3 => '(SNM\\-)?LT[0-9]{2,2}[a-z]?!!',
6368
+ 4 => '(SNM\\-)?M[0-9]{2,2}[a-z]!!',
6369
  ),
6370
  '@SO' =>
6371
  array (
6379
  7 => 'Softwinerf900',
6380
  8 => 'SoftwinerEvbV13',
6381
  9 => 'soho',
6382
+ 10 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
6383
  11 => 'SONIC',
6384
  12 => 'Sonim!!',
6385
  13 => 'SO-0[0-9][A-Z]!!',
6445
  12 => 'ST7001',
6446
  13 => 'ST8000',
6447
  14 => 'ST9001',
6448
+ 15 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
6449
+ 16 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
6450
+ 17 => 'ST10',
6451
+ 18 => 'ST940I-UP',
6452
+ 19 => 'STM[0-9]{3,3}H!!',
6453
+ 20 => 'Stylo',
6454
+ 21 => 'STARACTIVE',
6455
+ 22 => 'STARACTIVE 2',
6456
+ 23 => 'STARADDICT II',
6457
+ 24 => 'STARADDICT II Plus',
6458
+ 25 => 'STARADDICT III',
6459
+ 26 => 'STARADDICT 4',
6460
+ 27 => 'STARADDICT 5',
6461
+ 28 => 'STARADDICT 6',
6462
+ 29 => 'STARNAUTE II',
6463
+ 30 => 'STARNAUTE 3',
6464
+ 31 => 'STARNAUTE3',
6465
+ 32 => 'STARNAUTE4',
6466
+ 33 => 'Starshine',
6467
+ 34 => 'STARSHINE II',
6468
+ 35 => 'STARSHINE III',
6469
+ 36 => 'STARSHINE 4',
6470
+ 37 => 'STARSHINE5',
6471
+ 38 => 'STARTEXT II',
6472
+ 39 => 'STARTRAIL II',
6473
+ 40 => 'StarTrail III',
6474
+ 41 => 'STARTRAIL4',
6475
+ 42 => 'STARTRAIL 4',
6476
+ 43 => 'STARTRAIL5',
6477
+ 44 => 'STARTRAIL 6 4G',
6478
+ 45 => 'STARTRAIL6',
6479
+ 46 => 'STARTRAIL7',
6480
+ 47 => 'STARTRAIL 8',
6481
+ 48 => 'STARTRAIL 9',
6482
+ 49 => 'STARXTREM',
6483
+ 50 => 'STARXTREM II',
6484
+ 51 => 'STARXTREM3',
6485
+ 52 => 'STARXTREM 4',
6486
+ 53 => 'STARXTREM5',
6487
+ 54 => 'STARXTREM 6',
6488
+ 55 => 'STARTAB',
6489
+ 56 => 'ST[0-9]{2,2}[a-z]?!!',
6490
+ 57 => 'Star N8000',
6491
+ 58 => 'Star N9500',
6492
+ 59 => 'Star N9589',
6493
+ 60 => 'Star Q9000',
6494
+ 61 => 'STAR S5',
6495
+ 62 => 'STAR S7589',
6496
+ 63 => 'Starmobile!!',
6497
+ 64 => '(Starway )?Andromeda!!',
6498
+ 65 => 'STX!!',
6499
+ 66 => 'STOREX LinkBox',
6500
+ 67 => 'StarTab 715x',
6501
+ 68 => 'ST[0-9]{5,5}-[0-9]!!',
6502
+ 69 => 'ST-PAD',
6503
+ 70 => 'ST-PAD2',
6504
+ 71 => 'STAIRWAY',
6505
+ 72 => 'StarTrail TT',
6506
  ),
6507
  '@SU' =>
6508
  array (
6648
  5 => 'Tablet-P27',
6649
  6 => 'TA10CA3',
6650
  7 => '(tablet )?fnac!!',
6651
+ 8 => '(HUAWEI )?(ALP|BLA|CRR|EVR|HMA|LIO|LON|LYA|MATE|MHA|MT1|MT2|MT7|M200|NXT|SNE|TAS|Z100)!!',
6652
+ 9 => '(HW-|HUAWEI )?(ATU|DRA|FLA|JKM|TIT|TAG||MRD|NCE|POT|TRT|SLA)!!',
6653
+ 10 => '(HW-|HUAWEI )?(BLL|CHC|TAG|KII)!!',
6654
+ 11 => 'TA-FONE!!',
6655
+ 12 => 'TAB1011',
6656
+ 13 => 'TAB-1030',
6657
+ 14 => '(Lenovo )?(Tab ?)?(2 ?)?[AS](7|8|10)!!',
6658
+ 15 => 'TAB950',
6659
+ 16 => 'TAB1062',
6660
+ 17 => 'TAB192',
6661
+ 18 => 'TA-10(07|29)!',
6662
+ 19 => 'TA-10(84)!',
6663
+ 20 => 'TA-10(20|28|32|38)!',
6664
+ 21 => 'TA-10(24|27|44|53)!',
6665
+ 22 => 'TA-10(61|75|81|88)!',
6666
+ 23 => 'TA-10(00|03|21|25|33|39)!',
6667
+ 24 => 'TA-10(43|50|54|68)!',
6668
+ 25 => 'TA-10(41)!',
6669
+ 26 => 'TA-10(62)!',
6670
+ 27 => 'TA-10(04|12|52)!',
6671
+ 28 => 'TA-10(99)!',
6672
+ 29 => 'TA-11(03|16)!',
6673
+ 30 => '(POV )?TAB-PLAYTABPRO!',
6674
+ 31 => '(POV )?TAB-PROTAB25!',
6675
+ 32 => '(POV )?TAB-PROTAB26!',
6676
+ 33 => '(POV )?TAB-PROTAB30!',
6677
+ 34 => 'TAB-PROTAB2-IPS9',
6678
+ 35 => 'TAB-PROTAB2-IPS-3G',
6679
+ 36 => 'TAB-PROTAB2-IPS-16',
6680
+ 37 => 'TAB-PROTAB2.4',
6681
+ 38 => 'TAB-PROTAB2XL',
6682
+ 39 => 'TAB-PROTAB2.4XL',
6683
+ 40 => 'TAB-PROTAB2XXL',
6684
+ 41 => 'TAB-PROTAB2XXL(4)',
6685
+ 42 => '(POV )?TAB-PROTAB2XXL(4)!',
6686
+ 43 => '(POV )?TAB NAVI7 3G M!',
6687
+ 44 => 'Tablet P',
6688
+ 45 => 'Tablet S',
6689
+ 46 => 'Tabra QAV801',
6690
+ 47 => 'TAB 7 3G V8',
6691
+ 48 => 'TAB 8 3G V8',
6692
+ 49 => 'TAB9 3G',
6693
+ 50 => 'TAB9 3G V8',
6694
+ 51 => 'TAB 10 3G V16',
6695
+ 52 => 'TAB 7i 3G',
6696
+ 53 => 'TAB 10Q',
6697
+ 54 => 'TAB09-410',
6698
+ 55 => 'TAB10-410',
6699
+ 56 => 'TAB07-485',
6700
+ 57 => 'TAB07-200',
6701
+ 58 => 'TAB9-200',
6702
+ 59 => 'TAB10-201',
6703
+ 60 => 'TAB210',
6704
+ 61 => 'TAB220',
6705
+ 62 => 'TAB224',
6706
+ 63 => 'TAB250',
6707
+ 64 => 'TAB275',
6708
+ 65 => 'TAB260',
6709
+ 66 => 'TAB264',
6710
+ 67 => 'TAB360',
6711
+ 68 => 'TAB364',
6712
+ 69 => 'TAB410',
6713
+ 70 => 'TAB411',
6714
+ 71 => 'TAB420',
6715
+ 72 => 'TAB424',
6716
+ 73 => 'TAB450',
6717
+ 74 => 'TAB460',
6718
+ 75 => 'TAB461',
6719
+ 76 => 'TAB464',
6720
+ 77 => 'TAB465EUK',
6721
+ 78 => 'TAB468',
6722
+ 79 => 'TAB469',
6723
+ 80 => 'TAB466EUK',
6724
+ 81 => 'TAB467',
6725
+ 82 => 'TAB462',
6726
  ),
6727
  '@TB' =>
6728
  array (
6830
  array (
6831
  0 => 'Tilapia',
6832
  1 => 'Titan TV S320',
6833
+ 2 => '(HW-|HUAWEI )?(ATU|DRA|FLA|JKM|TIT|TAG||MRD|NCE|POT|TRT|SLA)!!',
6834
  3 => '(Karbonn|Titanium)!!',
6835
  4 => 'TI320-DU',
6836
  5 => 'TI320-DU TV',
6895
  49 => 'TM-1058',
6896
  50 => 'tmn!!',
6897
  ),
6898
+ '@TN' =>
6899
+ array (
6900
+ 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
6901
+ ),
6902
  '@TO' =>
6903
  array (
6904
  0 => 'Toro',
6952
  14 => 'TR720F',
6953
  15 => 'TR10CS1',
6954
  16 => 'TripNiCE Pyramid',
6955
+ 17 => '(HW-|HUAWEI )?(ATU|DRA|FLA|JKM|TIT|TAG||MRD|NCE|POT|TRT|SLA)!!',
6956
  18 => 'TR10RS1',
6957
  19 => '(KAZAM|Thunder|Tornado|Trooper)!!',
6958
  20 => 'Triumph',
7302
  20 => 'Vibo-A688',
7303
  21 => 'VitMod ExtraLite 1.6.5.fullodex for HTC HD7 Pro',
7304
  22 => 'Vivid 4G',
7305
+ 23 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
7306
  24 => 'Vibe K5 Plus',
7307
  25 => 'VIBE X2 (X2)',
7308
  26 => 'VIBE X3',
7354
  ),
7355
  '@VK' =>
7356
  array (
7357
+ 0 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
7358
  1 => 'VK410',
7359
  2 => 'VK700',
7360
  3 => 'VK810 4G',
7372
  ),
7373
  '@VN' =>
7374
  array (
7375
+ 0 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
7376
  ),
7377
  '@VO' =>
7378
  array (
7381
  2 => 'Volantisg',
7382
  3 => 'VOYAGER DG300',
7383
  4 => 'VOYAGER2 DG310',
7384
+ 5 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
7385
+ 6 => 'Vox',
7386
+ 7 => 'Vortex',
7387
+ 8 => 'vollo Vi86',
7388
+ 9 => 'VOTO GT2++',
7389
+ 10 => 'VOTO GT7',
7390
+ 11 => 'VOTO GT11',
7391
+ 12 => 'VOTO GT11 Pro',
7392
+ 13 => 'VOTO GT18',
7393
+ 14 => 'VOTO V5',
7394
+ 15 => 'VOTO VT868',
7395
+ 16 => 'VOTO VT888',
7396
+ 17 => 'VOTO VT898',
7397
+ 18 => 'VOTO VT898S',
7398
+ 19 => 'VOTO W5300',
7399
+ 20 => 'VOTO X2',
7400
+ 21 => 'VOYO A15',
7401
+ 22 => 'voyo X6',
7402
+ 23 => 'Vodafone!!',
7403
  ),
7404
  '@VS' =>
7405
  array (
7427
  ),
7428
  '@VT' =>
7429
  array (
7430
+ 0 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
7431
  1 => 'VT6078',
7432
  2 => 'VT75C',
7433
  3 => 'VT77C',
7522
  ),
7523
  '@WA' =>
7524
  array (
7525
+ 0 => '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!',
7526
  1 => 'WA-U420D',
7527
  2 => 'WALSUN S1 Pro',
7528
  3 => 'WALSUN S2',
7920
  2 => '(Xiaomi|Xiaomi Mi|MI) Note!!',
7921
  3 => '(Xiaomi )?(MI )?MAX$!',
7922
  4 => '(Xiaomi )?(MI )?MAX 2$!',
7923
+ 5 => '(Xiaomi )?(MI )?MAX 3$!',
7924
+ 6 => '(Xiaomi )?(MI )?MIX$!',
7925
+ 7 => '(Xiaomi )?(MI )?MIX 2$!',
7926
+ 8 => '(Xiaomi )?(MI )?MIX 2S$!',
7927
+ 9 => '(Xiaomi )?20!!',
7928
+ 10 => '(Xiaomi )?(Redmi|RedRice|HM)!!',
7929
+ 11 => '(Xiaomi )?(Redmi|HM)[ \\-]?Note!!',
7930
+ 12 => '(Xiaomi |HM)?20!!',
7931
+ 13 => 'Xiaomi MDT2!',
7932
+ 14 => 'Xiaomi MCT1!',
7933
+ 15 => 'Xiaomi MAT136!',
7934
+ 16 => 'Xiaomi MBT6A5!',
7935
+ 17 => '(Xiaomi|Xiaomi Mi|MI) Pad!!',
7936
+ 18 => '(Xiaomi|Xiaomi Mi|MI)Box!!',
7937
+ 19 => '(Xiaomi|Xiaomi Mi|MI)TV!!',
7938
  ),
7939
  '@XL' =>
7940
  array (
8041
  0 => 'Y6 Max',
8042
  1 => 'Y6 Piano',
8043
  ),
8044
+ '@YA' =>
8045
+ array (
8046
+ 0 => '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!',
8047
+ ),
8048
  '@YD' =>
8049
  array (
8050
  0 => 'YD201',
8216
  51 => 'Z01BDC',
8217
  52 => 'Z01BS',
8218
  53 => 'Z01FD',
8219
+ 54 => 'Z01GD',
8220
+ 55 => 'Z01HD',
8221
+ 56 => 'Z01HDA',
8222
+ 57 => 'Z01KD',
8223
+ 58 => 'Z01KDA',
8224
+ 59 => 'Z01MDA',
8225
+ 60 => 'Z00YD',
8226
  ),
8227
  '@Z1' =>
8228
  array (
8229
  0 => '(BB )?Z10$!',
8230
  1 => 'Z1-H39LW',
8231
+ 2 => '(HUAWEI )?(ALP|BLA|CRR|EVR|HMA|LIO|LON|LYA|MATE|MHA|MT1|MT2|MT7|M200|NXT|SNE|TAS|Z100)!!',
8232
  3 => 'Z1i',
8233
  ),
8234
  '@Z2' =>
8344
  7 => 'ZE550KL',
8345
  8 => 'ZE552KL',
8346
  9 => 'ZE553KL',
8347
+ 10 => 'ZE554KL',
8348
+ 11 => 'ZEN Touch 2',
8349
+ 12 => '(Highscreen|Alpha|Bay|Boost|Cosmo|Explosion|Power|Prime|Zera)!!',
8350
+ 13 => 'ZEN 4.5',
8351
+ 14 => 'ZEN 4.7',
8352
+ 15 => 'ZEN 5+',
8353
+ 16 => 'ZENITHINK C94!',
8354
+ 17 => 'Zen PO neo',
8355
+ 18 => 'ZEN U1',
8356
+ 19 => 'ZEN U4',
8357
+ 20 => 'ZEN U5',
8358
+ 21 => 'ZEN 303 3G',
8359
  ),
8360
  '@ZI' =>
8361
  array (
8486
  98 => 'ZTE B2016',
8487
  99 => 'ZTE B2017',
8488
  100 => 'ZTE B2017G',
8489
+ 101 => 'ZTE B2019G',
8490
+ 102 => 'ZTE C2016',
8491
+ 103 => 'ZTE C2017',
8492
+ 104 => 'ZTE STAR',
8493
+ 105 => 'ZTE Star 1',
8494
+ 106 => 'ZTE S2004',
8495
+ 107 => 'ZTE S2005',
8496
+ 108 => 'ZTE S2007',
8497
+ 109 => 'ZTE S2010',
8498
+ 110 => 'ZTE S2014',
8499
+ 111 => 'ZTE U9180',
8500
+ 112 => 'ZTE U9370',
8501
+ 113 => 'ZTE V6500',
8502
+ 114 => 'ZTE V8110',
8503
+ 115 => 'ZTE B860A',
8504
+ 116 => 'ZTE B860AV1',
8505
+ 117 => 'ZTE W1010',
8506
  ),
8507
  '@ZU' =>
8508
  array (
integration/whichbrowser/data/indices/models-firefoxos.php CHANGED
@@ -22,6 +22,7 @@ DeviceModels::$FIREFOXOS_INDEX = array (
22
  9 => 'ALCATELOneTouch4023!',
23
  10 => 'ALCATELOneTouch6015X!',
24
  11 => 'ALCATEL4044[MNOTVW]!',
 
25
  ),
26
  '@HU' =>
27
  array (
22
  9 => 'ALCATELOneTouch4023!',
23
  10 => 'ALCATELOneTouch6015X!',
24
  11 => 'ALCATEL4044[MNOTVW]!',
25
+ 12 => 'ALCATEL4044C!',
26
  ),
27
  '@HU' =>
28
  array (
integration/whichbrowser/data/indices/models-tizen.php CHANGED
@@ -42,6 +42,20 @@ DeviceModels::$TIZEN_INDEX = array (
42
  array (
43
  0 => 'NX300',
44
  ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  '@SC' =>
46
  array (
47
  0 => 'SC-03F',
@@ -83,6 +97,7 @@ DeviceModels::$TIZEN_INDEX = array (
83
  19 => 'SM-R760!',
84
  20 => 'SM-R765!',
85
  21 => 'SM-R770!',
 
86
  ),
87
  '@TI' =>
88
  array (
42
  array (
43
  0 => 'NX300',
44
  ),
45
+ '@RF' =>
46
+ array (
47
+ 0 => 'RF10M9995!',
48
+ 1 => 'RF23M8590!',
49
+ 2 => 'RF265BEAE!',
50
+ 3 => 'RF28M9580!',
51
+ 4 => 'RF56M9540!',
52
+ 5 => 'RF85K9993!',
53
+ 6 => 'RF85M95A2!',
54
+ ),
55
+ '@RH' =>
56
+ array (
57
+ 0 => 'RH81M8090!',
58
+ ),
59
  '@SC' =>
60
  array (
61
  0 => 'SC-03F',
97
  19 => 'SM-R760!',
98
  20 => 'SM-R765!',
99
  21 => 'SM-R770!',
100
+ 22 => 'SM-R805!',
101
  ),
102
  '@TI' =>
103
  array (
integration/whichbrowser/data/models-android.php CHANGED
@@ -261,12 +261,17 @@ DeviceModels::$ANDROID_MODELS = [
261
  'Pixel' => [ 'Google', 'Pixel' ],
262
  'Google Pixel' => [ 'Google', 'Pixel' ],
263
  'Pixel XL' => [ 'Google', 'Pixel XL' ],
264
- 'Google Pixel XL' => [ 'Google', 'Pixel XL' ],
265
  'Pixel 2' => [ 'Google', 'Pixel 2' ],
266
  'Google Pixel 2' => [ 'Google', 'Pixel 2' ],
267
  'Pixel 2XL' => [ 'Google', 'Pixel 2 XL' ],
268
  'Pixel 2 XL' => [ 'Google', 'Pixel 2 XL' ],
269
  'Google Pixel 2XL' => [ 'Google', 'Pixel 2 XL' ],
 
 
 
 
 
 
270
 
271
  /* Google Edition */
272
  'HTC One' => [ 'HTC', 'One (Google Edition)' ],
@@ -959,7 +964,7 @@ DeviceModels::$ANDROID_MODELS = [
959
  'one ?touch 4032!' => [ 'Alcatel', 'One Touch Pop C2' ],
960
  '4032[ADEX]!' => [ 'Alcatel', 'One Touch Pop C2' ],
961
  'one ?touch 4033!' => [ 'Alcatel', 'One Touch Pop C3' ],
962
- '4033[AL]!' => [ 'Alcatel', 'One Touch Pop C3' ],
963
  'ONETOUCH POPC3' => [ 'Alcatel', 'One Touch Pop C3' ],
964
  '4034[ADEFGX]!' => [ 'Alcatel', 'One Touch Pixi 4 (4)' ],
965
  'one ?touch 40(35|36|37)!' => [ 'Alcatel', 'One Touch Pop D3' ],
@@ -969,11 +974,14 @@ DeviceModels::$ANDROID_MODELS = [
969
  '4037[T]!' => [ 'Alcatel', 'One Touch Evolve 2' ],
970
  '4037[V]!' => [ 'Alcatel', 'One Touch Elevate' ],
971
  'one ?touch 5045!' => [ 'Alcatel', 'One Touch Pop 2 (4)' ],
972
- '4045[ADELOX]!' => [ 'Alcatel', 'One Touch Pop 2 (4)' ],
 
 
973
  '4055[JU]!' => [ 'Alcatel', 'One Touch Pixi 5 (4)' ],
974
  '4060[A]!' => [ 'Alcatel', 'IDEAL' ],
975
- '4060[W]!' => [ 'Alcatel', 'One Touch Pixi 4 (5)' ],
976
  '5010[DEGSUX]!' => [ 'Alcatel', 'One Touch Pixi 4 (5)' ],
 
977
  '5012[G]!' => [ 'Alcatel', 'One Touch Pixi 4 (5.5)' ],
978
  '5015[ADEX]!' => [ 'Alcatel', 'One Touch Pixi 3 (5)' ],
979
  '5016[AJ]!' => [ 'Alcatel', 'One Touch Pixi 3 (5)' ],
@@ -988,35 +996,51 @@ DeviceModels::$ANDROID_MODELS = [
988
  'one ?touch 5021!' => [ 'Alcatel', 'One Touch Soleil' ],
989
  '5022[DEX]!' => [ 'Alcatel', 'One Touch Pop Star' ],
990
  '5023[F]!' => [ 'Alcatel', 'One Touch Pixi 4 Plus Power' ],
 
991
  '5025[DEGX]!' => [ 'Alcatel', 'One Touch Pop 3' ],
992
  '5027[B]!' => [ 'Alcatel', 'One Touch Dawn' ],
 
 
993
  'one ?touch 5035!' => [ 'Alcatel', 'One Touch X\'Pop' ],
994
  '5036[D]!' => [ 'Alcatel', 'One Touch Pop C5' ],
995
  'one ?touch 50(36|37)!' => [ 'Alcatel', 'One Touch Pop C5' ],
996
  'ONETOUCH POPC5' => [ 'Alcatel', 'One Touch Pop C5' ],
997
  'one ?touch 50(38)!' => [ 'Alcatel', 'One Touch Pop D5' ],
998
  '5038[ADEX]!' => [ 'Alcatel', 'One Touch Pop D5' ],
 
 
999
  'one ?touch 5042!' => [ 'Alcatel', 'One Touch Pop 2 (4.5)' ],
1000
  '5042[ADEFGTWXY]!' => [ 'Alcatel', 'One Touch Pop 2 (4.5)' ],
1001
- '5044[ADOY]!' => [ 'Alcatel', 'U5' ],
1002
- '5045[ADGJTX]!' => [ 'Alcatel', 'One Touch Pixi 4 (5.0)' ],
1003
- '5046[Y]!' => [ 'Alcatel', 'A3' ],
 
 
1004
  'one ?touch 5050!' => [ 'Alcatel', 'One Touch Pop S3' ],
1005
  '5050[ASYX]!' => [ 'Alcatel', 'One Touch Pop S3' ],
1006
  '5051[ADJMX]!' => [ 'Alcatel', 'One Touch Pop 4 (5.0)' ],
 
 
1007
  '5054[ADOSTX]!' => [ 'Alcatel', 'One Touch Pixi 3 (5.5)' ],
1008
  '5054[NW]!' => [ 'Alcatel', 'One Touch Fierce XL' ],
1009
- '5056[ADENUWX]!' => [ 'Alcatel', 'One Touch Pop 4+' ],
1010
  '5056[O]!' => [ 'Alcatel', 'One Touch Allura' ],
1011
  '5057[M]!' => [ 'Alcatel', 'One Touch Pop Mirage' ],
 
 
 
1012
  '5065[ADJNWX]!' => [ 'Alcatel', 'One Touch Pixi 3 (5)' ],
1013
  '5070[DJX]!' => [ 'Alcatel', 'One Touch Pop Star' ],
1014
- '5080[DX]!' => [ 'Alcatel', 'One Touch Pixi 4 (6)' ],
1015
- '5085[CD]!' => [ 'Alcatel', 'A5 LED' ],
 
 
 
1016
  '5095[BIKY]!' => [ 'Alcatel', 'One Touch Pop 4S' ],
1017
- '5096[A]!' => [ 'Alcatel', 'One Touch Net' ],
1018
  '5098[OS]!' => [ 'Alcatel', 'One Touch Pixi 4 (6)' ],
1019
  'Alcatel 5098O' => [ 'Alcatel', 'One Touch Pixi 4 (6)' ],
 
1020
  'one ?touch 6010!' => [ 'Alcatel', 'One Touch Star' ],
1021
  'one ?touch 6012!' => [ 'Alcatel', 'One Touch Idol Mini' ],
1022
  'ONE TOUCH IDOL MINI' => [ 'Alcatel', 'One Touch Idol Mini' ],
@@ -1045,13 +1069,16 @@ DeviceModels::$ANDROID_MODELS = [
1045
  'one ?touch 6050!' => [ 'Alcatel', 'One Touch Idol 2S' ],
1046
  '6050[AFWY]!' => [ 'Alcatel', 'One Touch Idol 2S' ],
1047
  '6055[ABDHIKPUY]!' => [ 'Alcatel', 'One Touch Idol 4' ],
 
 
 
1048
  '6070[KOY]!' => [ 'Alcatel', 'One Touch Idol 4s' ],
1049
  'one ?touch 7024!' => [ 'Alcatel', 'One Touch Fierce' ],
1050
  'one touch fierce!' => [ 'Alcatel', 'One Touch Fierce' ],
1051
  'one ?touch 70(25|30)!' => [ 'Alcatel', 'One Touch Snap' ],
1052
  '7030[L]!' => [ 'Alcatel', 'One Touch Snap' ],
1053
  'one ?touch 70(40|41)!' => [ 'Alcatel', 'One Touch Pop C7' ],
1054
- '7040[NR]!' => [ 'Alcatel', 'One Touch Pop C7' ],
1055
  '7040[T]!' => [ 'Alcatel', 'One Touch Fierce 2' ],
1056
  'one ?touch 7042!' => [ 'Alcatel', 'One Touch Snap' ],
1057
  'one ?touch 7043!' => [ 'Alcatel', 'One Touch Pop 2 (5)' ],
@@ -1077,17 +1104,17 @@ DeviceModels::$ANDROID_MODELS = [
1077
  '8020[D]!' => [ 'Alcatel', 'One Touch Hero' ],
1078
  'one ?touch 8030!' => [ 'Alcatel', 'One Touch Hero 2' ],
1079
  '8030[BY]!' => [ 'Alcatel', 'One Touch Hero 2' ],
1080
- '9001[DX]!' => [ 'Alcatel', 'One Touch Pixi 4 (6)' ],
1081
  '9002[AWX]!' => [ 'Alcatel', 'One Touch Pixi 3 (7)', DeviceType::TABLET ],
1082
  '9003[AX]!' => [ 'Alcatel', 'One Touch Pixi 4 (7)', DeviceType::TABLET ],
1083
  '9005[X]!' => [ 'Alcatel', 'One Touch Pixi 3 (8)', DeviceType::TABLET ],
1084
  '9006[W]!' => [ 'Alcatel', 'One Touch Pixi 4 (7)', DeviceType::TABLET ],
1085
  '9007[ATX]!' => [ 'Alcatel', 'One Touch Pixi 3 (7)', DeviceType::TABLET ],
1086
- '9008[AIJTUX]!' => [ 'Alcatel', 'A3 XL', DeviceType::TABLET ],
1087
  '9010[X]!' => [ 'Alcatel', 'One Touch Pixi 3 (10)', DeviceType::TABLET ],
1088
- '9015[BJW]!' => [ 'Alcatel', 'One Touch POP7', DeviceType::TABLET ],
1089
  '9022[SX]!' => [ 'Alcatel', 'One Touch Pixi 3 (8)', DeviceType::TABLET ],
1090
- '9024[W]!' => [ 'Alcatel', 'A30', DeviceType::TABLET ],
1091
  '9025[MQ]!' => [ 'Alcatel', 'One Touch Pop 4 (7)', DeviceType::TABLET ],
1092
  'one ?touch T10!' => [ 'Alcatel', 'One Touch T10', DeviceType::TABLET ],
1093
  'one ?touch T20!' => [ 'Alcatel', 'One Touch T20', DeviceType::TABLET ],
@@ -1106,7 +1133,7 @@ DeviceModels::$ANDROID_MODELS = [
1106
  'ONE ?TOUCH P310(A|X)!' => [ 'Alcatel', 'One Touch POP7', DeviceType::TABLET ],
1107
  'ONE ?TOUCH P320(A|X)!' => [ 'Alcatel', 'One Touch POP8', DeviceType::TABLET ],
1108
  'ONE ?TOUCH P321!' => [ 'Alcatel', 'One Touch POP8', DeviceType::TABLET ],
1109
- '9021A' => [ 'Alcatel', 'One Touch POP8', DeviceType::TABLET ],
1110
  'P330X' => [ 'Alcatel', 'One Touch POP7S', DeviceType::TABLET ],
1111
  'P350X' => [ 'Alcatel', 'One Touch POP8S', DeviceType::TABLET ],
1112
  'ONE ?TOUCH POP 8S P350X!' => [ 'Alcatel', 'One Touch POP8S', DeviceType::TABLET ],
@@ -1294,9 +1321,8 @@ DeviceModels::$ANDROID_MODELS = [
1294
  'KFGIWI' => [ 'Amazon', 'Fire HD 8 (2016)', DeviceType::TABLET, Flag::FIREOS ], // xth generation 8" HD (1280 x 800)
1295
  'KFDOWI' => [ 'Amazon', 'Fire HD 8 (2017)', DeviceType::TABLET, Flag::FIREOS ], // xth generation 8" HD (1280 x 800)
1296
  'KFSUWI' => [ 'Amazon', 'Fire HD 10 (2017)', DeviceType::TABLET, Flag::FIREOS ], // 5th generation 10" HD (1280 x 800)
1297
- // 'KFSLWI'
1298
- // 'KFBJWI'
1299
- // 'KFHDX'
1300
  'SD4930UR' => [ 'Amazon', 'Fire Phone', DeviceType::MOBILE, Flag::FIREOS ],
1301
  'AFTB' => [ 'Amazon', 'Fire TV', DeviceType::TELEVISION, Flag::FIREOS ],
1302
  'AFTS' => [ 'Amazon', 'Fire TV (2015)', DeviceType::TELEVISION, Flag::FIREOS ],
@@ -1472,6 +1498,7 @@ DeviceModels::$ANDROID_MODELS = [
1472
  'Archos!!' => [
1473
  'ARCHOS 80G9' => [ 'Archos', '80 G9', DeviceType::TABLET ],
1474
  'ARCHOS 101G9' => [ 'Archos', '101 G9', DeviceType::TABLET ],
 
1475
  'ARCHOS 97XSLG10' => [ 'Archos', '97 XS', DeviceType::TABLET ],
1476
  'ARCHOS 80XSK' => [ 'Archos', '80 XS', DeviceType::TABLET ],
1477
  'ARCHOS 101G10' => [ 'Archos', '101 XS', DeviceType::TABLET ],
@@ -1537,6 +1564,7 @@ DeviceModels::$ANDROID_MODELS = [
1537
  'Archos 50e Neon' => [ 'Archos', '50e Neon' ],
1538
  'Archos 50f Neon' => [ 'Archos', '50f Neon' ],
1539
  'Archos 70 Neon' => [ 'Archos', '70 Neon', DeviceType::TABLET ],
 
1540
  'Archos 70b Neon' => [ 'Archos', '70b Neon', DeviceType::TABLET ],
1541
  'Archos 70c Neon' => [ 'Archos', '70c Neon', DeviceType::TABLET ],
1542
  'Archos 79 Neon' => [ 'Archos', '79 Neon', DeviceType::TABLET ],
@@ -1576,6 +1604,7 @@ DeviceModels::$ANDROID_MODELS = [
1576
  'Archos 5.3s Platinum' => [ 'Archos', '53s Platinum' ],
1577
  'Archos 55 Platinum' => [ 'Archos', '55 Platinum' ],
1578
  'Archos 55b Platinum' => [ 'Archos', '55b Platinum' ],
 
1579
  'Archos 70 Platinum' => [ 'Archos', '70 Platinum', DeviceType::TABLET ],
1580
  'Archos 70 Platinum 3G' => [ 'Archos', '70 Platinum', DeviceType::TABLET ],
1581
  'Archos 70 Platinum v3' => [ 'Archos', '70 Platinum', DeviceType::TABLET ],
@@ -1632,12 +1661,12 @@ DeviceModels::$ANDROID_MODELS = [
1632
  'ARCHOS 97 XENON' => [ 'Archos', '97 Xenon', DeviceType::TABLET ],
1633
  'Archos 101 Xenon' => [ 'Archos', '101 Xenon', DeviceType::TABLET ],
1634
  'Archos 101 Xenon v2' => [ 'Archos', '101 Xenon', DeviceType::TABLET ],
 
1635
  'Archos 101b Xenon v2' => [ 'Archos', '101b Xenon', DeviceType::TABLET ],
1636
  'Archos 101c Xenon' => [ 'Archos', '101c Xenon', DeviceType::TABLET ],
1637
  'ARCHOS 101 Xenon Lite' => [ 'Archos', '101 Xenon Lite', DeviceType::TABLET ],
1638
  'ARCHOS 80 CHILDPAD' => [ 'Archos', '80 Childpad', DeviceType::TABLET ],
1639
  'ARCHOS 101 CHILDPAD' => [ 'Archos', '101 Childpad', DeviceType::TABLET ],
1640
- 'Archos Access 45 4G' => [ 'Archos', 'Access 45' ],
1641
  'Archos Chefpad' => [ 'Archos', 'ChefPad', DeviceType::TABLET ],
1642
  'ARCHOS GAMEPAD' => [ 'Archos', 'Gamepad', [ DeviceType::GAMING, DeviceSubType::PORTABLE ] ],
1643
  'ARCHOS GAMEPAD2' => [ 'Archos', 'Gamepad 2', [ DeviceType::GAMING, DeviceSubType::PORTABLE ] ],
@@ -1645,6 +1674,19 @@ DeviceModels::$ANDROID_MODELS = [
1645
  'Archos 101 DB' => [ 'Archos', 'ArcBook', DeviceType::TABLET ],
1646
  'Archos Smart Home Tablet' => [ 'Archos', 'Smart Home Tablet', DeviceType::TABLET ],
1647
  'ARCHOS LUDOG10' => [ 'Archos', 'TV Connect', DeviceType::TELEVISION ],
 
 
 
 
 
 
 
 
 
 
 
 
 
1648
  ],
1649
 
1650
  'Artes D708' => [ 'Artes', 'D708', DeviceType::TABLET ],
@@ -1887,6 +1929,7 @@ DeviceModels::$ANDROID_MODELS = [
1887
  'Z01BDC' => [ 'Asus', 'ZenFone 3 Laser (ZC551KL)' ],
1888
  'Z01BS' => [ 'Asus', 'ZenFone 3 Laser (ZC551KL)' ],
1889
  'Z01FD' => [ 'Asus', 'ZenFone 3 Deluxe (ZS550KL)' ],
 
1890
  'Z01HD' => [ 'Asus', 'ZenFone 3 Zoom (ZE553KL)' ],
1891
  'Z01HDA' => [ 'Asus', 'ZenFone 3 Zoom (ZE553KL)' ],
1892
  'Z01KD' => [ 'Asus', 'ZenFone 4 (ZE554KL)' ],
@@ -1903,6 +1946,7 @@ DeviceModels::$ANDROID_MODELS = [
1903
  'ZE550KL' => [ 'Asus', 'ZenFone 2 Laser (ZE550KL)' ],
1904
  'ZE552KL' => [ 'Asus', 'ZenFone 3 (ZE552KL)' ],
1905
  'ZE553KL' => [ 'Asus', 'ZenFone 3 Zoom (ZE553KL)' ],
 
1906
 
1907
  'Z00YD' => [ 'Asus', 'Live' ],
1908
  'X002' => [ 'Asus', 'Pegasus' ],
@@ -2080,8 +2124,9 @@ DeviceModels::$ANDROID_MODELS = [
2080
  '(NOOK )?BNTV250!' => [ 'Barnes & Noble', 'NOOK Tablet', DeviceType::EREADER ],
2081
  '(NOOK )?BNRV350!' => [ 'Barnes & Noble', 'NOOK Simple Touch', DeviceType::EREADER ],
2082
  '(NOOK )?BNTV(400)!' => [ 'Barnes & Noble', 'NOOK HD Tablet', DeviceType::EREADER ],
 
2083
  '(NOOK )?BNTV(600)!' => [ 'Barnes & Noble', 'NOOK HD+ Tablet', DeviceType::EREADER ],
2084
- '(NOOK )?BNTV(800)!' => [ 'Barnes & Noble', 'NOOK BNTV800 Tablet', DeviceType::EREADER ],
2085
  'Barnes & Noble Nook HD' => [ 'Barnes & Noble', 'NOOK HD Tablet', DeviceType::EREADER ],
2086
  'Barnes & Noble Nook HD+' => [ 'Barnes & Noble', 'NOOK HD+ Tablet', DeviceType::EREADER ],
2087
  'Nook HD' => [ 'Barnes & Noble', 'NOOK HD Tablet', DeviceType::EREADER ],
@@ -2192,6 +2237,8 @@ DeviceModels::$ANDROID_MODELS = [
2192
  'BBB100-[0-9]!' => [ 'BlackBerry', 'KEYone' ],
2193
  'BBC100-[0-9]!' => [ 'BlackBerry', 'Aurora' ],
2194
  'BBD100-[0-9]!' => [ 'BlackBerry', 'Motion' ],
 
 
2195
 
2196
  'BV8000Pro' => [ 'Blackview', 'BV8000 Pro' ],
2197
  'P2Lite' => [ 'Blackview', 'P2 Lite' ],
@@ -3802,6 +3849,10 @@ DeviceModels::$ANDROID_MODELS = [
3802
  'DM016SH' => [ 'Sharp', 'DM016SH', 'carrier' => 'Disney Mobile' ],
3803
  ],
3804
 
 
 
 
 
3805
  'DJC Touchtab3' => [ 'DJC', 'Touchtab3', DeviceType::TABLET ],
3806
  'DJC Touchtab4' => [ 'DJC', 'Touchtab4', DeviceType::TABLET ],
3807
  'AirBook TTJ702' => [ 'DNS', 'Airbook TTJ702', DeviceType::TABLET ],
@@ -4274,6 +4325,7 @@ DeviceModels::$ANDROID_MODELS = [
4274
  'FS403' => [ 'Fly', 'FS403 Cumulus 1' ],
4275
  'FS407' => [ 'Fly', 'FS407 Stratus 6' ],
4276
  'FS451' => [ 'Fly', 'FS451 Nimbus 1' ],
 
4277
  'Fly Phoenix 2' => [ 'Fly', 'IQ4410i Phoenix 2' ],
4278
  'Fly Ego Art 2' => [ 'Fly', 'IQ455 Ego Art 2' ],
4279
 
@@ -4427,10 +4479,14 @@ DeviceModels::$ANDROID_MODELS = [
4427
  'F-01F' => [ 'Fujitsu', 'ARROWS NX F-01F', 'carrier' => 'DoCoMo' ],
4428
  'F-01H' => [ 'Fujitsu', 'arrows Fit F-01H', 'carrier' => 'DoCoMo' ],
4429
  'F-01J' => [ 'Fujitsu', 'arrows NX F-01J', 'carrier' => 'DoCoMo' ],
 
 
4430
  'F-02E' => [ 'Fujitsu', 'ARROWS X F-02E', 'carrier' => 'DoCoMo' ],
4431
  'F-02F' => [ 'Fujitsu', 'ARROWS Tab F-02F', DeviceType::TABLET, 'carrier' => 'DoCoMo' ],
4432
  'F-02G' => [ 'Fujitsu', 'ARROWS NX F-02G', 'carrier' => 'DoCoMo' ],
4433
  'F-02H' => [ 'Fujitsu', 'arrows NX F-02H', 'carrier' => 'DoCoMo' ],
 
 
4434
  'F-03D' => [ 'Fujitsu', 'ARROWS Kiss F-03D', 'carrier' => 'DoCoMo' ],
4435
  'F-03E' => [ 'Fujitsu', 'ARROWS Kiss with JILL STUART F-03E', 'carrier' => 'DoCoMo' ],
4436
  'F-03F' => [ 'Fujitsu', 'F-03F', 'carrier' => 'Disney Mobile' ],
@@ -4441,6 +4497,8 @@ DeviceModels::$ANDROID_MODELS = [
4441
  'F-04F' => [ 'Fujitsu', 'Business Smartphone F-04F', 'carrier' => 'DoCoMo' ],
4442
  'F-04G' => [ 'Fujitsu', 'ARROWS NX F-04G', 'carrier' => 'DoCoMo' ],
4443
  'F-04H' => [ 'Fujitsu', 'ARROWS Tab F-04H', DeviceType::TABLET, 'carrier' => 'DoCoMo' ],
 
 
4444
  'F-05D' => [ 'Fujitsu', 'ARROWS X LTE F-05D', 'carrier' => 'DoCoMo' ],
4445
  'F-05E' => [ 'Fujitsu', 'ARROWS Tab F-05E', 'carrier' => 'DoCoMo' ],
4446
  'F-05F' => [ 'Fujitsu', 'ARROWS NX F-05F', 'carrier' => 'DoCoMo' ],
@@ -5309,6 +5367,7 @@ DeviceModels::$ANDROID_MODELS = [
5309
  'HTC Desire 10 pro' => [ 'HTC', 'Desire 10 Pro' ],
5310
  'HTC D10i' => [ 'HTC', 'Desire 10 Pro' ],
5311
  'HTC D10w' => [ 'HTC', 'Desire 10 Pro' ],
 
5312
  'HTC Desire 200' => [ 'HTC', 'Desire 200' ],
5313
  'HTC Desire 210 dual sim' => [ 'HTC', 'Desire 210' ],
5314
  'HTC Desire 300' => [ 'HTC', 'Desire 300' ],
@@ -5431,6 +5490,7 @@ DeviceModels::$ANDROID_MODELS = [
5431
  'HTC 2PST5' => [ 'HTC', 'Desire 630' ],
5432
  'HTC Desire 650' => [ 'HTC', 'Desire 650' ],
5433
  'HTC Desire 650 dual sim' => [ 'HTC', 'Desire 650' ],
 
5434
  'HTC 2PYR1' => [ 'HTC', 'Desire 650' ],
5435
  'HTC 2PYR2' => [ 'HTC', 'Desire 650' ],
5436
  'HTC Desire 700 dual sim' => [ 'HTC', 'Desire 700' ],
@@ -5459,6 +5519,7 @@ DeviceModels::$ANDROID_MODELS = [
5459
  'HTC Desire 820G !' => [ 'HTC', 'Desire 820G' ],
5460
  'HTC Desire 820G+' => [ 'HTC', 'Desire 820G+' ],
5461
  'HTC Desire 820G PLUS dual sim' => [ 'HTC', 'Desire 820G+' ],
 
5462
  'HTC D820' => [ 'HTC', 'Desire 820' ],
5463
  'HTC D820(f|m|mt|mu|s|t|u|x)!' => [ 'HTC', 'Desire 820' ],
5464
  'HTC Desire 820' => [ 'HTC', 'Desire 820' ],
@@ -5495,6 +5556,7 @@ DeviceModels::$ANDROID_MODELS = [
5495
  'HTC Desire C N' => [ 'HTC', 'Desire C' ],
5496
  'HTC H1000C' => [ 'HTC', 'Desire C' ],
5497
  'HTC A320e' => [ 'HTC', 'Desire C' ],
 
5498
  'HTC Desire ?HD!' => [ 'HTC', 'Desire HD' ],
5499
  'HTC A91(91|92)!' => [ 'HTC', 'Desire HD' ],
5500
  'HTC 0PFH1!' => [ 'HTC', 'Desire Eye' ],
@@ -5609,6 +5671,7 @@ DeviceModels::$ANDROID_MODELS = [
5609
  'HTC Butterfly s 901s' => [ 'HTC', 'Butterfly S' ],
5610
  'HTC PO68' => [ 'HTC', 'Butterfly S' ],
5611
  'HTC 9060' => [ 'HTC', 'Butterfly S' ],
 
5612
  'HTC 9088' => [ 'HTC', 'Butterfly S' ],
5613
  'HTC 901e' => [ 'HTC', 'Butterfly S' ],
5614
  'HTC 909d' => [ 'HTC', 'Butterfly S' ],
@@ -5728,6 +5791,7 @@ DeviceModels::$ANDROID_MODELS = [
5728
  'HTC 0PK71' => [ 'HTC', 'One (M9 Plus)' ],
5729
  'HTC 0PK72' => [ 'HTC', 'One (M9 Plus)' ],
5730
  'HTC X9u' => [ 'HTC', 'One (X9)' ],
 
5731
  'HTC 2PS5200' => [ 'HTC', 'One (X9)' ],
5732
  'HTC 2PXH1' => [ 'HTC', 'One (X10)' ],
5733
  'HTC 2PXH2' => [ 'HTC', 'One (X10)' ],
@@ -5810,14 +5874,19 @@ DeviceModels::$ANDROID_MODELS = [
5810
  'HTC Mecha' => [ 'HTC', 'ThunderBolt'],
5811
  'HTC Kaiser' => [ 'HTC', 'TyTN II'],
5812
  'HTC U Play' => [ 'HTC', 'U Play'],
 
5813
  'HTC 2PZM3' => [ 'HTC', 'U Play'],
5814
  'HTC U Ultra' => [ 'HTC', 'U Ultra'],
5815
  'HTC U-1w' => [ 'HTC', 'U Ultra'],
5816
  'HTC 2PZF1' => [ 'HTC', 'U Ultra'],
5817
  'HTC U11' => [ 'HTC', 'U11'],
5818
  'HTC U-3w' => [ 'HTC', 'U11'],
 
5819
  'HTC 2PZC100' => [ 'HTC', 'U11'],
5820
  'HTC 2Q4D200' => [ 'HTC', 'U11 Plus'],
 
 
 
5821
  'HTC Velocity!' => [ 'HTC', 'Velocity 4G'],
5822
  'HTCVelocity 4G' => [ 'HTC', 'Velocity 4G'],
5823
  'HTC Vivid' => [ 'HTC', 'Vivid'],
@@ -6020,10 +6089,11 @@ DeviceModels::$ANDROID_MODELS = [
6020
  '2PS64' => [ 'HTC', '10' ],
6021
  'M7CDTU' => [ 'HTC', 'One' ],
6022
 
6023
- '[SX0][0-9]{2,2}HT!!' => [
6024
  'S31HT' => [ 'HTC', 'Aria S31HT', 'carrier' => 'EMOBILE' ],
6025
  'X06HT' => [ 'HTC', 'Desire X06HT', 'carrier' => 'Softbank' ],
6026
  '001HT' => [ 'HTC', 'Desire HD 001HT', 'carrier' => 'Softbank' ],
 
6027
  ],
6028
 
6029
  'ISW[0-9]{2,2}HT!!' => [
@@ -6125,10 +6195,15 @@ DeviceModels::$ANDROID_MODELS = [
6125
  'BTV-(DL09|W09)!' => [ 'Huawei', 'MediaPad M3', DeviceType::TABLET ],
6126
  'CPN-(W09|AL00|L09)!' => [ 'Huawei', 'MediaPad M3 Lite', DeviceType::TABLET ],
6127
  'BAH-(W09|AL00|L09)!' => [ 'Huawei', 'MediaPad M3 Lite', DeviceType::TABLET ],
 
 
 
6128
 
6129
  'JDN-W09' => [ 'Huawei', 'Honor Pad 2', DeviceType::TABLET ],
 
 
6130
 
6131
- '(HUAWEI )?(ALP|BLA|CRR|LON|MATE|MHA|MT1|MT2|MT7|M200|NXT|Z100)!!' => [
6132
  '(HW-|HUAWEI )?MT1-(T00|U06)!' => [ 'Huawei', 'Ascend Mate' ],
6133
  '(HW-|HUAWEI )?MATE-U06!' => [ 'Huawei', 'Ascend Mate' ],
6134
  '(HW-|HUAWEI )?MT2-?(C00|L01|L02|L03|L05)!' => [ 'Huawei', 'Ascend Mate 2' ],
@@ -6138,20 +6213,32 @@ DeviceModels::$ANDROID_MODELS = [
6138
  '(HW-|HUAWEI )?M200-(L09|UL00)!' => [ 'Huawei', 'Mate 8' ],
6139
  '(HW-|HUAWEI )?MHA-(AL00|L09|L29|TL00)!' => [ 'Huawei', 'Mate 9' ],
6140
  '(HW-|HUAWEI )?LON-(AL00|L29)!' => [ 'Huawei', 'Mate 9 Pro' ],
6141
- '(HW-|HUAWEI )?ALP-(AL00|L09|L29)!' => [ 'Huawei', 'Mate 10' ],
6142
- '(HW-|HUAWEI )?BLA-(AL00|L09|L29)!' => [ 'Huawei', 'Mate 10 Pro' ],
 
 
 
 
 
 
6143
  '(HW-|HUAWEI )?CRR-(L09|CL00|CL20|TL00|UL00|UL20)!' => [ 'Huawei', 'Mate S' ],
6144
  ],
6145
 
6146
- '(HW-|HUAWEI )?(TIT|TAG|NCE|TRT|SLA)!!' => [
6147
  '(HW-|HUAWEI )?TIT-(AL00|CL00|CL10|L01|TL00|U02)!' => [ 'Huawei', 'Enjoy 5' ],
6148
  '(HW-|HUAWEI )?TAG-(AL00|CL00|L13|TL00)!' => [ 'Huawei', 'Enjoy 5S' ],
6149
  '(HW-|HUAWEI )?NCE-(AL00|AL10|TL10)!' => [ 'Huawei', 'Enjoy 6' ],
6150
  '(HW-|HUAWEI )?SLA-(AL00|L02|L03|L22|TL10)!' => [ 'Huawei', 'Enjoy 7' ],
6151
  '(HW-|HUAWEI )?TRT-(AL00|L21|L53|LX1|LX2|LX3|TL10)!' => [ 'Huawei', 'Enjoy 7 Plus' ],
 
 
 
 
 
 
6152
  ],
6153
 
6154
- '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BND|CHE|CHM|DUK|DLI|EDI|FRD|HN3|H30|H60|HOL|KIW|LDD|NEM|NMO|PE|PLK|RNE|SCL|KNT|CAM|STF)!!' => [
6155
  'H30 U10' => [ 'Huawei', 'Honor 3C' ],
6156
  '(HW-|HUAWEI )?HN3-(U00|U01)!' => [ 'Huawei', 'Honor 3' ],
6157
  '(HW-|HUAWEI |HONOR )?H30[- ](C00|L01|L02|T00|T10|U10)!' => [ 'Huawei', 'Honor 3C' ],
@@ -6161,7 +6248,7 @@ DeviceModels::$ANDROID_MODELS = [
6161
  '(HW-|HUAWEI )?CHE-(TL00|TL00H)!' => [ 'Huawei', 'Honor 4X' ],
6162
  '(HW-|HUAWEI )?Che1-(L04|CL10|CL20)!' => [ 'Huawei', 'Honor 4X' ],
6163
  '(HW-|HUAWEI )?Che2-(L11|L12|L23|TL00|UL00)!' => [ 'Huawei', 'Honor 4X' ],
6164
- '(HW-|HUAWEI )?NEM-(AL10|L21|L22|L51|TL00|TL00H|UL10)!' => [ 'Huawei', 'Honor 5C' ],
6165
  '(HW-|HUAWEI )?NMO-(L22|L23|L31)!' => [ 'Huawei', 'Honor 5C' ],
6166
  '(HW-|HUAWEI )?KIW-(AL10|CL00|L21|L22|L24|UL00|TL00|TL00H)!' => [ 'Huawei', 'Honor 5X' ],
6167
  '(HW-|HUAWEI )?H60-(J1|L01|L02|L03|L04|L11|L12|L21)!' => [ 'Huawei', 'Honor 6' ],
@@ -6170,16 +6257,29 @@ DeviceModels::$ANDROID_MODELS = [
6170
  '(HW-|HUAWEI )?PE-(CL00|TL00|TL00M|TL10|TL20|UL00)!' => [ 'Huawei', 'Honor 6 Plus' ],
6171
  '(HW-|HUAWEI |HONOR )?PLK-(L01|AL10|CL00|UL00|TL00|TL01H)!' => [ 'Huawei', 'Honor 7' ],
6172
  '(HW-|HUAWEI )?ATH-(AL00|CL00|TL00|TL00H|UL00)!' => [ 'Huawei', 'Honor 7i' ],
6173
- '(HW-|HUAWEI )?BND-(AL10|L24)!' => [ 'Huawei', 'Honor 7X' ],
 
 
6174
  '(HW-|HUAWEI )?FRD-(AL00|AL10|DL00|L02|L04|L09|L14|L19)!' => [ 'Huawei', 'Honor 8' ],
 
 
6175
  '(HW-|HUAWEI )?ATH-(UL01|UL06)!' => [ 'Huawei', 'Honor ShotX' ],
6176
  '(HW-|HUAWEI )?KNT-(AL10|AL20|TL10|UL10)!' => [ 'Huawei', 'Honor V8' ],
6177
  '(HW-|HUAWEI )?EDI-(AL10)!' => [ 'Huawei', 'Honor Note 8' ],
6178
  '(HW-|HUAWEI )?STF-(AL00|AL10|L09|TL10)!' => [ 'Huawei', 'Honor 9' ],
6179
- '(HW-|HUAWEI )?LLD-(L31)!' => [ 'Huawei', 'Honor 9 Lite' ],
6180
- '(HW-|HUAWEI )?RNE-(AL00|L01|L21|L22|L31)!' => [ 'Huawei', 'Honor 9i' ],
 
 
 
 
6181
  '(HW-|HUAWEI )?DUK-(AL20|L09|TL30)!' => [ 'Huawei', 'Honor V9' ],
6182
- '(HW-|HUAWEI )?BKL-(AL00|AL20|L09)!' => [ 'Huawei', 'Honor V10' ],
 
 
 
 
 
6183
  ],
6184
 
6185
  '(HW-|HUAWEI )?(BLL|CHC|TAG|KII)!!' => [
@@ -6189,7 +6289,7 @@ DeviceModels::$ANDROID_MODELS = [
6189
  '(HW-|HUAWEI )?BLL-(L21|L22|L23)!' => [ 'Huawei', 'GR5 (2017)' ],
6190
  ],
6191
 
6192
- '(HW-|HUAWEI )?(ALE|D2|DAV|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|VIE|VKY|VNS|VTR|WAS)!!' => [
6193
  'HUAWEI D2' => [ 'Huawei', 'Ascend D2' ],
6194
  '(HW-|HUAWEI )?D2-(0082|2010|5000|6070|6114)!' => [ 'Huawei', 'Ascend D2' ],
6195
  '(HW-|HUAWEI )?G6-(C00|L11|L22|L33|T00|U00|U10|U34|U251)!' => [ 'Huawei', 'Ascend G6' ],
@@ -6213,28 +6313,39 @@ DeviceModels::$ANDROID_MODELS = [
6213
  '(HW-|HUAWEI )?VTR-?(AL00|L09|L29|TL00)!' => [ 'Huawei', 'P10' ],
6214
  '(HW-|HUAWEI )?WAS-?(AL00|L03T|LX1|LX1A|LX2|LX2J|LX3|TL10)!' => [ 'Huawei', 'P10 Lite' ],
6215
  '(HW-|HUAWEI )?VKY-?(AL00|L09|L29|TL00)!' => [ 'Huawei', 'P10 Plus' ],
6216
- '(HW-|HUAWEI )?FIG-?(AL10|LX1)!' => [ 'Huawei', 'P Smart' ],
 
 
 
 
 
 
6217
  ],
6218
 
6219
  'Rock-(AL00|CL00|L01|L03)!' => [ 'Huawei', 'Ascend G7' ],
6220
  'HUAWEI A168-(AL10|DL09|L09|L29)!' => [ 'Huawei', 'P9' ],
6221
 
6222
- '(HW-|HUAWEI )?(CRO|LUA|CUN|SCC|SCU|CAM|LYO|MYA)!!' => [
6223
  '(HW-|HUAWEI )?CRO-(L02|L03|L22|U00)!' => [ 'Huawei', 'Y3 (2017)' ],
6224
  '(HW-|HUAWEI )?LUA-(L01|L02|L03|L13|L21|L22|L23|U02|U03|U22|U23)!' => [ 'Huawei', 'Y3 II' ],
6225
  '(HW-|HUAWEI )?CUN-(AL00|L01|L02|L03|L21|L22|L23|L33|TL00|U29)!' => [ 'Huawei', 'Y5 II' ],
6226
- '(HW-|HUAWEI )?MYA-(AL10|L02|L03|L11|L13|L22|L23|L41)!' => [ 'Huawei', 'Y5 (2017)' ],
6227
  '(HW-|HUAWEI )?SCC-(U21)!' => [ 'Huawei', 'Y6' ],
6228
  '(HW-|HUAWEI )?SCU-(U31)!' => [ 'Huawei', 'Y6C' ],
6229
  '(HW-|HUAWEI )?CAM-(L01|L03|L11|L21|L23|L32|AL00|CL00|TL00|UL00)!' => [ 'Huawei', 'Y6 II' ],
6230
  '(HW-|HUAWEI )?LYO-(L01|L02|L21)!' => [ 'Huawei', 'Y6 II Compact' ],
 
6231
  ],
6232
 
6233
  '(HW-|HUAWEI )?CAZ-(AL10|TL10|TL20)!' => [ 'Huawei', 'Nova' ],
6234
  '(HW-|HUAWEI )?CAN-(L01|L11|L12)!' => [ 'Huawei', 'Nova' ],
6235
  '(HW-|HUAWEI )?MLA-(L01|L03|L11|L12|L13)!' => [ 'Huawei', 'Nova Plus' ],
6236
  '(HW-|HUAWEI )?DIG-(AL00|L01|L03|L21|TL10)!' => [ 'Huawei', 'Nova Smart' ],
6237
- '(HW-|HUAWEI )?BAC-(AL00|L03|L21|L22)!' => [ 'Huawei', 'Nova 2 Plus' ],
 
 
 
 
6238
  '(HW-|HUAWEI )?MLA-(AL00|AL10)!' => [ 'Huawei', 'Maimang 5' ],
6239
  '(HW-|HUAWEI )?MLA-(TL00|TL10|UL00)!' => [ 'Huawei', 'G9 Plus' ],
6240
 
@@ -6269,7 +6380,7 @@ DeviceModels::$ANDROID_MODELS = [
6269
  'Y220T' => [ 'Huawei', 'Ascend Y220' ],
6270
  'Y221-(U22)!' => [ 'Huawei', 'Ascend Y221' ],
6271
  'Y301-(A1|A2)!' => [ 'Huawei', 'Valiant' ],
6272
- 'Y320-(U01|U10)!' => [ 'Huawei', 'Ascend Y320' ],
6273
  'Y325-T00' => [ 'Huawei', 'Ascend Y325' ],
6274
  'Y330-U11' => [ 'Huawei', 'Ascend Y330' ],
6275
  'Y340-U081' => [ 'Huawei', 'Ascend Y340' ],
@@ -6518,7 +6629,10 @@ DeviceModels::$ANDROID_MODELS = [
6518
  '402HW' => [ 'Huawei', 'MediaPad 10 Link+ 402HW', DeviceType::TABLET, 'carrier' => 'Softbank' ],
6519
  '403HW' => [ 'Huawei', 'MediaPad M1 8.0 403HW', DeviceType::TABLET, 'carrier' => 'Y! Mobile' ],
6520
  '503HW' => [ 'Huawei', 'LUMIERE 503HW', 'carrier' => 'Y! Mobile' ],
 
6521
  '606HW' => [ 'Huawei', 'MediaPad T2 Pro 606HW', DeviceType::TABLET, 'carrier' => 'Y! Mobile' ],
 
 
6522
  ],
6523
 
6524
  'CM980' => [ 'Huawei', 'Evolution II' ],
@@ -6615,9 +6729,12 @@ DeviceModels::$ANDROID_MODELS = [
6615
  'GS03' => [ 'Huawei', 'GS03', 'carrier' => 'EMOBILE' ],
6616
  'GL07S' => [ 'Huawei', 'STREAM X GL07S', 'carrier' => 'EMOBILE' ],
6617
  'HW-01E' => [ 'Huawei', 'Ascend HW-01E', 'carrier' => 'DoCoMo' ],
 
6618
  'HW-03E' => [ 'Huawei', 'Ascend D2 HW-03E', 'carrier' => 'DoCoMo' ],
6619
  'HWT31' => [ 'Huawei', 'Qua tab 02 HWT31', 'carrier' => 'au' ],
 
6620
  'H710VL' => [ 'Huawei', 'Sensa' ],
 
6621
  'H866C' => [ 'Huawei', 'Ascend Y H866C' ],
6622
  'H882L' => [ 'Huawei', 'Ascend Y301-A' ],
6623
 
@@ -7012,6 +7129,7 @@ DeviceModels::$ANDROID_MODELS = [
7012
  'Infinix NOTE 3 Pro' => [ 'Infinix', 'Note 3 Pro X601' ],
7013
  'Infinix Zero 4' => [ 'Infinix', 'Zero 4 X602' ],
7014
  'Infinix Zero 4 Plus' => [ 'Infinix', 'Zero 4 Plus X602' ],
 
7015
  'Infinix X800' => [ 'Infinix', 'Joypad 8 X800', DeviceType::TABLET ],
7016
  'Infinix X801' => [ 'Infinix', 'Joypad 8S X801', DeviceType::TABLET ],
7017
  'Infinix X1000' => [ 'Infinix', 'Joypad 10 X1000', DeviceType::TABLET ],
@@ -7805,6 +7923,7 @@ DeviceModels::$ANDROID_MODELS = [
7805
 
7806
  'KY[FLTYV][0-9]{2,2}!!' => [
7807
  'KYF31' => [ 'Kyocera', 'GRATINA KYF31', 'carrier' => 'au' ],
 
7808
  'KYF37' => [ 'Kyocera', 'GRATINA KYF37', 'carrier' => 'au' ],
7809
  'KYL23' => [ 'Kyocera', 'miraie KYL23', 'carrier' => 'au' ],
7810
  'KYY21' => [ 'Kyocera', 'URBANO L01', 'carrier' => 'au' ],
@@ -7817,8 +7936,18 @@ DeviceModels::$ANDROID_MODELS = [
7817
  'KYV35' => [ 'Kyocera', 'TORQUE G02', 'carrier' => 'au' ],
7818
  'KYV36' => [ 'Kyocera', 'DIGNO rafre KYV36', 'carrier' => 'au' ],
7819
  'KYV37' => [ 'Kyocera', 'Qua phone', 'carrier' => 'au' ],
 
 
7820
  'KYV40' => [ 'Kyocera', 'rafre KYV40', 'carrier' => 'au' ],
 
 
 
 
 
 
7821
  'KYT31' => [ 'Kyocera', 'Qua tab', DeviceType::TABLET, 'carrier' => 'au' ],
 
 
7822
  ],
7823
 
7824
  'URBANO PROGRESSO' => [ 'Kyocera', 'URBANO PROGRESSO', 'carrier' => 'au' ],
@@ -7831,6 +7960,7 @@ DeviceModels::$ANDROID_MODELS = [
7831
  '404KC' => [ 'Kyocera', 'DIGNO C 404KC', 'carrier' => 'Y! Mobile' ],
7832
  '503KC' => [ 'Kyocera', 'DIGNO E 503KC', 'carrier' => 'Y! Mobile' ],
7833
  '602KC' => [ 'Kyocera', 'DIGNO G 602KC', 'carrier' => 'Softbank' ],
 
7834
  ],
7835
 
7836
  'K\-?Touch!!' => [
@@ -8640,6 +8770,7 @@ DeviceModels::$ANDROID_MODELS = [
8640
  'LenovoTV 40S9' => [ 'Lenovo', 'TV 40S9', DeviceType::TELEVISION ],
8641
  'LenovoTV 50S52' => [ 'Lenovo', 'TV 50S52', DeviceType::TELEVISION ],
8642
  '501LV' => [ 'Lenovo', 'Tab2 501LV', 'carrier' => 'Softbank' ],
 
8643
 
8644
  'ZUK Z1' => [ 'Lenovo', 'ZUK Z1' ],
8645
  'ZUK Z2' => [ 'Lenovo', 'ZUK Z2' ],
@@ -8732,7 +8863,9 @@ DeviceModels::$ANDROID_MODELS = [
8732
  'LGAS991' => [ 'LG', 'G4' ],
8733
  'LG-AS9(91)!' => [ 'LG', 'G4' ],
8734
  'LGAS992' => [ 'LG', 'G5' ],
 
8735
  'LGAS995' => [ 'LG', 'G Flex 2' ],
 
8736
  ],
8737
 
8738
  'LG-?C[0-9]{3,3}!!' => [
@@ -8871,6 +9004,7 @@ DeviceModels::$ANDROID_MODELS = [
8871
  'LG-F820!' => [ 'LG', 'U' ],
8872
  ],
8873
 
 
8874
  'LG-GT540!' => [ 'LG', 'Optimus' ],
8875
  'LG-GW620!' => [ 'LG', 'GW620 Eve' ],
8876
 
@@ -8985,6 +9119,8 @@ DeviceModels::$ANDROID_MODELS = [
8985
  'LGL86C!' => [ 'LG', 'Optimus Showtime' ],
8986
  'LG-L95G!' => [ 'LG', 'L95G' ],
8987
  'LGL96G' => [ 'LG', 'Ultimate' ],
 
 
8988
  'LG-L160L' => [ 'LG', 'Optimus LTE2' ],
8989
  'LGL163BL' => [ 'LG', 'Fiesta 2' ],
8990
  'LGL164VL' => [ 'LG', 'Fiesta' ],
@@ -9072,6 +9208,7 @@ DeviceModels::$ANDROID_MODELS = [
9072
  'LG-M4(30)!' => [ 'LG', 'Stylo 3' ],
9073
  'LG-M4(70)!' => [ 'LG', 'Stylo 3 Plus' ],
9074
  'LG-M7(00|03)!' => [ 'LG', 'Q6' ],
 
9075
  ],
9076
 
9077
  'LG-?MS[0-9]{3,3}!!' => [
@@ -9085,6 +9222,7 @@ DeviceModels::$ANDROID_MODELS = [
9085
  'LGMS500' => [ 'LG', 'Optimus F6' ],
9086
  'LG-MS500' => [ 'LG', 'Optimus F6' ],
9087
  'LGMS550' => [ 'LG', 'G Stylo 2' ],
 
9088
  'LGMS631' => [ 'LG', 'G Stylo' ],
9089
  'LG-MS659' => [ 'LG', 'Optimus F3' ],
9090
  'LGMS659' => [ 'LG', 'Optimus F3' ],
@@ -9139,6 +9277,16 @@ DeviceModels::$ANDROID_MODELS = [
9139
  'LG-P815!' => [ 'LG', 'G Pad II 8.3', DeviceType::TABLET ],
9140
  ],
9141
 
 
 
 
 
 
 
 
 
 
 
9142
  'LG-SU[0-9]{3,3}!!' => [
9143
  'LG-SU370' => [ 'LG', 'Optimus One' ],
9144
  'LG-SU540' => [ 'LG', 'PRADA 3.0' ],
@@ -9155,8 +9303,6 @@ DeviceModels::$ANDROID_MODELS = [
9155
  'LG-TP260' => [ 'LG', 'K20 Plus' ],
9156
  'LG-TP450' => [ 'LG', 'Stylo 3 Plus' ],
9157
 
9158
- 'RS988' => [ 'LG', 'G5' ],
9159
-
9160
  'LG-SU-760' => [ 'LG', 'Optimus 3D' ],
9161
  'LGUK410' => [ 'LG', 'G Pad 7.0', DeviceType::TABLET ],
9162
  'LG-UK495' => [ 'LG', 'G Pad F 8.0', DeviceType::TABLET ],
@@ -9169,9 +9315,11 @@ DeviceModels::$ANDROID_MODELS = [
9169
  'LGUS215' => [ 'LG', 'K8 2017' ],
9170
  'LGUS375' => [ 'LG', 'K8' ],
9171
  'LGUS550' => [ 'LG', 'Logos' ],
 
9172
  'LGUS610' => [ 'LG', 'X Power' ],
9173
  'LG-US670' => [ 'LG', 'Optimus U' ],
9174
- 'LG-US701' => [ 'LG', 'X venture' ],
 
9175
  'LG-US730' => [ 'LG', 'Splendor' ],
9176
  'LG-US780' => [ 'LG', 'Optimus F7' ],
9177
  'LGUS990!' => [ 'LG', 'G3' ],
@@ -9181,6 +9329,7 @@ DeviceModels::$ANDROID_MODELS = [
9181
  'LGUS995!' => [ 'LG', 'G Flex 2' ],
9182
  'LG-US996!' => [ 'LG', 'V20' ],
9183
  'LG-US997' => [ 'LG', 'G6' ],
 
9184
  ],
9185
 
9186
  'LG-V[0-9]{3,3}!!' => [
@@ -9267,11 +9416,45 @@ DeviceModels::$ANDROID_MODELS = [
9267
  'LGM-K120[KLS]!' => [ 'LG', 'X300' ],
9268
  'LGM-K121[KLS]!' => [ 'LG', 'X400' ],
9269
  'LGM-V300[KLS]!' => [ 'LG', 'V30' ],
 
9270
  'LGM-X320[KLS]!' => [ 'LG', 'X500' ],
 
9271
  'LGM-X600[KLS]!' => [ 'LG', 'Q6' ],
9272
  'LGM-X800[KLS]!' => [ 'LG', 'Q8' ],
9273
  ],
9274
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9275
  'lge-F160!' => [ 'LG', 'Optimus LTE II' ],
9276
  'LGE-E988!' => [ 'LG', 'Optimus G Pro' ],
9277
  'lgp-970' => [ 'LG', 'Optimus Black' ],
@@ -9291,6 +9474,7 @@ DeviceModels::$ANDROID_MODELS = [
9291
  'LGL24' => [ 'LG', 'isai FL LGL24', 'carrier' => 'au' ],
9292
  'LGL25' => [ 'LG', 'Fx0 LGL25', 'carrier' => 'au' ],
9293
  'LGS01' => [ 'LG', 'Wine Smart LGS01', 'carrier' => 'J:COM' ],
 
9294
  'LGV31' => [ 'LG', 'isai VL LGV31', 'carrier' => 'au' ],
9295
  'LGV32' => [ 'LG', 'isai vivid LGV32', 'carrier' => 'au' ],
9296
  'LGV33' => [ 'LG', 'Qua phone PX LGV33', 'carrier' => 'au' ],
@@ -9354,11 +9538,13 @@ DeviceModels::$ANDROID_MODELS = [
9354
  'L-01D' => [ 'LG', 'Optimus LTE L-01D', 'carrier' => 'DoCoMo' ],
9355
  'L-01E' => [ 'LG', 'Optimus G L-01E', 'carrier' => 'DoCoMo' ],
9356
  'L-01F' => [ 'LG', 'G2 L-01F', 'carrier' => 'DoCoMo' ],
 
9357
  'L-01K' => [ 'LG', 'V30+ L-01K', 'carrier' => 'DoCoMo' ],
9358
  'L-02D' => [ 'LG', 'PRADA phone L-02D', 'carrier' => 'DoCoMo' ],
9359
  'L-02E' => [ 'LG', 'Optimus LIFE L-02E', 'carrier' => 'DoCoMo' ],
9360
  'L-02F' => [ 'LG', 'WiFi STATION L-02F', 'carrier' => 'DoCoMo' ],
9361
  'L-02K' => [ 'LG', 'JOJO L-02K', 'carrier' => 'DoCoMo' ],
 
9362
  'L-04C' => [ 'LG', 'Optimus chat L-04C', 'carrier' => 'DoCoMo' ],
9363
  'L-04E' => [ 'LG', 'Optimus G Pro L-04E', 'carrier' => 'DoCoMo' ],
9364
  'L-05D' => [ 'LG', 'Optimus it L-05D', 'carrier' => 'DoCoMo' ],
@@ -9375,6 +9561,7 @@ DeviceModels::$ANDROID_MODELS = [
9375
  ],
9376
 
9377
  'DM-01G' => [ 'LG', 'DM-01G', 'carrier' => 'Disney Mobile' ],
 
9378
  'DM-02H' => [ 'LG', 'DM-02H', 'carrier' => 'Disney Mobile' ],
9379
 
9380
  'LG!!' => [
@@ -9754,6 +9941,7 @@ DeviceModels::$ANDROID_MODELS = [
9754
  'LIFETAB S1033X' => [ 'Medion', 'Lifetab S1033X', DeviceType::TABLET ],
9755
  'LIFETAB S1034X' => [ 'Medion', 'Lifetab S1034X', DeviceType::TABLET ],
9756
  'LIFETAB S1036X' => [ 'Medion', 'Lifetab S1036X', DeviceType::TABLET ],
 
9757
  'MEDION LIFE P4012' => [ 'Medion', 'Life P4012' ],
9758
  'MEDION P4013' => [ 'Medion', 'Life P4013' ],
9759
  'MEDION-P4013' => [ 'Medion', 'Life P4013' ],
@@ -9778,6 +9966,7 @@ DeviceModels::$ANDROID_MODELS = [
9778
  'MEEG 210R' => [ 'MEEG', '210R' ],
9779
  ],
9780
 
 
9781
  'M1' => [ 'Meizu', 'M1' ],
9782
  'm1 metal' => [ 'Meizu', 'M1 Metal' ],
9783
  'meizu m1note' => [ 'Meizu', 'M1 Note' ],
@@ -9797,7 +9986,9 @@ DeviceModels::$ANDROID_MODELS = [
9797
  'M3s' => [ 'Meizu', 'M3s' ],
9798
  'M4' => [ 'Meizu', 'M4' ],
9799
  'M5' => [ 'Meizu', 'M5' ],
 
9800
  'MEIZU M5' => [ 'Meizu', 'M5' ],
 
9801
  'M8' => [ 'Meizu', 'M8' ],
9802
  'M9' => [ 'Meizu', 'M9' ],
9803
  'M9-unlocked' => [ 'Meizu', 'M9' ],
@@ -9818,11 +10009,13 @@ DeviceModels::$ANDROID_MODELS = [
9818
  'MX4 Pro' => [ 'Meizu', 'MX4 Pro' ],
9819
  'MZ-MX4 Pro' => [ 'Meizu', 'MX4 Pro' ],
9820
  'MX5' => [ 'Meizu', 'MX5' ],
 
9821
  'MX6' => [ 'Meizu', 'MX6' ],
9822
  'PRO 5' => [ 'Meizu', 'PRO 5' ],
9823
  'PRO 6' => [ 'Meizu', 'PRO 6' ],
9824
  'PRO 6s' => [ 'Meizu', 'PRO 6s' ],
9825
  'PRO 6 Plus' => [ 'Meizu', 'PRO 6 Plus' ],
 
9826
 
9827
  '(MEO )?Smart A!!' => [
9828
  'meo smart a12' => [ 'MEO', 'Smart A12' ],
@@ -9847,7 +10040,6 @@ DeviceModels::$ANDROID_MODELS = [
9847
  'SlidePad 104' => [ 'Memup', 'Slidepad 104', DeviceType::TABLET ],
9848
  'SlidePad 108' => [ 'Memup', 'Slidepad 108', DeviceType::TABLET ],
9849
  'SlidePad704CE' => [ 'Memup', 'Slidepad 704CE', DeviceType::TABLET ],
9850
- '704DC' => [ 'Memup', 'Slidepad 704DC', DeviceType::TABLET ],
9851
  'SlidePad 816P' => [ 'Memup', 'Slidepad 816P', DeviceType::TABLET ],
9852
  'SlidePad Elite 9708' => [ 'Memup', 'Slidepad Elite 9708', DeviceType::TABLET ],
9853
  'SlidePad Kids' => [ 'Memup', 'Slidepad Kids', DeviceType::TABLET ],
@@ -9855,6 +10047,8 @@ DeviceModels::$ANDROID_MODELS = [
9855
  'SlidePad NG 704DC' => [ 'Memup', 'Slidepad NG 704DC', DeviceType::TABLET ],
9856
  ],
9857
 
 
 
9858
  'SPNG9716DC' => [ 'Memup', 'Slidepad NG 9716DC', DeviceType::TABLET ],
9859
  'Mi-A402' => [ 'Mi-fone', 'FAB 4.0' ],
9860
 
@@ -10490,6 +10684,13 @@ DeviceModels::$ANDROID_MODELS = [
10490
  'XT19(02)!' => [ 'Lenovo', 'K8 Note' ],
10491
  ],
10492
 
 
 
 
 
 
 
 
10493
  'Atrix 2' => [ 'Motorola', 'ATRIX 2' ],
10494
  'Atrix 2 WeifanZ' => [ 'Motorola', 'ATRIX 2' ],
10495
  'Atrix 4G' => [ 'Motorola', 'ATRIX 4G' ],
@@ -10544,21 +10745,48 @@ DeviceModels::$ANDROID_MODELS = [
10544
  '(Moto)?E2\(4G-LTE\)$!' => [ 'Motorola', 'Moto E (2015)' ],
10545
  'surnia' => [ 'Motorola', 'Moto E (2015)' ],
10546
  'Motorola MotoE2!' => [ 'Motorola', 'Moto E2' ],
 
10547
  'Moto E (4)' => [ 'Motorola', 'Moto E4' ],
10548
  'Moto E (4) Plus' => [ 'Motorola', 'Moto E4 Plus' ],
 
 
10549
  '(Moto)?G3$!' => [ 'Motorola', 'Moto G (2015)' ],
10550
  '(Moto)?G3-TE$!' => [ 'Motorola', 'Moto G (2015)' ],
 
 
 
10551
  'MOTOROLA MOTOG' => [ 'Motorola', 'Moto G' ],
10552
  'Moto G Play' => [ 'Motorola', 'Moto G Play' ],
 
10553
  'Moto G4' => [ 'Motorola', 'Moto G4' ],
 
10554
  'Moto G (4)' => [ 'Motorola', 'Moto G4' ],
10555
  'Moto G4 Plus' => [ 'Motorola', 'Moto G4 Plus' ],
 
 
10556
  'Moto G (5)' => [ 'Motorola', 'Moto G5' ],
10557
  'Moto G (5) Plus' => [ 'Motorola', 'Moto G5 Plus' ],
 
 
10558
  'Moto G (5S) Plus' => [ 'Motorola', 'Moto G5S Plus' ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10559
  'Moto Z (2)' => [ 'Motorola', 'Moto Z2' ],
10560
  'Moto Z2 Play' => [ 'Motorola', 'Moto Z2 Play' ],
10561
  'Moto X Pro' => [ 'Motorola', 'Moto X Pro' ],
 
10562
  'roiX' => [ 'Motorola', 'Droid X' ],
10563
  'Moto Backflip' => [ 'Motorola', 'BACKFLIP' ],
10564
  'RAZR' => [ 'Motorola', 'RAZR' ],
@@ -10952,11 +11180,39 @@ DeviceModels::$ANDROID_MODELS = [
10952
 
10953
  'NBX-T7013N' => [ 'Noblex', 'T7013N', DeviceType::TABLET ],
10954
  'NBX-T7023N' => [ 'Noblex', 'T7023N', DeviceType::TABLET ],
 
 
10955
  'TA-10(20|28|32|38)!' => [ 'Nokia', '3' ],
 
10956
  'TA-10(24|27|44|53)!' => [ 'Nokia', '5' ],
 
10957
  'TA-10(00|03|21|25|33|39)!' => [ 'Nokia', '6' ],
 
10958
  'TA-10(41)!' => [ 'Nokia', '7' ],
 
10959
  'TA-10(04|12|52)!' => [ 'Nokia', '8' ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10960
  'Nokia N9' => [ 'Nokia', 'N9' ],
10961
  'Nokia N900' => [ 'Nokia', 'N900' ],
10962
  'Nokia X' => [ 'Nokia', 'X', DeviceType::MOBILE, Flag::NOKIAX ],
@@ -11087,6 +11343,14 @@ DeviceModels::$ANDROID_MODELS = [
11087
  'ONEPLUS A3010' => [ 'OnePlus', '3T' ],
11088
  'ONEPLUS A5000' => [ 'OnePlus', '5' ],
11089
  'ONEPLUS A5010' => [ 'OnePlus', '5T' ],
 
 
 
 
 
 
 
 
11090
  'ONE E1000' => [ 'OnePlus', 'X' ],
11091
  'ONE E1001' => [ 'OnePlus', 'X' ],
11092
  'ONE E1003' => [ 'OnePlus', 'X' ],
@@ -11131,6 +11395,19 @@ DeviceModels::$ANDROID_MODELS = [
11131
  'N2T' => [ 'ONN', 'N2T', DeviceType::TABLET ],
11132
  'Renesas!' => [ 'Opad', 'Renesas', DeviceType::TABLET ],
11133
  'A11w' => [ 'Oppo', 'Joy 3' ],
 
 
 
 
 
 
 
 
 
 
 
 
 
11134
  'OPPO A30' => [ 'Oppo', 'A30' ],
11135
  'A31' => [ 'Oppo', 'A31' ],
11136
  'OPPO A31' => [ 'Oppo', 'A31' ],
@@ -11138,6 +11415,7 @@ DeviceModels::$ANDROID_MODELS = [
11138
  'A31c' => [ 'Oppo', 'A31c' ],
11139
  'A31t' => [ 'Oppo', 'A31t' ],
11140
  'OPPO A31t' => [ 'Oppo', 'A31t' ],
 
11141
  'OPPO A33' => [ 'Oppo', 'A33' ],
11142
  'A33f' => [ 'Oppo', 'A33f' ],
11143
  'OPPO A33m' => [ 'Oppo', 'A33m' ],
@@ -11146,9 +11424,11 @@ DeviceModels::$ANDROID_MODELS = [
11146
  'A37fw' => [ 'Oppo', 'A37fw' ],
11147
  'OPPO A37m' => [ 'Oppo', 'A37m' ],
11148
  'CPH1605' => [ 'Oppo', 'A39' ],
 
11149
  'A51f' => [ 'Oppo', 'A51f' ],
11150
  'OPPO A53' => [ 'Oppo', 'A53' ],
11151
  'OPPO A53m' => [ 'Oppo', 'A53m' ],
 
11152
  'CPH1701' => [ 'Oppo', 'A57' ],
11153
  'OPPO A57' => [ 'Oppo', 'A57' ],
11154
  'OPPO A57t' => [ 'Oppo', 'A57t' ],
@@ -11156,8 +11436,19 @@ DeviceModels::$ANDROID_MODELS = [
11156
  'OPPO A59s' => [ 'Oppo', 'A59s' ],
11157
  'OPPO A59st' => [ 'Oppo', 'A59st' ],
11158
  'CPH1717' => [ 'Oppo', 'A71' ],
 
 
 
 
11159
  'OPPO A77' => [ 'Oppo', 'A77' ],
11160
  'OPPO A77t' => [ 'Oppo', 'A77t' ],
 
 
 
 
 
 
 
11161
  'OPPO A800' => [ 'Oppo', 'A800' ],
11162
  'A1603' => [ 'Oppo', 'C1' ],
11163
  'F1f' => [ 'Oppo', 'F1f' ],
@@ -11166,6 +11457,13 @@ DeviceModels::$ANDROID_MODELS = [
11166
  'CPH1609' => [ 'Oppo', 'F3' ],
11167
  'CPH1613' => [ 'Oppo', 'F3 Plus' ],
11168
  'CPH1723' => [ 'Oppo', 'F5' ],
 
 
 
 
 
 
 
11169
  'Find 5' => [ 'Oppo', 'Find 5' ],
11170
  'X903' => [ 'Oppo', 'Find Me X903' ],
11171
  'X903S' => [ 'Oppo', 'Find X903S' ],
@@ -11182,6 +11480,7 @@ DeviceModels::$ANDROID_MODELS = [
11182
  'X9000' => [ 'Oppo', 'Find 7a X9000' ],
11183
  'X9006' => [ 'Oppo', 'Find 7a X9006' ],
11184
  'X9007' => [ 'Oppo', 'Find 7a X9007' ],
 
11185
  'X9009' => [ 'Oppo', 'F1 Plus X9009' ],
11186
  'X9015' => [ 'Oppo', 'Find X9015' ],
11187
  'OPPOX9015' => [ 'Oppo', 'Find X9015' ],
@@ -11283,10 +11582,18 @@ DeviceModels::$ANDROID_MODELS = [
11283
  'OPPOU7015' => [ 'Oppo', 'Find Way U7015' ],
11284
  'U7015' => [ 'Oppo', 'Find Way U7015' ],
11285
  'A51w' => [ 'Oppo', 'Mirror 5' ],
 
 
 
 
11286
  'OPPO N1' => [ 'Oppo', 'N1' ],
11287
  'N51(10|11|16|17)!' => [ 'Oppo', 'N1 mini' ],
11288
  'N52(06|07|09)!' => [ 'Oppo', 'N3' ],
 
 
11289
  'OPPO R7' => [ 'Oppo', 'R7' ],
 
 
11290
  'R7f' => [ 'Oppo', 'R7f' ],
11291
  'R7i' => [ 'Oppo', 'R7i' ],
11292
  'R7kf' => [ 'Oppo', 'R7kf' ],
@@ -11295,15 +11602,19 @@ DeviceModels::$ANDROID_MODELS = [
11295
  'OPPO R7sm' => [ 'Oppo', 'R7sm' ],
11296
  'OPPO R7st' => [ 'Oppo', 'R7st' ],
11297
  'OPPO R7t' => [ 'Oppo', 'R7t' ],
 
 
11298
  'OPPO R9m' => [ 'Oppo', 'R9m' ],
11299
  'OPPO R9tm' => [ 'Oppo', 'R9tm' ],
11300
  'OPPO R9km' => [ 'Oppo', 'R9km' ],
11301
  'OPPO R9s' => [ 'Oppo', 'R9s' ],
11302
  'OPPO R9sk' => [ 'Oppo', 'R9sk' ],
11303
  'OPPO R9st' => [ 'Oppo', 'R9st' ],
 
11304
  'OPPO R9t' => [ 'Oppo', 'R9t' ],
11305
  'OPPO R9tm' => [ 'Oppo', 'R9tm' ],
11306
  'OPPO R11' => [ 'Oppo', 'R11' ],
 
11307
  'OPPO R11t' => [ 'Oppo', 'R11t' ],
11308
  'OPPO R7 Plus' => [ 'Oppo', 'R7 Plus' ],
11309
  'R7Plus' => [ 'Oppo', 'R7 Plus' ],
@@ -11314,14 +11625,41 @@ DeviceModels::$ANDROID_MODELS = [
11314
  'OPPO R9 Plustm A' => [ 'Oppo', 'R9 Plus' ],
11315
  'CPH1611' => [ 'Oppo', 'R9s Plus' ],
11316
  'OPPO R9s Plus' => [ 'Oppo', 'R9s Plus' ],
 
11317
  'OPPO R11 Plus' => [ 'Oppo', 'R11 Plus' ],
11318
- 'OPPO R11 Plusk' => [ 'Oppo', 'R11 Plus' ],
11319
- 'OPPO R11 Pluskt' => [ 'Oppo', 'R11 Plus' ],
 
11320
  'OPPO R11s Plus' => [ 'Oppo', 'R11s Plus' ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11321
  'W8' => [ 'Oppo', 'W8' ],
 
11322
  '1105' => [ 'Oppo', '1105' ],
11323
  '1107' => [ 'Oppo', '1107' ],
11324
  'OB-OPPO 3005' => [ 'Oppo', '3005' ],
 
 
 
 
 
 
 
 
 
11325
 
11326
  'OPSSON!!' => [
11327
  'OPSSON D1' => [ 'Opsson', 'D1' ],
@@ -11492,6 +11830,7 @@ DeviceModels::$ANDROID_MODELS = [
11492
  'FZ-A2A' => [ 'Panasonic', 'Toughpad FZ-A2', DeviceType::TABLET ],
11493
  'FZ-B2(B|D)!' => [ 'Panasonic', 'Toughpad FZ-B1', DeviceType::TABLET ],
11494
  'FZ-N1' => [ 'Panasonic', 'Toughpad FZ-N1' ],
 
11495
  'FZ-X1' => [ 'Panasonic', 'Toughpad FZ-X1' ],
11496
 
11497
  'Altus 18' => [ 'Panasonic', 'Altus 18', DeviceType::INFLIGHT ],
@@ -12916,24 +13255,50 @@ DeviceModels::$ANDROID_MODELS = [
12916
  'SMT-i9100' => [ 'Samsung', 'Galaxy Tab 7.0', DeviceType::TABLET ],
12917
 
12918
  'SM-A[0-9]{3,3}!!' => [
 
 
 
 
 
 
 
 
 
12919
  'SM-A300!' => [ 'Samsung', 'Galaxy A3' ],
 
 
12920
  'SM-A310!' => [ 'Samsung', 'Galaxy A3 (2016)' ],
12921
  'SM-A320!' => [ 'Samsung', 'Galaxy A3 (2017)' ],
 
12922
  'SM-A430!' => [ 'Samsung', 'Galaxy A4' ],
12923
  'SM-A450!' => [ 'Samsung', 'Galaxy A4 (2017)' ],
 
12924
  'SM-A500!' => [ 'Samsung', 'Galaxy A5' ],
 
 
12925
  'SM-A510!' => [ 'Samsung', 'Galaxy A5 (2016)' ],
 
 
12926
  'SM-A520!' => [ 'Samsung', 'Galaxy A5 (2017)' ],
12927
  'SM-A530!' => [ 'Samsung', 'Galaxy A8 (2018)' ],
 
 
 
 
12928
  'SM-A700!' => [ 'Samsung', 'Galaxy A7' ],
 
12929
  'SM-A710!' => [ 'Samsung', 'Galaxy A7 (2016)' ],
 
12930
  'SM-A720!' => [ 'Samsung', 'Galaxy A7 (2017)' ],
12931
  'SM-A730!' => [ 'Samsung', 'Galaxy A8+ (2018)' ],
 
12932
  'SM-A800!' => [ 'Samsung', 'Galaxy A8' ],
 
12933
  'SM-A810!' => [ 'Samsung', 'Galaxy A8 (2016)' ],
12934
  'SM-A850!' => [ 'Samsung', 'Galaxy Alpha' ],
12935
  'SM-A900!' => [ 'Samsung', 'Galaxy A9 (2016)' ],
12936
  'SM-A910!' => [ 'Samsung', 'Galaxy A9 Pro' ],
 
12937
  ],
12938
 
12939
  'SM-C[0-9]{3,3}!!' => [
@@ -12952,6 +13317,14 @@ DeviceModels::$ANDROID_MODELS = [
12952
  'SM-E700!' => [ 'Samsung', 'Galaxy E7' ],
12953
  ],
12954
 
 
 
 
 
 
 
 
 
12955
  'SM-G[0-9]{3,3}!!' => [
12956
  'SM-G110!' => [ 'Samsung', 'Galaxy Pocket 2' ],
12957
  'SM-G130BT' => [ 'Samsung', 'Galaxy Young 2' ],
@@ -12962,7 +13335,7 @@ DeviceModels::$ANDROID_MODELS = [
12962
  'SM-G130HN' => [ 'Samsung', 'Galaxy Young 2 Duos' ],
12963
  'SM-G130M' => [ 'Samsung', 'Galaxy Young 2 Duos' ],
12964
  'SM-G1(50|55)!' => [ 'Samsung', 'Galaxy Folder' ],
12965
- 'SM-G160!' => [ 'Samsung', 'Galaxy Folder 2' ],
12966
  'SM-G310H' => [ 'Samsung', 'Galaxy Ace 4' ],
12967
  'SM-G310HN' => [ 'Samsung', 'Galaxy Ace Style' ],
12968
  'SM-G310R5' => [ 'Samsung', 'GreatCall Touch 3' ],
@@ -13005,17 +13378,24 @@ DeviceModels::$ANDROID_MODELS = [
13005
  'SM-G570!' => [ 'Samsung', 'Galaxy J5 Prime' ],
13006
  'SM-G600!' => [ 'Samsung', 'Galaxy On7' ],
13007
  'SM-G610!' => [ 'Samsung', 'Galaxy J7 Prime' ],
 
13008
  'SM-G615!' => [ 'Samsung', 'Galaxy J7 Max' ],
 
13009
  'SM-G710!' => [ 'Samsung', 'Galaxy Grand 2' ],
 
13010
  'SM-G720!' => [ 'Samsung', 'Galaxy Grand 3' ],
13011
  'SM-G730!' => [ 'Samsung', 'Galaxy S III Mini' ],
13012
  'SM-G750!' => [ 'Samsung', 'Galaxy Mega 2 ' ],
13013
- 'SM-G770!' => [ 'Samsung', 'Galaxy On7' ],
13014
  'SM-G800!' => [ 'Samsung', 'Galaxy S5 Mini' ],
13015
  'SM-G850!' => [ 'Samsung', 'Galaxy Alpha' ],
13016
  'SM-G860!' => [ 'Samsung', 'Galaxy S5 Sport' ],
13017
  'SM-G870!' => [ 'Samsung', 'Galaxy S5 Active' ],
 
13018
  'SM-G880!' => [ 'Samsung', 'Galaxy S7 mini' ],
 
 
 
13019
  'SM-G890!' => [ 'Samsung', 'Galaxy S6 Active' ],
13020
  'SM-G891!' => [ 'Samsung', 'Galaxy S7 Active' ],
13021
  'SM-G892!' => [ 'Samsung', 'Galaxy S8 Active' ],
@@ -13029,12 +13409,22 @@ DeviceModels::$ANDROID_MODELS = [
13029
  'SM-G920!' => [ 'Samsung', 'Galaxy S6' ],
13030
  'SM-G925!' => [ 'Samsung', 'Galaxy S6 Edge' ],
13031
  'SM-G928!' => [ 'Samsung', 'Galaxy S6 Edge+' ],
 
13032
  'SM-G930!' => [ 'Samsung', 'Galaxy S7' ],
13033
  'SM-G935!' => [ 'Samsung', 'Galaxy S7 Edge' ],
13034
  'SM-G950!' => [ 'Samsung', 'Galaxy S8' ],
13035
  'SM-G955!' => [ 'Samsung', 'Galaxy S8+' ],
13036
  'SM-G960!' => [ 'Samsung', 'Galaxy S9' ],
13037
  'SM-G965!' => [ 'Samsung', 'Galaxy S9+' ],
 
 
 
 
 
 
 
 
 
13038
  ],
13039
 
13040
  'SM-I9500' => [ 'Samsung', 'Galaxy S4' ],
@@ -13048,24 +13438,40 @@ DeviceModels::$ANDROID_MODELS = [
13048
  'SM-J200!' => [ 'Samsung', 'Galaxy J2' ],
13049
  'SM-J210!' => [ 'Samsung', 'Galaxy J2 (2016)' ],
13050
  'SM-J250!' => [ 'Samsung', 'Galaxy J2 (2018)' ],
 
13051
  'SM-J3(10|20)!' => [ 'Samsung', 'Galaxy J3' ],
13052
  'SM-J311!' => [ 'Samsung', 'Galaxy J3 (2016)' ],
13053
  'SM-J321!' => [ 'Samsung', 'Galaxy Sol' ],
13054
  'SM-J326!' => [ 'Samsung', 'Galaxy Sol 2' ],
13055
  'SM-J327!' => [ 'Samsung', 'Galaxy J3 Emerge' ],
13056
  'SM-J330!' => [ 'Samsung', 'Galaxy J3 (2017)' ],
 
 
 
 
13057
  'SM-J500!' => [ 'Samsung', 'Galaxy J5' ],
13058
  'SM-J510!' => [ 'Samsung', 'Galaxy J5 (2016)' ],
13059
  'SM-J530!' => [ 'Samsung', 'Galaxy J5 (2017)' ],
 
 
13060
  'SM-J700!' => [ 'Samsung', 'Galaxy J7' ],
13061
  'SM-J701!' => [ 'Samsung', 'Galaxy J7 Core' ],
13062
  'SM-J710!' => [ 'Samsung', 'Galaxy J7 (2016)' ],
 
13063
  'SM-J727!' => [ 'Samsung', 'Galaxy J7 Perx' ],
13064
  'SM-J730!' => [ 'Samsung', 'Galaxy J7 (2017)' ],
 
13065
  'SM-J800!' => [ 'Samsung', 'Galaxy J8' ],
 
13066
  'SM-J900!' => [ 'Samsung', 'Galaxy J9' ],
13067
  ],
13068
 
 
 
 
 
 
 
13069
  'SM-N[0-9]{3,4}!!' => [
13070
  'SM-N750[025789][QV]?!' => [ 'Samsung', 'Galaxy Note 3 Neo' ],
13071
  'SM-N750[LS]?!' => [ 'Samsung', 'Galaxy Note 3 Neo' ],
@@ -13078,7 +13484,13 @@ DeviceModels::$ANDROID_MODELS = [
13078
  'SM-N920!' => [ 'Samsung', 'Galaxy Note 5' ],
13079
  'SM-N930!' => [ 'Samsung', 'Galaxy Note 7' ],
13080
  'SM-N935!' => [ 'Samsung', 'Galaxy Note FE' ],
13081
- 'SM-N950!' => [ 'Samsung', 'Galaxy Note 8' ],
 
 
 
 
 
 
13082
  ],
13083
 
13084
  'SM-P[0-9]{3,3}!!' => [
@@ -13086,6 +13498,7 @@ DeviceModels::$ANDROID_MODELS = [
13086
  'SM-P55[015]!' => [ 'Samsung', 'Galaxy Tab A Plus 9.7', DeviceType::TABLET ],
13087
  'SM-P58[058]!' => [ 'Samsung', 'Galaxy Tab A 10.1 with S Pen (2016)', DeviceType::TABLET ],
13088
  'SM-P60[01257]!' => [ 'Samsung', 'Galaxy Note 10.1 (2014)', DeviceType::TABLET ],
 
13089
  'SM-P90[01257]!' => [ 'Samsung', 'Galaxy Note Pro', DeviceType::TABLET ],
13090
  ],
13091
 
@@ -13094,11 +13507,14 @@ DeviceModels::$ANDROID_MODELS = [
13094
  'SM-S320VL' => [ 'Samsung', 'Galaxy Sky' ],
13095
  'SM-S327VL' => [ 'Samsung', 'Galaxy J3 Luna Pro' ],
13096
  'SM-S337TL' => [ 'Samsung', 'Galaxy J3 Luna Pro' ],
 
13097
  'SM-S550TL' => [ 'Samsung', 'Galaxy On5' ],
13098
  'SM-S727VL' => [ 'Samsung', 'Galaxy J7 Sky Pro' ],
13099
  'SM-S737TL' => [ 'Samsung', 'Galaxy J7 Sky Pro' ],
 
13100
  'SM-S765C' => [ 'Samsung', 'Galaxy Ace Style' ],
13101
  'SM-S766C' => [ 'Samsung', 'Galaxy Stardust' ],
 
13102
  'SM-S777C' => [ 'Samsung', 'Galaxy J1' ],
13103
  'SM-S780L' => [ 'Samsung', 'Galaxy Mega 6.3' ],
13104
  'SM-S820L' => [ 'Samsung', 'Galaxy Core Prime' ],
@@ -13121,6 +13537,8 @@ DeviceModels::$ANDROID_MODELS = [
13121
  'SM-T255[68S]!' => [ 'Samsung', 'Galaxy Tab Q' ],
13122
  'SM-T23[012579]!' => [ 'Samsung', 'Galaxy Tab 4 7.0', DeviceType::TABLET ],
13123
  'SM-T28[057]!' => [ 'Samsung', 'Galaxy Tab A 7.0', DeviceType::TABLET ],
 
 
13124
  'SM-T31[0125]!' => [ 'Samsung', 'Galaxy Tab 3 8.0', DeviceType::TABLET ],
13125
  'SM-T32[0125]!' => [ 'Samsung', 'Galaxy Tab Pro 8.4', DeviceType::TABLET ],
13126
  'SM-T33[01257]!' => [ 'Samsung', 'Galaxy Tab 4 8.0', DeviceType::TABLET ],
@@ -13129,7 +13547,9 @@ DeviceModels::$ANDROID_MODELS = [
13129
  'SM-T36[05]!' => [ 'Samsung', 'Galaxy Tab Active 8.0', DeviceType::TABLET ],
13130
  'SM-T37[578]!' => [ 'Samsung', 'Galaxy Tab E 8.0', DeviceType::TABLET ],
13131
  'SM-T38[05]!' => [ 'Samsung', 'Galaxy Tab A 8.0 (2017)', DeviceType::TABLET ],
13132
- 'SM-T39[5]!' => [ 'Samsung', 'Galaxy Tab Active2 8.0', DeviceType::TABLET ],
 
 
13133
  'SM-T520CC' => [ 'Samsung', 'Galaxy Tab Pro 10.1 Chef Collection', DeviceType::TABLET ],
13134
  'SM-T52[057]!' => [ 'Samsung', 'Galaxy Tab Pro 10.1', DeviceType::TABLET ],
13135
  'SM-T530NU' => [ 'Samsung', 'Galaxy Tab 4 Nook 10.1', DeviceType::TABLET ],
@@ -13138,17 +13558,25 @@ DeviceModels::$ANDROID_MODELS = [
13138
  'SM-T53[157]!' => [ 'Samsung', 'Galaxy Tab 4 10.0', DeviceType::TABLET ],
13139
  'SM-T55[015]!' => [ 'Samsung', 'Galaxy Tab A 9.7', DeviceType::TABLET ],
13140
  'SM-T58[057]!' => [ 'Samsung', 'Galaxy Tab A 10.1 (2016)', DeviceType::TABLET ],
 
13141
  'SM-T56[0127]!' => [ 'Samsung', 'Galaxy Tab E 9.6', DeviceType::TABLET ],
 
13142
  'SM-T67[07]!' => [ 'Samsung', 'Galaxy View', DeviceType::TABLET ],
13143
  'SM-T70[057]!' => [ 'Samsung', 'Galaxy Tab S 8.4', DeviceType::TABLET ],
13144
  'SM-T71[05]!' => [ 'Samsung', 'Galaxy Tab S2 8.0', DeviceType::TABLET ],
13145
  'SM-T71[39]!' => [ 'Samsung', 'Galaxy Tab S2 8.0 (2016)', DeviceType::TABLET ],
 
13146
  'SM-T80[0157]!' => [ 'Samsung', 'Galaxy Tab S 10.5', DeviceType::TABLET ],
13147
  'SM-T81[057]!' => [ 'Samsung', 'Galaxy Tab S2 9.7', DeviceType::TABLET ],
13148
  'SM-T81[39]!' => [ 'Samsung', 'Galaxy Tab S2 9.7 (2016)', DeviceType::TABLET ],
13149
  'SM-T81[8]!' => [ 'Samsung', 'Galaxy Tab S2 Plus 9.7', DeviceType::TABLET ],
13150
  'SM-T82[057]!' => [ 'Samsung', 'Galaxy Tab S3 9.7', DeviceType::TABLET ],
 
 
 
13151
  'SM-T90[05]!' => [ 'Samsung', 'Galaxy Tab Pro 12.2', DeviceType::TABLET ],
 
 
13152
  ],
13153
 
13154
  'SM-V700' => [ 'Samsung', 'Galaxy Gear', DeviceType::WATCH ],
@@ -13290,6 +13718,8 @@ DeviceModels::$ANDROID_MODELS = [
13290
  'SC-01G' => [ 'Samsung', 'GALAXY Note Edge SC-01G', 'carrier' => 'DoCoMo' ],
13291
  'SC-01H' => [ 'Samsung', 'GALAXY Active neo SC-01H', 'carrier' => 'DoCoMo' ],
13292
  'SC-01K' => [ 'Samsung', 'GALAXY Note 8 SC-01K', 'carrier' => 'DoCoMo' ],
 
 
13293
  'SC-02B' => [ 'Samsung', 'GALAXY S SC-02B', 'carrier' => 'DoCoMo' ],
13294
  'SC-02C' => [ 'Samsung', 'GALAXY S II SC-02C', 'carrier' => 'DoCoMo' ],
13295
  'SC-02D' => [ 'Samsung', 'GALAXY Tab 7.0 Plus SC-02D', DeviceType::TABLET, 'carrier' => 'DoCoMo' ],
@@ -13298,16 +13728,21 @@ DeviceModels::$ANDROID_MODELS = [
13298
  'SC-02G' => [ 'Samsung', 'GALAXY S5 Active SC-02G', 'carrier' => 'DoCoMo' ],
13299
  'SC-02H' => [ 'Samsung', 'Galaxy S7 Edge SC-02H', 'carrier' => 'DoCoMo' ],
13300
  'SC-02J' => [ 'Samsung', 'Galaxy S8 SC-02J', 'carrier' => 'DoCoMo' ],
 
 
13301
  'SC-03D' => [ 'Samsung', 'GALAXY S II LTE SC-03D', 'carrier' => 'DoCoMo' ],
13302
  'SC-03E' => [ 'Samsung', 'GALAXY S III α SC-03E', 'carrier' => 'DoCoMo' ],
13303
  'SC03E' => [ 'Samsung', 'GALAXY S III α SC-03E', 'carrier' => 'DoCoMo' ],
13304
  'SC-03G' => [ 'Samsung', 'GALAXY Tab S 8.4 SC-03G', DeviceType::TABLET, 'carrier' => 'DoCoMo' ],
13305
  'SC-03J' => [ 'Samsung', 'GALAXY S8+ SC-03J', 'carrier' => 'DoCoMo' ],
 
 
13306
  'SC-04D' => [ 'Samsung', 'GALAXY NEXUS SC-04D', 'carrier' => 'DoCoMo' ],
13307
  'SC-04E' => [ 'Samsung', 'GALAXY S4 SC-04E', 'carrier' => 'DoCoMo' ],
13308
  'SC-04F' => [ 'Samsung', 'GALAXY S5 SC-04F', 'carrier' => 'DoCoMo' ],
13309
  'SC-04G' => [ 'Samsung', 'GALAXY S6 Edge SC-04G', 'carrier' => 'DoCoMo' ],
13310
  'SC-04J' => [ 'Samsung', 'GALAXY Feel SC-04J', 'carrier' => 'DoCoMo' ],
 
13311
  'SC-05D' => [ 'Samsung', 'GALAXY Note SC-05D', 'carrier' => 'DoCoMo' ],
13312
  'SC-05G' => [ 'Samsung', 'GALAXY S6 SC-05G', 'carrier' => 'DoCoMo' ],
13313
  'SC-06D' => [ 'Samsung', 'GALAXY S III SC-06D', 'carrier' => 'DoCoMo' ],
@@ -13322,9 +13757,14 @@ DeviceModels::$ANDROID_MODELS = [
13322
  'SCV31' => [ 'Samsung', 'GALAXY S6 Edge SCV31', 'carrier' => 'au' ],
13323
  'SCV32' => [ 'Samsung', 'GALAXY A8 SCV32', 'carrier' => 'au' ],
13324
  'SCV33' => [ 'Samsung', 'GALAXY S7 edge Injustice Edition SCV33', 'carrier' => 'au' ],
 
13325
  'SCV35' => [ 'Samsung', 'GALAXY S8+ SCV35', 'carrier' => 'au' ],
13326
  'SCV36' => [ 'Samsung', 'GALAXY S8 SCV36', 'carrier' => 'au' ],
13327
  'SCV37' => [ 'Samsung', 'GALAXY Note8 SCV37', 'carrier' => 'au' ],
 
 
 
 
13328
  ],
13329
 
13330
  'ISW11SC' => [ 'Samsung', 'GALAXY S II WiMAX ISW11SC', 'carrier' => 'au' ],
@@ -13398,7 +13838,7 @@ DeviceModels::$ANDROID_MODELS = [
13398
  'SFR StarTab' => [ 'SFR', 'STARTAB', DeviceType::TABLET ],
13399
  'Bambook S1' => [ 'Shanda', 'Bambook S1', DeviceType::TABLET ],
13400
 
13401
- '[456A]0[0-9]SH!!' => [
13402
  '401SH' => [ 'Sharp', '401SH', 'carrier' => 'Softbank' ],
13403
  '402SH' => [ 'Sharp', 'AQUOS CRYSTAL X 402SH', 'carrier' => 'Softbank' ],
13404
  '403SH' => [ 'Sharp', 'AQUOS CRYSTAL 2 403SH', 'carrier' => 'Softbank' ],
@@ -13460,7 +13900,7 @@ DeviceModels::$ANDROID_MODELS = [
13460
  'SBM306SH' => [ 'Sharp', 'AQUOS CRYSTAL 306SH' ], // The U.S. Sprint version (now part of Softbank)
13461
  ],
13462
 
13463
- '(3|5|6)0[0-9]SH!!' => [
13464
  '304SH' => [ 'Sharp', 'AQUOS Xx 304SH', 'carrier' => 'Softbank' ],
13465
  '305SH' => [ 'Sharp', 'AQUOS CRYSTAL 305SH', 'carrier' => 'Softbank' ],
13466
  '306SH' => [ 'Sharp', 'AQUOS CRYSTAL 306SH' ], // The U.S. Sprint version (now part of Softbank)
@@ -13468,6 +13908,8 @@ DeviceModels::$ANDROID_MODELS = [
13468
  '507SH' => [ 'Sharp', 'Android One 507SH', 'carrier' => 'Y! Mobile' ],
13469
  '509SH' => [ 'Sharp', 'シンプルスマホ3 509SH', 'carrier' => 'Softbank' ],
13470
  '605SH' => [ 'Sharp', 'AQUOS R 605SH', 'carrier' => 'Softbank' ],
 
 
13471
  ],
13472
 
13473
  'SH01D' => [ 'Sharp', 'AQUOS PHONE SH-01D', 'carrier' => 'DoCoMo' ],
@@ -13478,6 +13920,7 @@ DeviceModels::$ANDROID_MODELS = [
13478
  'SH-M02' => [ 'Sharp', 'AQUOS SH-M02' ],
13479
  'SH-M02-EVA20' => [ 'Sharp', 'AQUOS SH-M02' ],
13480
  'SH-M03' => [ 'Sharp', 'AQUOS mini SH-M03' ],
 
13481
  'SH-RM02' => [ 'Sharp', 'AQUOS SH-RM02' ],
13482
 
13483
  'SH-[01][0-9][A-Z]!!' => [
@@ -13488,6 +13931,9 @@ DeviceModels::$ANDROID_MODELS = [
13488
  'SH-01FDQ' => [ 'Sharp', 'SH-01F DRAGON QUEST', 'carrier' => 'DoCoMo' ],
13489
  'SH-01G' => [ 'Sharp', 'AQUOS PHONE ZETA SH-01G', 'carrier' => 'DoCoMo' ],
13490
  'SH-01H' => [ 'Sharp', 'AQUOS PHONE ZETA SH-01H', 'carrier' => 'DoCoMo' ],
 
 
 
13491
  'SH-02D' => [ 'Sharp', 'AQUOS PHONE slider SH-02D', 'carrier' => 'DoCoMo' ],
13492
  'SH-02E' => [ 'Sharp', 'AQUOS PHONE ZETA SH-02E', 'carrier' => 'DoCoMo' ],
13493
  'SH-02F' => [ 'Sharp', 'AQUOS PHONE EX SH-02F', 'carrier' => 'DoCoMo' ],
@@ -13499,6 +13945,7 @@ DeviceModels::$ANDROID_MODELS = [
13499
  'SH-03G' => [ 'Sharp', 'AQUOS ZETA SH-03G', 'carrier' => 'DoCoMo' ],
13500
  'SH-03H' => [ 'Sharp', 'SH-03H', 'carrier' => 'DoCoMo' ],
13501
  'SH-03J' => [ 'Sharp', 'AQUOS R SH-03J', 'carrier' => 'DoCoMo' ],
 
13502
  'SH-04D' => [ 'Sharp', 'Q-pot.Phone SH-04D', 'carrier' => 'DoCoMo' ],
13503
  'SH-04E' => [ 'Sharp', 'AQUOS PHONE EX SH-04E', 'carrier' => 'DoCoMo' ],
13504
  'SH-04F' => [ 'Sharp', 'AQUOS ZETA SH-04F', 'carrier' => 'DoCoMo' ],
@@ -13575,9 +14022,13 @@ DeviceModels::$ANDROID_MODELS = [
13575
  'SHV35' => [ 'Sharp', 'AQUOS U SHV35', 'carrier' => 'au' ],
13576
  'SHV36' => [ 'Sharp', 'BASIO2 SHV36', 'carrier' => 'au' ],
13577
  'SHV37' => [ 'Sharp', 'AQUOS U SHV37', 'carrier' => 'au' ],
 
13578
  'SHV38' => [ 'Sharp', 'AQUOS SERIE mini SHV38', 'carrier' => 'au' ],
13579
  'SHV39' => [ 'Sharp', 'AQUOS R SHV39', 'carrier' => 'au' ],
 
 
13580
  'SHV41' => [ 'Sharp', 'AQUOS R compact SHV41', 'carrier' => 'au' ],
 
13581
  ],
13582
  'WX04SH' => [ 'Sharp', 'AQUOS PHONE es WX04SH', 'carrier' => 'Willcom' ],
13583
  'WX05SH' => [ 'Sharp', 'AQUOS PHONE ef WX05SH', 'carrier' => 'Willcom' ],
@@ -13817,7 +14268,7 @@ DeviceModels::$ANDROID_MODELS = [
13817
  ],
13818
 
13819
  'G[0-9]{4,4}!!' => [
13820
- 'G31(12|16|21|23|25)!' => [ 'Sony', 'Xperia XA1' ],
13821
  'G32(12|21|23|26)!' => [ 'Sony', 'Xperia XA1 Ultra' ],
13822
  'G33(11|12|13)!' => [ 'Sony', 'Xperia L1' ],
13823
  'G34(12|16|21|23|26)!' => [ 'Sony', 'Xperia XA1 Plus' ],
@@ -13828,7 +14279,25 @@ DeviceModels::$ANDROID_MODELS = [
13828
  ],
13829
 
13830
  'H[0-9]{4,4}!!' => [
13831
- 'H42(33)!' => [ 'Sony', 'Xperia XA2 Ultra' ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13832
  ],
13833
 
13834
  'E[0-9]{2,2}[a-z]!!' => [
@@ -13935,6 +14404,7 @@ DeviceModels::$ANDROID_MODELS = [
13935
  'SO-01H' => [ 'Sony', 'Xperia Z5 SO-01H', 'carrier' => 'DoCoMo' ], // ...
13936
  'SO-01J' => [ 'Sony', 'Xperia XZ SO-01J', 'carrier' => 'DoCoMo' ], // ...
13937
  'SO-01K' => [ 'Sony', 'Xperia XZ1 SO-01K', 'carrier' => 'DoCoMo' ], // ...
 
13938
  'SO-02C' => [ 'Sony Ericsson', 'Xperia acro SO-02C', 'carrier' => 'DoCoMo' ], // Azusa
13939
  'SO-02D' => [ 'Sony Ericsson', 'Xperia NX SO-02D', 'carrier' => 'DoCoMo' ], // Nozomi
13940
  'SO-02E' => [ 'Sony', 'Xperia Z SO-02E', 'carrier' => 'DoCoMo' ], // Yuga
@@ -13942,6 +14412,7 @@ DeviceModels::$ANDROID_MODELS = [
13942
  'SO-02G' => [ 'Sony', 'Xperia Z3 Compact SO-02G', 'carrier' => 'DoCoMo' ], // ...
13943
  'SO-02H' => [ 'Sony', 'Xperia Z5 Compact SO-02H', 'carrier' => 'DoCoMo' ], // ...
13944
  'SO-02J' => [ 'Sony', 'Xperia X Compact SO-02J', 'carrier' => 'DoCoMo' ], // ...
 
13945
  'SO-03C' => [ 'Sony Ericsson', 'Xperia ray SO-03C', 'carrier' => 'DoCoMo' ], // Urushi
13946
  'SO-03D' => [ 'Sony Ericsson', 'Xperia acro HD SO-03D', 'carrier' => 'DoCoMo' ], // Hikari
13947
  'SO-03E' => [ 'Sony', 'Xperia Tablet Z SO-03E', DeviceType::TABLET, 'carrier' => 'DoCoMo' ], // Pollux
@@ -13949,6 +14420,8 @@ DeviceModels::$ANDROID_MODELS = [
13949
  'SO-03G' => [ 'Sony', 'Xperia Z4 SO-03G', 'carrier' => 'DoCoMo' ],
13950
  'SO-03H' => [ 'Sony', 'Xperia Z5 Premium SO-03H', 'carrier' => 'DoCoMo' ],
13951
  'SO-03J' => [ 'Sony', 'Xperia XZs SO-03J', 'carrier' => 'DoCoMo' ],
 
 
13952
  'SO-04D' => [ 'Sony', 'Xperia GX SO-04D', 'carrier' => 'DoCoMo' ], // Hayabusa
13953
  'SO-04E' => [ 'Sony', 'Xperia A SO-04E', 'carrier' => 'DoCoMo' ], // Dogo
13954
  'SO-04EM' => [ 'Sony', 'Xperia feat. HATSUNE MIKU SO-04E', 'carrier' => 'DoCoMo' ],
@@ -13956,9 +14429,11 @@ DeviceModels::$ANDROID_MODELS = [
13956
  'SO-04G' => [ 'Sony', 'Xperia A4 SO-04G', 'carrier' => 'DoCoMo' ],
13957
  'SO-04H' => [ 'Sony', 'Xperia X Performance SO-04H', 'carrier' => 'DoCoMo' ],
13958
  'SO-04J' => [ 'Sony', 'Xperia XZ Premium SO-04J', 'carrier' => 'DoCoMo' ],
 
13959
  'SO-05D' => [ 'Sony', 'Xperia SX SO-05D', 'carrier' => 'DoCoMo' ], // Komachi
13960
  'SO-05F' => [ 'Sony', 'Xperia Tablet Z2 SO-05F', DeviceType::TABLET, 'carrier' => 'DoCoMo' ], // Castor
13961
  'SO-05G' => [ 'Sony', 'Xperia Tablet Z4 SO-05G', DeviceType::TABLET, 'carrier' => 'DoCoMo' ], // ...
 
13962
  'SO-07D' => [ 'Sony', 'SO-07D', DeviceType::TABLET, 'carrier' => 'DoCoMo' ], // ...
13963
  ],
13964
 
@@ -13977,6 +14452,10 @@ DeviceModels::$ANDROID_MODELS = [
13977
  'SOV34' => [ 'Sony', 'Xperia XZ SOV34', 'carrier' => 'au' ], // ...
13978
  'SOV35' => [ 'Sony', 'Xperia XZs SOV35', 'carrier' => 'au' ], // ...
13979
  'SOV36' => [ 'Sony', 'Xperia XZ1 SOV36', 'carrier' => 'au' ], // ...
 
 
 
 
13980
  ],
13981
 
13982
  '40[0-9]SO!!' => [
@@ -13991,6 +14470,12 @@ DeviceModels::$ANDROID_MODELS = [
13991
 
13992
  '60[0-9]SO!!' => [
13993
  '601SO' => [ 'Sony', 'Xperia XZ 601SO', 'carrier' => 'Softbank' ], // ...
 
 
 
 
 
 
13994
  ],
13995
 
13996
  'Xperia!!' => [
@@ -16361,9 +16846,22 @@ DeviceModels::$ANDROID_MODELS = [
16361
  '(Xiaomi )?(Xiaomi|Xiaomi M|MI)[ \-]?5s Plus$!' => [ 'Xiaomi', 'Mi 5s Plus' ],
16362
  '(Xiaomi )?(Xiaomi|Xiaomi M|MI)[ \-]?5x$!' => [ 'Xiaomi', 'Mi 5x' ],
16363
  '(Xiaomi )?(Xiaomi|Xiaomi M|MI)[ \-]?6$!' => [ 'Xiaomi', 'Mi 6' ],
 
 
16364
  '(Xiaomi )?(Xiaomi|Xiaomi M|MI)[ \-]?A1$!' => [ 'Xiaomi', 'Mi A1' ],
16365
- ],
16366
-
 
 
 
 
 
 
 
 
 
 
 
16367
  '(Xiaomi|Xiaomi Mi|MI) Note!!' => [
16368
  '(Xiaomi|Xiaomi Mi|MI) Note (LTE|4G)$!' => [ 'Xiaomi', 'Mi Note' ],
16369
  '(Xiaomi|Xiaomi Mi|MI) Note ?2!' => [ 'Xiaomi', 'Mi Note 2' ],
@@ -16374,8 +16872,10 @@ DeviceModels::$ANDROID_MODELS = [
16374
 
16375
  '(Xiaomi )?(MI )?MAX$!' => [ 'Xiaomi', 'Mi Max' ],
16376
  '(Xiaomi )?(MI )?MAX 2$!' => [ 'Xiaomi', 'Mi Max 2' ],
 
16377
  '(Xiaomi )?(MI )?MIX$!' => [ 'Xiaomi', 'Mi MIX' ],
16378
  '(Xiaomi )?(MI )?MIX 2$!' => [ 'Xiaomi', 'Mi MIX 2' ],
 
16379
 
16380
  '(Xiaomi )?20!!' => [
16381
  '(Xiaomi )?20130(61)!' => [ 'Xiaomi', 'Mi 3' ],
@@ -16397,15 +16897,23 @@ DeviceModels::$ANDROID_MODELS = [
16397
  '(Xiaomi )?(Redmi|HM) ?3X!' => [ 'Xiaomi', 'Redmi 3X' ],
16398
  '(Xiaomi )?(Redmi|HM) ?Pro!' => [ 'Xiaomi', 'Redmi Pro' ],
16399
  '(Xiaomi )?(Redmi|HM) ?4$!' => [ 'Xiaomi', 'Redmi 4' ],
16400
- '(Xiaomi )?(Redmi|HM) ?4 Prime!' => [ 'Xiaomi', 'Redmi 4 Prime' ],
16401
- '(Xiaomi )?(Redmi|HM) ?4 Pro!' => [ 'Xiaomi', 'Redmi 4 Pro' ],
16402
  '(Xiaomi )?(Redmi|HM) ?4A!' => [ 'Xiaomi', 'Redmi 4A' ],
16403
  '(Xiaomi )?(Redmi|HM) ?4X!' => [ 'Xiaomi', 'Redmi 4X' ],
16404
  '(Xiaomi )?(Redmi|HM) ?5$!' => [ 'Xiaomi', 'Redmi 5' ],
16405
  '(Xiaomi )?(Redmi|HM) ?5 Plus!' => [ 'Xiaomi', 'Redmi 5 Plus' ],
16406
  '(Xiaomi )?(Redmi|HM) ?5A!' => [ 'Xiaomi', 'Redmi 5A' ],
 
 
 
 
 
 
 
16407
  '(Xiaomi )?Redmi[ \-]Y1$!' => [ 'Xiaomi', 'Redmi Y1' ],
16408
  '(Xiaomi )?Redmi[ \-]Y1 Lite!' => [ 'Xiaomi', 'Redmi Y1 Lite' ],
 
16409
  ],
16410
 
16411
  '(Xiaomi )?(Redmi|HM)[ \-]?Note!!' => [
@@ -16415,7 +16923,12 @@ DeviceModels::$ANDROID_MODELS = [
16415
  '(Xiaomi )?Redmi[ \-]Note 3 Pro!' => [ 'Xiaomi', 'Redmi Note 3 Pro' ],
16416
  '(Xiaomi )?Redmi[ \-]Note ?4$!' => [ 'Xiaomi', 'Redmi Note 4' ],
16417
  '(Xiaomi )?Redmi[ \-]Note ?4X!' => [ 'Xiaomi', 'Redmi Note 4X' ],
 
16418
  '(Xiaomi )?Redmi[ \-]Note ?5A!' => [ 'Xiaomi', 'Redmi Note 5A' ],
 
 
 
 
16419
  ],
16420
 
16421
  '(Xiaomi |HM)?20!!' => [
@@ -16438,6 +16951,8 @@ DeviceModels::$ANDROID_MODELS = [
16438
  '(Xiaomi |HM)?20160(51)!' => [ 'Xiaomi', 'Redmi Note 4' ],
16439
  ],
16440
 
 
 
16441
  'Xiaomi MDT2!' => [ 'Xiaomi', 'Mi 5x' ],
16442
  'Xiaomi MCT1!' => [ 'Xiaomi', 'Mi 6' ],
16443
  'Xiaomi MAT136!' => [ 'Xiaomi', 'Redmi 4X' ],
@@ -17414,8 +17929,11 @@ DeviceModels::$ANDROID_MODELS = [
17414
  'ZTE Blade A2 plus' => [ 'ZTE', 'Blade A2 Plus' ],
17415
  'ZTE Blade A5' => [ 'ZTE', 'Blade A5' ],
17416
  'ZTE BLADE A5 PRO' => [ 'ZTE', 'Blade A5 Pro' ],
 
 
17417
  'ZTE BLADE A110' => [ 'ZTE', 'Blade A110' ],
17418
  'ZTE BLADE A112' => [ 'ZTE', 'Blade A112' ],
 
17419
  'ZTE BLADE A210' => [ 'ZTE', 'Blade A210' ],
17420
  'ZTE BLADE A310' => [ 'ZTE', 'Blade A310' ],
17421
  'ZTE Blade A315' => [ 'ZTE', 'Blade A315' ],
@@ -17445,6 +17963,7 @@ DeviceModels::$ANDROID_MODELS = [
17445
  'ZTE BLADE A610' => [ 'ZTE', 'Blade A610' ],
17446
  'ZTE BLADE A610C' => [ 'ZTE', 'Blade A610C' ],
17447
  'ZTE BLADE A612' => [ 'ZTE', 'Blade A612' ],
 
17448
  'ZTE BLADE A910' => [ 'ZTE', 'Blade A910' ],
17449
  'ZTE Blade AF5' => [ 'ZTE', 'Blade AF5' ],
17450
  'ZTE BLADE B112' => [ 'ZTE', 'Blade B112' ],
@@ -17494,6 +18013,7 @@ DeviceModels::$ANDROID_MODELS = [
17494
  'ZTE Blade L5 Plus' => [ 'ZTE', 'Blade L5 Plus' ],
17495
  'ZTE BLADE L0510' => [ 'ZTE', 'Blade L5 Plus' ],
17496
  'ZTE Blade L6' => [ 'ZTE', 'Blade L6' ],
 
17497
  'ZTE BLADE L110' => [ 'ZTE', 'Blade L110' ],
17498
  'ZTE BLADE L111' => [ 'ZTE', 'Blade L111' ],
17499
  'ZTE Blade L370' => [ 'ZTE', 'Blade L370' ],
@@ -17529,6 +18049,7 @@ DeviceModels::$ANDROID_MODELS = [
17529
  'ZTE BLADE V0850' => [ 'ZTE', 'Blade V8 Mini' ],
17530
  'BLADE V8 SE' => [ 'ZTE', 'Blade V8 SE' ],
17531
  'ZTE BLADE V0900' => [ 'ZTE', 'Blade V9' ],
 
17532
  'ZTE Blade V220' => [ 'ZTE', 'Blade V220' ],
17533
  'ZTE Blade V580' => [ 'ZTE', 'Blade V580' ],
17534
  'ZTE Blade V770' => [ 'ZTE', 'Blade V770' ],
@@ -17704,6 +18225,7 @@ DeviceModels::$ANDROID_MODELS = [
17704
  'ZTE B2016' => [ 'ZTE', 'Axon Mini' ],
17705
  'ZTE B2017' => [ 'ZTE', 'Axon Mini' ],
17706
  'ZTE B2017G' => [ 'ZTE', 'Axon Mini' ],
 
17707
  'ZTE C2016' => [ 'ZTE', 'Axon Max' ],
17708
  'ZTE C2017' => [ 'ZTE', 'Axon Max' ],
17709
  'ZTE STAR' => [ 'ZTE', 'Star 1' ],
@@ -17731,7 +18253,9 @@ DeviceModels::$ANDROID_MODELS = [
17731
  '009Z' => [ 'ZTE', 'STAR7 009Z', 'carrier' => 'Softbank' ],
17732
  '402ZT' => [ 'ZTE', 'Blade Q+ 402ZT', 'carrier' => 'Softbank' ],
17733
  '502ZT' => [ 'ZTE', 'Spro 2 502ZT', DeviceType::PROJECTOR, 'carrier' => 'Softbank' ],
 
17734
  'MO-01J' => [ 'ZTE', 'MONO MO-01J', 'carrier' => 'DoCoMo' ],
 
17735
 
17736
  'ZA400' => [ 'Zonda', 'Mini Colors ZA400' ],
17737
  'ZA402' => [ 'Zonda', 'Scratch ZA402' ],
@@ -17939,6 +18463,7 @@ DeviceModels::$ANDROID_MODELS = [
17939
  'GM 5 Plus d' => [ 'General Mobile', 'GM5 Plus' ],
17940
  'GM 6' => [ 'General Mobile', 'GM6' ],
17941
  'GM 6 d' => [ 'General Mobile', 'GM6' ],
 
17942
  'GM Discovery tab 8' => [ 'General Mobile', 'tab 8', DeviceType::TABLET ],
17943
  'etab5' => [ 'General Mobile', 'Etab 5', DeviceType::TABLET ],
17944
 
261
  'Pixel' => [ 'Google', 'Pixel' ],
262
  'Google Pixel' => [ 'Google', 'Pixel' ],
263
  'Pixel XL' => [ 'Google', 'Pixel XL' ],
 
264
  'Pixel 2' => [ 'Google', 'Pixel 2' ],
265
  'Google Pixel 2' => [ 'Google', 'Pixel 2' ],
266
  'Pixel 2XL' => [ 'Google', 'Pixel 2 XL' ],
267
  'Pixel 2 XL' => [ 'Google', 'Pixel 2 XL' ],
268
  'Google Pixel 2XL' => [ 'Google', 'Pixel 2 XL' ],
269
+ 'Pixel 3' => [ 'Google', 'Pixel 3' ],
270
+ 'Pixel 3 XL' => [ 'Google', 'Pixel 3 XL' ],
271
+ 'Pixel 3a' => [ 'Google', 'Pixel 3a' ],
272
+ 'Pixel 3a XL' => [ 'Google', 'Pixel 3a XL' ],
273
+ 'Pixel 4' => [ 'Google', 'Pixel 4' ],
274
+ 'Pixel 4 XL' => [ 'Google', 'Pixel 4 XL' ],
275
 
276
  /* Google Edition */
277
  'HTC One' => [ 'HTC', 'One (Google Edition)' ],
964
  'one ?touch 4032!' => [ 'Alcatel', 'One Touch Pop C2' ],
965
  '4032[ADEX]!' => [ 'Alcatel', 'One Touch Pop C2' ],
966
  'one ?touch 4033!' => [ 'Alcatel', 'One Touch Pop C3' ],
967
+ '4033[ADLX]!' => [ 'Alcatel', 'One Touch Pop C3' ],
968
  'ONETOUCH POPC3' => [ 'Alcatel', 'One Touch Pop C3' ],
969
  '4034[ADEFGX]!' => [ 'Alcatel', 'One Touch Pixi 4 (4)' ],
970
  'one ?touch 40(35|36|37)!' => [ 'Alcatel', 'One Touch Pop D3' ],
974
  '4037[T]!' => [ 'Alcatel', 'One Touch Evolve 2' ],
975
  '4037[V]!' => [ 'Alcatel', 'One Touch Elevate' ],
976
  'one ?touch 5045!' => [ 'Alcatel', 'One Touch Pop 2 (4)' ],
977
+ '4045[ADEFLOYX]!' => [ 'Alcatel', 'One Touch Pop 2 (4)' ],
978
+ '4047[ADFGX]!' => [ 'Alcatel', 'U5' ],
979
+ '4049[DG]!' => [ 'Alcatel', 'U3' ],
980
  '4055[JU]!' => [ 'Alcatel', 'One Touch Pixi 5 (4)' ],
981
  '4060[A]!' => [ 'Alcatel', 'IDEAL' ],
982
+ '4060[SW]!' => [ 'Alcatel', 'One Touch Pixi 4 (5)' ],
983
  '5010[DEGSUX]!' => [ 'Alcatel', 'One Touch Pixi 4 (5)' ],
984
+ '5011[A]!' => [ 'Alcatel', 'A3 Plus' ],
985
  '5012[G]!' => [ 'Alcatel', 'One Touch Pixi 4 (5.5)' ],
986
  '5015[ADEX]!' => [ 'Alcatel', 'One Touch Pixi 3 (5)' ],
987
  '5016[AJ]!' => [ 'Alcatel', 'One Touch Pixi 3 (5)' ],
996
  'one ?touch 5021!' => [ 'Alcatel', 'One Touch Soleil' ],
997
  '5022[DEX]!' => [ 'Alcatel', 'One Touch Pop Star' ],
998
  '5023[F]!' => [ 'Alcatel', 'One Touch Pixi 4 Plus Power' ],
999
+ '5024[D]!' => [ 'Alcatel', '1S' ],
1000
  '5025[DEGX]!' => [ 'Alcatel', 'One Touch Pop 3' ],
1001
  '5027[B]!' => [ 'Alcatel', 'One Touch Dawn' ],
1002
+ '5033[ADJOX]!' => [ 'Alcatel', '1' ],
1003
+ '5034[D]!' => [ 'Alcatel', '3L' ],
1004
  'one ?touch 5035!' => [ 'Alcatel', 'One Touch X\'Pop' ],
1005
  '5036[D]!' => [ 'Alcatel', 'One Touch Pop C5' ],
1006
  'one ?touch 50(36|37)!' => [ 'Alcatel', 'One Touch Pop C5' ],
1007
  'ONETOUCH POPC5' => [ 'Alcatel', 'One Touch Pop C5' ],
1008
  'one ?touch 50(38)!' => [ 'Alcatel', 'One Touch Pop D5' ],
1009
  '5038[ADEX]!' => [ 'Alcatel', 'One Touch Pop D5' ],
1010
+ '5039[D]!' => [ 'Alcatel', 'One Touch 3L' ],
1011
+ '5041[C]!' => [ 'Alcatel', 'TETRA' ],
1012
  'one ?touch 5042!' => [ 'Alcatel', 'One Touch Pop 2 (4.5)' ],
1013
  '5042[ADEFGTWXY]!' => [ 'Alcatel', 'One Touch Pop 2 (4.5)' ],
1014
+ '5044[ADGIOSTY]!' => [ 'Alcatel', 'U5' ],
1015
+ '5045[ADFGJTXY]!' => [ 'Alcatel', 'One Touch Pixi 4 (5.0)' ],
1016
+ '5046[DGIJUY]!' => [ 'Alcatel', 'A3' ],
1017
+ '5047[DIUY]!' => [ 'Alcatel', 'U5 HD' ],
1018
+ '5049[EGSWZ]!' => [ 'Alcatel', 'A30 Fierce' ],
1019
  'one ?touch 5050!' => [ 'Alcatel', 'One Touch Pop S3' ],
1020
  '5050[ASYX]!' => [ 'Alcatel', 'One Touch Pop S3' ],
1021
  '5051[ADJMX]!' => [ 'Alcatel', 'One Touch Pop 4 (5.0)' ],
1022
+ '5052[DY]!' => [ 'Alcatel', '3' ],
1023
+ '5053[D]!' => [ 'Alcatel', '3 (2019)' ],
1024
  '5054[ADOSTX]!' => [ 'Alcatel', 'One Touch Pixi 3 (5.5)' ],
1025
  '5054[NW]!' => [ 'Alcatel', 'One Touch Fierce XL' ],
1026
+ '5056[ADEINUWX]!' => [ 'Alcatel', 'One Touch Pop 4+' ],
1027
  '5056[O]!' => [ 'Alcatel', 'One Touch Allura' ],
1028
  '5057[M]!' => [ 'Alcatel', 'One Touch Pop Mirage' ],
1029
+ '5058[I]!' => [ 'Alcatel', '3X' ],
1030
+ '5059[ADJTXY]!' => [ 'Alcatel', '1X' ],
1031
+ '5060[D]!' => [ 'Alcatel', '5V' ],
1032
  '5065[ADJNWX]!' => [ 'Alcatel', 'One Touch Pixi 3 (5)' ],
1033
  '5070[DJX]!' => [ 'Alcatel', 'One Touch Pop Star' ],
1034
+ '5080[A]!' => [ 'Alcatel', 'Shine Lite' ],
1035
+ '5080[DFQX]!' => [ 'Alcatel', 'One Touch Pixi 4 (6)' ],
1036
+ '5085[CDJNOYX]!' => [ 'Alcatel', 'A5 LED' ],
1037
+ '5086[ADY]!' => [ 'Alcatel', '5' ],
1038
+ '5090[Y]!' => [ 'Alcatel', 'A7' ],
1039
  '5095[BIKY]!' => [ 'Alcatel', 'One Touch Pop 4S' ],
1040
+ '5096[AI]!' => [ 'Alcatel', 'One Touch Net' ],
1041
  '5098[OS]!' => [ 'Alcatel', 'One Touch Pixi 4 (6)' ],
1042
  'Alcatel 5098O' => [ 'Alcatel', 'One Touch Pixi 4 (6)' ],
1043
+ '5099[ADY]!' => [ 'Alcatel', '3V' ],
1044
  'one ?touch 6010!' => [ 'Alcatel', 'One Touch Star' ],
1045
  'one ?touch 6012!' => [ 'Alcatel', 'One Touch Idol Mini' ],
1046
  'ONE TOUCH IDOL MINI' => [ 'Alcatel', 'One Touch Idol Mini' ],
1069
  'one ?touch 6050!' => [ 'Alcatel', 'One Touch Idol 2S' ],
1070
  '6050[AFWY]!' => [ 'Alcatel', 'One Touch Idol 2S' ],
1071
  '6055[ABDHIKPUY]!' => [ 'Alcatel', 'One Touch Idol 4' ],
1072
+ '6058[D]!' => [ 'Alcatel', 'One Touch Idol 5' ],
1073
+ '6060[S]!' => [ 'Alcatel', 'One Touch Idol 5s' ],
1074
+ '6062[W]!' => [ 'Alcatel', '7' ],
1075
  '6070[KOY]!' => [ 'Alcatel', 'One Touch Idol 4s' ],
1076
  'one ?touch 7024!' => [ 'Alcatel', 'One Touch Fierce' ],
1077
  'one touch fierce!' => [ 'Alcatel', 'One Touch Fierce' ],
1078
  'one ?touch 70(25|30)!' => [ 'Alcatel', 'One Touch Snap' ],
1079
  '7030[L]!' => [ 'Alcatel', 'One Touch Snap' ],
1080
  'one ?touch 70(40|41)!' => [ 'Alcatel', 'One Touch Pop C7' ],
1081
+ '7040[DNR]!' => [ 'Alcatel', 'One Touch Pop C7' ],
1082
  '7040[T]!' => [ 'Alcatel', 'One Touch Fierce 2' ],
1083
  'one ?touch 7042!' => [ 'Alcatel', 'One Touch Snap' ],
1084
  'one ?touch 7043!' => [ 'Alcatel', 'One Touch Pop 2 (5)' ],
1104
  '8020[D]!' => [ 'Alcatel', 'One Touch Hero' ],
1105
  'one ?touch 8030!' => [ 'Alcatel', 'One Touch Hero 2' ],
1106
  '8030[BY]!' => [ 'Alcatel', 'One Touch Hero 2' ],
1107
+ '9001[DIX]!' => [ 'Alcatel', 'One Touch Pixi 4 (6)' ],
1108
  '9002[AWX]!' => [ 'Alcatel', 'One Touch Pixi 3 (7)', DeviceType::TABLET ],
1109
  '9003[AX]!' => [ 'Alcatel', 'One Touch Pixi 4 (7)', DeviceType::TABLET ],
1110
  '9005[X]!' => [ 'Alcatel', 'One Touch Pixi 3 (8)', DeviceType::TABLET ],
1111
  '9006[W]!' => [ 'Alcatel', 'One Touch Pixi 4 (7)', DeviceType::TABLET ],
1112
  '9007[ATX]!' => [ 'Alcatel', 'One Touch Pixi 3 (7)', DeviceType::TABLET ],
1113
+ '9008[ADIJTUX]!' => [ 'Alcatel', 'A3 XL', DeviceType::TABLET ],
1114
  '9010[X]!' => [ 'Alcatel', 'One Touch Pixi 3 (10)', DeviceType::TABLET ],
1115
+ '9015[BJWQ]!' => [ 'Alcatel', 'One Touch POP7', DeviceType::TABLET ],
1116
  '9022[SX]!' => [ 'Alcatel', 'One Touch Pixi 3 (8)', DeviceType::TABLET ],
1117
+ '9024[OW]!' => [ 'Alcatel', 'A30', DeviceType::TABLET ],
1118
  '9025[MQ]!' => [ 'Alcatel', 'One Touch Pop 4 (7)', DeviceType::TABLET ],
1119
  'one ?touch T10!' => [ 'Alcatel', 'One Touch T10', DeviceType::TABLET ],
1120
  'one ?touch T20!' => [ 'Alcatel', 'One Touch T20', DeviceType::TABLET ],
1133
  'ONE ?TOUCH P310(A|X)!' => [ 'Alcatel', 'One Touch POP7', DeviceType::TABLET ],
1134
  'ONE ?TOUCH P320(A|X)!' => [ 'Alcatel', 'One Touch POP8', DeviceType::TABLET ],
1135
  'ONE ?TOUCH P321!' => [ 'Alcatel', 'One Touch POP8', DeviceType::TABLET ],
1136
+ '9021[AM]!' => [ 'Alcatel', 'One Touch POP8', DeviceType::TABLET ],
1137
  'P330X' => [ 'Alcatel', 'One Touch POP7S', DeviceType::TABLET ],
1138
  'P350X' => [ 'Alcatel', 'One Touch POP8S', DeviceType::TABLET ],
1139
  'ONE ?TOUCH POP 8S P350X!' => [ 'Alcatel', 'One Touch POP8S', DeviceType::TABLET ],
1321
  'KFGIWI' => [ 'Amazon', 'Fire HD 8 (2016)', DeviceType::TABLET, Flag::FIREOS ], // xth generation 8" HD (1280 x 800)
1322
  'KFDOWI' => [ 'Amazon', 'Fire HD 8 (2017)', DeviceType::TABLET, Flag::FIREOS ], // xth generation 8" HD (1280 x 800)
1323
  'KFSUWI' => [ 'Amazon', 'Fire HD 10 (2017)', DeviceType::TABLET, Flag::FIREOS ], // 5th generation 10" HD (1280 x 800)
1324
+ 'KFMAWI' => [ 'Amazon', 'Fire HD 8 (2018)', DeviceType::TABLET, Flag::FIREOS ],
1325
+ 'KFMUWI' => [ 'Amazon', 'Fire 7 (2019)', DeviceType::TABLET, Flag::FIREOS ],
 
1326
  'SD4930UR' => [ 'Amazon', 'Fire Phone', DeviceType::MOBILE, Flag::FIREOS ],
1327
  'AFTB' => [ 'Amazon', 'Fire TV', DeviceType::TELEVISION, Flag::FIREOS ],
1328
  'AFTS' => [ 'Amazon', 'Fire TV (2015)', DeviceType::TELEVISION, Flag::FIREOS ],
1498
  'Archos!!' => [
1499
  'ARCHOS 80G9' => [ 'Archos', '80 G9', DeviceType::TABLET ],
1500
  'ARCHOS 101G9' => [ 'Archos', '101 G9', DeviceType::TABLET ],
1501
+ 'Archos G9' => [ 'Archos', '101 G9', DeviceType::TABLET ],
1502
  'ARCHOS 97XSLG10' => [ 'Archos', '97 XS', DeviceType::TABLET ],
1503
  'ARCHOS 80XSK' => [ 'Archos', '80 XS', DeviceType::TABLET ],
1504
  'ARCHOS 101G10' => [ 'Archos', '101 XS', DeviceType::TABLET ],
1564
  'Archos 50e Neon' => [ 'Archos', '50e Neon' ],
1565
  'Archos 50f Neon' => [ 'Archos', '50f Neon' ],
1566
  'Archos 70 Neon' => [ 'Archos', '70 Neon', DeviceType::TABLET ],
1567
+ 'Archos 70 Neon Plus' => [ 'Archos', '70 Neon Plus', DeviceType::TABLET ],
1568
  'Archos 70b Neon' => [ 'Archos', '70b Neon', DeviceType::TABLET ],
1569
  'Archos 70c Neon' => [ 'Archos', '70c Neon', DeviceType::TABLET ],
1570
  'Archos 79 Neon' => [ 'Archos', '79 Neon', DeviceType::TABLET ],
1604
  'Archos 5.3s Platinum' => [ 'Archos', '53s Platinum' ],
1605
  'Archos 55 Platinum' => [ 'Archos', '55 Platinum' ],
1606
  'Archos 55b Platinum' => [ 'Archos', '55b Platinum' ],
1607
+ 'Archos 60 Platinum' => [ 'Archos', '60 Platinum' ],
1608
  'Archos 70 Platinum' => [ 'Archos', '70 Platinum', DeviceType::TABLET ],
1609
  'Archos 70 Platinum 3G' => [ 'Archos', '70 Platinum', DeviceType::TABLET ],
1610
  'Archos 70 Platinum v3' => [ 'Archos', '70 Platinum', DeviceType::TABLET ],
1661
  'ARCHOS 97 XENON' => [ 'Archos', '97 Xenon', DeviceType::TABLET ],
1662
  'Archos 101 Xenon' => [ 'Archos', '101 Xenon', DeviceType::TABLET ],
1663
  'Archos 101 Xenon v2' => [ 'Archos', '101 Xenon', DeviceType::TABLET ],
1664
+ 'Archos 101b Xenon' => [ 'Archos', '101b Xenon', DeviceType::TABLET ],
1665
  'Archos 101b Xenon v2' => [ 'Archos', '101b Xenon', DeviceType::TABLET ],
1666
  'Archos 101c Xenon' => [ 'Archos', '101c Xenon', DeviceType::TABLET ],
1667
  'ARCHOS 101 Xenon Lite' => [ 'Archos', '101 Xenon Lite', DeviceType::TABLET ],
1668
  'ARCHOS 80 CHILDPAD' => [ 'Archos', '80 Childpad', DeviceType::TABLET ],
1669
  'ARCHOS 101 CHILDPAD' => [ 'Archos', '101 Childpad', DeviceType::TABLET ],
 
1670
  'Archos Chefpad' => [ 'Archos', 'ChefPad', DeviceType::TABLET ],
1671
  'ARCHOS GAMEPAD' => [ 'Archos', 'Gamepad', [ DeviceType::GAMING, DeviceSubType::PORTABLE ] ],
1672
  'ARCHOS GAMEPAD2' => [ 'Archos', 'Gamepad 2', [ DeviceType::GAMING, DeviceSubType::PORTABLE ] ],
1674
  'Archos 101 DB' => [ 'Archos', 'ArcBook', DeviceType::TABLET ],
1675
  'Archos Smart Home Tablet' => [ 'Archos', 'Smart Home Tablet', DeviceType::TABLET ],
1676
  'ARCHOS LUDOG10' => [ 'Archos', 'TV Connect', DeviceType::TELEVISION ],
1677
+ 'Archos Access 45 4G' => [ 'Archos', 'Access 45' ],
1678
+ 'Archos Access 50 4G' => [ 'Archos', 'Access 50' ],
1679
+ 'Archos Access 50 Color 3G' => [ 'Archos', 'Access 50 Color' ],
1680
+ 'Archos Access 70 3G' => [ 'Archos', 'Access 70', DeviceType::TABLET ],
1681
+ 'Archos Access 101 3G' => [ 'Archos', 'Access 101', DeviceType::TABLET ],
1682
+ 'Archos Access 101 3G V2' => [ 'Archos', 'Access 101', DeviceType::TABLET ],
1683
+ 'Archos Core 50 4G' => [ 'Archos', 'Core 50' ],
1684
+ 'Archos Core 55 4G' => [ 'Archos', 'Core 55' ],
1685
+ 'Archos Core 70 3G' => [ 'Archos', 'Core 70', DeviceType::TABLET ],
1686
+ 'ARCHOS Core 101 Wifi' => [ 'Archos', 'Core 101', DeviceType::TABLET ],
1687
+ 'Archos Core 101 3G' => [ 'Archos', 'Core 101', DeviceType::TABLET ],
1688
+ 'Archos Sense 55 DC' => [ 'Archos', 'Sense 55' ],
1689
+ 'Archos Sense 55 S' => [ 'Archos', 'Sense 55' ],
1690
  ],
1691
 
1692
  'Artes D708' => [ 'Artes', 'D708', DeviceType::TABLET ],
1929
  'Z01BDC' => [ 'Asus', 'ZenFone 3 Laser (ZC551KL)' ],
1930
  'Z01BS' => [ 'Asus', 'ZenFone 3 Laser (ZC551KL)' ],
1931
  'Z01FD' => [ 'Asus', 'ZenFone 3 Deluxe (ZS550KL)' ],
1932
+ 'Z01GD' => [ 'Asus', 'ZenFone 4 Pro (ZS551KL)' ],
1933
  'Z01HD' => [ 'Asus', 'ZenFone 3 Zoom (ZE553KL)' ],
1934
  'Z01HDA' => [ 'Asus', 'ZenFone 3 Zoom (ZE553KL)' ],
1935
  'Z01KD' => [ 'Asus', 'ZenFone 4 (ZE554KL)' ],
1946
  'ZE550KL' => [ 'Asus', 'ZenFone 2 Laser (ZE550KL)' ],
1947
  'ZE552KL' => [ 'Asus', 'ZenFone 3 (ZE552KL)' ],
1948
  'ZE553KL' => [ 'Asus', 'ZenFone 3 Zoom (ZE553KL)' ],
1949
+ 'ZE554KL' => [ 'Asus', 'ZenFone 4 (ZE554KL)' ],
1950
 
1951
  'Z00YD' => [ 'Asus', 'Live' ],
1952
  'X002' => [ 'Asus', 'Pegasus' ],
2124
  '(NOOK )?BNTV250!' => [ 'Barnes & Noble', 'NOOK Tablet', DeviceType::EREADER ],
2125
  '(NOOK )?BNRV350!' => [ 'Barnes & Noble', 'NOOK Simple Touch', DeviceType::EREADER ],
2126
  '(NOOK )?BNTV(400)!' => [ 'Barnes & Noble', 'NOOK HD Tablet', DeviceType::EREADER ],
2127
+ '(NOOK )?BNTV(450)!' => [ 'Barnes & Noble', 'NOOK 7"', DeviceType::EREADER ],
2128
  '(NOOK )?BNTV(600)!' => [ 'Barnes & Noble', 'NOOK HD+ Tablet', DeviceType::EREADER ],
2129
+ '(NOOK )?BNTV(800)!' => [ 'Barnes & Noble', 'NOOK 8"', DeviceType::EREADER ],
2130
  'Barnes & Noble Nook HD' => [ 'Barnes & Noble', 'NOOK HD Tablet', DeviceType::EREADER ],
2131
  'Barnes & Noble Nook HD+' => [ 'Barnes & Noble', 'NOOK HD+ Tablet', DeviceType::EREADER ],
2132
  'Nook HD' => [ 'Barnes & Noble', 'NOOK HD Tablet', DeviceType::EREADER ],
2237
  'BBB100-[0-9]!' => [ 'BlackBerry', 'KEYone' ],
2238
  'BBC100-[0-9]!' => [ 'BlackBerry', 'Aurora' ],
2239
  'BBD100-[0-9]!' => [ 'BlackBerry', 'Motion' ],
2240
+ 'BBE100-[0-9]!' => [ 'BlackBerry', '"BBE100"' ],
2241
+ 'BBF100-[0-9]!' => [ 'BlackBerry', 'KEY2' ],
2242
 
2243
  'BV8000Pro' => [ 'Blackview', 'BV8000 Pro' ],
2244
  'P2Lite' => [ 'Blackview', 'P2 Lite' ],
3849
  'DM016SH' => [ 'Sharp', 'DM016SH', 'carrier' => 'Disney Mobile' ],
3850
  ],
3851
 
3852
+ 'DM001c Frozen' => [ 'Disney Mobile', 'DM001C Frozen', 'carrier' => 'Disney Mobile' ],
3853
+ 'DM001c Mickey' => [ 'Disney Mobile', 'DM001C Mickey', 'carrier' => 'Disney Mobile' ],
3854
+ 'DM001c Princess' => [ 'Disney Mobile', 'DM001C Princess', 'carrier' => 'Disney Mobile' ],
3855
+
3856
  'DJC Touchtab3' => [ 'DJC', 'Touchtab3', DeviceType::TABLET ],
3857
  'DJC Touchtab4' => [ 'DJC', 'Touchtab4', DeviceType::TABLET ],
3858
  'AirBook TTJ702' => [ 'DNS', 'Airbook TTJ702', DeviceType::TABLET ],
4325
  'FS403' => [ 'Fly', 'FS403 Cumulus 1' ],
4326
  'FS407' => [ 'Fly', 'FS407 Stratus 6' ],
4327
  'FS451' => [ 'Fly', 'FS451 Nimbus 1' ],
4328
+ 'FS514' => [ 'Fly', 'FS514 Cirrus 8' ],
4329
  'Fly Phoenix 2' => [ 'Fly', 'IQ4410i Phoenix 2' ],
4330
  'Fly Ego Art 2' => [ 'Fly', 'IQ455 Ego Art 2' ],
4331
 
4479
  'F-01F' => [ 'Fujitsu', 'ARROWS NX F-01F', 'carrier' => 'DoCoMo' ],
4480
  'F-01H' => [ 'Fujitsu', 'arrows Fit F-01H', 'carrier' => 'DoCoMo' ],
4481
  'F-01J' => [ 'Fujitsu', 'arrows NX F-01J', 'carrier' => 'DoCoMo' ],
4482
+ 'F-01K' => [ 'Fujitsu', 'arrows NX F-01K', 'carrier' => 'DoCoMo' ],
4483
+ 'F-01L' => [ 'Fujitsu', 'らくらくスマートフォン me F-01L', 'carrier' => 'DoCoMo' ],
4484
  'F-02E' => [ 'Fujitsu', 'ARROWS X F-02E', 'carrier' => 'DoCoMo' ],
4485
  'F-02F' => [ 'Fujitsu', 'ARROWS Tab F-02F', DeviceType::TABLET, 'carrier' => 'DoCoMo' ],
4486
  'F-02G' => [ 'Fujitsu', 'ARROWS NX F-02G', 'carrier' => 'DoCoMo' ],
4487
  'F-02H' => [ 'Fujitsu', 'arrows NX F-02H', 'carrier' => 'DoCoMo' ],
4488
+ 'F-02K' => [ 'Fujitsu', 'ARROWS Tab F-02K', DeviceType::TABLET, 'carrier' => 'DoCoMo' ],
4489
+ 'F-02L' => [ 'Fujitsu', 'arrows Be3 F-02L', 'carrier' => 'DoCoMo' ],
4490
  'F-03D' => [ 'Fujitsu', 'ARROWS Kiss F-03D', 'carrier' => 'DoCoMo' ],
4491
  'F-03E' => [ 'Fujitsu', 'ARROWS Kiss with JILL STUART F-03E', 'carrier' => 'DoCoMo' ],
4492
  'F-03F' => [ 'Fujitsu', 'F-03F', 'carrier' => 'Disney Mobile' ],
4497
  'F-04F' => [ 'Fujitsu', 'Business Smartphone F-04F', 'carrier' => 'DoCoMo' ],
4498
  'F-04G' => [ 'Fujitsu', 'ARROWS NX F-04G', 'carrier' => 'DoCoMo' ],
4499
  'F-04H' => [ 'Fujitsu', 'ARROWS Tab F-04H', DeviceType::TABLET, 'carrier' => 'DoCoMo' ],
4500
+ 'F-04J' => [ 'Fujitsu', 'らくらくスマートフォン4 F-04J', 'carrier' => 'DoCoMo' ],
4501
+ 'F-04K' => [ 'Fujitsu', 'ARROWS Be F-04K', 'carrier' => 'DoCoMo' ],
4502
  'F-05D' => [ 'Fujitsu', 'ARROWS X LTE F-05D', 'carrier' => 'DoCoMo' ],
4503
  'F-05E' => [ 'Fujitsu', 'ARROWS Tab F-05E', 'carrier' => 'DoCoMo' ],
4504
  'F-05F' => [ 'Fujitsu', 'ARROWS NX F-05F', 'carrier' => 'DoCoMo' ],
5367
  'HTC Desire 10 pro' => [ 'HTC', 'Desire 10 Pro' ],
5368
  'HTC D10i' => [ 'HTC', 'Desire 10 Pro' ],
5369
  'HTC D10w' => [ 'HTC', 'Desire 10 Pro' ],
5370
+ 'HTC Desire 12+' => [ 'HTC', 'Desire 12+' ],
5371
  'HTC Desire 200' => [ 'HTC', 'Desire 200' ],
5372
  'HTC Desire 210 dual sim' => [ 'HTC', 'Desire 210' ],
5373
  'HTC Desire 300' => [ 'HTC', 'Desire 300' ],
5490
  'HTC 2PST5' => [ 'HTC', 'Desire 630' ],
5491
  'HTC Desire 650' => [ 'HTC', 'Desire 650' ],
5492
  'HTC Desire 650 dual sim' => [ 'HTC', 'Desire 650' ],
5493
+ 'HTC 2PYA1' => [ 'HTC', 'Desire 650' ],
5494
  'HTC 2PYR1' => [ 'HTC', 'Desire 650' ],
5495
  'HTC 2PYR2' => [ 'HTC', 'Desire 650' ],
5496
  'HTC Desire 700 dual sim' => [ 'HTC', 'Desire 700' ],
5519
  'HTC Desire 820G !' => [ 'HTC', 'Desire 820G' ],
5520
  'HTC Desire 820G+' => [ 'HTC', 'Desire 820G+' ],
5521
  'HTC Desire 820G PLUS dual sim' => [ 'HTC', 'Desire 820G+' ],
5522
+ 'HTC 820G Plus Dual Sim' => [ 'HTC', 'Desire 820G+' ],
5523
  'HTC D820' => [ 'HTC', 'Desire 820' ],
5524
  'HTC D820(f|m|mt|mu|s|t|u|x)!' => [ 'HTC', 'Desire 820' ],
5525
  'HTC Desire 820' => [ 'HTC', 'Desire 820' ],
5556
  'HTC Desire C N' => [ 'HTC', 'Desire C' ],
5557
  'HTC H1000C' => [ 'HTC', 'Desire C' ],
5558
  'HTC A320e' => [ 'HTC', 'Desire C' ],
5559
+ 'HTC A320E DESIRE C' => [ 'HTC', 'Desire C' ],
5560
  'HTC Desire ?HD!' => [ 'HTC', 'Desire HD' ],
5561
  'HTC A91(91|92)!' => [ 'HTC', 'Desire HD' ],
5562
  'HTC 0PFH1!' => [ 'HTC', 'Desire Eye' ],
5671
  'HTC Butterfly s 901s' => [ 'HTC', 'Butterfly S' ],
5672
  'HTC PO68' => [ 'HTC', 'Butterfly S' ],
5673
  'HTC 9060' => [ 'HTC', 'Butterfly S' ],
5674
+ 'HTC 9066' => [ 'HTC', 'Butterfly S' ],
5675
  'HTC 9088' => [ 'HTC', 'Butterfly S' ],
5676
  'HTC 901e' => [ 'HTC', 'Butterfly S' ],
5677
  'HTC 909d' => [ 'HTC', 'Butterfly S' ],
5791
  'HTC 0PK71' => [ 'HTC', 'One (M9 Plus)' ],
5792
  'HTC 0PK72' => [ 'HTC', 'One (M9 Plus)' ],
5793
  'HTC X9u' => [ 'HTC', 'One (X9)' ],
5794
+ 'HTC 2PS511' => [ 'HTC', 'One (X9)' ],
5795
  'HTC 2PS5200' => [ 'HTC', 'One (X9)' ],
5796
  'HTC 2PXH1' => [ 'HTC', 'One (X10)' ],
5797
  'HTC 2PXH2' => [ 'HTC', 'One (X10)' ],
5874
  'HTC Mecha' => [ 'HTC', 'ThunderBolt'],
5875
  'HTC Kaiser' => [ 'HTC', 'TyTN II'],
5876
  'HTC U Play' => [ 'HTC', 'U Play'],
5877
+ 'HTC 2PZM1' => [ 'HTC', 'U Play'],
5878
  'HTC 2PZM3' => [ 'HTC', 'U Play'],
5879
  'HTC U Ultra' => [ 'HTC', 'U Ultra'],
5880
  'HTC U-1w' => [ 'HTC', 'U Ultra'],
5881
  'HTC 2PZF1' => [ 'HTC', 'U Ultra'],
5882
  'HTC U11' => [ 'HTC', 'U11'],
5883
  'HTC U-3w' => [ 'HTC', 'U11'],
5884
+ 'HTC U-3u' => [ 'HTC', 'U11'],
5885
  'HTC 2PZC100' => [ 'HTC', 'U11'],
5886
  'HTC 2Q4D200' => [ 'HTC', 'U11 Plus'],
5887
+ 'HTC 2Q3F2' => [ 'HTC', 'U11 Plus'],
5888
+ 'HTC 2Q3F3' => [ 'HTC', 'U11 Plus'],
5889
+ 'HTC U12+' => [ 'HTC', 'U12+'],
5890
  'HTC Velocity!' => [ 'HTC', 'Velocity 4G'],
5891
  'HTCVelocity 4G' => [ 'HTC', 'Velocity 4G'],
5892
  'HTC Vivid' => [ 'HTC', 'Vivid'],
6089
  '2PS64' => [ 'HTC', '10' ],
6090
  'M7CDTU' => [ 'HTC', 'One' ],
6091
 
6092
+ '[SX06][0-9]{2,2}HT!!' => [
6093
  'S31HT' => [ 'HTC', 'Aria S31HT', 'carrier' => 'EMOBILE' ],
6094
  'X06HT' => [ 'HTC', 'Desire X06HT', 'carrier' => 'Softbank' ],
6095
  '001HT' => [ 'HTC', 'Desire HD 001HT', 'carrier' => 'Softbank' ],
6096
+ '601HT' => [ 'HTC', 'U11 601HT', 'carrier' => 'Softbank' ],
6097
  ],
6098
 
6099
  'ISW[0-9]{2,2}HT!!' => [
6195
  'BTV-(DL09|W09)!' => [ 'Huawei', 'MediaPad M3', DeviceType::TABLET ],
6196
  'CPN-(W09|AL00|L09)!' => [ 'Huawei', 'MediaPad M3 Lite', DeviceType::TABLET ],
6197
  'BAH-(W09|AL00|L09)!' => [ 'Huawei', 'MediaPad M3 Lite', DeviceType::TABLET ],
6198
+ 'CMR-(AL09|AL19|W09|W19)!' => [ 'Huawei', 'MediaPad M5', DeviceType::TABLET ],
6199
+ 'BAH2-(AL10|L09|W09|W19)!' => [ 'Huawei', 'MediaPad M5 Lite', DeviceType::TABLET ],
6200
+ 'SCM-(AL09|W09)!' => [ 'Huawei', 'MediaPad M6', DeviceType::TABLET ],
6201
 
6202
  'JDN-W09' => [ 'Huawei', 'Honor Pad 2', DeviceType::TABLET ],
6203
+ 'JDN2-AL00HN' => [ 'Huawei', 'Honor Tab 5', DeviceType::TABLET ],
6204
+ 'JDN2-W09HN' => [ 'Huawei', 'Honor Tab 5', DeviceType::TABLET ],
6205
 
6206
+ '(HUAWEI )?(ALP|BLA|CRR|EVR|HMA|LIO|LON|LYA|MATE|MHA|MT1|MT2|MT7|M200|NXT|SNE|TAS|Z100)!!' => [
6207
  '(HW-|HUAWEI )?MT1-(T00|U06)!' => [ 'Huawei', 'Ascend Mate' ],
6208
  '(HW-|HUAWEI )?MATE-U06!' => [ 'Huawei', 'Ascend Mate' ],
6209
  '(HW-|HUAWEI )?MT2-?(C00|L01|L02|L03|L05)!' => [ 'Huawei', 'Ascend Mate 2' ],
6213
  '(HW-|HUAWEI )?M200-(L09|UL00)!' => [ 'Huawei', 'Mate 8' ],
6214
  '(HW-|HUAWEI )?MHA-(AL00|L09|L29|TL00)!' => [ 'Huawei', 'Mate 9' ],
6215
  '(HW-|HUAWEI )?LON-(AL00|L29)!' => [ 'Huawei', 'Mate 9 Pro' ],
6216
+ '(HW-|HUAWEI )?ALP-(AL00|L09|L29|TL00)!' => [ 'Huawei', 'Mate 10' ],
6217
+ '(HW-|HUAWEI )?BLA-(A09|AL00|L09|L29|L30|TL00)!' => [ 'Huawei', 'Mate 10 Pro' ],
6218
+ '(HW-|HUAWEI )?HMA-(AL00|L09|L29|TL00)!' => [ 'Huawei', 'Mate 20' ],
6219
+ '(HW-|HUAWEI )?EVR-(AL00|AN00|L29|N29|TL00)!' => [ 'Huawei', 'Mate 20 X' ],
6220
+ '(HW-|HUAWEI )?SNE-(AL00|LX1|LX2|LX3)!' => [ 'Huawei', 'Mate 20 Lite' ],
6221
+ '(HW-|HUAWEI )?LYA-(AL00|AL00P|AL10|L09|L0C|L29|TL00)!' => [ 'Huawei', 'Mate 20 Pro' ],
6222
+ '(HW-|HUAWEI )?TAS-(AL00)!' => [ 'Huawei', 'Mate 30' ],
6223
+ '(HW-|HUAWEI )?LIO-(AL00|AN00|L29)!' => [ 'Huawei', 'Mate 30 Pro' ],
6224
  '(HW-|HUAWEI )?CRR-(L09|CL00|CL20|TL00|UL00|UL20)!' => [ 'Huawei', 'Mate S' ],
6225
  ],
6226
 
6227
+ '(HW-|HUAWEI )?(ATU|DRA|FLA|JKM|TIT|TAG||MRD|NCE|POT|TRT|SLA)!!' => [
6228
  '(HW-|HUAWEI )?TIT-(AL00|CL00|CL10|L01|TL00|U02)!' => [ 'Huawei', 'Enjoy 5' ],
6229
  '(HW-|HUAWEI )?TAG-(AL00|CL00|L13|TL00)!' => [ 'Huawei', 'Enjoy 5S' ],
6230
  '(HW-|HUAWEI )?NCE-(AL00|AL10|TL10)!' => [ 'Huawei', 'Enjoy 6' ],
6231
  '(HW-|HUAWEI )?SLA-(AL00|L02|L03|L22|TL10)!' => [ 'Huawei', 'Enjoy 7' ],
6232
  '(HW-|HUAWEI )?TRT-(AL00|L21|L53|LX1|LX2|LX3|TL10)!' => [ 'Huawei', 'Enjoy 7 Plus' ],
6233
+ '(HW-|HUAWEI )?FLA-(AL10|AL20|LX1|LX2|LX3|TL10)!' => [ 'Huawei', 'Enjoy 8 Plus' ],
6234
+ '(HW-|HUAWEI )?DRA-(AL00|L01|L21|LX2)!' => [ 'Huawei', 'Enjoy 8e' ],
6235
+ '(HW-|HUAWEI )?ATU-(AL10|L11|L21|L22|L31|LX3|TL10)!' => [ 'Huawei', 'Enjoy 8e' ],
6236
+ '(HW-|HUAWEI )?POT-(AL00a|LX1|LX1AF|LX1T|LX2J|LX3)!' => [ 'Huawei', 'Enjoy 9S' ],
6237
+ '(HW-|HUAWEI )?MRD-(AL00|LX1|LX1F|LX1N|LX2|LX3)!' => [ 'Huawei', 'Enjoy 9e' ],
6238
+ '(HW-|HUAWEI )?JKM-(AL00|AL00a|AL00b|LX1|LX2|LX3|TL00)!' => [ 'Huawei', 'Enjoy 9 Plus' ],
6239
  ],
6240
 
6241
+ '(HW-|HUAWEI |HONOR )?(ATH|BLN|BKL|BKK|BND|CHE|CHM|COL|DUA|DUK|DLI|EDI|FRD|HLK|HN3|H30|H60|HOL|JMM|JSN|LRA|KIW|LLD|NEM|NMO|OXF|PE|PCT|PLK|RNE|SCL|TNY|KNT|CAM|STF|HDN|YAL)!!' => [
6242
  'H30 U10' => [ 'Huawei', 'Honor 3C' ],
6243
  '(HW-|HUAWEI )?HN3-(U00|U01)!' => [ 'Huawei', 'Honor 3' ],
6244
  '(HW-|HUAWEI |HONOR )?H30[- ](C00|L01|L02|T00|T10|U10)!' => [ 'Huawei', 'Honor 3C' ],
6248
  '(HW-|HUAWEI )?CHE-(TL00|TL00H)!' => [ 'Huawei', 'Honor 4X' ],
6249
  '(HW-|HUAWEI )?Che1-(L04|CL10|CL20)!' => [ 'Huawei', 'Honor 4X' ],
6250
  '(HW-|HUAWEI )?Che2-(L11|L12|L23|TL00|UL00)!' => [ 'Huawei', 'Honor 4X' ],
6251
+ '(HW-|HUAWEI )?NEM-(AL10|CL00|L21|L22|L51|TL00|TL00H|UL10)!' => [ 'Huawei', 'Honor 5C' ],
6252
  '(HW-|HUAWEI )?NMO-(L22|L23|L31)!' => [ 'Huawei', 'Honor 5C' ],
6253
  '(HW-|HUAWEI )?KIW-(AL10|CL00|L21|L22|L24|UL00|TL00|TL00H)!' => [ 'Huawei', 'Honor 5X' ],
6254
  '(HW-|HUAWEI )?H60-(J1|L01|L02|L03|L04|L11|L12|L21)!' => [ 'Huawei', 'Honor 6' ],
6257
  '(HW-|HUAWEI )?PE-(CL00|TL00|TL00M|TL10|TL20|UL00)!' => [ 'Huawei', 'Honor 6 Plus' ],
6258
  '(HW-|HUAWEI |HONOR )?PLK-(L01|AL10|CL00|UL00|TL00|TL01H)!' => [ 'Huawei', 'Honor 7' ],
6259
  '(HW-|HUAWEI )?ATH-(AL00|CL00|TL00|TL00H|UL00)!' => [ 'Huawei', 'Honor 7i' ],
6260
+ '(HW-|HUAWEI )?DUA-(L22)!' => [ 'Huawei', 'Honor 7S' ],
6261
+ '(HW-|HUAWEI )?BND-(AL00|AL10|L21|L24|L31|L34|TL10)!' => [ 'Huawei', 'Honor 7X' ],
6262
+ '(HW-|HUAWEI )?DUA-(AL00|TL00)!' => [ 'Huawei', 'Honor 7 Play' ],
6263
  '(HW-|HUAWEI )?FRD-(AL00|AL10|DL00|L02|L04|L09|L14|L19)!' => [ 'Huawei', 'Honor 8' ],
6264
+ '(HW-|HUAWEI )?BKK-(AL00|AL10|L21|LX2)!' => [ 'Huawei', 'Honor 8C' ],
6265
+ '(HW-|HUAWEI )?JSN-(AL00|AL00a|L21|L22|L23|L42|TL00)!' => [ 'Huawei', 'Honor 8X' ],
6266
  '(HW-|HUAWEI )?ATH-(UL01|UL06)!' => [ 'Huawei', 'Honor ShotX' ],
6267
  '(HW-|HUAWEI )?KNT-(AL10|AL20|TL10|UL10)!' => [ 'Huawei', 'Honor V8' ],
6268
  '(HW-|HUAWEI )?EDI-(AL10)!' => [ 'Huawei', 'Honor Note 8' ],
6269
  '(HW-|HUAWEI )?STF-(AL00|AL10|L09|TL10)!' => [ 'Huawei', 'Honor 9' ],
6270
+ '(HW-|HUAWEI )?LLD-(AL00|AL10|AL20|L21|L31)!' => [ 'Huawei', 'Honor 9 Lite' ],
6271
+ '(HW-|HUAWEI )?RNE-(AL00|L01|L02|L03|L21|L22|L23|L31)!' => [ 'Huawei', 'Honor 9i' ],
6272
+ '(HW-|HUAWEI )?HLK-(AL00|AL10)!' => [ 'Huawei', 'Honor 9X' ],
6273
+ '(HW-|HUAWEI )?COL-(AL00|AL10|L29|TL00|TL10)!' => [ 'Huawei', 'Honor 10' ],
6274
+ '(HW-|HUAWEI )?YAL-(AL00|AL10|L21|L41)!' => [ 'Huawei', 'Honor 20' ],
6275
+ '(HW-|HUAWEI )?LRA-(AL00)!' => [ 'Huawei', 'Honor 20 Lite' ],
6276
  '(HW-|HUAWEI )?DUK-(AL20|L09|TL30)!' => [ 'Huawei', 'Honor V9' ],
6277
+ '(HW-|HUAWEI )?JMM-(AL00|AL10|L22|L22HN|TL00)!' => [ 'Huawei', 'Honor V9 Play' ],
6278
+ '(HW-|HUAWEI )?BKL-(AL00|AL20|L04|L09)!' => [ 'Huawei', 'Honor V10' ],
6279
+ '(HW-|HUAWEI )?PCT-(AL10|L29|TL10)!' => [ 'Huawei', 'Honor V20' ],
6280
+ '(HW-|HUAWEI )?OXF-(AN10)!' => [ 'Huawei', 'Honor V30 Pro' ],
6281
+ '(HW-|HUAWEI )?TNY-(AL00)!' => [ 'Huawei', 'Honor Magic 2' ],
6282
+ '(HW-|HUAWEI )?HDN-(L09|W09)!' => [ 'Huawei', 'Honor WaterPlay', DeviceType::TABLET ],
6283
  ],
6284
 
6285
  '(HW-|HUAWEI )?(BLL|CHC|TAG|KII)!!' => [
6289
  '(HW-|HUAWEI )?BLL-(L21|L22|L23)!' => [ 'Huawei', 'GR5 (2017)' ],
6290
  ],
6291
 
6292
+ '(HW-|HUAWEI )?(ALE|ANE|CLT|D2|DAV|ELE|EML|EVA|FIG|G6|G7|GRA|M100|P2|P6|P7|PRA|RIO|SC|Sophia|STK|VIE|VKY|VNS|VOG|VTR|WAS)!!' => [
6293
  'HUAWEI D2' => [ 'Huawei', 'Ascend D2' ],
6294
  '(HW-|HUAWEI )?D2-(0082|2010|5000|6070|6114)!' => [ 'Huawei', 'Ascend D2' ],
6295
  '(HW-|HUAWEI )?G6-(C00|L11|L22|L33|T00|U00|U10|U34|U251)!' => [ 'Huawei', 'Ascend G6' ],
6313
  '(HW-|HUAWEI )?VTR-?(AL00|L09|L29|TL00)!' => [ 'Huawei', 'P10' ],
6314
  '(HW-|HUAWEI )?WAS-?(AL00|L03T|LX1|LX1A|LX2|LX2J|LX3|TL10)!' => [ 'Huawei', 'P10 Lite' ],
6315
  '(HW-|HUAWEI )?VKY-?(AL00|L09|L29|TL00)!' => [ 'Huawei', 'P10 Plus' ],
6316
+ '(HW-|HUAWEI )?FIG-?(AL00|AL10|LA1|LX1|LX3|TL00)!' => [ 'Huawei', 'P Smart' ],
6317
+ '(HW-|HUAWEI )?STK-?(L22|LX1|LX3)!' => [ 'Huawei', 'P Smart Z' ],
6318
+ '(HW-|HUAWEI )?EML-?(AL00|L09|L29|TL00)!' => [ 'Huawei', 'P20' ],
6319
+ '(HW-|HUAWEI )?ANE-?(AL00|L21|LX1|LX2|LX2J|LX3)!' => [ 'Huawei', 'P20 Lite' ],
6320
+ '(HW-|HUAWEI )?CLT-?(AL00|AL01|L04|L09|L29|L39|TL00|TL01)!' => [ 'Huawei', 'P20 Pro' ],
6321
+ '(HW-|HUAWEI )?ELE-?(AL00|L04|L09|L29|TL00)!' => [ 'Huawei', 'P30' ],
6322
+ '(HW-|HUAWEI )?VOG-?(AL00|AL10|L04|L09|L29|TL00)!' => [ 'Huawei', 'P30 Pro' ],
6323
  ],
6324
 
6325
  'Rock-(AL00|CL00|L01|L03)!' => [ 'Huawei', 'Ascend G7' ],
6326
  'HUAWEI A168-(AL10|DL09|L09|L29)!' => [ 'Huawei', 'P9' ],
6327
 
6328
+ '(HW-|HUAWEI )?(CRO|LUA|CUN|SCC|SCU|CAM|LDN|LYO|MYA)!!' => [
6329
  '(HW-|HUAWEI )?CRO-(L02|L03|L22|U00)!' => [ 'Huawei', 'Y3 (2017)' ],
6330
  '(HW-|HUAWEI )?LUA-(L01|L02|L03|L13|L21|L22|L23|U02|U03|U22|U23)!' => [ 'Huawei', 'Y3 II' ],
6331
  '(HW-|HUAWEI )?CUN-(AL00|L01|L02|L03|L21|L22|L23|L33|TL00|U29)!' => [ 'Huawei', 'Y5 II' ],
6332
+ '(HW-|HUAWEI )?MYA-(AL10|L02|L03|L11|L13|L22|L23|L41|TL10)!' => [ 'Huawei', 'Y5 (2017)' ],
6333
  '(HW-|HUAWEI )?SCC-(U21)!' => [ 'Huawei', 'Y6' ],
6334
  '(HW-|HUAWEI )?SCU-(U31)!' => [ 'Huawei', 'Y6C' ],
6335
  '(HW-|HUAWEI )?CAM-(L01|L03|L11|L21|L23|L32|AL00|CL00|TL00|UL00)!' => [ 'Huawei', 'Y6 II' ],
6336
  '(HW-|HUAWEI )?LYO-(L01|L02|L21)!' => [ 'Huawei', 'Y6 II Compact' ],
6337
+ '(HW-|HUAWEI )?LDN-(AL00|L01|L21|LX2|LX3|TL00)!' => [ 'Huawei', 'Y7 Prime (2018)' ],
6338
  ],
6339
 
6340
  '(HW-|HUAWEI )?CAZ-(AL10|TL10|TL20)!' => [ 'Huawei', 'Nova' ],
6341
  '(HW-|HUAWEI )?CAN-(L01|L11|L12)!' => [ 'Huawei', 'Nova' ],
6342
  '(HW-|HUAWEI )?MLA-(L01|L03|L11|L12|L13)!' => [ 'Huawei', 'Nova Plus' ],
6343
  '(HW-|HUAWEI )?DIG-(AL00|L01|L03|L21|TL10)!' => [ 'Huawei', 'Nova Smart' ],
6344
+ '(HW-|HUAWEI )?BAC-(AL00|L03|L21|L22|TL00)!' => [ 'Huawei', 'Nova 2 Plus' ],
6345
+ '(HW-|HUAWEI )?HWI-(AL00|TL00)!' => [ 'Huawei', 'Nova 2S' ],
6346
+ '(HW-|HUAWEI )?PAR-(AL00|LX1|LX1M|LX9|TL00)!' => [ 'Huawei', 'Nova 3' ],
6347
+ '(HW-|HUAWEI )?INE-(AL00|LX1|LX1r|LX2||LX2r|TL00)!' => [ 'Huawei', 'Nova 3i' ],
6348
+ '(HW-|HUAWEI )?MAR-(AL00|LX1A|LX1M|LX2|LX3A|TL00)!' => [ 'Huawei', 'Nova 4e' ],
6349
  '(HW-|HUAWEI )?MLA-(AL00|AL10)!' => [ 'Huawei', 'Maimang 5' ],
6350
  '(HW-|HUAWEI )?MLA-(TL00|TL10|UL00)!' => [ 'Huawei', 'G9 Plus' ],
6351
 
6380
  'Y220T' => [ 'Huawei', 'Ascend Y220' ],
6381
  'Y221-(U22)!' => [ 'Huawei', 'Ascend Y221' ],
6382
  'Y301-(A1|A2)!' => [ 'Huawei', 'Valiant' ],
6383
+ 'Y320-(U01|U10|U151)!' => [ 'Huawei', 'Ascend Y320' ],
6384
  'Y325-T00' => [ 'Huawei', 'Ascend Y325' ],
6385
  'Y330-U11' => [ 'Huawei', 'Ascend Y330' ],
6386
  'Y340-U081' => [ 'Huawei', 'Ascend Y340' ],
6629
  '402HW' => [ 'Huawei', 'MediaPad 10 Link+ 402HW', DeviceType::TABLET, 'carrier' => 'Softbank' ],
6630
  '403HW' => [ 'Huawei', 'MediaPad M1 8.0 403HW', DeviceType::TABLET, 'carrier' => 'Y! Mobile' ],
6631
  '503HW' => [ 'Huawei', 'LUMIERE 503HW', 'carrier' => 'Y! Mobile' ],
6632
+ '605HW' => [ 'Huawei', 'MediaPad T2 Pro 605HW', DeviceType::TABLET, 'carrier' => 'Softbank' ],
6633
  '606HW' => [ 'Huawei', 'MediaPad T2 Pro 606HW', DeviceType::TABLET, 'carrier' => 'Y! Mobile' ],
6634
+ '608HW' => [ 'Huawei', 'nova lite 608HW', 'carrier' => 'Y! Mobile' ],
6635
+ '704HW' => [ 'Huawei', 'nova lite 2 704HW', 'carrier' => 'Softbank' ],
6636
  ],
6637
 
6638
  'CM980' => [ 'Huawei', 'Evolution II' ],
6729
  'GS03' => [ 'Huawei', 'GS03', 'carrier' => 'EMOBILE' ],
6730
  'GL07S' => [ 'Huawei', 'STREAM X GL07S', 'carrier' => 'EMOBILE' ],
6731
  'HW-01E' => [ 'Huawei', 'Ascend HW-01E', 'carrier' => 'DoCoMo' ],
6732
+ 'HW-01K' => [ 'Huawei', 'P20 Pro HW-01K', 'carrier' => 'DoCoMo' ],
6733
  'HW-03E' => [ 'Huawei', 'Ascend D2 HW-03E', 'carrier' => 'DoCoMo' ],
6734
  'HWT31' => [ 'Huawei', 'Qua tab 02 HWT31', 'carrier' => 'au' ],
6735
+ 'HWV32' => [ 'Huawei', 'P20 lite HWV32', 'carrier' => 'au' ],
6736
  'H710VL' => [ 'Huawei', 'Sensa' ],
6737
+ 'H715BL' => [ 'Huawei', 'Sensa LTE' ],
6738
  'H866C' => [ 'Huawei', 'Ascend Y H866C' ],
6739
  'H882L' => [ 'Huawei', 'Ascend Y301-A' ],
6740
 
7129
  'Infinix NOTE 3 Pro' => [ 'Infinix', 'Note 3 Pro X601' ],
7130
  'Infinix Zero 4' => [ 'Infinix', 'Zero 4 X602' ],
7131
  'Infinix Zero 4 Plus' => [ 'Infinix', 'Zero 4 Plus X602' ],
7132
+ 'Infinix X603' => [ 'Infinix', 'Zero 5 X603' ],
7133
  'Infinix X800' => [ 'Infinix', 'Joypad 8 X800', DeviceType::TABLET ],
7134
  'Infinix X801' => [ 'Infinix', 'Joypad 8S X801', DeviceType::TABLET ],
7135
  'Infinix X1000' => [ 'Infinix', 'Joypad 10 X1000', DeviceType::TABLET ],
7923
 
7924
  'KY[FLTYV][0-9]{2,2}!!' => [
7925
  'KYF31' => [ 'Kyocera', 'GRATINA KYF31', 'carrier' => 'au' ],
7926
+ 'KYF33' => [ 'Kyocera', 'TORQUE X01 KYF31', 'carrier' => 'au' ],
7927
  'KYF37' => [ 'Kyocera', 'GRATINA KYF37', 'carrier' => 'au' ],
7928
  'KYL23' => [ 'Kyocera', 'miraie KYL23', 'carrier' => 'au' ],
7929
  'KYY21' => [ 'Kyocera', 'URBANO L01', 'carrier' => 'au' ],
7936
  'KYV35' => [ 'Kyocera', 'TORQUE G02', 'carrier' => 'au' ],
7937
  'KYV36' => [ 'Kyocera', 'DIGNO rafre KYV36', 'carrier' => 'au' ],
7938
  'KYV37' => [ 'Kyocera', 'Qua phone', 'carrier' => 'au' ],
7939
+ 'KYV38' => [ 'Kyocera', 'URBANO V03 KYV38', 'carrier' => 'au' ],
7940
+ 'KYV39' => [ 'Kyocera', 'miraie f KYL39', 'carrier' => 'au' ],
7941
  'KYV40' => [ 'Kyocera', 'rafre KYV40', 'carrier' => 'au' ],
7942
+ 'KYV40U' => [ 'Kyocera', 'DIGNO W KYV40U', 'carrier' => 'UQ mobile' ],
7943
+ 'KYV41' => [ 'Kyocera', 'TORQUE G03 KYV41', 'carrier' => 'au' ],
7944
+ 'KYV42' => [ 'Kyocera', 'Qua phone QX', 'carrier' => 'au' ],
7945
+ 'KYV42 u' => [ 'Kyocera', 'DIGNO V KYV42', 'carrier' => 'UQ mobile' ],
7946
+ 'KYV44' => [ 'Kyocera', 'Qua phone QZ', 'carrier' => 'au' ],
7947
+ 'KYV44 u' => [ 'Kyocera', 'DIGNO A KYV44', 'carrier' => 'UQ mobile' ],
7948
  'KYT31' => [ 'Kyocera', 'Qua tab', DeviceType::TABLET, 'carrier' => 'au' ],
7949
+ 'KYT32' => [ 'Kyocera', 'Qua tab QZ8', DeviceType::TABLET, 'carrier' => 'au' ],
7950
+ 'KYT33' => [ 'Kyocera', 'Qua tab QZ10', DeviceType::TABLET, 'carrier' => 'au' ],
7951
  ],
7952
 
7953
  'URBANO PROGRESSO' => [ 'Kyocera', 'URBANO PROGRESSO', 'carrier' => 'au' ],
7960
  '404KC' => [ 'Kyocera', 'DIGNO C 404KC', 'carrier' => 'Y! Mobile' ],
7961
  '503KC' => [ 'Kyocera', 'DIGNO E 503KC', 'carrier' => 'Y! Mobile' ],
7962
  '602KC' => [ 'Kyocera', 'DIGNO G 602KC', 'carrier' => 'Softbank' ],
7963
+ '704KC' => [ 'Kyocera', 'DIGNO J 704KC', 'carrier' => 'Softbank' ],
7964
  ],
7965
 
7966
  'K\-?Touch!!' => [
8770
  'LenovoTV 40S9' => [ 'Lenovo', 'TV 40S9', DeviceType::TELEVISION ],
8771
  'LenovoTV 50S52' => [ 'Lenovo', 'TV 50S52', DeviceType::TELEVISION ],
8772
  '501LV' => [ 'Lenovo', 'Tab2 501LV', 'carrier' => 'Softbank' ],
8773
+ '602LV' => [ 'Lenovo', 'Tab3 602LV', 'carrier' => 'Softbank' ],
8774
 
8775
  'ZUK Z1' => [ 'Lenovo', 'ZUK Z1' ],
8776
  'ZUK Z2' => [ 'Lenovo', 'ZUK Z2' ],
8863
  'LGAS991' => [ 'LG', 'G4' ],
8864
  'LG-AS9(91)!' => [ 'LG', 'G4' ],
8865
  'LGAS992' => [ 'LG', 'G5' ],
8866
+ 'LG-AS993' => [ 'LG', 'G6' ],
8867
  'LGAS995' => [ 'LG', 'G Flex 2' ],
8868
+ 'LG-AS998' => [ 'LG', 'V30' ],
8869
  ],
8870
 
8871
  'LG-?C[0-9]{3,3}!!' => [
9004
  'LG-F820!' => [ 'LG', 'U' ],
9005
  ],
9006
 
9007
+ 'LG-FL40L!' => [ 'LG', '070 Touch' ],
9008
  'LG-GT540!' => [ 'LG', 'Optimus' ],
9009
  'LG-GW620!' => [ 'LG', 'GW620 Eve' ],
9010
 
9119
  'LGL86C!' => [ 'LG', 'Optimus Showtime' ],
9120
  'LG-L95G!' => [ 'LG', 'L95G' ],
9121
  'LGL96G' => [ 'LG', 'Ultimate' ],
9122
+ 'LGL157BL' => [ 'LG', 'Rebel 3' ],
9123
+ 'LGL158VL' => [ 'LG', 'Rebel 3' ],
9124
  'LG-L160L' => [ 'LG', 'Optimus LTE2' ],
9125
  'LGL163BL' => [ 'LG', 'Fiesta 2' ],
9126
  'LGL164VL' => [ 'LG', 'Fiesta' ],
9208
  'LG-M4(30)!' => [ 'LG', 'Stylo 3' ],
9209
  'LG-M4(70)!' => [ 'LG', 'Stylo 3 Plus' ],
9210
  'LG-M7(00|03)!' => [ 'LG', 'Q6' ],
9211
+ 'LG-M7(10)!' => [ 'LG', 'X Venture' ],
9212
  ],
9213
 
9214
  'LG-?MS[0-9]{3,3}!!' => [
9222
  'LGMS500' => [ 'LG', 'Optimus F6' ],
9223
  'LG-MS500' => [ 'LG', 'Optimus F6' ],
9224
  'LGMS550' => [ 'LG', 'G Stylo 2' ],
9225
+ 'LG-MS550' => [ 'LG', 'G Stylo 2' ],
9226
  'LGMS631' => [ 'LG', 'G Stylo' ],
9227
  'LG-MS659' => [ 'LG', 'Optimus F3' ],
9228
  'LGMS659' => [ 'LG', 'Optimus F3' ],
9277
  'LG-P815!' => [ 'LG', 'G Pad II 8.3', DeviceType::TABLET ],
9278
  ],
9279
 
9280
+ 'LG-Q710!' => [ 'LG', 'Stylo 4' ],
9281
+
9282
+ 'LG-RS988!' => [ 'LG', 'G5' ],
9283
+ 'RS988' => [ 'LG', 'G5' ],
9284
+
9285
+ 'LG-SP[0-9]{3,3}!!' => [
9286
+ 'LG-SP200' => [ 'LG', 'Tribute Dynasty' ],
9287
+ 'LG-SP320' => [ 'LG', 'X Charge' ],
9288
+ ],
9289
+
9290
  'LG-SU[0-9]{3,3}!!' => [
9291
  'LG-SU370' => [ 'LG', 'Optimus One' ],
9292
  'LG-SU540' => [ 'LG', 'PRADA 3.0' ],
9303
  'LG-TP260' => [ 'LG', 'K20 Plus' ],
9304
  'LG-TP450' => [ 'LG', 'Stylo 3 Plus' ],
9305
 
 
 
9306
  'LG-SU-760' => [ 'LG', 'Optimus 3D' ],
9307
  'LGUK410' => [ 'LG', 'G Pad 7.0', DeviceType::TABLET ],
9308
  'LG-UK495' => [ 'LG', 'G Pad F 8.0', DeviceType::TABLET ],
9315
  'LGUS215' => [ 'LG', 'K8 2017' ],
9316
  'LGUS375' => [ 'LG', 'K8' ],
9317
  'LGUS550' => [ 'LG', 'Logos' ],
9318
+ 'LG-US601' => [ 'LG', 'X Charge' ],
9319
  'LGUS610' => [ 'LG', 'X Power' ],
9320
  'LG-US670' => [ 'LG', 'Optimus U' ],
9321
+ 'LG-US700' => [ 'LG', 'Q6' ],
9322
+ 'LG-US701' => [ 'LG', 'X Venture' ],
9323
  'LG-US730' => [ 'LG', 'Splendor' ],
9324
  'LG-US780' => [ 'LG', 'Optimus F7' ],
9325
  'LGUS990!' => [ 'LG', 'G3' ],
9329
  'LGUS995!' => [ 'LG', 'G Flex 2' ],
9330
  'LG-US996!' => [ 'LG', 'V20' ],
9331
  'LG-US997' => [ 'LG', 'G6' ],
9332
+ 'LG-US998' => [ 'LG', 'V30' ],
9333
  ],
9334
 
9335
  'LG-V[0-9]{3,3}!!' => [
9416
  'LGM-K120[KLS]!' => [ 'LG', 'X300' ],
9417
  'LGM-K121[KLS]!' => [ 'LG', 'X400' ],
9418
  'LGM-V300[KLS]!' => [ 'LG', 'V30' ],
9419
+ 'LGM-X100[S]!' => [ 'LG', 'Smart Folder' ],
9420
  'LGM-X320[KLS]!' => [ 'LG', 'X500' ],
9421
+ 'LGM-X401[S]!' => [ 'LG', 'X401' ],
9422
  'LGM-X600[KLS]!' => [ 'LG', 'Q6' ],
9423
  'LGM-X800[KLS]!' => [ 'LG', 'Q8' ],
9424
  ],
9425
 
9426
+ 'LM-G710!' => [ 'LG', 'G7 ThinQ' ],
9427
+ 'LM-G715!' => [ 'LG', 'G7 ThinQ' ],
9428
+ 'LM-G810!' => [ 'LG', 'G8s ThinQ' ],
9429
+ 'LM-G820!' => [ 'LG', 'G8 ThinQ' ],
9430
+ 'LM-Q610!' => [ 'LG', 'Q7' ],
9431
+ 'LM-Q617!' => [ 'LG', 'Q7 BTS Edition' ],
9432
+ 'LM-Q710!' => [ 'LG', 'Q Stylus+' ],
9433
+ 'LM-Q720!' => [ 'LG', 'Stylo 5' ],
9434
+ 'LM-Q725!' => [ 'LG', 'Q7 Plus' ],
9435
+ 'LM-Q815!' => [ 'LG', 'Q8 (2018)' ],
9436
+ 'LM-Q850!' => [ 'LG', 'G7 Fit' ],
9437
+ 'LM-Q910!' => [ 'LG', 'G7 One' ],
9438
+ 'LM-Q925!' => [ 'LG', 'Q9' ],
9439
+ 'LM-V350!' => [ 'LG', 'V35 ThinQ' ],
9440
+ 'LM-V40[59]!' => [ 'LG', 'V40 ThinQ' ],
9441
+ 'LM-V450!' => [ 'LG', 'V50 ThinQ' ],
9442
+ 'LM-V500!' => [ 'LG', 'V50 ThinQ' ],
9443
+ 'LM-X120!' => [ 'LG', 'K20' ],
9444
+ 'LM-X210!' => [ 'LG', 'Aristo 2' ],
9445
+ 'LM-X212!' => [ 'LG', 'K8' ],
9446
+ 'LM-X220!' => [ 'LG', 'Aristo 3' ],
9447
+ 'LM-X320!' => [ 'LG', 'K30' ],
9448
+ 'LM-X410!' => [ 'LG', 'X4' ],
9449
+ 'LM-X415!' => [ 'LG', 'X4+' ],
9450
+ 'LM-X420!' => [ 'LG', 'X4 (2019)' ],
9451
+ 'LM-X510!' => [ 'LG', 'X5' ],
9452
+ 'LM-X525!' => [ 'LG', 'K12 Prime' ],
9453
+ 'LM-X625!' => [ 'LG', 'X6 (2019)' ],
9454
+ 'LM-Y110!' => [ 'LG', 'Folder' ],
9455
+
9456
+ 'LGMP450' => [ 'LG', 'Stylo 3 Plus' ],
9457
+
9458
  'lge-F160!' => [ 'LG', 'Optimus LTE II' ],
9459
  'LGE-E988!' => [ 'LG', 'Optimus G Pro' ],
9460
  'lgp-970' => [ 'LG', 'Optimus Black' ],
9474
  'LGL24' => [ 'LG', 'isai FL LGL24', 'carrier' => 'au' ],
9475
  'LGL25' => [ 'LG', 'Fx0 LGL25', 'carrier' => 'au' ],
9476
  'LGS01' => [ 'LG', 'Wine Smart LGS01', 'carrier' => 'J:COM' ],
9477
+ 'LGS02' => [ 'LG', 'X screen LGS02', 'carrier' => 'J:COM' ],
9478
  'LGV31' => [ 'LG', 'isai VL LGV31', 'carrier' => 'au' ],
9479
  'LGV32' => [ 'LG', 'isai vivid LGV32', 'carrier' => 'au' ],
9480
  'LGV33' => [ 'LG', 'Qua phone PX LGV33', 'carrier' => 'au' ],
9538
  'L-01D' => [ 'LG', 'Optimus LTE L-01D', 'carrier' => 'DoCoMo' ],
9539
  'L-01E' => [ 'LG', 'Optimus G L-01E', 'carrier' => 'DoCoMo' ],
9540
  'L-01F' => [ 'LG', 'G2 L-01F', 'carrier' => 'DoCoMo' ],
9541
+ 'L-01J' => [ 'LG', 'V20 PRO L-01J', 'carrier' => 'DoCoMo' ],
9542
  'L-01K' => [ 'LG', 'V30+ L-01K', 'carrier' => 'DoCoMo' ],
9543
  'L-02D' => [ 'LG', 'PRADA phone L-02D', 'carrier' => 'DoCoMo' ],
9544
  'L-02E' => [ 'LG', 'Optimus LIFE L-02E', 'carrier' => 'DoCoMo' ],
9545
  'L-02F' => [ 'LG', 'WiFi STATION L-02F', 'carrier' => 'DoCoMo' ],
9546
  'L-02K' => [ 'LG', 'JOJO L-02K', 'carrier' => 'DoCoMo' ],
9547
+ 'L-03K' => [ 'LG', 'style L-03K', 'carrier' => 'DoCoMo' ],
9548
  'L-04C' => [ 'LG', 'Optimus chat L-04C', 'carrier' => 'DoCoMo' ],
9549
  'L-04E' => [ 'LG', 'Optimus G Pro L-04E', 'carrier' => 'DoCoMo' ],
9550
  'L-05D' => [ 'LG', 'Optimus it L-05D', 'carrier' => 'DoCoMo' ],
9561
  ],
9562
 
9563
  'DM-01G' => [ 'LG', 'DM-01G', 'carrier' => 'Disney Mobile' ],
9564
+ 'DM-01K' => [ 'LG', 'DM-01K', 'carrier' => 'Disney Mobile' ],
9565
  'DM-02H' => [ 'LG', 'DM-02H', 'carrier' => 'Disney Mobile' ],
9566
 
9567
  'LG!!' => [
9941
  'LIFETAB S1033X' => [ 'Medion', 'Lifetab S1033X', DeviceType::TABLET ],
9942
  'LIFETAB S1034X' => [ 'Medion', 'Lifetab S1034X', DeviceType::TABLET ],
9943
  'LIFETAB S1036X' => [ 'Medion', 'Lifetab S1036X', DeviceType::TABLET ],
9944
+ 'X1030X' => [ 'Medion', 'Lifetab X1030X', DeviceType::TABLET ],
9945
  'MEDION LIFE P4012' => [ 'Medion', 'Life P4012' ],
9946
  'MEDION P4013' => [ 'Medion', 'Life P4013' ],
9947
  'MEDION-P4013' => [ 'Medion', 'Life P4013' ],
9966
  'MEEG 210R' => [ 'MEEG', '210R' ],
9967
  ],
9968
 
9969
+ 'MEIZU E3' => [ 'Meizu', 'E3' ],
9970
  'M1' => [ 'Meizu', 'M1' ],
9971
  'm1 metal' => [ 'Meizu', 'M1 Metal' ],
9972
  'meizu m1note' => [ 'Meizu', 'M1 Note' ],
9986
  'M3s' => [ 'Meizu', 'M3s' ],
9987
  'M4' => [ 'Meizu', 'M4' ],
9988
  'M5' => [ 'Meizu', 'M5' ],
9989
+ 'MZ-M5' => [ 'Meizu', 'M5' ],
9990
  'MEIZU M5' => [ 'Meizu', 'M5' ],
9991
+ 'MZ-MEIZU M6' => [ 'Meizu', 'M6' ],
9992
  'M8' => [ 'Meizu', 'M8' ],
9993
  'M9' => [ 'Meizu', 'M9' ],
9994
  'M9-unlocked' => [ 'Meizu', 'M9' ],
10009
  'MX4 Pro' => [ 'Meizu', 'MX4 Pro' ],
10010
  'MZ-MX4 Pro' => [ 'Meizu', 'MX4 Pro' ],
10011
  'MX5' => [ 'Meizu', 'MX5' ],
10012
+ 'MZ-MX5' => [ 'Meizu', 'MX5' ],
10013
  'MX6' => [ 'Meizu', 'MX6' ],
10014
  'PRO 5' => [ 'Meizu', 'PRO 5' ],
10015
  'PRO 6' => [ 'Meizu', 'PRO 6' ],
10016
  'PRO 6s' => [ 'Meizu', 'PRO 6s' ],
10017
  'PRO 6 Plus' => [ 'Meizu', 'PRO 6 Plus' ],
10018
+ 'Meizu S6' => [ 'Meizu', 'S6' ],
10019
 
10020
  '(MEO )?Smart A!!' => [
10021
  'meo smart a12' => [ 'MEO', 'Smart A12' ],
10040
  'SlidePad 104' => [ 'Memup', 'Slidepad 104', DeviceType::TABLET ],
10041
  'SlidePad 108' => [ 'Memup', 'Slidepad 108', DeviceType::TABLET ],
10042
  'SlidePad704CE' => [ 'Memup', 'Slidepad 704CE', DeviceType::TABLET ],
 
10043
  'SlidePad 816P' => [ 'Memup', 'Slidepad 816P', DeviceType::TABLET ],
10044
  'SlidePad Elite 9708' => [ 'Memup', 'Slidepad Elite 9708', DeviceType::TABLET ],
10045
  'SlidePad Kids' => [ 'Memup', 'Slidepad Kids', DeviceType::TABLET ],
10047
  'SlidePad NG 704DC' => [ 'Memup', 'Slidepad NG 704DC', DeviceType::TABLET ],
10048
  ],
10049
 
10050
+ '704DC' => [ 'Memup', 'Slidepad 704DC', DeviceType::TABLET ],
10051
+
10052
  'SPNG9716DC' => [ 'Memup', 'Slidepad NG 9716DC', DeviceType::TABLET ],
10053
  'Mi-A402' => [ 'Mi-fone', 'FAB 4.0' ],
10054
 
10684
  'XT19(02)!' => [ 'Lenovo', 'K8 Note' ],
10685
  ],
10686
 
10687
+ 'motorola one' => [ 'Motorola', 'One' ],
10688
+ 'motorola one action' => [ 'Motorola', 'One Action' ],
10689
+ 'motorola one macro' => [ 'Motorola', 'One Macro' ],
10690
+ 'motorola one power' => [ 'Motorola', 'One Power' ],
10691
+ 'motorola one vision' => [ 'Motorola', 'One Vision' ],
10692
+ 'motorola one zoom' => [ 'Motorola', 'One Zoom' ],
10693
+
10694
  'Atrix 2' => [ 'Motorola', 'ATRIX 2' ],
10695
  'Atrix 2 WeifanZ' => [ 'Motorola', 'ATRIX 2' ],
10696
  'Atrix 4G' => [ 'Motorola', 'ATRIX 4G' ],
10745
  '(Moto)?E2\(4G-LTE\)$!' => [ 'Motorola', 'Moto E (2015)' ],
10746
  'surnia' => [ 'Motorola', 'Moto E (2015)' ],
10747
  'Motorola MotoE2!' => [ 'Motorola', 'Moto E2' ],
10748
+ 'Moto E4' => [ 'Motorola', 'Moto E4' ],
10749
  'Moto E (4)' => [ 'Motorola', 'Moto E4' ],
10750
  'Moto E (4) Plus' => [ 'Motorola', 'Moto E4 Plus' ],
10751
+ 'moto e5 cruise' => [ 'Motorola', 'Moto E5 Cruise' ],
10752
+ 'moto e5 play' => [ 'Motorola', 'Moto E5 Play' ],
10753
  '(Moto)?G3$!' => [ 'Motorola', 'Moto G (2015)' ],
10754
  '(Moto)?G3-TE$!' => [ 'Motorola', 'Moto G (2015)' ],
10755
+ 'Moto G 2015' => [ 'Motorola', 'Moto G (2015)' ],
10756
+ 'Moto G (2015)' => [ 'Motorola', 'Moto G (2015)' ],
10757
+ 'Moto G (2014' => [ 'Motorola', 'Moto G' ],
10758
  'MOTOROLA MOTOG' => [ 'Motorola', 'Moto G' ],
10759
  'Moto G Play' => [ 'Motorola', 'Moto G Play' ],
10760
+ 'Moto G Turbo' => [ 'Motorola', 'Moto G Turbo' ],
10761
  'Moto G4' => [ 'Motorola', 'Moto G4' ],
10762
+ 'Moto G (4' => [ 'Motorola', 'Moto G4' ],
10763
  'Moto G (4)' => [ 'Motorola', 'Moto G4' ],
10764
  'Moto G4 Plus' => [ 'Motorola', 'Moto G4 Plus' ],
10765
+ 'Moto G 5' => [ 'Motorola', 'Moto G5' ],
10766
+ 'Moto G (5' => [ 'Motorola', 'Moto G5' ],
10767
  'Moto G (5)' => [ 'Motorola', 'Moto G5' ],
10768
  'Moto G (5) Plus' => [ 'Motorola', 'Moto G5 Plus' ],
10769
+ 'Moto G (5S' => [ 'Motorola', 'Moto G5S' ],
10770
+ 'Moto G (5S)' => [ 'Motorola', 'Moto G5S' ],
10771
  'Moto G (5S) Plus' => [ 'Motorola', 'Moto G5S Plus' ],
10772
+ 'moto g(6' => [ 'Motorola', 'Moto G6' ],
10773
+ 'moto g(6)' => [ 'Motorola', 'Moto G6' ],
10774
+ 'moto g(6) (XT1925DL)' => [ 'Motorola', 'Moto G6' ],
10775
+ 'moto g(6) forge' => [ 'Motorola', 'Moto G6 Forge' ],
10776
+ 'moto g(6) play' => [ 'Motorola', 'Moto G6 Play' ],
10777
+ 'moto g(6) plus' => [ 'Motorola', 'Moto G6 Plus' ],
10778
+ 'moto g(7' => [ 'Motorola', 'Moto G7' ],
10779
+ 'moto g(7)' => [ 'Motorola', 'Moto G7' ],
10780
+ 'moto g(7) optimo (XT1952DL)' => [ 'Motorola', 'Moto G7 Optimo' ],
10781
+ 'moto g(7) play' => [ 'Motorola', 'Moto G7 Play' ],
10782
+ 'moto g(7) plus' => [ 'Motorola', 'Moto G7 Plus' ],
10783
+ 'moto g(7) power' => [ 'Motorola', 'Moto G7 Power' ],
10784
+ 'moto g(7) supra' => [ 'Motorola', 'Moto G7 Supra' ],
10785
+ 'moto g(8' => [ 'Motorola', 'Moto G8' ],
10786
  'Moto Z (2)' => [ 'Motorola', 'Moto Z2' ],
10787
  'Moto Z2 Play' => [ 'Motorola', 'Moto Z2 Play' ],
10788
  'Moto X Pro' => [ 'Motorola', 'Moto X Pro' ],
10789
+ 'moto x4' => [ 'Motorola', 'Moto X4' ],
10790
  'roiX' => [ 'Motorola', 'Droid X' ],
10791
  'Moto Backflip' => [ 'Motorola', 'BACKFLIP' ],
10792
  'RAZR' => [ 'Motorola', 'RAZR' ],
11180
 
11181
  'NBX-T7013N' => [ 'Noblex', 'T7013N', DeviceType::TABLET ],
11182
  'NBX-T7023N' => [ 'Noblex', 'T7023N', DeviceType::TABLET ],
11183
+ 'TA-10(07|29)!' => [ 'Nokia', '2' ],
11184
+ 'TA-10(84)!' => [ 'Nokia', '2.1' ],
11185
  'TA-10(20|28|32|38)!' => [ 'Nokia', '3' ],
11186
+ // 'TA-10()!' => [ 'Nokia', '3.1' ],
11187
  'TA-10(24|27|44|53)!' => [ 'Nokia', '5' ],
11188
+ 'TA-10(61|75|81|88)!' => [ 'Nokia', '5.1' ],
11189
  'TA-10(00|03|21|25|33|39)!' => [ 'Nokia', '6' ],
11190
+ 'TA-10(43|50|54|68)!' => [ 'Nokia', '6.1' ],
11191
  'TA-10(41)!' => [ 'Nokia', '7' ],
11192
+ 'TA-10(62)!' => [ 'Nokia', '7 Plus' ],
11193
  'TA-10(04|12|52)!' => [ 'Nokia', '8' ],
11194
+ 'TA-10(99)!' => [ 'Nokia', 'X6' ],
11195
+ 'TA-11(03|16)!' => [ 'Nokia', 'X6' ],
11196
+ 'Nokia 1 Plus' => [ 'Nokia', '1 Plus' ],
11197
+ 'Nokia 1' => [ 'Nokia', '1' ],
11198
+ 'Nokia 2.1' => [ 'Nokia', '2.1' ],
11199
+ 'Nokia 2' => [ 'Nokia', '2' ],
11200
+ 'Nokia 3.1 Plus' => [ 'Nokia', '3.1 Plus' ],
11201
+ 'Nokia 3.1' => [ 'Nokia', '3.1' ],
11202
+ 'Nokia 4.2' => [ 'Nokia', '4.2' ],
11203
+ 'Nokia 5.1 Plus' => [ 'Nokia', '5.1 Plus' ],
11204
+ 'Nokia 5.1' => [ 'Nokia', '5.1' ],
11205
+ 'Nokia 6.1 Plus' => [ 'Nokia', '6.1 Plus' ],
11206
+ 'Nokia 6.1' => [ 'Nokia', '6.1' ],
11207
+ 'Nokia 6.2' => [ 'Nokia', '6.2' ],
11208
+ 'Nokia 6' => [ 'Nokia', '6' ],
11209
+ 'Nokia 7.1' => [ 'Nokia', '7.1' ],
11210
+ 'Nokia 7 Plus' => [ 'Nokia', '7 Plus' ],
11211
+ 'Nokia 8.1' => [ 'Nokia', '8.1' ],
11212
+ 'Nokia 8 Sirocco' => [ 'Nokia', '8 Sirocco' ],
11213
+ 'Nokia 8' => [ 'Nokia', '8' ],
11214
+ 'Nokia 9' => [ 'Nokia', '9' ],
11215
+ 'Nokia 10.1' => [ 'Nokia', '10.1' ],
11216
  'Nokia N9' => [ 'Nokia', 'N9' ],
11217
  'Nokia N900' => [ 'Nokia', 'N900' ],
11218
  'Nokia X' => [ 'Nokia', 'X', DeviceType::MOBILE, Flag::NOKIAX ],
11343
  'ONEPLUS A3010' => [ 'OnePlus', '3T' ],
11344
  'ONEPLUS A5000' => [ 'OnePlus', '5' ],
11345
  'ONEPLUS A5010' => [ 'OnePlus', '5T' ],
11346
+ 'ONEPLUS A6000' => [ 'OnePlus', '6' ],
11347
+ 'ONEPLUS A6003' => [ 'OnePlus', '6' ],
11348
+ 'ONEPLUS A6010' => [ 'OnePlus', '6T' ],
11349
+ 'ONEPLUS A6013' => [ 'OnePlus', '6T' ],
11350
+ 'HD190[01]!' => [ 'OnePlus', '7T' ],
11351
+ 'HD191[03]!' => [ 'OnePlus', '7T Pro' ],
11352
+ 'GM190[0135]!' => [ 'OnePlus', '7' ],
11353
+ 'GM191[01357]!' => [ 'OnePlus', '7 Pro' ],
11354
  'ONE E1000' => [ 'OnePlus', 'X' ],
11355
  'ONE E1001' => [ 'OnePlus', 'X' ],
11356
  'ONE E1003' => [ 'OnePlus', 'X' ],
11395
  'N2T' => [ 'ONN', 'N2T', DeviceType::TABLET ],
11396
  'Renesas!' => [ 'Opad', 'Renesas', DeviceType::TABLET ],
11397
  'A11w' => [ 'Oppo', 'Joy 3' ],
11398
+ 'PADM00' => [ 'Oppo', 'A3' ],
11399
+ 'PADT00' => [ 'Oppo', 'A3' ],
11400
+ 'CPH1803' => [ 'Oppo', 'A3s' ],
11401
+ 'CPH1809' => [ 'Oppo', 'A5' ],
11402
+ 'PBAM00' => [ 'Oppo', 'A5' ],
11403
+ 'OPPO PBAM00' => [ 'Oppo', 'A5' ],
11404
+ 'PBAT00' => [ 'Oppo', 'A5' ],
11405
+ 'CPH1901' => [ 'Oppo', 'A7' ],
11406
+ 'PBFT00' => [ 'Oppo', 'A7' ],
11407
+ 'OPPO PBFT00' => [ 'Oppo', 'A7' ],
11408
+ 'PBBM00' => [ 'Oppo', 'A7x' ],
11409
+ 'CPH1937' => [ 'Oppo', 'A9 2020' ],
11410
+ 'CPH1941' => [ 'Oppo', 'A9 2020' ],
11411
  'OPPO A30' => [ 'Oppo', 'A30' ],
11412
  'A31' => [ 'Oppo', 'A31' ],
11413
  'OPPO A31' => [ 'Oppo', 'A31' ],
11415
  'A31c' => [ 'Oppo', 'A31c' ],
11416
  'A31t' => [ 'Oppo', 'A31t' ],
11417
  'OPPO A31t' => [ 'Oppo', 'A31t' ],
11418
+ 'A31u' => [ 'Oppo', 'A31u' ],
11419
  'OPPO A33' => [ 'Oppo', 'A33' ],
11420
  'A33f' => [ 'Oppo', 'A33f' ],
11421
  'OPPO A33m' => [ 'Oppo', 'A33m' ],
11424
  'A37fw' => [ 'Oppo', 'A37fw' ],
11425
  'OPPO A37m' => [ 'Oppo', 'A37m' ],
11426
  'CPH1605' => [ 'Oppo', 'A39' ],
11427
+ 'A51' => [ 'Oppo', 'A51' ],
11428
  'A51f' => [ 'Oppo', 'A51f' ],
11429
  'OPPO A53' => [ 'Oppo', 'A53' ],
11430
  'OPPO A53m' => [ 'Oppo', 'A53m' ],
11431
+ 'OPPO A53t' => [ 'Oppo', 'A53t' ],
11432
  'CPH1701' => [ 'Oppo', 'A57' ],
11433
  'OPPO A57' => [ 'Oppo', 'A57' ],
11434
  'OPPO A57t' => [ 'Oppo', 'A57t' ],
11436
  'OPPO A59s' => [ 'Oppo', 'A59s' ],
11437
  'OPPO A59st' => [ 'Oppo', 'A59st' ],
11438
  'CPH1717' => [ 'Oppo', 'A71' ],
11439
+ 'CPH1801' => [ 'Oppo', 'A71 (2018)' ],
11440
+ 'A73' => [ 'Oppo', 'A73' ],
11441
+ 'OPPO A73' => [ 'Oppo', 'A73' ],
11442
+ 'OPPO A73t' => [ 'Oppo', 'A73t' ],
11443
  'OPPO A77' => [ 'Oppo', 'A77' ],
11444
  'OPPO A77t' => [ 'Oppo', 'A77t' ],
11445
+ 'OPPO A79' => [ 'Oppo', 'A79' ],
11446
+ 'OPPO A79kt' => [ 'Oppo', 'A79kt' ],
11447
+ 'OPPO A79t' => [ 'Oppo', 'A79t' ],
11448
+ 'OPPO A83' => [ 'Oppo', 'A83' ],
11449
+ 'CPH1729' => [ 'Oppo', 'A83' ],
11450
+ 'CPH1827' => [ 'Oppo', 'A83' ],
11451
+ 'OPPO A83t' => [ 'Oppo', 'A83t' ],
11452
  'OPPO A800' => [ 'Oppo', 'A800' ],
11453
  'A1603' => [ 'Oppo', 'C1' ],
11454
  'F1f' => [ 'Oppo', 'F1f' ],
11457
  'CPH1609' => [ 'Oppo', 'F3' ],
11458
  'CPH1613' => [ 'Oppo', 'F3 Plus' ],
11459
  'CPH1723' => [ 'Oppo', 'F5' ],
11460
+ 'CPH1727' => [ 'Oppo', 'F5' ],
11461
+ 'CPH1819' => [ 'Oppo', 'F7' ],
11462
+ 'CPH1821' => [ 'Oppo', 'F7' ],
11463
+ 'CPH1859' => [ 'Oppo', 'F7 Youth' ],
11464
+ 'CPH1881' => [ 'Oppo', 'F9' ],
11465
+ 'CPH1823' => [ 'Oppo', 'F9 Pro' ],
11466
+ 'CPH1969' => [ 'Oppo', 'F11 Pro' ],
11467
  'Find 5' => [ 'Oppo', 'Find 5' ],
11468
  'X903' => [ 'Oppo', 'Find Me X903' ],
11469
  'X903S' => [ 'Oppo', 'Find X903S' ],
11480
  'X9000' => [ 'Oppo', 'Find 7a X9000' ],
11481
  'X9006' => [ 'Oppo', 'Find 7a X9006' ],
11482
  'X9007' => [ 'Oppo', 'Find 7a X9007' ],
11483
+ 'OPPO X9007' => [ 'Oppo', 'Find 7a X9007' ],
11484
  'X9009' => [ 'Oppo', 'F1 Plus X9009' ],
11485
  'X9015' => [ 'Oppo', 'Find X9015' ],
11486
  'OPPOX9015' => [ 'Oppo', 'Find X9015' ],
11582
  'OPPOU7015' => [ 'Oppo', 'Find Way U7015' ],
11583
  'U7015' => [ 'Oppo', 'Find Way U7015' ],
11584
  'A51w' => [ 'Oppo', 'Mirror 5' ],
11585
+ 'PBCM30' => [ 'Oppo', 'K1' ],
11586
+ 'OPPO PBCM30' => [ 'Oppo', 'K1' ],
11587
+ 'OPPO PBCT10' => [ 'Oppo', 'K1' ],
11588
+ 'PCGM00' => [ 'Oppo', 'K3' ],
11589
  'OPPO N1' => [ 'Oppo', 'N1' ],
11590
  'N51(10|11|16|17)!' => [ 'Oppo', 'N1 mini' ],
11591
  'N52(06|07|09)!' => [ 'Oppo', 'N3' ],
11592
+ 'OB-OPPO R8205' => [ 'Oppo', 'R1c' ],
11593
+ 'OB-OPPO R7005' => [ 'Oppo', 'R3' ],
11594
  'OPPO R7' => [ 'Oppo', 'R7' ],
11595
+ 'OPPO R7Plus' => [ 'Oppo', 'R7 Plus' ],
11596
+ 'OB-OPPO R7c' => [ 'Oppo', 'R7c' ],
11597
  'R7f' => [ 'Oppo', 'R7f' ],
11598
  'R7i' => [ 'Oppo', 'R7i' ],
11599
  'R7kf' => [ 'Oppo', 'R7kf' ],
11602
  'OPPO R7sm' => [ 'Oppo', 'R7sm' ],
11603
  'OPPO R7st' => [ 'Oppo', 'R7st' ],
11604
  'OPPO R7t' => [ 'Oppo', 'R7t' ],
11605
+ 'R7t' => [ 'Oppo', 'R7t' ],
11606
+ 'OPPO R9k' => [ 'Oppo', 'R9k' ],
11607
  'OPPO R9m' => [ 'Oppo', 'R9m' ],
11608
  'OPPO R9tm' => [ 'Oppo', 'R9tm' ],
11609
  'OPPO R9km' => [ 'Oppo', 'R9km' ],
11610
  'OPPO R9s' => [ 'Oppo', 'R9s' ],
11611
  'OPPO R9sk' => [ 'Oppo', 'R9sk' ],
11612
  'OPPO R9st' => [ 'Oppo', 'R9st' ],
11613
+ 'OPPO R9skt' => [ 'Oppo', 'R9skt' ],
11614
  'OPPO R9t' => [ 'Oppo', 'R9t' ],
11615
  'OPPO R9tm' => [ 'Oppo', 'R9tm' ],
11616
  'OPPO R11' => [ 'Oppo', 'R11' ],
11617
+ 'CPH1721' => [ 'Oppo', 'R11s' ],
11618
  'OPPO R11t' => [ 'Oppo', 'R11t' ],
11619
  'OPPO R7 Plus' => [ 'Oppo', 'R7 Plus' ],
11620
  'R7Plus' => [ 'Oppo', 'R7 Plus' ],
11625
  'OPPO R9 Plustm A' => [ 'Oppo', 'R9 Plus' ],
11626
  'CPH1611' => [ 'Oppo', 'R9s Plus' ],
11627
  'OPPO R9s Plus' => [ 'Oppo', 'R9s Plus' ],
11628
+ 'OPPO R9s Plust' => [ 'Oppo', 'R9st Plus' ],
11629
  'OPPO R11 Plus' => [ 'Oppo', 'R11 Plus' ],
11630
+ 'OPPO R11 Plusk' => [ 'Oppo', 'R11k Plus' ],
11631
+ 'OPPO R11 Pluskt' => [ 'Oppo', 'R11kt Plus' ],
11632
+ 'OPPO R11s' => [ 'Oppo', 'R11s' ],
11633
  'OPPO R11s Plus' => [ 'Oppo', 'R11s Plus' ],
11634
+ 'OPPO R11st' => [ 'Oppo', 'R11st' ],
11635
+ 'OPPO R11s Plust' => [ 'Oppo', 'R11st Plus' ],
11636
+ 'PAAM00' => [ 'Oppo', 'R15' ],
11637
+ 'OPPO PAAM00' => [ 'Oppo', 'R15' ],
11638
+ 'PACM00' => [ 'Oppo', 'R15' ],
11639
+ 'OPPO PACM00' => [ 'Oppo', 'R15' ],
11640
+ 'PACT00' => [ 'Oppo', 'R15' ],
11641
+ 'OPPO PACT00' => [ 'Oppo', 'R15' ],
11642
+ 'PAAT00' => [ 'Oppo', 'R15 Dream Mirror' ],
11643
+ 'CPH1879' => [ 'Oppo', 'R17' ],
11644
+ 'PBEM00' => [ 'Oppo', 'R17' ],
11645
+ 'PBET00' => [ 'Oppo', 'R17' ],
11646
+ 'PBDM00' => [ 'Oppo', 'R17 Pro' ],
11647
+ 'OPPO PBDM00' => [ 'Oppo', 'R17 Pro' ],
11648
+ 'CPH1861' => [ 'Oppo', 'Realme 1' ],
11649
  'W8' => [ 'Oppo', 'W8' ],
11650
+ 'OB-OPPO 1105' => [ 'Oppo', '1105' ],
11651
  '1105' => [ 'Oppo', '1105' ],
11652
  '1107' => [ 'Oppo', '1107' ],
11653
  'OB-OPPO 3005' => [ 'Oppo', '3005' ],
11654
+ '3007' => [ 'Oppo', '3007' ],
11655
+ '6607' => [ 'Oppo', 'U3' ],
11656
+ 'PAFM00' => [ 'Oppo', 'Find X' ],
11657
+ 'OPPO PAFM00' => [ 'Oppo', 'Find X' ],
11658
+ 'PAHM00' => [ 'Oppo', 'Find X' ],
11659
+ 'PCAM00' => [ 'Oppo', 'Reno' ],
11660
+ 'PCAM10' => [ 'Oppo', 'Reno Lite' ],
11661
+ 'PCCM00' => [ 'Oppo', 'Reno 10x Zoom' ],
11662
+ 'CPH1979' => [ 'Oppo', 'Reno Z' ],
11663
 
11664
  'OPSSON!!' => [
11665
  'OPSSON D1' => [ 'Opsson', 'D1' ],
11830
  'FZ-A2A' => [ 'Panasonic', 'Toughpad FZ-A2', DeviceType::TABLET ],
11831
  'FZ-B2(B|D)!' => [ 'Panasonic', 'Toughpad FZ-B1', DeviceType::TABLET ],
11832
  'FZ-N1' => [ 'Panasonic', 'Toughpad FZ-N1' ],
11833
+ 'FZ-T1' => [ 'Panasonic', 'Toughbook FZ-T1' ],
11834
  'FZ-X1' => [ 'Panasonic', 'Toughpad FZ-X1' ],
11835
 
11836
  'Altus 18' => [ 'Panasonic', 'Altus 18', DeviceType::INFLIGHT ],
13255
  'SMT-i9100' => [ 'Samsung', 'Galaxy Tab 7.0', DeviceType::TABLET ],
13256
 
13257
  'SM-A[0-9]{3,3}!!' => [
13258
+ 'SM-A015!' => [ 'Samsung', 'Galaxy A01' ],
13259
+ 'SM-A102!' => [ 'Samsung', 'Galaxy A10e' ],
13260
+ 'SM-A105!' => [ 'Samsung', 'Galaxy A10' ],
13261
+ 'SM-A115!' => [ 'Samsung', 'Galaxy A11' ],
13262
+ 'SM-A107!' => [ 'Samsung', 'Galaxy A10s' ],
13263
+ 'SM-A202!' => [ 'Samsung', 'Galaxy A20e' ],
13264
+ 'SM-A205!' => [ 'Samsung', 'Galaxy A20' ],
13265
+ 'SM-A215!' => [ 'Samsung', 'Galaxy A21' ],
13266
+ 'SM-A260!' => [ 'Samsung', 'Galaxy A2 Core' ],
13267
  'SM-A300!' => [ 'Samsung', 'Galaxy A3' ],
13268
+ 'SM-A305!' => [ 'Samsung', 'Galaxy A30' ],
13269
+ 'SM-A307!' => [ 'Samsung', 'Galaxy A30s' ],
13270
  'SM-A310!' => [ 'Samsung', 'Galaxy A3 (2016)' ],
13271
  'SM-A320!' => [ 'Samsung', 'Galaxy A3 (2017)' ],
13272
+ 'SM-A405!' => [ 'Samsung', 'Galaxy A40' ],
13273
  'SM-A430!' => [ 'Samsung', 'Galaxy A4' ],
13274
  'SM-A450!' => [ 'Samsung', 'Galaxy A4 (2017)' ],
13275
+ 'SM-A460!' => [ 'Samsung', 'SM-A460' ],
13276
  'SM-A500!' => [ 'Samsung', 'Galaxy A5' ],
13277
+ 'SM-A505!' => [ 'Samsung', 'Galaxy A50' ],
13278
+ 'SM-A507!' => [ 'Samsung', 'Galaxy A50s' ],
13279
  'SM-A510!' => [ 'Samsung', 'Galaxy A5 (2016)' ],
13280
+ 'SM-A515!' => [ 'Samsung', 'Galaxy A51' ],
13281
+ 'SM-A516!' => [ 'Samsung', 'Galaxy A51 5G' ],
13282
  'SM-A520!' => [ 'Samsung', 'Galaxy A5 (2017)' ],
13283
  'SM-A530!' => [ 'Samsung', 'Galaxy A8 (2018)' ],
13284
+ 'SM-A600!' => [ 'Samsung', 'Galaxy A6 (2018)' ],
13285
+ 'SM-A6050!' => [ 'Samsung', 'Galaxy A9 Star Lite' ],
13286
+ 'SM-A605!' => [ 'Samsung', 'Galaxy A6+ (2018)' ],
13287
+ 'SM-A606!' => [ 'Samsung', 'Galaxy A60' ],
13288
  'SM-A700!' => [ 'Samsung', 'Galaxy A7' ],
13289
+ 'SM-A705!' => [ 'Samsung', 'Galaxy A70' ],
13290
  'SM-A710!' => [ 'Samsung', 'Galaxy A7 (2016)' ],
13291
+ 'SM-A716!' => [ 'Samsung', 'Galaxy A71 5G' ],
13292
  'SM-A720!' => [ 'Samsung', 'Galaxy A7 (2017)' ],
13293
  'SM-A730!' => [ 'Samsung', 'Galaxy A8+ (2018)' ],
13294
+ 'SM-A750!' => [ 'Samsung', 'Galaxy A7 (2018)' ],
13295
  'SM-A800!' => [ 'Samsung', 'Galaxy A8' ],
13296
+ 'SM-A805!' => [ 'Samsung', 'Galaxy A80' ],
13297
  'SM-A810!' => [ 'Samsung', 'Galaxy A8 (2016)' ],
13298
  'SM-A850!' => [ 'Samsung', 'Galaxy Alpha' ],
13299
  'SM-A900!' => [ 'Samsung', 'Galaxy A9 (2016)' ],
13300
  'SM-A910!' => [ 'Samsung', 'Galaxy A9 Pro' ],
13301
+ 'SM-A920!' => [ 'Samsung', 'Galaxy A9 (2018)' ],
13302
  ],
13303
 
13304
  'SM-C[0-9]{3,3}!!' => [
13317
  'SM-E700!' => [ 'Samsung', 'Galaxy E7' ],
13318
  ],
13319
 
13320
+ 'SM-F[0-9]{3,3}!!' => [
13321
+ 'SM-F700!' => [ 'Samsung', 'Galaxy Z Flip' ],
13322
+ 'SM-F707!' => [ 'Samsung', 'Galaxy Z Flip 5G' ],
13323
+ 'SM-F900!' => [ 'Samsung', 'Galaxy Fold' ],
13324
+ 'SM-F910!' => [ 'Samsung', 'Galaxy Z Fold2' ],
13325
+ 'SM-F916!' => [ 'Samsung', 'Galaxy Z Fold2 5G' ],
13326
+ ],
13327
+
13328
  'SM-G[0-9]{3,3}!!' => [
13329
  'SM-G110!' => [ 'Samsung', 'Galaxy Pocket 2' ],
13330
  'SM-G130BT' => [ 'Samsung', 'Galaxy Young 2' ],
13335
  'SM-G130HN' => [ 'Samsung', 'Galaxy Young 2 Duos' ],
13336
  'SM-G130M' => [ 'Samsung', 'Galaxy Young 2 Duos' ],
13337
  'SM-G1(50|55)!' => [ 'Samsung', 'Galaxy Folder' ],
13338
+ 'SM-G1(60|65)!' => [ 'Samsung', 'Galaxy Folder 2' ],
13339
  'SM-G310H' => [ 'Samsung', 'Galaxy Ace 4' ],
13340
  'SM-G310HN' => [ 'Samsung', 'Galaxy Ace Style' ],
13341
  'SM-G310R5' => [ 'Samsung', 'GreatCall Touch 3' ],
13378
  'SM-G570!' => [ 'Samsung', 'Galaxy J5 Prime' ],
13379
  'SM-G600!' => [ 'Samsung', 'Galaxy On7' ],
13380
  'SM-G610!' => [ 'Samsung', 'Galaxy J7 Prime' ],
13381
+ 'SM-G611!' => [ 'Samsung', 'Galaxy On7 Prime (2018)' ],
13382
  'SM-G615!' => [ 'Samsung', 'Galaxy J7 Max' ],
13383
+ 'SM-G620!' => [ 'Samsung', 'Galaxy J7 Prime (2018)' ],
13384
  'SM-G710!' => [ 'Samsung', 'Galaxy Grand 2' ],
13385
+ 'SM-G715!' => [ 'Samsung', 'Galaxy XCover Pro' ],
13386
  'SM-G720!' => [ 'Samsung', 'Galaxy Grand 3' ],
13387
  'SM-G730!' => [ 'Samsung', 'Galaxy S III Mini' ],
13388
  'SM-G750!' => [ 'Samsung', 'Galaxy Mega 2 ' ],
13389
+ 'SM-G770!' => [ 'Samsung', 'Galaxy S10 Lite' ],
13390
  'SM-G800!' => [ 'Samsung', 'Galaxy S5 Mini' ],
13391
  'SM-G850!' => [ 'Samsung', 'Galaxy Alpha' ],
13392
  'SM-G860!' => [ 'Samsung', 'Galaxy S5 Sport' ],
13393
  'SM-G870!' => [ 'Samsung', 'Galaxy S5 Active' ],
13394
+ 'SM-G875!' => [ 'Samsung', 'Galaxy S Lite Luxury' ],
13395
  'SM-G880!' => [ 'Samsung', 'Galaxy S7 mini' ],
13396
+ 'SM-G885[FSY]!' => [ 'Samsung', 'Galaxy A8 Star' ],
13397
+ 'SM-G8850!' => [ 'Samsung', 'Galaxy A9 Star' ],
13398
+ 'SM-G887!' => [ 'Samsung', 'Galaxy A9 Pro (2019)' ],
13399
  'SM-G890!' => [ 'Samsung', 'Galaxy S6 Active' ],
13400
  'SM-G891!' => [ 'Samsung', 'Galaxy S7 Active' ],
13401
  'SM-G892!' => [ 'Samsung', 'Galaxy S8 Active' ],
13409
  'SM-G920!' => [ 'Samsung', 'Galaxy S6' ],
13410
  'SM-G925!' => [ 'Samsung', 'Galaxy S6 Edge' ],
13411
  'SM-G928!' => [ 'Samsung', 'Galaxy S6 Edge+' ],
13412
+ 'SM-G929!' => [ 'Samsung', '"Project Valley"' ],
13413
  'SM-G930!' => [ 'Samsung', 'Galaxy S7' ],
13414
  'SM-G935!' => [ 'Samsung', 'Galaxy S7 Edge' ],
13415
  'SM-G950!' => [ 'Samsung', 'Galaxy S8' ],
13416
  'SM-G955!' => [ 'Samsung', 'Galaxy S8+' ],
13417
  'SM-G960!' => [ 'Samsung', 'Galaxy S9' ],
13418
  'SM-G965!' => [ 'Samsung', 'Galaxy S9+' ],
13419
+ 'SM-G970!' => [ 'Samsung', 'Galaxy S10e' ],
13420
+ 'SM-G973!' => [ 'Samsung', 'Galaxy S10' ],
13421
+ 'SM-G975!' => [ 'Samsung', 'Galaxy S10+' ],
13422
+ 'SM-G977!' => [ 'Samsung', 'Galaxy S10 5G' ],
13423
+ 'SM-G980!' => [ 'Samsung', 'Galaxy S20' ],
13424
+ 'SM-G981!' => [ 'Samsung', 'Galaxy S20' ],
13425
+ 'SM-G985!' => [ 'Samsung', 'Galaxy S20+' ],
13426
+ 'SM-G986!' => [ 'Samsung', 'Galaxy S20+' ],
13427
+ 'SM-G988!' => [ 'Samsung', 'Galaxy S20 Ultra' ],
13428
  ],
13429
 
13430
  'SM-I9500' => [ 'Samsung', 'Galaxy S4' ],
13438
  'SM-J200!' => [ 'Samsung', 'Galaxy J2' ],
13439
  'SM-J210!' => [ 'Samsung', 'Galaxy J2 (2016)' ],
13440
  'SM-J250!' => [ 'Samsung', 'Galaxy J2 (2018)' ],
13441
+ 'SM-J260!' => [ 'Samsung', 'Galaxy J2 Pure' ],
13442
  'SM-J3(10|20)!' => [ 'Samsung', 'Galaxy J3' ],
13443
  'SM-J311!' => [ 'Samsung', 'Galaxy J3 (2016)' ],
13444
  'SM-J321!' => [ 'Samsung', 'Galaxy Sol' ],
13445
  'SM-J326!' => [ 'Samsung', 'Galaxy Sol 2' ],
13446
  'SM-J327!' => [ 'Samsung', 'Galaxy J3 Emerge' ],
13447
  'SM-J330!' => [ 'Samsung', 'Galaxy J3 (2017)' ],
13448
+ 'SM-J337!' => [ 'Samsung', 'Galaxy J3 (2018)' ],
13449
+ 'SM-J400!' => [ 'Samsung', 'Galaxy J4' ],
13450
+ 'SM-J410!' => [ 'Samsung', 'Galaxy J4 Core' ],
13451
+ 'SM-J415!' => [ 'Samsung', 'Galaxy J4+' ],
13452
  'SM-J500!' => [ 'Samsung', 'Galaxy J5' ],
13453
  'SM-J510!' => [ 'Samsung', 'Galaxy J5 (2016)' ],
13454
  'SM-J530!' => [ 'Samsung', 'Galaxy J5 (2017)' ],
13455
+ 'SM-J600!' => [ 'Samsung', 'Galaxy J6' ],
13456
+ 'SM-J610!' => [ 'Samsung', 'Galaxy J6+' ],
13457
  'SM-J700!' => [ 'Samsung', 'Galaxy J7' ],
13458
  'SM-J701!' => [ 'Samsung', 'Galaxy J7 Core' ],
13459
  'SM-J710!' => [ 'Samsung', 'Galaxy J7 (2016)' ],
13460
+ 'SM-J720!' => [ 'Samsung', 'Galaxy J7 Duo' ],
13461
  'SM-J727!' => [ 'Samsung', 'Galaxy J7 Perx' ],
13462
  'SM-J730!' => [ 'Samsung', 'Galaxy J7 (2017)' ],
13463
+ 'SM-J737!' => [ 'Samsung', 'Galaxy Wide 3' ],
13464
  'SM-J800!' => [ 'Samsung', 'Galaxy J8' ],
13465
+ 'SM-J810!' => [ 'Samsung', 'Galaxy J8 (2018)' ],
13466
  'SM-J900!' => [ 'Samsung', 'Galaxy J9' ],
13467
  ],
13468
 
13469
+ 'SM-M[0-9]{3,4}!!' => [
13470
+ 'SM-M105!' => [ 'Samsung', 'Galaxy M10' ],
13471
+ 'SM-M205!' => [ 'Samsung', 'Galaxy M20' ],
13472
+ 'SM-M305!' => [ 'Samsung', 'Galaxy M30' ],
13473
+ ],
13474
+
13475
  'SM-N[0-9]{3,4}!!' => [
13476
  'SM-N750[025789][QV]?!' => [ 'Samsung', 'Galaxy Note 3 Neo' ],
13477
  'SM-N750[LS]?!' => [ 'Samsung', 'Galaxy Note 3 Neo' ],
13484
  'SM-N920!' => [ 'Samsung', 'Galaxy Note 5' ],
13485
  'SM-N930!' => [ 'Samsung', 'Galaxy Note 7' ],
13486
  'SM-N935!' => [ 'Samsung', 'Galaxy Note FE' ],
13487
+ 'SM-N95[05]!' => [ 'Samsung', 'Galaxy Note 8' ],
13488
+ 'SM-N960!' => [ 'Samsung', 'Galaxy Note 9' ],
13489
+ 'SM-N970!' => [ 'Samsung', 'Galaxy Note 10' ],
13490
+ 'SM-N975!' => [ 'Samsung', 'Galaxy Note 10+' ],
13491
+ 'SM-N976!' => [ 'Samsung', 'Galaxy Note 10+ 5G' ],
13492
+ 'SM-N981!' => [ 'Samsung', 'Galaxy Note 20 5G' ],
13493
+ 'SM-N986!' => [ 'Samsung', 'Galaxy Note 20 Ultra 5G' ],
13494
  ],
13495
 
13496
  'SM-P[0-9]{3,3}!!' => [
13498
  'SM-P55[015]!' => [ 'Samsung', 'Galaxy Tab A Plus 9.7', DeviceType::TABLET ],
13499
  'SM-P58[058]!' => [ 'Samsung', 'Galaxy Tab A 10.1 with S Pen (2016)', DeviceType::TABLET ],
13500
  'SM-P60[01257]!' => [ 'Samsung', 'Galaxy Note 10.1 (2014)', DeviceType::TABLET ],
13501
+ 'SM-P61[0]!' => [ 'Samsung', 'Galaxy Tab S6 Lite', DeviceType::TABLET ],
13502
  'SM-P90[01257]!' => [ 'Samsung', 'Galaxy Note Pro', DeviceType::TABLET ],
13503
  ],
13504
 
13507
  'SM-S320VL' => [ 'Samsung', 'Galaxy Sky' ],
13508
  'SM-S327VL' => [ 'Samsung', 'Galaxy J3 Luna Pro' ],
13509
  'SM-S337TL' => [ 'Samsung', 'Galaxy J3 Luna Pro' ],
13510
+ 'SM-S367VL' => [ 'Samsung', 'Galaxy J3 Orbit' ],
13511
  'SM-S550TL' => [ 'Samsung', 'Galaxy On5' ],
13512
  'SM-S727VL' => [ 'Samsung', 'Galaxy J7 Sky Pro' ],
13513
  'SM-S737TL' => [ 'Samsung', 'Galaxy J7 Sky Pro' ],
13514
+ 'SM-S757BL' => [ 'Samsung', 'Galaxy J7 Top' ],
13515
  'SM-S765C' => [ 'Samsung', 'Galaxy Ace Style' ],
13516
  'SM-S766C' => [ 'Samsung', 'Galaxy Stardust' ],
13517
+ 'SM-S767VL' => [ 'Samsung', 'Galaxy J7 Crown' ],
13518
  'SM-S777C' => [ 'Samsung', 'Galaxy J1' ],
13519
  'SM-S780L' => [ 'Samsung', 'Galaxy Mega 6.3' ],
13520
  'SM-S820L' => [ 'Samsung', 'Galaxy Core Prime' ],
13537
  'SM-T255[68S]!' => [ 'Samsung', 'Galaxy Tab Q' ],
13538
  'SM-T23[012579]!' => [ 'Samsung', 'Galaxy Tab 4 7.0', DeviceType::TABLET ],
13539
  'SM-T28[057]!' => [ 'Samsung', 'Galaxy Tab A 7.0', DeviceType::TABLET ],
13540
+ 'SM-T29[0]!' => [ 'Samsung', 'Galaxy Tab A 8.0 (2019)', DeviceType::TABLET ],
13541
+ 'SM-T30[7]!' => [ 'Samsung', 'Galaxy Tab A 8.4 (2020)', DeviceType::TABLET ],
13542
  'SM-T31[0125]!' => [ 'Samsung', 'Galaxy Tab 3 8.0', DeviceType::TABLET ],
13543
  'SM-T32[0125]!' => [ 'Samsung', 'Galaxy Tab Pro 8.4', DeviceType::TABLET ],
13544
  'SM-T33[01257]!' => [ 'Samsung', 'Galaxy Tab 4 8.0', DeviceType::TABLET ],
13547
  'SM-T36[05]!' => [ 'Samsung', 'Galaxy Tab Active 8.0', DeviceType::TABLET ],
13548
  'SM-T37[578]!' => [ 'Samsung', 'Galaxy Tab E 8.0', DeviceType::TABLET ],
13549
  'SM-T38[05]!' => [ 'Samsung', 'Galaxy Tab A 8.0 (2017)', DeviceType::TABLET ],
13550
+ 'SM-T387!' => [ 'Samsung', 'Galaxy Tab A 8.0 (2018)', DeviceType::TABLET ],
13551
+ 'SM-T39[05]!' => [ 'Samsung', 'Galaxy Tab Active2 8.0', DeviceType::TABLET ],
13552
+ 'SM-T51[05]!' => [ 'Samsung', 'Galaxy Tab A 10.1 (2019)', DeviceType::TABLET ],
13553
  'SM-T520CC' => [ 'Samsung', 'Galaxy Tab Pro 10.1 Chef Collection', DeviceType::TABLET ],
13554
  'SM-T52[057]!' => [ 'Samsung', 'Galaxy Tab Pro 10.1', DeviceType::TABLET ],
13555
  'SM-T530NU' => [ 'Samsung', 'Galaxy Tab 4 Nook 10.1', DeviceType::TABLET ],
13558
  'SM-T53[157]!' => [ 'Samsung', 'Galaxy Tab 4 10.0', DeviceType::TABLET ],
13559
  'SM-T55[015]!' => [ 'Samsung', 'Galaxy Tab A 9.7', DeviceType::TABLET ],
13560
  'SM-T58[057]!' => [ 'Samsung', 'Galaxy Tab A 10.1 (2016)', DeviceType::TABLET ],
13561
+ 'SM-T583!' => [ 'Samsung', 'Galaxy Tab Advanced2', DeviceType::TABLET ],
13562
  'SM-T56[0127]!' => [ 'Samsung', 'Galaxy Tab E 9.6', DeviceType::TABLET ],
13563
+ 'SM-T59[057]!' => [ 'Samsung', 'Galaxy Tab A 10.5', DeviceType::TABLET ],
13564
  'SM-T67[07]!' => [ 'Samsung', 'Galaxy View', DeviceType::TABLET ],
13565
  'SM-T70[057]!' => [ 'Samsung', 'Galaxy Tab S 8.4', DeviceType::TABLET ],
13566
  'SM-T71[05]!' => [ 'Samsung', 'Galaxy Tab S2 8.0', DeviceType::TABLET ],
13567
  'SM-T71[39]!' => [ 'Samsung', 'Galaxy Tab S2 8.0 (2016)', DeviceType::TABLET ],
13568
+ 'SM-T72[057]!' => [ 'Samsung', 'Galaxy Tab S5e', DeviceType::TABLET ],
13569
  'SM-T80[0157]!' => [ 'Samsung', 'Galaxy Tab S 10.5', DeviceType::TABLET ],
13570
  'SM-T81[057]!' => [ 'Samsung', 'Galaxy Tab S2 9.7', DeviceType::TABLET ],
13571
  'SM-T81[39]!' => [ 'Samsung', 'Galaxy Tab S2 9.7 (2016)', DeviceType::TABLET ],
13572
  'SM-T81[8]!' => [ 'Samsung', 'Galaxy Tab S2 Plus 9.7', DeviceType::TABLET ],
13573
  'SM-T82[057]!' => [ 'Samsung', 'Galaxy Tab S3 9.7', DeviceType::TABLET ],
13574
+ 'SM-T83[057]!' => [ 'Samsung', 'Galaxy Tab S4 10.5', DeviceType::TABLET ],
13575
+ 'SM-T86[057]!' => [ 'Samsung', 'Galaxy Tab S6 10.5', DeviceType::TABLET ],
13576
+ 'SM-T87[0]!' => [ 'Samsung', 'Galaxy Tab S7 11.0', DeviceType::TABLET ],
13577
  'SM-T90[05]!' => [ 'Samsung', 'Galaxy Tab Pro 12.2', DeviceType::TABLET ],
13578
+ 'SM-T92[7]!' => [ 'Samsung', 'Galaxy View2 (2019)', DeviceType::TABLET ],
13579
+ 'SM-T97[0]!' => [ 'Samsung', 'Galaxy Tab S7+ 12.4', DeviceType::TABLET ],
13580
  ],
13581
 
13582
  'SM-V700' => [ 'Samsung', 'Galaxy Gear', DeviceType::WATCH ],
13718
  'SC-01G' => [ 'Samsung', 'GALAXY Note Edge SC-01G', 'carrier' => 'DoCoMo' ],
13719
  'SC-01H' => [ 'Samsung', 'GALAXY Active neo SC-01H', 'carrier' => 'DoCoMo' ],
13720
  'SC-01K' => [ 'Samsung', 'GALAXY Note 8 SC-01K', 'carrier' => 'DoCoMo' ],
13721
+ 'SC-01L' => [ 'Samsung', 'GALAXY Note9 SC-01L', 'carrier' => 'DoCoMo' ],
13722
+ 'SC-01M' => [ 'Samsung', 'GALAXY Note10+ SC-01M', 'carrier' => 'DoCoMo' ],
13723
  'SC-02B' => [ 'Samsung', 'GALAXY S SC-02B', 'carrier' => 'DoCoMo' ],
13724
  'SC-02C' => [ 'Samsung', 'GALAXY S II SC-02C', 'carrier' => 'DoCoMo' ],
13725
  'SC-02D' => [ 'Samsung', 'GALAXY Tab 7.0 Plus SC-02D', DeviceType::TABLET, 'carrier' => 'DoCoMo' ],
13728
  'SC-02G' => [ 'Samsung', 'GALAXY S5 Active SC-02G', 'carrier' => 'DoCoMo' ],
13729
  'SC-02H' => [ 'Samsung', 'Galaxy S7 Edge SC-02H', 'carrier' => 'DoCoMo' ],
13730
  'SC-02J' => [ 'Samsung', 'Galaxy S8 SC-02J', 'carrier' => 'DoCoMo' ],
13731
+ 'SC-02K' => [ 'Samsung', 'Galaxy S9 SC-02K', 'carrier' => 'DoCoMo' ],
13732
+ 'SC-02L' => [ 'Samsung', 'Galaxy Feel2 SC-02L', 'carrier' => 'DoCoMo' ],
13733
  'SC-03D' => [ 'Samsung', 'GALAXY S II LTE SC-03D', 'carrier' => 'DoCoMo' ],
13734
  'SC-03E' => [ 'Samsung', 'GALAXY S III α SC-03E', 'carrier' => 'DoCoMo' ],
13735
  'SC03E' => [ 'Samsung', 'GALAXY S III α SC-03E', 'carrier' => 'DoCoMo' ],
13736
  'SC-03G' => [ 'Samsung', 'GALAXY Tab S 8.4 SC-03G', DeviceType::TABLET, 'carrier' => 'DoCoMo' ],
13737
  'SC-03J' => [ 'Samsung', 'GALAXY S8+ SC-03J', 'carrier' => 'DoCoMo' ],
13738
+ 'SC-03K' => [ 'Samsung', 'GALAXY S9+ SC-03K', 'carrier' => 'DoCoMo' ],
13739
+ 'SC-03L' => [ 'Samsung', 'Galaxy S10 SC-03L', 'carrier' => 'DoCoMo' ],
13740
  'SC-04D' => [ 'Samsung', 'GALAXY NEXUS SC-04D', 'carrier' => 'DoCoMo' ],
13741
  'SC-04E' => [ 'Samsung', 'GALAXY S4 SC-04E', 'carrier' => 'DoCoMo' ],
13742
  'SC-04F' => [ 'Samsung', 'GALAXY S5 SC-04F', 'carrier' => 'DoCoMo' ],
13743
  'SC-04G' => [ 'Samsung', 'GALAXY S6 Edge SC-04G', 'carrier' => 'DoCoMo' ],
13744
  'SC-04J' => [ 'Samsung', 'GALAXY Feel SC-04J', 'carrier' => 'DoCoMo' ],
13745
+ 'SC-04L' => [ 'Samsung', 'Galaxy S10+ SC-04L', 'carrier' => 'DoCoMo' ],
13746
  'SC-05D' => [ 'Samsung', 'GALAXY Note SC-05D', 'carrier' => 'DoCoMo' ],
13747
  'SC-05G' => [ 'Samsung', 'GALAXY S6 SC-05G', 'carrier' => 'DoCoMo' ],
13748
  'SC-06D' => [ 'Samsung', 'GALAXY S III SC-06D', 'carrier' => 'DoCoMo' ],
13757
  'SCV31' => [ 'Samsung', 'GALAXY S6 Edge SCV31', 'carrier' => 'au' ],
13758
  'SCV32' => [ 'Samsung', 'GALAXY A8 SCV32', 'carrier' => 'au' ],
13759
  'SCV33' => [ 'Samsung', 'GALAXY S7 edge Injustice Edition SCV33', 'carrier' => 'au' ],
13760
+ 'SCV34' => [ 'Samsung', 'GALAXY Note7 SCV34', 'carrier' => 'au' ],
13761
  'SCV35' => [ 'Samsung', 'GALAXY S8+ SCV35', 'carrier' => 'au' ],
13762
  'SCV36' => [ 'Samsung', 'GALAXY S8 SCV36', 'carrier' => 'au' ],
13763
  'SCV37' => [ 'Samsung', 'GALAXY Note8 SCV37', 'carrier' => 'au' ],
13764
+ 'SCV38' => [ 'Samsung', 'Galaxy S9 SCV38', 'carrier' => 'au' ],
13765
+ 'SCV39' => [ 'Samsung', 'Galaxy S9+ SCV39', 'carrier' => 'au' ],
13766
+ 'SCV40' => [ 'Samsung', 'Galaxy Note9 SCV40', 'carrier' => 'au' ],
13767
+ 'SCV41' => [ 'Samsung', 'Galaxy S10 SCV41', 'carrier' => 'au' ],
13768
  ],
13769
 
13770
  'ISW11SC' => [ 'Samsung', 'GALAXY S II WiMAX ISW11SC', 'carrier' => 'au' ],
13838
  'SFR StarTab' => [ 'SFR', 'STARTAB', DeviceType::TABLET ],
13839
  'Bambook S1' => [ 'Shanda', 'Bambook S1', DeviceType::TABLET ],
13840
 
13841
+ '[4567A]0[0-9]SH!!' => [
13842
  '401SH' => [ 'Sharp', '401SH', 'carrier' => 'Softbank' ],
13843
  '402SH' => [ 'Sharp', 'AQUOS CRYSTAL X 402SH', 'carrier' => 'Softbank' ],
13844
  '403SH' => [ 'Sharp', 'AQUOS CRYSTAL 2 403SH', 'carrier' => 'Softbank' ],
13900
  'SBM306SH' => [ 'Sharp', 'AQUOS CRYSTAL 306SH' ], // The U.S. Sprint version (now part of Softbank)
13901
  ],
13902
 
13903
+ '(3|5|6|7)0[0-9]SH!!' => [
13904
  '304SH' => [ 'Sharp', 'AQUOS Xx 304SH', 'carrier' => 'Softbank' ],
13905
  '305SH' => [ 'Sharp', 'AQUOS CRYSTAL 305SH', 'carrier' => 'Softbank' ],
13906
  '306SH' => [ 'Sharp', 'AQUOS CRYSTAL 306SH' ], // The U.S. Sprint version (now part of Softbank)
13908
  '507SH' => [ 'Sharp', 'Android One 507SH', 'carrier' => 'Y! Mobile' ],
13909
  '509SH' => [ 'Sharp', 'シンプルスマホ3 509SH', 'carrier' => 'Softbank' ],
13910
  '605SH' => [ 'Sharp', 'AQUOS R 605SH', 'carrier' => 'Softbank' ],
13911
+ '606SH' => [ 'Sharp', 'AQUOS ea 606SH', 'carrier' => 'Softbank' ],
13912
+ '706SH' => [ 'Sharp', 'AQUOS R2 706SH', 'carrier' => 'Softbank' ],
13913
  ],
13914
 
13915
  'SH01D' => [ 'Sharp', 'AQUOS PHONE SH-01D', 'carrier' => 'DoCoMo' ],
13920
  'SH-M02' => [ 'Sharp', 'AQUOS SH-M02' ],
13921
  'SH-M02-EVA20' => [ 'Sharp', 'AQUOS SH-M02' ],
13922
  'SH-M03' => [ 'Sharp', 'AQUOS mini SH-M03' ],
13923
+ 'SH-M07' => [ 'Sharp', 'AQUOS sense plus SH-M07' ],
13924
  'SH-RM02' => [ 'Sharp', 'AQUOS SH-RM02' ],
13925
 
13926
  'SH-[01][0-9][A-Z]!!' => [
13931
  'SH-01FDQ' => [ 'Sharp', 'SH-01F DRAGON QUEST', 'carrier' => 'DoCoMo' ],
13932
  'SH-01G' => [ 'Sharp', 'AQUOS PHONE ZETA SH-01G', 'carrier' => 'DoCoMo' ],
13933
  'SH-01H' => [ 'Sharp', 'AQUOS PHONE ZETA SH-01H', 'carrier' => 'DoCoMo' ],
13934
+ 'SH-01J' => [ 'Sharp', 'AQUOS ケータイ SH-01J', 'carrier' => 'DoCoMo' ],
13935
+ 'SH-01K' => [ 'Sharp', 'AQUOS sense SH-01K', 'carrier' => 'DoCoMo' ],
13936
+ 'SH-01L' => [ 'Sharp', 'AQUOS sense2 SH-01L', 'carrier' => 'DoCoMo' ],
13937
  'SH-02D' => [ 'Sharp', 'AQUOS PHONE slider SH-02D', 'carrier' => 'DoCoMo' ],
13938
  'SH-02E' => [ 'Sharp', 'AQUOS PHONE ZETA SH-02E', 'carrier' => 'DoCoMo' ],
13939
  'SH-02F' => [ 'Sharp', 'AQUOS PHONE EX SH-02F', 'carrier' => 'DoCoMo' ],
13945
  'SH-03G' => [ 'Sharp', 'AQUOS ZETA SH-03G', 'carrier' => 'DoCoMo' ],
13946
  'SH-03H' => [ 'Sharp', 'SH-03H', 'carrier' => 'DoCoMo' ],
13947
  'SH-03J' => [ 'Sharp', 'AQUOS R SH-03J', 'carrier' => 'DoCoMo' ],
13948
+ 'SH-03K' => [ 'Sharp', 'AQUOS R2 SH-03K', 'carrier' => 'DoCoMo' ],
13949
  'SH-04D' => [ 'Sharp', 'Q-pot.Phone SH-04D', 'carrier' => 'DoCoMo' ],
13950
  'SH-04E' => [ 'Sharp', 'AQUOS PHONE EX SH-04E', 'carrier' => 'DoCoMo' ],
13951
  'SH-04F' => [ 'Sharp', 'AQUOS ZETA SH-04F', 'carrier' => 'DoCoMo' ],
14022
  'SHV35' => [ 'Sharp', 'AQUOS U SHV35', 'carrier' => 'au' ],
14023
  'SHV36' => [ 'Sharp', 'BASIO2 SHV36', 'carrier' => 'au' ],
14024
  'SHV37' => [ 'Sharp', 'AQUOS U SHV37', 'carrier' => 'au' ],
14025
+ 'SHV37 u' => [ 'Sharp', 'AQUOS L SHV37', 'carrier' => 'UQ mobile' ],
14026
  'SHV38' => [ 'Sharp', 'AQUOS SERIE mini SHV38', 'carrier' => 'au' ],
14027
  'SHV39' => [ 'Sharp', 'AQUOS R SHV39', 'carrier' => 'au' ],
14028
+ 'SHV40' => [ 'Sharp', 'AQUOS sense SHV40', 'carrier' => 'au' ],
14029
+ 'SHV40 u' => [ 'Sharp', 'AQUOS sense SHV40', 'carrier' => 'UQ mobile' ],
14030
  'SHV41' => [ 'Sharp', 'AQUOS R compact SHV41', 'carrier' => 'au' ],
14031
+ 'SHV42' => [ 'Sharp', 'AQUOS R2 SHV42', 'carrier' => 'au' ],
14032
  ],
14033
  'WX04SH' => [ 'Sharp', 'AQUOS PHONE es WX04SH', 'carrier' => 'Willcom' ],
14034
  'WX05SH' => [ 'Sharp', 'AQUOS PHONE ef WX05SH', 'carrier' => 'Willcom' ],
14268
  ],
14269
 
14270
  'G[0-9]{4,4}!!' => [
14271
+ 'G31(12|13|16|21|23|25)!' => [ 'Sony', 'Xperia XA1' ],
14272
  'G32(12|21|23|26)!' => [ 'Sony', 'Xperia XA1 Ultra' ],
14273
  'G33(11|12|13)!' => [ 'Sony', 'Xperia L1' ],
14274
  'G34(12|16|21|23|26)!' => [ 'Sony', 'Xperia XA1 Plus' ],
14279
  ],
14280
 
14281
  'H[0-9]{4,4}!!' => [
14282
+ 'H31(13|23)!' => [ 'Sony', 'Xperia XA2 Ultra' ],
14283
+ 'H32(13|23)!' => [ 'Sony', 'Xperia XA2 Ultra' ],
14284
+ 'H33(11|21)!' => [ 'Sony', 'Xperia L2' ],
14285
+ 'H41(13|33)!' => [ 'Sony', 'Xperia XA2' ],
14286
+ 'H42(13|33)!' => [ 'Sony', 'Xperia XA2 Ultra' ],
14287
+ 'H43(11|31)!' => [ 'Sony', 'Xperia L2' ],
14288
+ 'H44(13|93)!' => [ 'Sony', 'Xperia XA2 Plus' ],
14289
+ 'H81(16|66)!' => [ 'Sony', 'Xperia XZ2 Premium' ],
14290
+ 'H82(16|66|76|96)!' => [ 'Sony', 'Xperia XZ2' ],
14291
+ 'H83(14|24)!' => [ 'Sony', 'Xperia XZ2 Compact' ],
14292
+ 'H84(16)!' => [ 'Sony', 'Xperia XZ3' ],
14293
+ 'H84(41)!' => [ 'Sony', 'Xperia XZ1 Compact' ],
14294
+ ],
14295
+
14296
+ 'I[0-9]{4,4}!!' => [
14297
+ 'I31(13|23)!' => [ 'Sony', 'Xperia 10' ],
14298
+ 'I32(13|23)!' => [ 'Sony', 'Xperia 10 Plus' ],
14299
+ 'I41(13|93)!' => [ 'Sony', 'Xperia 10' ],
14300
+ 'I42(13|93)!' => [ 'Sony', 'Xperia 10 Plus' ],
14301
  ],
14302
 
14303
  'E[0-9]{2,2}[a-z]!!' => [
14404
  'SO-01H' => [ 'Sony', 'Xperia Z5 SO-01H', 'carrier' => 'DoCoMo' ], // ...
14405
  'SO-01J' => [ 'Sony', 'Xperia XZ SO-01J', 'carrier' => 'DoCoMo' ], // ...
14406
  'SO-01K' => [ 'Sony', 'Xperia XZ1 SO-01K', 'carrier' => 'DoCoMo' ], // ...
14407
+ 'SO-01L' => [ 'Sony', 'Xperia XZ3 SO-01L', 'carrier' => 'DoCoMo' ], // ...
14408
  'SO-02C' => [ 'Sony Ericsson', 'Xperia acro SO-02C', 'carrier' => 'DoCoMo' ], // Azusa
14409
  'SO-02D' => [ 'Sony Ericsson', 'Xperia NX SO-02D', 'carrier' => 'DoCoMo' ], // Nozomi
14410
  'SO-02E' => [ 'Sony', 'Xperia Z SO-02E', 'carrier' => 'DoCoMo' ], // Yuga
14412
  'SO-02G' => [ 'Sony', 'Xperia Z3 Compact SO-02G', 'carrier' => 'DoCoMo' ], // ...
14413
  'SO-02H' => [ 'Sony', 'Xperia Z5 Compact SO-02H', 'carrier' => 'DoCoMo' ], // ...
14414
  'SO-02J' => [ 'Sony', 'Xperia X Compact SO-02J', 'carrier' => 'DoCoMo' ], // ...
14415
+ 'SO-02K' => [ 'Sony', 'Xperia XZ1 Compact SO-02K', 'carrier' => 'DoCoMo' ], // ...
14416
  'SO-03C' => [ 'Sony Ericsson', 'Xperia ray SO-03C', 'carrier' => 'DoCoMo' ], // Urushi
14417
  'SO-03D' => [ 'Sony Ericsson', 'Xperia acro HD SO-03D', 'carrier' => 'DoCoMo' ], // Hikari
14418
  'SO-03E' => [ 'Sony', 'Xperia Tablet Z SO-03E', DeviceType::TABLET, 'carrier' => 'DoCoMo' ], // Pollux
14420
  'SO-03G' => [ 'Sony', 'Xperia Z4 SO-03G', 'carrier' => 'DoCoMo' ],
14421
  'SO-03H' => [ 'Sony', 'Xperia Z5 Premium SO-03H', 'carrier' => 'DoCoMo' ],
14422
  'SO-03J' => [ 'Sony', 'Xperia XZs SO-03J', 'carrier' => 'DoCoMo' ],
14423
+ 'SO-03K' => [ 'Sony', 'Xperia XZ2 SO-03K', 'carrier' => 'DoCoMo' ],
14424
+ 'SO-03L' => [ 'Sony', 'Xperia 1 SO-03L', 'carrier' => 'DoCoMo' ],
14425
  'SO-04D' => [ 'Sony', 'Xperia GX SO-04D', 'carrier' => 'DoCoMo' ], // Hayabusa
14426
  'SO-04E' => [ 'Sony', 'Xperia A SO-04E', 'carrier' => 'DoCoMo' ], // Dogo
14427
  'SO-04EM' => [ 'Sony', 'Xperia feat. HATSUNE MIKU SO-04E', 'carrier' => 'DoCoMo' ],
14429
  'SO-04G' => [ 'Sony', 'Xperia A4 SO-04G', 'carrier' => 'DoCoMo' ],
14430
  'SO-04H' => [ 'Sony', 'Xperia X Performance SO-04H', 'carrier' => 'DoCoMo' ],
14431
  'SO-04J' => [ 'Sony', 'Xperia XZ Premium SO-04J', 'carrier' => 'DoCoMo' ],
14432
+ 'SO-04K' => [ 'Sony', 'Xperia XZ2 Premium SO-04K', 'carrier' => 'DoCoMo' ],
14433
  'SO-05D' => [ 'Sony', 'Xperia SX SO-05D', 'carrier' => 'DoCoMo' ], // Komachi
14434
  'SO-05F' => [ 'Sony', 'Xperia Tablet Z2 SO-05F', DeviceType::TABLET, 'carrier' => 'DoCoMo' ], // Castor
14435
  'SO-05G' => [ 'Sony', 'Xperia Tablet Z4 SO-05G', DeviceType::TABLET, 'carrier' => 'DoCoMo' ], // ...
14436
+ 'SO-05K' => [ 'Sony', 'Xperia XZ2 Compact SO-05K', 'carrier' => 'DoCoMo' ],
14437
  'SO-07D' => [ 'Sony', 'SO-07D', DeviceType::TABLET, 'carrier' => 'DoCoMo' ], // ...
14438
  ],
14439
 
14452
  'SOV34' => [ 'Sony', 'Xperia XZ SOV34', 'carrier' => 'au' ], // ...
14453
  'SOV35' => [ 'Sony', 'Xperia XZs SOV35', 'carrier' => 'au' ], // ...
14454
  'SOV36' => [ 'Sony', 'Xperia XZ1 SOV36', 'carrier' => 'au' ], // ...
14455
+ 'SOV37' => [ 'Sony', 'Xperia XZ2 SOV37', 'carrier' => 'au' ], // ...
14456
+ 'SOV38' => [ 'Sony', 'Xperia XZ2 Premium SOV38', 'carrier' => 'au' ], // ...
14457
+ 'SOV39' => [ 'Sony', 'Xperia XZ3 SOV39', 'carrier' => 'au' ], // ...
14458
+ 'SOV40' => [ 'Sony', 'Xperia 1 SOV40', 'carrier' => 'au' ], // ...
14459
  ],
14460
 
14461
  '40[0-9]SO!!' => [
14470
 
14471
  '60[0-9]SO!!' => [
14472
  '601SO' => [ 'Sony', 'Xperia XZ 601SO', 'carrier' => 'Softbank' ], // ...
14473
+ '602SO' => [ 'Sony', 'Xperia XZs 602SO', 'carrier' => 'Softbank' ], // ...
14474
+ ],
14475
+
14476
+ '70[0-9]SO!!' => [
14477
+ '701SO' => [ 'Sony', 'Xperia XZ1 701SO', 'carrier' => 'Softbank' ], // ...
14478
+ '702SO' => [ 'Sony', 'Xperia XZ2 702SO', 'carrier' => 'Softbank' ], // ...
14479
  ],
14480
 
14481
  'Xperia!!' => [
16846
  '(Xiaomi )?(Xiaomi|Xiaomi M|MI)[ \-]?5s Plus$!' => [ 'Xiaomi', 'Mi 5s Plus' ],
16847
  '(Xiaomi )?(Xiaomi|Xiaomi M|MI)[ \-]?5x$!' => [ 'Xiaomi', 'Mi 5x' ],
16848
  '(Xiaomi )?(Xiaomi|Xiaomi M|MI)[ \-]?6$!' => [ 'Xiaomi', 'Mi 6' ],
16849
+ '(Xiaomi )?(Xiaomi|Xiaomi M|MI)[ \-]?6X$!' => [ 'Xiaomi', 'Mi 6X' ],
16850
+ '(Xiaomi )?(Xiaomi|Xiaomi M|MI)[ \-]?7S$!' => [ 'Xiaomi', 'Mi 7S' ],
16851
  '(Xiaomi )?(Xiaomi|Xiaomi M|MI)[ \-]?A1$!' => [ 'Xiaomi', 'Mi A1' ],
16852
+ '(Xiaomi )?(Xiaomi|Xiaomi M|MI)[ \-]?A2$!' => [ 'Xiaomi', 'Mi A2' ],
16853
+ '(Xiaomi )?(Xiaomi|Xiaomi M|MI)[ \-]?A2 Lite!' => [ 'Xiaomi', 'Mi A2 Lite' ],
16854
+ '(Xiaomi )?(Xiaomi|Xiaomi M|MI)[ \-]?A3$!' => [ 'Xiaomi', 'Mi A3' ],
16855
+ ],
16856
+
16857
+ 'MI 8' => [ 'Xiaomi', 'Mi 8' ],
16858
+ 'MI 8 SE' => [ 'Xiaomi', 'Mi 8 SE' ],
16859
+ 'MI 8 UD' => [ 'Xiaomi', 'Mi 8 UD' ],
16860
+ 'MI 8 Lite' => [ 'Xiaomi', 'Mi 8 Lite' ],
16861
+ 'MI 9' => [ 'Xiaomi', 'Mi 9' ],
16862
+ 'Mi 9T Pro' => [ 'Xiaomi', 'Mi 9T Pro' ],
16863
+ 'Mi9 Pro 5G' => [ 'Xiaomi', 'Mi 9 Pro' ],
16864
+
16865
  '(Xiaomi|Xiaomi Mi|MI) Note!!' => [
16866
  '(Xiaomi|Xiaomi Mi|MI) Note (LTE|4G)$!' => [ 'Xiaomi', 'Mi Note' ],
16867
  '(Xiaomi|Xiaomi Mi|MI) Note ?2!' => [ 'Xiaomi', 'Mi Note 2' ],
16872
 
16873
  '(Xiaomi )?(MI )?MAX$!' => [ 'Xiaomi', 'Mi Max' ],
16874
  '(Xiaomi )?(MI )?MAX 2$!' => [ 'Xiaomi', 'Mi Max 2' ],
16875
+ '(Xiaomi )?(MI )?MAX 3$!' => [ 'Xiaomi', 'Mi Max 3' ],
16876
  '(Xiaomi )?(MI )?MIX$!' => [ 'Xiaomi', 'Mi MIX' ],
16877
  '(Xiaomi )?(MI )?MIX 2$!' => [ 'Xiaomi', 'Mi MIX 2' ],
16878
+ '(Xiaomi )?(MI )?MIX 2S$!' => [ 'Xiaomi', 'Mi MIX 2S' ],
16879
 
16880
  '(Xiaomi )?20!!' => [
16881
  '(Xiaomi )?20130(61)!' => [ 'Xiaomi', 'Mi 3' ],
16897
  '(Xiaomi )?(Redmi|HM) ?3X!' => [ 'Xiaomi', 'Redmi 3X' ],
16898
  '(Xiaomi )?(Redmi|HM) ?Pro!' => [ 'Xiaomi', 'Redmi Pro' ],
16899
  '(Xiaomi )?(Redmi|HM) ?4$!' => [ 'Xiaomi', 'Redmi 4' ],
16900
+ '(Xiaomi )?(Redmi|HM) ?4 ?Prime!' => [ 'Xiaomi', 'Redmi 4 Prime' ],
16901
+ '(Xiaomi )?(Redmi|HM) ?4 ?Pro!' => [ 'Xiaomi', 'Redmi 4 Pro' ],
16902
  '(Xiaomi )?(Redmi|HM) ?4A!' => [ 'Xiaomi', 'Redmi 4A' ],
16903
  '(Xiaomi )?(Redmi|HM) ?4X!' => [ 'Xiaomi', 'Redmi 4X' ],
16904
  '(Xiaomi )?(Redmi|HM) ?5$!' => [ 'Xiaomi', 'Redmi 5' ],
16905
  '(Xiaomi )?(Redmi|HM) ?5 Plus!' => [ 'Xiaomi', 'Redmi 5 Plus' ],
16906
  '(Xiaomi )?(Redmi|HM) ?5A!' => [ 'Xiaomi', 'Redmi 5A' ],
16907
+ '(Xiaomi )?(Redmi|HM) ?6A!' => [ 'Xiaomi', 'Redmi 6A' ],
16908
+ '(Xiaomi )?(Redmi|HM) ?6 Pro!' => [ 'Xiaomi', 'Redmi 6 Pro' ],
16909
+ '(Xiaomi )?(Redmi|HM) ?7$!' => [ 'Xiaomi', 'Redmi 7' ],
16910
+ '(Xiaomi )?(Redmi|HM) ?7A!' => [ 'Xiaomi', 'Redmi 7A' ],
16911
+ '(Xiaomi )?(Redmi|HM) ?8$!' => [ 'Xiaomi', 'Redmi 8' ],
16912
+ '(Xiaomi )?Redmi[ \-]K20 Pro!' => [ 'Xiaomi', 'Redmi K20 Pro' ],
16913
+ '(Xiaomi )?Redmi[ \-]S2$!' => [ 'Xiaomi', 'Redmi S2' ],
16914
  '(Xiaomi )?Redmi[ \-]Y1$!' => [ 'Xiaomi', 'Redmi Y1' ],
16915
  '(Xiaomi )?Redmi[ \-]Y1 Lite!' => [ 'Xiaomi', 'Redmi Y1 Lite' ],
16916
+ '(Xiaomi )?Redmi[ \-]Go$!' => [ 'Xiaomi', 'Redmi Go' ],
16917
  ],
16918
 
16919
  '(Xiaomi )?(Redmi|HM)[ \-]?Note!!' => [
16923
  '(Xiaomi )?Redmi[ \-]Note 3 Pro!' => [ 'Xiaomi', 'Redmi Note 3 Pro' ],
16924
  '(Xiaomi )?Redmi[ \-]Note ?4$!' => [ 'Xiaomi', 'Redmi Note 4' ],
16925
  '(Xiaomi )?Redmi[ \-]Note ?4X!' => [ 'Xiaomi', 'Redmi Note 4X' ],
16926
+ '(Xiaomi )?Redmi[ \-]Note ?5$!' => [ 'Xiaomi', 'Redmi Note 5' ],
16927
  '(Xiaomi )?Redmi[ \-]Note ?5A!' => [ 'Xiaomi', 'Redmi Note 5A' ],
16928
+ '(Xiaomi )?Redmi[ \-]Note 5 Pro!' => [ 'Xiaomi', 'Redmi Note 5 Pro' ],
16929
+ '(Xiaomi )?Redmi[ \-]Note 7$!' => [ 'Xiaomi', 'Redmi Note 7' ],
16930
+ '(Xiaomi )?Redmi[ \-]Note 7 Pro!' => [ 'Xiaomi', 'Redmi Note 7 Pro' ],
16931
+ '(Xiaomi )?Redmi[ \-]Note 8$!' => [ 'Xiaomi', 'Redmi Note 8' ],
16932
  ],
16933
 
16934
  '(Xiaomi |HM)?20!!' => [
16951
  '(Xiaomi |HM)?20160(51)!' => [ 'Xiaomi', 'Redmi Note 4' ],
16952
  ],
16953
 
16954
+ 'POCOPHONE F1' => [ 'Xiaomi', 'Pocophone F1' ],
16955
+
16956
  'Xiaomi MDT2!' => [ 'Xiaomi', 'Mi 5x' ],
16957
  'Xiaomi MCT1!' => [ 'Xiaomi', 'Mi 6' ],
16958
  'Xiaomi MAT136!' => [ 'Xiaomi', 'Redmi 4X' ],
17929
  'ZTE Blade A2 plus' => [ 'ZTE', 'Blade A2 Plus' ],
17930
  'ZTE Blade A5' => [ 'ZTE', 'Blade A5' ],
17931
  'ZTE BLADE A5 PRO' => [ 'ZTE', 'Blade A5 Pro' ],
17932
+ 'ZTE BLADE A6' => [ 'ZTE', 'Blade A6' ],
17933
+ 'ZTE BLADE A6 MAX' => [ 'ZTE', 'Blade A6 Max' ],
17934
  'ZTE BLADE A110' => [ 'ZTE', 'Blade A110' ],
17935
  'ZTE BLADE A112' => [ 'ZTE', 'Blade A112' ],
17936
+ 'ZTE BLADE A125' => [ 'ZTE', 'Blade A125' ],
17937
  'ZTE BLADE A210' => [ 'ZTE', 'Blade A210' ],
17938
  'ZTE BLADE A310' => [ 'ZTE', 'Blade A310' ],
17939
  'ZTE Blade A315' => [ 'ZTE', 'Blade A315' ],
17963
  'ZTE BLADE A610' => [ 'ZTE', 'Blade A610' ],
17964
  'ZTE BLADE A610C' => [ 'ZTE', 'Blade A610C' ],
17965
  'ZTE BLADE A612' => [ 'ZTE', 'Blade A612' ],
17966
+ 'ZTE BLADE A0620' => [ 'ZTE', 'Blade A620' ],
17967
  'ZTE BLADE A910' => [ 'ZTE', 'Blade A910' ],
17968
  'ZTE Blade AF5' => [ 'ZTE', 'Blade AF5' ],
17969
  'ZTE BLADE B112' => [ 'ZTE', 'Blade B112' ],
18013
  'ZTE Blade L5 Plus' => [ 'ZTE', 'Blade L5 Plus' ],
18014
  'ZTE BLADE L0510' => [ 'ZTE', 'Blade L5 Plus' ],
18015
  'ZTE Blade L6' => [ 'ZTE', 'Blade L6' ],
18016
+ 'ZTE BLADE L7' => [ 'ZTE', 'Blade L7' ],
18017
  'ZTE BLADE L110' => [ 'ZTE', 'Blade L110' ],
18018
  'ZTE BLADE L111' => [ 'ZTE', 'Blade L111' ],
18019
  'ZTE Blade L370' => [ 'ZTE', 'Blade L370' ],
18049
  'ZTE BLADE V0850' => [ 'ZTE', 'Blade V8 Mini' ],
18050
  'BLADE V8 SE' => [ 'ZTE', 'Blade V8 SE' ],
18051
  'ZTE BLADE V0900' => [ 'ZTE', 'Blade V9' ],
18052
+ 'ZTE BLADE V9' => [ 'ZTE', 'Blade V9' ],
18053
  'ZTE Blade V220' => [ 'ZTE', 'Blade V220' ],
18054
  'ZTE Blade V580' => [ 'ZTE', 'Blade V580' ],
18055
  'ZTE Blade V770' => [ 'ZTE', 'Blade V770' ],
18225
  'ZTE B2016' => [ 'ZTE', 'Axon Mini' ],
18226
  'ZTE B2017' => [ 'ZTE', 'Axon Mini' ],
18227
  'ZTE B2017G' => [ 'ZTE', 'Axon Mini' ],
18228
+ 'ZTE B2019G' => [ 'ZTE', 'Axon 7' ],
18229
  'ZTE C2016' => [ 'ZTE', 'Axon Max' ],
18230
  'ZTE C2017' => [ 'ZTE', 'Axon Max' ],
18231
  'ZTE STAR' => [ 'ZTE', 'Star 1' ],
18253
  '009Z' => [ 'ZTE', 'STAR7 009Z', 'carrier' => 'Softbank' ],
18254
  '402ZT' => [ 'ZTE', 'Blade Q+ 402ZT', 'carrier' => 'Softbank' ],
18255
  '502ZT' => [ 'ZTE', 'Spro 2 502ZT', DeviceType::PROJECTOR, 'carrier' => 'Softbank' ],
18256
+ '602ZT' => [ 'ZTE', 'Libero 2 602ZT', 'carrier' => 'Softbank' ],
18257
  'MO-01J' => [ 'ZTE', 'MONO MO-01J', 'carrier' => 'DoCoMo' ],
18258
+ 'MO-01K' => [ 'ZTE', 'MONO MO-01K', 'carrier' => 'DoCoMo' ],
18259
 
18260
  'ZA400' => [ 'Zonda', 'Mini Colors ZA400' ],
18261
  'ZA402' => [ 'Zonda', 'Scratch ZA402' ],
18463
  'GM 5 Plus d' => [ 'General Mobile', 'GM5 Plus' ],
18464
  'GM 6' => [ 'General Mobile', 'GM6' ],
18465
  'GM 6 d' => [ 'General Mobile', 'GM6' ],
18466
+ 'GM 8 d' => [ 'General Mobile', 'GM8' ],
18467
  'GM Discovery tab 8' => [ 'General Mobile', 'tab 8', DeviceType::TABLET ],
18468
  'etab5' => [ 'General Mobile', 'Etab 5', DeviceType::TABLET ],
18469
 
integration/whichbrowser/data/models-firefoxos.php CHANGED
@@ -30,6 +30,7 @@ DeviceModels::$FIREFOXOS_MODELS = [
30
  'OPEN2' => [ 'ZTE', 'Open II' ],
31
 
32
  'ALCATEL4044[MNOTVW]!' => [ 'Alcatel', 'Go Flip' ],
 
33
  '.LYF\/.F30C!' => [ 'Jio', 'JioPhone F30C' ],
34
  '.LYF\/.F101K!' => [ 'Jio', 'JioPhone F101K' ],
35
  'LYF\/F30C!' => [ 'Jio', 'JioPhone F30C' ],
30
  'OPEN2' => [ 'ZTE', 'Open II' ],
31
 
32
  'ALCATEL4044[MNOTVW]!' => [ 'Alcatel', 'Go Flip' ],
33
+ 'ALCATEL4044C!' => [ 'Alcatel', 'QUICKFLIP' ],
34
  '.LYF\/.F30C!' => [ 'Jio', 'JioPhone F30C' ],
35
  '.LYF\/.F101K!' => [ 'Jio', 'JioPhone F101K' ],
36
  'LYF\/F30C!' => [ 'Jio', 'JioPhone F30C' ],
integration/whichbrowser/data/models-ios.php CHANGED
@@ -50,12 +50,20 @@ DeviceModels::$IOS_MODELS = [
50
  'iPhone10,4' => [ 'Apple', 'iPhone 8', DeviceType::MOBILE ],
51
  'iPhone10,5' => [ 'Apple', 'iPhone 8 Plus', DeviceType::MOBILE ],
52
  'iPhone10,6' => [ 'Apple', 'iPhone X', DeviceType::MOBILE ],
 
 
 
 
 
 
 
53
  'iPod1,1' => [ 'Apple', 'iPod touch', DeviceType::MEDIA ],
54
  'iPod2,1' => [ 'Apple', 'iPod touch (2nd gen)', DeviceType::MEDIA ],
55
  'iPod3,1' => [ 'Apple', 'iPod touch (3rd gen)', DeviceType::MEDIA ],
56
  'iPod4,1' => [ 'Apple', 'iPod touch (4th gen)', DeviceType::MEDIA ],
57
  'iPod5,1' => [ 'Apple', 'iPod touch (5th gen)', DeviceType::MEDIA ],
58
  'iPod7,1' => [ 'Apple', 'iPod touch (6th gen)', DeviceType::MEDIA ],
 
59
  'iPad1,1' => [ 'Apple', 'iPad', DeviceType::TABLET ],
60
  'iPad1,2' => [ 'Apple', 'iPad 2', DeviceType::TABLET ],
61
  'iPad2,1' => [ 'Apple', 'iPad 2', DeviceType::TABLET ],
@@ -94,4 +102,20 @@ DeviceModels::$IOS_MODELS = [
94
  'iPad7,2' => [ 'Apple', 'iPad Pro (12.9″, 2nd gen)', DeviceType::TABLET ],
95
  'iPad7,3' => [ 'Apple', 'iPad Pro (10.5″)', DeviceType::TABLET ],
96
  'iPad7,4' => [ 'Apple', 'iPad Pro (10.5″)', DeviceType::TABLET ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  ];
50
  'iPhone10,4' => [ 'Apple', 'iPhone 8', DeviceType::MOBILE ],
51
  'iPhone10,5' => [ 'Apple', 'iPhone 8 Plus', DeviceType::MOBILE ],
52
  'iPhone10,6' => [ 'Apple', 'iPhone X', DeviceType::MOBILE ],
53
+ 'iPhone11,2' => [ 'Apple', 'iPhone XS', DeviceType::MOBILE ],
54
+ 'iPhone11,4' => [ 'Apple', 'iPhone XS Max', DeviceType::MOBILE ],
55
+ 'iPhone11,6' => [ 'Apple', 'iPhone XS Max', DeviceType::MOBILE ],
56
+ 'iPhone11,8' => [ 'Apple', 'iPhone XR', DeviceType::MOBILE ],
57
+ 'iPhone12,1' => [ 'Apple', 'iPhone 11', DeviceType::MOBILE ],
58
+ 'iPhone12,3' => [ 'Apple', 'iPhone 11 Pro', DeviceType::MOBILE ],
59
+ 'iPhone12,5' => [ 'Apple', 'iPhone 11 Pro Max', DeviceType::MOBILE ],
60
  'iPod1,1' => [ 'Apple', 'iPod touch', DeviceType::MEDIA ],
61
  'iPod2,1' => [ 'Apple', 'iPod touch (2nd gen)', DeviceType::MEDIA ],
62
  'iPod3,1' => [ 'Apple', 'iPod touch (3rd gen)', DeviceType::MEDIA ],
63
  'iPod4,1' => [ 'Apple', 'iPod touch (4th gen)', DeviceType::MEDIA ],
64
  'iPod5,1' => [ 'Apple', 'iPod touch (5th gen)', DeviceType::MEDIA ],
65
  'iPod7,1' => [ 'Apple', 'iPod touch (6th gen)', DeviceType::MEDIA ],
66
+ 'iPod9,1' => [ 'Apple', 'iPod touch (7th gen)', DeviceType::MEDIA ],
67
  'iPad1,1' => [ 'Apple', 'iPad', DeviceType::TABLET ],
68
  'iPad1,2' => [ 'Apple', 'iPad 2', DeviceType::TABLET ],
69
  'iPad2,1' => [ 'Apple', 'iPad 2', DeviceType::TABLET ],
102
  'iPad7,2' => [ 'Apple', 'iPad Pro (12.9″, 2nd gen)', DeviceType::TABLET ],
103
  'iPad7,3' => [ 'Apple', 'iPad Pro (10.5″)', DeviceType::TABLET ],
104
  'iPad7,4' => [ 'Apple', 'iPad Pro (10.5″)', DeviceType::TABLET ],
105
+ 'iPad7,5' => [ 'Apple', 'iPad (9.7″, 6th gen)', DeviceType::TABLET ],
106
+ 'iPad7,6' => [ 'Apple', 'iPad (9.7″, 6th gen)', DeviceType::TABLET ],
107
+ 'iPad7,11' => [ 'Apple', 'iPad (10.2″, 7th gen)', DeviceType::TABLET ],
108
+ 'iPad7,12' => [ 'Apple', 'iPad (10.2″, 7th gen)', DeviceType::TABLET ],
109
+ 'iPad8,1' => [ 'Apple', 'iPad Pro (11.0″)', DeviceType::TABLET ],
110
+ 'iPad8,2' => [ 'Apple', 'iPad Pro (11.0″)', DeviceType::TABLET ],
111
+ 'iPad8,3' => [ 'Apple', 'iPad Pro (11.0″)', DeviceType::TABLET ],
112
+ 'iPad8,4' => [ 'Apple', 'iPad Pro (11.0″)', DeviceType::TABLET ],
113
+ 'iPad8,5' => [ 'Apple', 'iPad Pro (12.9″, 3rd gen)', DeviceType::TABLET ],
114
+ 'iPad8,6' => [ 'Apple', 'iPad Pro (12.9″, 3rd gen)', DeviceType::TABLET ],
115
+ 'iPad8,7' => [ 'Apple', 'iPad Pro (12.9″, 3rd gen)', DeviceType::TABLET ],
116
+ 'iPad8,8' => [ 'Apple', 'iPad Pro (12.9″, 3rd gen)', DeviceType::TABLET ],
117
+ 'iPad11,1' => [ 'Apple', 'iPad mini (5th gen)', DeviceType::TABLET ],
118
+ 'iPad11,2' => [ 'Apple', 'iPad mini (5th gen)', DeviceType::TABLET ],
119
+ 'iPad11,3' => [ 'Apple', 'iPad Air (3rd gen)', DeviceType::TABLET ],
120
+ 'iPad11,4' => [ 'Apple', 'iPad Air (3rd gen)', DeviceType::TABLET ],
121
  ];
integration/whichbrowser/data/models-tizen.php CHANGED
@@ -43,10 +43,20 @@ DeviceModels::$TIZEN_MODELS = [
43
  'SM-R760!' => [ 'Samsung', 'Gear S3', DeviceType::WATCH ],
44
  'SM-R765!' => [ 'Samsung', 'Gear S3', DeviceType::WATCH ],
45
  'SM-R770!' => [ 'Samsung', 'Gear S3 Classic', DeviceType::WATCH ],
 
46
 
47
  'NX300' => [ 'Samsung', 'NX300', DeviceType::CAMERA ],
48
 
49
  'FamilyHub' => [ 'Samsung', 'Family Hub', DeviceType::APPLIANCE ],
 
 
 
 
 
 
 
 
 
50
 
51
  'hawkp' => [ 'Samsung', '"Hawkp"', DeviceType::TELEVISION ],
52
 
43
  'SM-R760!' => [ 'Samsung', 'Gear S3', DeviceType::WATCH ],
44
  'SM-R765!' => [ 'Samsung', 'Gear S3', DeviceType::WATCH ],
45
  'SM-R770!' => [ 'Samsung', 'Gear S3 Classic', DeviceType::WATCH ],
46
+ 'SM-R805!' => [ 'Samsung', 'Gear S4', DeviceType::WATCH ],
47
 
48
  'NX300' => [ 'Samsung', 'NX300', DeviceType::CAMERA ],
49
 
50
  'FamilyHub' => [ 'Samsung', 'Family Hub', DeviceType::APPLIANCE ],
51
+ 'RF10M9995!' => [ 'Samsung', 'Family Hub', DeviceType::APPLIANCE ],
52
+ 'RF23M8590!' => [ 'Samsung', 'Family Hub', DeviceType::APPLIANCE ],
53
+ 'RF265BEAE!' => [ 'Samsung', 'Family Hub', DeviceType::APPLIANCE ],
54
+ 'RF28M9580!' => [ 'Samsung', 'Family Hub', DeviceType::APPLIANCE ],
55
+ 'RF56M9540!' => [ 'Samsung', 'Family Hub', DeviceType::APPLIANCE ],
56
+ 'RF85K9993!' => [ 'Samsung', 'Family Hub', DeviceType::APPLIANCE ],
57
+ 'RF85M95A2!' => [ 'Samsung', 'Family Hub', DeviceType::APPLIANCE ],
58
+ 'RH81M8090!' => [ 'Samsung', 'Family Hub', DeviceType::APPLIANCE ],
59
+
60
 
61
  'hawkp' => [ 'Samsung', '"Hawkp"', DeviceType::TELEVISION ],
62
 
integration/whichbrowser/data/profiles.php CHANGED
@@ -220,6 +220,7 @@ DeviceProfiles::$PROFILES = [
220
  'http://www-ccpp.tcl-ta.com/files/ALCATEL_ONETOUCH_Flash_Plus.xml' => [ 'Alcatel', 'One Touch Flash Plus', 'Android', DeviceType::MOBILE ],
221
  'http://www-ccpp.tcl-ta.com/files/7048A.xml' => [ 'Alcatel', 'One Touch Go Play', 'Android', DeviceType::MOBILE ],
222
  'http://www-ccpp.tcl-ta.com/files/7048X.xml' => [ 'Alcatel', 'One Touch Go Play', 'Android', DeviceType::MOBILE ],
 
223
  'http://www-ccpp.tcl-ta.com/files/ONE_TOUCH_8020E.xml' => [ 'Alcatel', 'One Touch Hero', 'Android', DeviceType::MOBILE ],
224
  'http://www-ccpp.tcl-ta.com/files/7055A.xml' => [ 'Alcatel', 'One Touch Hero 2C', 'Android', DeviceType::MOBILE ],
225
  'http://www-ccpp.tcl-ta.com/files/ALCATEL_ONE_TOUCH_6030A.xml' => [ 'Alcatel', 'One Touch Idol', 'Android', DeviceType::MOBILE ],
@@ -418,6 +419,7 @@ DeviceProfiles::$PROFILES = [
418
  'http://www-ccpp.tcl-ta.com/files/ALCATEL_ONE_TOUCH_5035D.xml' => [ 'Alcatel', 'One Touch X\'Pop', 'Android', DeviceType::MOBILE ],
419
  'http://www-ccpp.tcl-ta.com/files/ALCATEL_ONE_TOUCH_5035E.xml' => [ 'Alcatel', 'One Touch X\'Pop', 'Android', DeviceType::MOBILE ],
420
  'http://www-ccpp.tcl-ta.com/files/ALCATEL_ONE_TOUCH_5035X.xml' => [ 'Alcatel', 'One Touch X\'Pop', 'Android', DeviceType::MOBILE ],
 
421
  'http://www-ccpp.tcl-ta.com/files/ALCATEL_TRIBE_3075A.rdf' => [ 'Alcatel', 'Tribe 3075A', null, DeviceType::MOBILE ],
422
  'http://uaprof.vmobl.com/PCD/ADR2045-VMUB/1.0/UAProf.xml' => [ 'Alcatel', 'Venture', 'Android', DeviceType::MOBILE ],
423
  'http://pluto.alphacell.com/uaprof/m5p.xml' => [ 'AlphaCell', 'M5', null, DeviceType::MOBILE ],
@@ -745,6 +747,7 @@ DeviceProfiles::$PROFILES = [
745
  'http://wap.sonyericsson.com/UAprof/T68R503.xml' => [ 'Ericsson', 'T68', null, DeviceType::MOBILE ],
746
  'http://www.ztemt.com/mobile/uaprof/V6500_Etisalat_EG.xml' => [ 'Etisalat', 'Smartphone', 'Android', DeviceType::MOBILE ],
747
  'http://uaprof.qma.com.tw/BenQ-A3c.xml' => [ 'Ezcast', 'Dongle', 'Android', ],
 
748
  'http://www.msai.in/uaprof/Lava/Flair%20P2.xml' => [ 'Fairphone', '2', 'Android', DeviceType::MOBILE ],
749
  'http://www.c2dms.com/UAProfile/N26/FarEastone_Smart501.xml' => [ 'Fareastone', 'Smart 501', 'Android', DeviceType::MOBILE ],
750
  'http://www.wizdevice.com/support/rise/uaprof.xml' => [ 'Fareastone', 'Smart 701', 'Android', DeviceType::TABLET ],
@@ -1049,6 +1052,7 @@ DeviceProfiles::$PROFILES = [
1049
  'http://www.htcmms.com.tw/Android/Common/7QtMcMcyB2/ua-profile.xml' => [ 'HTC', 'Desire 816', 'Android', DeviceType::MOBILE ],
1050
  'http://www.htcmms.com.tw/Android/Common/geUXhkfboO/ua-profile.xml' => [ 'HTC', 'Desire 816', 'Android', DeviceType::MOBILE ],
1051
  'http://www.htcmms.com.tw/Android/Common/HRobRleNsO/ua-profile.xml' => [ 'HTC', 'Desire 816', 'Android', DeviceType::MOBILE ],
 
1052
  'http://www.htcmms.com.tw/Android/Common/miKNCjjDHJ/ua-profile.xml' => [ 'HTC', 'Desire 816', 'Android', DeviceType::MOBILE ],
1053
  'http://www.htcmms.com.tw/Android/Common/rLgUe79qmx/ua-profile.xml' => [ 'HTC', 'Desire 816', 'Android', DeviceType::MOBILE ],
1054
  'http://www.htcmms.com.tw/Android/Common/rYMdtoVVAt/ua-profile.xml' => [ 'HTC', 'Desire 816', 'Android', DeviceType::MOBILE ],
@@ -1317,6 +1321,7 @@ DeviceProfiles::$PROFILES = [
1317
  'http://device.sprintpcs.com/HTC/2PQ93-SPRINT/1106511.rdf' => [ 'HTC', 'One (A9)', 'Android', DeviceType::MOBILE ],
1318
  'http://device.sprintpcs.com/HTC/2PQ93-SPRINT/1576511.rdf' => [ 'HTC', 'One (A9)', 'Android', DeviceType::MOBILE ],
1319
  'http://device.sprintpcs.com/HTC/2PQ93-SPRINT/1606514.rdf' => [ 'HTC', 'One (A9)', 'Android', DeviceType::MOBILE ],
 
1320
  'http://www.htcmms.com.tw/Android/Common/rjXLBq21RC/ua-profile.xml' => [ 'HTC', 'One (A9)', 'Android', DeviceType::MOBILE ],
1321
  'http://device.sprintpcs.com/HTC/0PAJ5-Chameleon/1116512.rdf' => [ 'HTC', 'One (E8)', 'Android', DeviceType::MOBILE ],
1322
  'http://device.sprintpcs.com/HTC/0PAJ5-Chameleon/1226511.rdf' => [ 'HTC', 'One (E8)', 'Android', DeviceType::MOBILE ],
@@ -1775,6 +1780,7 @@ DeviceProfiles::$PROFILES = [
1775
  'http://wap1.huawei.com/uaprof/HUAWEI_%s_UAProfile.xml' => [ 'Huawei', 'Ascend G7', 'Android', DeviceType::MOBILE ],
1776
  'http://wap1.huawei.com/uaprof/HUAWEI_G7-L01_OrangeUAProfile.xml' => [ 'Huawei', 'Ascend G7', 'Android', DeviceType::MOBILE ],
1777
  'http://wap1.huawei.com/uaprof/HUAWEI_G7-L01_UAProfile.xml' => [ 'Huawei', 'Ascend G7', 'Android', DeviceType::MOBILE ],
 
1778
  'http://wap1.huawei.com/uaprof/HUAWEI_G7-L03_DRMFL_UAProfile.xml' => [ 'Huawei', 'Ascend G7', 'Android', DeviceType::MOBILE ],
1779
  'http://wap1.huawei.com/uaprof/HUAWEI_G7-L03_UAProfile.xml' => [ 'Huawei', 'Ascend G7', 'Android', DeviceType::MOBILE ],
1780
  'http://wap1.huawei.com/uaprof/HUAWEI_G7-L11_UAProfile.xml' => [ 'Huawei', 'Ascend G7', 'Android', DeviceType::MOBILE ],
@@ -2081,7 +2087,9 @@ DeviceProfiles::$PROFILES = [
2081
  'http://wap1.huawei.com/uaprof/TIT-AL00C583_UAProfile.xml' => [ 'Huawei', 'Enjoy 5', 'Android', DeviceType::MOBILE ],
2082
  'http://wap1.huawei.com/uaprof/HUAWEI_TANGO_UAProfile.xml' => [ 'Huawei', 'Enjoy 5S', 'Android', DeviceType::MOBILE ],
2083
  'http://wap1.huawei.com/uaprof/HUAWEI_NCE-AL00_UAProfile.xml' => [ 'Huawei', 'Enjoy 6', 'Windows', DeviceType::MOBILE ],
 
2084
  'http://wap1.huawei.com/uaprof/HUAWEI_SLA-TL10_UAProfile.xml' => [ 'Huawei', 'Enjoy 7', 'Android', DeviceType::MOBILE ],
 
2085
  'http://wap1.huawei.com/uaprof/HUAWEI_TRT-TL10_UAProfile.xml' => [ 'Huawei', 'Enjoy 7 Plus', 'Android', DeviceType::MOBILE ],
2086
  'http://wap1.huawei.com/uaprof/HW_HUAWEI_CM990_1_20130108.xml' => [ 'Huawei', 'Evolución 3', 'Android', DeviceType::MOBILE ],
2087
  'http://wap1.huawei.com/uaprof/HuaweiUM840v100GPRS.xml' => [ 'Huawei', 'Evolution', 'Android', DeviceType::MOBILE ],
@@ -2105,6 +2113,7 @@ DeviceProfiles::$PROFILES = [
2105
  'http://wap1.huawei.com/uaprof/HW_KII-L23_DRM_UAProfile.xml' => [ 'Huawei', 'GR5', 'Android', DeviceType::MOBILE ],
2106
  'http://wap1.huawei.com/uaprof/HW_KII-L23_UAProfile.xml' => [ 'Huawei', 'GR5', 'Android', DeviceType::MOBILE ],
2107
  'http://wap1.huawei.com/uaprof/HW_KII-L23_UAProfile_FL_Only.xml' => [ 'Huawei', 'GR5', 'Android', DeviceType::MOBILE ],
 
2108
  'http://wap1.huawei.com/uaprof/HW_HUAWEI_H870C.xml' => [ 'Huawei', 'H870C', 'Android', DeviceType::MOBILE ],
2109
  'http://wap1.huawei.com/uaprof/HuaweiU8860-51GPRS-Normal.xml' => [ 'Huawei', 'Honor', 'Android', DeviceType::MOBILE ],
2110
  'http://wap1.huawei.com/uaprof/HuaweiU8860-51WCDMA-Normal.xml' => [ 'Huawei', 'Honor', 'Android', DeviceType::MOBILE ],
@@ -2243,6 +2252,7 @@ DeviceProfiles::$PROFILES = [
2243
  'http://wap1.huawei.com/uaprof/HUAWEI_ATH-UL01_DRM_Uaprofile.xml' => [ 'Huawei', 'Honor ShotX', 'Android', DeviceType::MOBILE ],
2244
  'http://wap1.huawei.com/uaprof/HUAWEI_ATH-UL01_Uaprofile.xml' => [ 'Huawei', 'Honor ShotX', 'Android', DeviceType::MOBILE ],
2245
  'http://wap1.huawei.com/uaprof/HUAWEI_ATH-UL06_Uaprofile.xml' => [ 'Huawei', 'Honor ShotX', 'Android', DeviceType::MOBILE ],
 
2246
  'http://wap1.huawei.com/uaprof/HW_HUAWEI_C8950D_1_20120704.xml' => [ 'Huawei', 'Honor+', 'Android', DeviceType::MOBILE ],
2247
  'http://wap1.huawei.com/uaprof/HuaweiU8150v100WCDMA.xml' => [ 'Huawei', 'IDEOS', 'Android', DeviceType::MOBILE ],
2248
  'http://wap.huawei.com/uaprof/Huawei-S7.xml' => [ 'Huawei', 'IDEOS S7', 'Android', DeviceType::MOBILE ],
@@ -2369,6 +2379,9 @@ DeviceProfiles::$PROFILES = [
2369
  'http://provantage.cleartalk.csky.us/ua/huawei_M886.xml' => [ 'Huawei', 'Mercury', 'Android', DeviceType::MOBILE ],
2370
  'http://wap1.huawei.com/uaprof/HuaweiM886-Cricket.xml' => [ 'Huawei', 'Mercury', 'Android', DeviceType::MOBILE ],
2371
  'http://wap1.huawei.com/uaprof/HUAWEI_CAZ-TL10_UAProfile.xml' => [ 'Huawei', 'Nova', 'Android', DeviceType::MOBILE ],
 
 
 
2372
  'http://wap1.huawei.com/uaprof/HUAWEI_WAS-TL10_UAProfile.xml' => [ 'Huawei', 'P10 Lite', 'Android', DeviceType::MOBILE ],
2373
  'http://wap1.huawei.com/uaprof/HUAWEI_VKY-TL00_UAProfile.xml' => [ 'Huawei', 'P10 Plus', 'Android', DeviceType::MOBILE ],
2374
  'http://wap1.huawei.com/uaprof/HW_GRA-CL10_1_20150105.xml' => [ 'Huawei', 'P8', 'Android', DeviceType::MOBILE ],
@@ -2383,9 +2396,11 @@ DeviceProfiles::$PROFILES = [
2383
  'http://wap1.huawei.com/uaprof/HW_EVA-CL00_3_20160226.xml' => [ 'Huawei', 'P9', 'Android', DeviceType::MOBILE ],
2384
  'http://wap1.huawei.com/uaprof/HUAWEI_VNS-TL00_UAProfile.xml' => [ 'Huawei', 'P9 Lite', 'Windows', DeviceType::MOBILE ],
2385
  'http://wap1.huawei.com/uaprof/HUAWEI_VNS_AL00_UAProfile.xml' => [ 'Huawei', 'P9 Lite', 'Android', DeviceType::MOBILE ],
 
2386
  'http://wap1.huawei.com/uaprof/HUAWEI_VIE-AL10_UAProfile.xml' => [ 'Huawei', 'P9 Plus', 'Android', DeviceType::MOBILE ],
2387
  'http://uaprof.metropcs.net/UAProf/Huawei-M931.xml' => [ 'Huawei', 'Premia 4G', 'Android', DeviceType::MOBILE ],
2388
  'http://wap1.huawei.com/uaprof/HW_HUAWEI_H891L.xml' => [ 'Huawei', 'Pronto', 'Android', DeviceType::MOBILE ],
 
2389
  'http://nmsc.ctvap.cn/uaprof/HW/HW_HUAWEI_S8520_1_20110819.xml' => [ 'Huawei', 'S8520', 'Android', DeviceType::MOBILE ],
2390
  'http://nmsc.ctvap.cn/uaprof/HW/HW_HUAWEI_S8600_1_20110825.xml' => [ 'Huawei', 'S8600', 'Android', DeviceType::MOBILE ],
2391
  'http://wap1.huawei.com/uaprof/HuaweiU8650GPRS-Normal.xml' => [ 'Huawei', 'Sonic', 'Android', DeviceType::MOBILE ],
@@ -2464,6 +2479,7 @@ DeviceProfiles::$PROFILES = [
2464
  'http://device.sprintpcs.com/Huawei/Y538-VIRGIN/Y538C237B150.rdf' => [ 'Huawei', 'Union', 'Android', DeviceType::MOBILE ],
2465
  'http://wap1.huawei.com/uaprof/HuaweiU8850v100WCDMA.xml' => [ 'Huawei', 'Vision', 'Android', DeviceType::MOBILE ],
2466
  'http://wap1.huawei.com/uaprof/HUAWEI_LUNA_UAProfile.xml' => [ 'Huawei', 'Y3 II', 'Android', DeviceType::MOBILE ],
 
2467
  'http://wap1.huawei.com/uaprof/LUA-U22_UAProfile.xml' => [ 'Huawei', 'Y3 II', 'Android', DeviceType::MOBILE ],
2468
  'http://wap1.huawei.com/uaprof/LUA-U23_UAProfile.xml' => [ 'Huawei', 'Y3 II', 'Android', DeviceType::MOBILE ],
2469
  'http://wap1.huawei.com/uaprof/HUAWEI_CANCUN_UAProfile.xml,http://wap1.huawei.com/uaprof/HUAWEI_CUN_L_UAProfile.xml'=> [ 'Huawei', 'Y5 II', 'Android', DeviceType::MOBILE ],
@@ -2681,6 +2697,7 @@ DeviceProfiles::$PROFILES = [
2681
  'http://www.1066.cn/uaprof/prof/lava/LAVA_IRIS506Q.xml' => [ 'Lava', 'Iris 506Q', 'Android', DeviceType::MOBILE ],
2682
  'http://www.msai.in/uaprof/Lava/iris_alfa.xml' => [ 'Lava', 'Iris Alfa', 'Android', DeviceType::MOBILE ],
2683
  'http://www.msai.in/uaprof/Lava/Iris_Alfa_L.xml' => [ 'Lava', 'Iris Alfa L', 'Android', DeviceType::MOBILE ],
 
2684
  'http://www.msai.in/uaprof/Lava/iris_Fuel20.xml' => [ 'Lava', 'Iris fuel20', 'Android', DeviceType::MOBILE ],
2685
  'http://www.1066.cn/uaprof/prof/Micromax/Micromax_A107.xml' => [ 'Lava', 'Iris fuel50', 'Android', DeviceType::MOBILE ],
2686
  'http://www.msai.in/uaprof/Lava/Iris%20Fuel60.xml' => [ 'Lava', 'Iris fuel60', 'Android', DeviceType::MOBILE ],
@@ -2920,6 +2937,7 @@ DeviceProfiles::$PROFILES = [
2920
  'http://gsm.lge.com/html/gsm/D950-M10-D1-KK.xml' => [ 'LG', 'G Flex', 'Android', DeviceType::MOBILE ],
2921
  'http://gsm.lge.com/html/gsm/D950-M10-D1.xml' => [ 'LG', 'G Flex', 'Android', DeviceType::MOBILE ],
2922
  'http://gsm.lge.com/html/gsm/D950-M3-D1.xml' => [ 'LG', 'G Flex', 'Android', DeviceType::MOBILE ],
 
2923
  'http://gsm.lge.com/html/gsm/D955-M10-D1.xml' => [ 'LG', 'G Flex', 'Android', DeviceType::MOBILE ],
2924
  'http://gsm.lge.com/html/gsm/D955-M3-D1-KK.xml' => [ 'LG', 'G Flex', 'Android', DeviceType::MOBILE ],
2925
  'http://gsm.lge.com/html/gsm/D955-M3-D1.xml' => [ 'LG', 'G Flex', 'Android', DeviceType::MOBILE ],
@@ -2941,6 +2959,7 @@ DeviceProfiles::$PROFILES = [
2941
  'http://device.sprintpcs.com/LG/LS996-SPRINT/LS996ZV8.rdf' => [ 'LG', 'G Flex 2', 'Android', DeviceType::MOBILE ],
2942
  'http://device.sprintpcs.com/LG/LS996-SPRINT/LS996ZV9.rdf' => [ 'LG', 'G Flex 2', 'Android', DeviceType::MOBILE ],
2943
  'http://device.sprintpcs.com/LG/LS996-SPRINT/LS996ZVB.rdf' => [ 'LG', 'G Flex 2', 'Android', DeviceType::MOBILE ],
 
2944
  'http://gsm.lge.com/html/gsm/2D_2BD_BlBeXhXq5/H955-M3-D1.xml' => [ 'LG', 'G Flex 2', 'Android', DeviceType::MOBILE ],
2945
  'http://gsm.lge.com/html/gsm/2D_2BD_BlBeXhXq5/H955-M5-D1.xml' => [ 'LG', 'G Flex 2', 'Android', DeviceType::MOBILE ],
2946
  'http://gsm.lge.com/html/gsm/2D_2BD_BlBeXhXq5/H955-M6-D1.xml' => [ 'LG', 'G Flex 2', 'Android', DeviceType::MOBILE ],
@@ -2956,6 +2975,7 @@ DeviceProfiles::$PROFILES = [
2956
  'http://pix.cspire.com/UA/profile/lg/as995/as995.xml' => [ 'LG', 'G Flex 2', 'Android', DeviceType::MOBILE ],
2957
  'http://gsm.lge.com/html/gsm/V410-D1.xml' => [ 'LG', 'G Pad 7.0', 'Android', DeviceType::TABLET ],
2958
  'http://gsm.lge.com/html/gsm/V410-M10-D1.xml' => [ 'LG', 'G Pad 7.0', 'Android', DeviceType::TABLET ],
 
2959
  'http://gsm.lge.com/html/gsm/V410GO-D1.xml' => [ 'LG', 'G Pad 7.0', 'Android', DeviceType::TABLET ],
2960
  'http://gsm.lge.com/html/gsm/V490-M3-D1.xml' => [ 'LG', 'G Pad 7.0', 'Android', DeviceType::TABLET ],
2961
  'http://device.sprintpcs.com/LG/LK430-Chameleon/latest' => [ 'LG', 'G Pad F 7.0', 'Android', DeviceType::TABLET ],
@@ -2965,6 +2985,7 @@ DeviceProfiles::$PROFILES = [
2965
  'http://device.sprintpcs.com/LG/LK430-SPRINT/LK430ZV6.rdf' => [ 'LG', 'G Pad F 7.0', 'Android', DeviceType::TABLET ],
2966
  'http://device.sprintpcs.com/LG/LK430-SPRINT/LK430ZV7.rdf' => [ 'LG', 'G Pad F 7.0', 'Android', DeviceType::TABLET ],
2967
  'http://gsm.lge.com/html/gsm/iBpgg_0u_ASxAV_F/V495-D1.xml' => [ 'LG', 'G Pad F 7.0', 'Android', DeviceType::TABLET ],
 
2968
  'http://gsm.lge.com/html/gsm/rGTs_Yxuw5wT0ZyW/V495-D1.xml' => [ 'LG', 'G Pad F 8.0', 'Android', DeviceType::TABLET ],
2969
  'http://gsm.lge.com/html/gsm/TksSP_-GkCHZ7K__/V930-D1.xml' => [ 'LG', 'G Pad X 10.1', 'Android', DeviceType::TABLET ],
2970
  'http://gsm.lge.com/html/gsm/_-0_bP_4P_s73ov-/V930-D1.xml' => [ 'LG', 'G Pad X 10.1', 'Android', DeviceType::TABLET ],
@@ -3014,6 +3035,7 @@ DeviceProfiles::$PROFILES = [
3014
  'http://device.sprintpcs.com/LG/LS770-VIRGIN/LS770ZVA.rdf' => [ 'LG', 'G Stylo', 'Android', DeviceType::MOBILE ],
3015
  'http://device.sprintpcs.com/LG/LS770-VIRGIN/LS770ZVB.rdf' => [ 'LG', 'G Stylo', 'Android', DeviceType::MOBILE ],
3016
  'http://gsm.lge.com/html/gsm/5uyruBAm__1ZuYMa/H631-M10-D1.xml' => [ 'LG', 'G Stylo', 'Android', DeviceType::MOBILE ],
 
3017
  'http://gsm.lge.com/html/gsm/b7_gceeg_u9fMBZq/H635-M5-D1.xml' => [ 'LG', 'G Stylo', 'Android', DeviceType::MOBILE ],
3018
  'http://gsm.lge.com/html/gsm/b7_gceeg_u9fMBZq/H635-M6-D1.xml' => [ 'LG', 'G Stylo', 'Android', DeviceType::MOBILE ],
3019
  'http://gsm.lge.com/html/gsm/b7_gceeg_u9fMBZq/H636-M10-D1.xml' => [ 'LG', 'G Stylo', 'Android', DeviceType::MOBILE ],
@@ -3179,6 +3201,7 @@ DeviceProfiles::$PROFILES = [
3179
  'http://gsm.lge.com/html/gsm/HD_8T0W9FihEqY5S/D727-M10-D1.xml' => [ 'LG', 'G3 Beat', 'Android', DeviceType::MOBILE ],
3180
  'http://nmsc.ctvap.cn/uaprof/LG/LG_LG-D729_2_20140627.xml' => [ 'LG', 'G3 Beat', 'Android', DeviceType::MOBILE ],
3181
  'http://gsm.lge.com/html/gsm/F460K-M10-D1.xml' => [ 'LG', 'G3 Cat.6', 'Android', DeviceType::MOBILE ],
 
3182
  'http://gsm.lge.com/html/gsm/F460S-M10-D1.xml' => [ 'LG', 'G3 Cat.6', 'Android', DeviceType::MOBILE ],
3183
  'http://device.sprintpcs.com/LG/LS885-Chameleon/latest' => [ 'LG', 'G3 mini', 'Android', DeviceType::MOBILE ],
3184
  'http://device.sprintpcs.com/LG/LS885-SPRINT/LS885ZV4.rdf' => [ 'LG', 'G3 mini', 'Android', DeviceType::MOBILE ],
@@ -3201,6 +3224,7 @@ DeviceProfiles::$PROFILES = [
3201
  'http://gsm.lge.com/html/gsm/D693-M3-D1.xml' => [ 'LG', 'G3 Stylus', 'Android', DeviceType::MOBILE ],
3202
  'http://gsm.lge.com/html/gsm/D693n-M10-D1.xml' => [ 'LG', 'G3 Stylus', 'Android', DeviceType::MOBILE ],
3203
  'http://gsm.lge.com/html/gsm/D693n-M3-D1.xml' => [ 'LG', 'G3 Stylus', 'Android', DeviceType::MOBILE ],
 
3204
  'http://gsm.lge.com/html/gsm/D693TR-M5-D1.xml' => [ 'LG', 'G3 Stylus', 'Android', DeviceType::MOBILE ],
3205
  'http://gsm.lge.com/html/gsm/RNTp_ElEPgL_QrBQ/D690-M3-D1.xml' => [ 'LG', 'G3 Stylus', 'Android', DeviceType::MOBILE ],
3206
  'http://device.sprintpcs.com/LG/LS885-SPRINT/LS885ZV6.rdf' => [ 'LG', 'G3 Vigor', 'Android', DeviceType::MOBILE ],
@@ -3214,6 +3238,7 @@ DeviceProfiles::$PROFILES = [
3214
  'http://gsm.lge.com/html/gsm/YSdHbanpHC5h2R_E/H810-M10-D1.xml' => [ 'LG', 'G4', 'Android', DeviceType::MOBILE ],
3215
  'http://gsm.lge.com/html/gsm/YSdHbanpHC5h2R_E/H810-M3-D1.xml' => [ 'LG', 'G4', 'Android', DeviceType::MOBILE ],
3216
  'http://gsm.lge.com/html/gsm/YSdHbanpHC5h2R_E/H811-M10-D1.xml' => [ 'LG', 'G4', 'Android', DeviceType::MOBILE ],
 
3217
  'http://gsm.lge.com/html/gsm/YSdHbanpHC5h2R_E/H812-M10-D1.xml' => [ 'LG', 'G4', 'Android', DeviceType::MOBILE ],
3218
  'http://gsm.lge.com/html/gsm/YSdHbanpHC5h2R_E/H815-M10-D1.xml' => [ 'LG', 'G4', 'Android', DeviceType::MOBILE ],
3219
  'http://gsm.lge.com/html/gsm/YSdHbanpHC5h2R_E/H815-M20-D1.xml' => [ 'LG', 'G4', 'Android', DeviceType::MOBILE ],
@@ -3387,6 +3412,7 @@ DeviceProfiles::$PROFILES = [
3387
  'http://gsm.lge.com/html/gsm/D335-M3-D1.xml' => [ 'LG', 'L Bello', 'Android', DeviceType::MOBILE ],
3388
  'http://gsm.lge.com/html/gsm/D337-M3-D1.xml' => [ 'LG', 'L Bello', 'Android', DeviceType::MOBILE ],
3389
  'http://gsm.lge.com/html/gsm/RNTp_ElEPgL_QrBQ/D335-M3-D1.xml' => [ 'LG', 'L Bello', 'Android', DeviceType::MOBILE ],
 
3390
  'http://gsm.lge.com/html/gsm/U_EOJw1JxwmQJceD/31-M10-D1.xml' => [ 'LG', 'L Bello', 'Android', DeviceType::MOBILE ],
3391
  'http://gsm.lge.com/html/gsm/U_EOJw1JxwmQJceD/D331-M5-D1.xml' => [ 'LG', 'L Bello', 'Android', DeviceType::MOBILE ],
3392
  'http://gsm.lge.com/html/gsm/U_EOJw1JxwmQJceD/D335-M3-D1.xml' => [ 'LG', 'L Bello', 'Android', DeviceType::MOBILE ],
@@ -3980,6 +4006,7 @@ DeviceProfiles::$PROFILES = [
3980
  'http://gsm.lge.com/html/gsm/LG-U830.xml' => [ 'LG', 'U830 Chocolate', null, DeviceType::MOBILE ],
3981
  'http://gsm.lge.com/html/gsm/LG-U900.xml' => [ 'LG', 'U900', null, DeviceType::MOBILE ],
3982
  'http://gsm.lge.com/html/gsm/LG-U970.xml' => [ 'LG', 'U970 Shine', null, DeviceType::MOBILE ],
 
3983
  'http://gsm.lge.com/html/gsm/eNsCGw_apwMhnXPM/H960-M10-D1.xml' => [ 'LG', 'V10', 'Android', DeviceType::MOBILE ],
3984
  'http://gsm.lge.com/html/gsm/eNsCGw_apwMhnXPM/H960-M3-D1.xml' => [ 'LG', 'V10', 'Android', DeviceType::MOBILE ],
3985
  'http://gsm.lge.com/html/gsm/eNsCGw_apwMhnXPM/H961N-M3-D1.xml' => [ 'LG', 'V10', 'Android', DeviceType::MOBILE ],
@@ -4404,10 +4431,12 @@ DeviceProfiles::$PROFILES = [
4404
  'http://nds1.nds.nokia.com/uaprof/Nokia210.2r100.xml' => [ 'Nokia', '210', 'Series40', DeviceType::MOBILE ],
4405
  'http://nds1.nds.nokia.com/uaprof/Nokia220r100.xml' => [ 'Nokia', '220', 'Series30', DeviceType::MOBILE ],
4406
  'http://nds1.nds.nokia.com/uaprof/Nokia225r100.xml' => [ 'Nokia', '225', 'Series30', DeviceType::MOBILE ],
 
4407
  'http://nds1.nds.nokia.com/uaprof/N2322cr100.xml' => [ 'Nokia', '2322 classic', 'Series40', DeviceType::MOBILE ],
4408
  'http://nds1.nds.nokia.com/uaprof/N2600c-2r100.xml' => [ 'Nokia', '2600 classic', 'Series40', DeviceType::MOBILE ],
4409
  'http://nds1.nds.nokia.com/uaprof/N2600cr100.xml' => [ 'Nokia', '2600 classic', 'Series40', DeviceType::MOBILE ],
4410
  'http://nds.nokia.com/uaprof/N2610r100.xml' => [ 'Nokia', '2610', 'Series40', DeviceType::MOBILE ],
 
4411
  'http://nds.nokia.com/uaprof/N2626r100.xml' => [ 'Nokia', '2626', 'Series40', DeviceType::MOBILE ],
4412
  'http://nds1.nds.nokia.com/uaprof/N2626r100.xml' => [ 'Nokia', '2626', null, DeviceType::MOBILE ],
4413
  'http://nds.nokia.com/uaprof/N2630r100.xml' => [ 'Nokia', '2630', 'Series40', DeviceType::MOBILE ],
@@ -4468,6 +4497,7 @@ DeviceProfiles::$PROFILES = [
4468
  'http://nds.nokia.com/uaprof/N3300r100.xml' => [ 'Nokia', '3300', 'Series40', DeviceType::MOBILE ],
4469
  'http://nds.nokia.com/uaprof/N3300r200.xml' => [ 'Nokia', '3300', 'Series40', DeviceType::MOBILE ],
4470
  'http://useragentprofile.hmdglobal.com/uaprof/Nokia3310r100.xml' => [ 'Nokia', '3310 (2017)', null, DeviceType::MOBILE ],
 
4471
  'http://nds.nokia.com/uaprof/N3330r100.xml' => [ 'Nokia', '3330', null, DeviceType::MOBILE ],
4472
  'http://nds.nokia.com/uaprof/N3350r100.xml' => [ 'Nokia', '3350', null, DeviceType::MOBILE ],
4473
  'http://nds.nokia.com/uaprof/N3360r100.xml' => [ 'Nokia', '3360', null, DeviceType::MOBILE ],
@@ -4971,6 +5001,7 @@ DeviceProfiles::$PROFILES = [
4971
  'http://nds.nokia.com/uaprof/N8801r301.xml' => [ 'Nokia', '8801', 'Series40', DeviceType::MOBILE ],
4972
  'http://nds.nokia.com/uaprof/N8801r400.xml' => [ 'Nokia', '8801', 'Series40', DeviceType::MOBILE ],
4973
  'http://nds.nokia.com/uaprof/N8801r401.xml' => [ 'Nokia', '8801', 'Series40', DeviceType::MOBILE ],
 
4974
  'http://nds.nokia.com/uaprof/N8910r100.xml' => [ 'Nokia', '8910', null, DeviceType::MOBILE ],
4975
  'http://nds.nokia.com/uaprof/N8910ir100.xml' => [ 'Nokia', '8910i', null, DeviceType::MOBILE ],
4976
  'http://nds.nokia.com/uaprof/N9110r100.xml' => [ 'Nokia', '9110 Communicator', 'GOES', DeviceType::MOBILE ],
@@ -5354,6 +5385,7 @@ DeviceProfiles::$PROFILES = [
5354
  'http://ua.prof.oppo.com/resource/ua-PROF/OPPON1.xml' => [ 'Oppo', 'N1', 'Android', DeviceType::MOBILE ],
5355
  'http://ua.prof.oppo.com/resource/ua-PROF/OPPON5111.xml' => [ 'Oppo', 'N1 mini', 'Android', DeviceType::MOBILE ],
5356
  'http://ua.prof.oppo.com/resource/ua-PROF/OPPON5116.xml' => [ 'Oppo', 'N1 mini', 'Android', DeviceType::MOBILE ],
 
5357
  'http://www.oppo.com/resource/UA-PROF/OPPON5117.xml' => [ 'Oppo', 'N1 mini', 'Android', DeviceType::MOBILE ],
5358
  'http://www.oppo.com/resource/UA-PROF/OPPON5207.xml' => [ 'Oppo', 'N3', 'Android', DeviceType::MOBILE ],
5359
  'http://www.oppo.com/resource/UA-PROF/OPPON5209.xml' => [ 'Oppo', 'N3', 'Android', DeviceType::MOBILE ],
@@ -5768,6 +5800,7 @@ DeviceProfiles::$PROFILES = [
5768
  'http://www.blackberry.net/go/mobile/profiles/uaprof/8820/4.5.0.rdf' => [ 'RIM', 'BlackBerry 8820', 'BlackBerry OS', DeviceType::MOBILE ],
5769
  'http://www.blackberry.net/go/mobile/profiles/uaprof/8830/4.2.2.rdf' => [ 'RIM', 'BlackBerry 8830', 'BlackBerry OS', DeviceType::MOBILE ],
5770
  'http://www.blackberry.net/go/mobile/profiles/uaprof/9315_edge/7.1.0.rdf' => [ 'RIM', 'BlackBerry 9315', 'BlackBerry OS', DeviceType::MOBILE ],
 
5771
  'http://www.blackberry.net/go/mobile/profiles/uaprof/9620_80211g/7.1.0.rdf' => [ 'RIM', 'BlackBerry 9620', 'BlackBerry OS', DeviceType::MOBILE ],
5772
  'http://www.blackberry.net/go/mobile/profiles/uaprof/9620_edge/7.1.0.rdf' => [ 'RIM', 'BlackBerry 9620', 'BlackBerry OS', DeviceType::MOBILE ],
5773
  'http://www.blackberry.net/go/mobile/profiles/uaprof/9620_umts/7.1.0.rdf' => [ 'RIM', 'BlackBerry 9620', 'BlackBerry OS', DeviceType::MOBILE ],
@@ -6190,6 +6223,7 @@ DeviceProfiles::$PROFILES = [
6190
  'http://wap.samsungmobile.com/uaprof/GT-B5310.rdf' => [ 'Samsung', 'Corby Pro', 'Touchwiz', DeviceType::MOBILE ],
6191
  'http://wap.samsungmobile.com/uaprof/GT-B5310_3G.rdf' => [ 'Samsung', 'Corby Pro', 'Touchwiz', DeviceType::MOBILE ],
6192
  'http://wap.samsungmobile.com/uaprof/GT-B3210UAProf.xml' => [ 'Samsung', 'Corby TXT', null, DeviceType::MOBILE ],
 
6193
  'http://wap.samsungmobile.com/uaprof/SGH-T499.xml' => [ 'Samsung', 'Dart', 'Android', DeviceType::MOBILE ],
6194
  'http://wap.samsungmobile.com/uaprof/SGH-I857.xml' => [ 'Samsung', 'DoubleTime', 'Android', DeviceType::MOBILE ],
6195
  'http://wap.samsungmobile.com/uaprof/GT-I6712BR.xml' => [ 'Samsung', 'Duos TV', 'Touchwiz', DeviceType::MOBILE ],
@@ -6363,6 +6397,7 @@ DeviceProfiles::$PROFILES = [
6363
  'http://wap.samsungmobile.com/uaprof/SM-G350.xml' => [ 'Samsung', 'Galaxy Core Plus', 'Android', DeviceType::MOBILE ],
6364
  'http://wap.samsungmobile.com/uaprof/SM-G350BO.xml' => [ 'Samsung', 'Galaxy Core Plus', 'Android', DeviceType::MOBILE ],
6365
  'http://wap.samsungmobile.com/uaprof/SM-G350L.xml' => [ 'Samsung', 'Galaxy Core Plus', 'Android', DeviceType::MOBILE ],
 
6366
  'http://device.sprintpcs.com/Samsung/SM-G360P-2012071301/NL8.rdf' => [ 'Samsung', 'Galaxy Core Prime', 'Android', DeviceType::MOBILE ],
6367
  'http://device.sprintpcs.com/Samsung/SM-G360P-2012071301/OH1.rdf' => [ 'Samsung', 'Galaxy Core Prime', 'Android', DeviceType::MOBILE ],
6368
  'http://device.sprintpcs.com/Samsung/SM-G360P-BOOST/NL8.rdf' => [ 'Samsung', 'Galaxy Core Prime', 'Android', DeviceType::MOBILE ],
@@ -6450,6 +6485,7 @@ DeviceProfiles::$PROFILES = [
6450
  'http://wap.samsungmobile.com/uaprof/GT-I9060L.xml' => [ 'Samsung', 'Galaxy Grand Neo', 'Android', DeviceType::MOBILE ],
6451
  'http://wap.samsungmobile.com/uaprof/GT-I9060M.xml' => [ 'Samsung', 'Galaxy Grand Neo', 'Android', DeviceType::MOBILE ],
6452
  'http://wap.samsungmobile.com/uaprof/GT-I9063T.xml' => [ 'Samsung', 'Galaxy Grand Neo Duos', 'Android', DeviceType::MOBILE ],
 
6453
  'http://device.sprintpcs.com/Samsung/SM-G530P-SPRINT/OF8.rdf' => [ 'Samsung', 'Galaxy Grand Prime', 'Android', DeviceType::MOBILE ],
6454
  'http://device.sprintpcs.com/Samsung/SM-G530P-SPRINT/OG2.rdf' => [ 'Samsung', 'Galaxy Grand Prime', 'Android', DeviceType::MOBILE ],
6455
  'http://device.sprintpcs.com/Samsung/SM-G530P-SPRINT/OI1.rdf' => [ 'Samsung', 'Galaxy Grand Prime', 'Android', DeviceType::MOBILE ],
@@ -6506,6 +6542,7 @@ DeviceProfiles::$PROFILES = [
6506
  'http://device.sprintpcs.com/Samsung/SM-J320P-BOOST/PK2.rdf' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
6507
  'http://device.sprintpcs.com/Samsung/SM-J320P-BOOST/QD2.rdf' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
6508
  'http://device.sprintpcs.com/Samsung/SM-J320P-BOOST/QG3.rdf' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
 
6509
  'http://device.sprintpcs.com/Samsung/SM-J320P-Chameleon/latest' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
6510
  'http://device.sprintpcs.com/Samsung/SM-J320P-SPRINT/OL2.rdf' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
6511
  'http://device.sprintpcs.com/Samsung/SM-J320P-SPRINT/PE1.rdf' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
@@ -6513,6 +6550,7 @@ DeviceProfiles::$PROFILES = [
6513
  'http://device.sprintpcs.com/Samsung/SM-J320P-SPRINT/PK2.rdf' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
6514
  'http://device.sprintpcs.com/Samsung/SM-J320P-SPRINT/QD2.rdf' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
6515
  'http://device.sprintpcs.com/Samsung/SM-J320P-SPRINT/QG3.rdf' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
 
6516
  'http://device.sprintpcs.com/Samsung/SM-J320P-VIRGIN/OL2.rdf' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
6517
  'http://device.sprintpcs.com/Samsung/SM-J320P-VIRGIN/PK2.rdf' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
6518
  'http://device.sprintpcs.com/Samsung/SM-J320P-VIRGIN/QG3.rdf' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
@@ -6527,11 +6565,17 @@ DeviceProfiles::$PROFILES = [
6527
  'http://device.sprintpcs.com/Samsung/SM-J327P-BOOST/PL1.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
6528
  'http://device.sprintpcs.com/Samsung/SM-J327P-BOOST/QB6.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
6529
  'http://device.sprintpcs.com/Samsung/SM-J327P-BOOST/QF4.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
 
 
 
 
6530
  'http://device.sprintpcs.com/Samsung/SM-J327P-SPRINT/PL1.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
6531
  'http://device.sprintpcs.com/Samsung/SM-J327P-SPRINT/QB6.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
6532
  'http://device.sprintpcs.com/Samsung/SM-J327P-SPRINT/QF4.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
6533
  'http://device.sprintpcs.com/Samsung/SM-J327P-SPRINT/QI2.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
6534
  'http://device.sprintpcs.com/Samsung/SM-J327P-SPRINT/QJ3.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
 
 
6535
  'http://device.sprintpcs.com/Samsung/SM-J327P-VIRGIN/QB6.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
6536
  'http://device.sprintpcs.com/Samsung/SM-J327P-VIRGIN/QF4.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
6537
  'http://wap.samsungmobile.com/uaprof/SM-J500F.xml' => [ 'Samsung', 'Galaxy J5', 'Android', DeviceType::MOBILE ],
@@ -6561,6 +6605,7 @@ DeviceProfiles::$PROFILES = [
6561
  'http://wap.samsungmobile.com/uaprof/SM-J710FPTR.xml' => [ 'Samsung', 'Galaxy J7 (2016)', 'Android', DeviceType::MOBILE ],
6562
  'http://wap.samsungmobile.com/uaprof/SM-J710GN.xml' => [ 'Samsung', 'Galaxy J7 (2016)', 'Android', DeviceType::MOBILE ],
6563
  'http://device.sprintpcs.com/Samsung/SM-J727P-BOOST/QF5.rdf' => [ 'Samsung', 'Galaxy J7 Perx', 'Android', DeviceType::MOBILE ],
 
6564
  'http://wap.samsungmobile.com/uaprof/SM-G610F.xml' => [ 'Samsung', 'Galaxy J7 Prime', 'Android', DeviceType::MOBILE ],
6565
  'http://wap.samsungmobile.com/uaprof/SM-G610Y.xml' => [ 'Samsung', 'Galaxy J7 Prime', 'Android', DeviceType::MOBILE ],
6566
  'http://wap.samsungmobile.com/uaprof/SGH-N075T.xml' => [ 'Samsung', 'GALAXY J SC-02F', 'Android', DeviceType::MOBILE ],
@@ -6578,6 +6623,7 @@ DeviceProfiles::$PROFILES = [
6578
  'http://nmsc.ctvap.cn/uaprof/SCH/SCH_SCH-P709E_1_20140113.xml' => [ 'Samsung', 'Galaxy Mega 5.8', 'Android', DeviceType::MOBILE ],
6579
  'http://wap.samsungmobile.com/uaprof/GT-I9150.xml' => [ 'Samsung', 'Galaxy Mega 5.8', 'Android', DeviceType::MOBILE ],
6580
  'http://wap.samsungmobile.com/uaprof/GT-I9152.xml' => [ 'Samsung', 'Galaxy Mega 5.8 Duos', 'Android', DeviceType::MOBILE ],
 
6581
  'http://device.sprintpcs.com/Samsung/SPH-L600-SPRINT/MI6.rdf' => [ 'Samsung', 'Galaxy Mega 6.3', 'Android', DeviceType::MOBILE ],
6582
  'http://device.sprintpcs.com/Samsung/SPH-L600-SPRINT/MK1.rdf' => [ 'Samsung', 'Galaxy Mega 6.3', 'Android', DeviceType::MOBILE ],
6583
  'http://device.sprintpcs.com/Samsung/SPH-L600-SPRINT/NA7.rdf' => [ 'Samsung', 'Galaxy Mega 6.3', 'Android', DeviceType::MOBILE ],
@@ -6660,6 +6706,7 @@ DeviceProfiles::$PROFILES = [
6660
  'http://device.sprintpcs.com/Samsung/SM-N900P-SPRINT/OK2.rdf' => [ 'Samsung', 'Galaxy Note 3', 'Android', DeviceType::MOBILE ],
6661
  'http://device.sprintpcs.com/Samsung/SM-N900P-SPRINT/PH1.rdf' => [ 'Samsung', 'Galaxy Note 3', 'Android', DeviceType::MOBILE ],
6662
  'http://device.sprintpcs.com/Samsung/SM-N900P-SPRINT/PL1.rdf' => [ 'Samsung', 'Galaxy Note 3', 'Android', DeviceType::MOBILE ],
 
6663
  'http://nmsc.ctvap.cn/uaprof/SCH/SCH_SM-N9009_2_20130829.xml' => [ 'Samsung', 'Galaxy Note 3', 'Android', DeviceType::MOBILE ],
6664
  'http://wap.samsungmobile.com/uaprof/SAMSUNG-SM-N900A.xml' => [ 'Samsung', 'Galaxy Note 3', 'Android', DeviceType::MOBILE ],
6665
  'http://wap.samsungmobile.com/uaprof/SM-N900.xml' => [ 'Samsung', 'Galaxy Note 3', 'Android', DeviceType::MOBILE ],
@@ -6708,6 +6755,7 @@ DeviceProfiles::$PROFILES = [
6708
  'http://wap.samsungmobile.com/uaprof/SM-N9106W.xml' => [ 'Samsung', 'Galaxy Note 4', 'Android', DeviceType::MOBILE ],
6709
  'http://wap.samsungmobile.com/uaprof/SM-N910A.xml' => [ 'Samsung', 'Galaxy Note 4', 'Android', DeviceType::MOBILE ],
6710
  'http://wap.samsungmobile.com/uaprof/SM-N910C.xml' => [ 'Samsung', 'Galaxy Note 4', 'Android', DeviceType::MOBILE ],
 
6711
  'http://wap.samsungmobile.com/uaprof/SM-N910F.xml' => [ 'Samsung', 'Galaxy Note 4', 'Android', DeviceType::MOBILE ],
6712
  'http://wap.samsungmobile.com/uaprof/SM-N910FPTR.xml' => [ 'Samsung', 'Galaxy Note 4', 'Android', DeviceType::MOBILE ],
6713
  'http://wap.samsungmobile.com/uaprof/SM-N910G.xml' => [ 'Samsung', 'Galaxy Note 4', 'Android', DeviceType::MOBILE ],
@@ -7086,6 +7134,7 @@ DeviceProfiles::$PROFILES = [
7086
  'http://device.sprintpcs.com/Samsung/SPH-L720-2011011301/OD2.rdf' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
7087
  'http://device.sprintpcs.com/Samsung/SPH-L720-2011011301/OH1.rdf' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
7088
  'http://device.sprintpcs.com/Samsung/SPH-L720-2012083001/NG2.rdf' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
 
7089
  'http://device.sprintpcs.com/Samsung/SPH-L720-500002419/NAE.rdf' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
7090
  'http://device.sprintpcs.com/Samsung/SPH-L720-Chameleon/latest' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
7091
  'http://device.sprintpcs.com/Samsung/SPH-L720-Chameleon/MCI.rdf' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
@@ -7108,6 +7157,7 @@ DeviceProfiles::$PROFILES = [
7108
  'http://device.sprintpcs.com/Samsung/SPH-L720-SPRINT/PI2.rdf' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
7109
  'http://device.sprintpcs.com/Samsung/SPH-L720-SPRINT/PL1.rdf' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
7110
  'http://device.sprintpcs.com/Samsung/SPH-L720T-BOOST/OK3.rdf' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
 
7111
  'http://device.sprintpcs.com/Samsung/SPH-L720T-Chameleon/latest' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
7112
  'http://device.sprintpcs.com/Samsung/SPH-L720T-Chameleon/NG5.rdf' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
7113
  'http://device.sprintpcs.com/Samsung/SPH-L720T-MVNO/NC6.rdf' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
@@ -7398,6 +7448,7 @@ DeviceProfiles::$PROFILES = [
7398
  'http://device.sprintpcs.com/Samsung/SM-G930P-SPRINT/QAA.rdf' => [ 'Samsung', 'Galaxy S7', 'Android', DeviceType::MOBILE ],
7399
  'http://device.sprintpcs.com/Samsung/SM-G930P-SPRINT/QC1.rdf' => [ 'Samsung', 'Galaxy S7', 'Android', DeviceType::MOBILE ],
7400
  'http://device.sprintpcs.com/Samsung/SM-G930P-SPRINT/QD2.rdf' => [ 'Samsung', 'Galaxy S7', 'Android', DeviceType::MOBILE ],
 
7401
  'http://wap.samsungmobile.com/uaprof/SM-G930F.xml' => [ 'Samsung', 'Galaxy S7', 'Android', DeviceType::MOBILE ],
7402
  'http://device.sprintpcs.com/Samsung/SM-G935P-Chameleon/latest' => [ 'Samsung', 'Galaxy S7 Edge', 'Android', DeviceType::MOBILE ],
7403
  'http://device.sprintpcs.com/Samsung/SM-G935P-SPRINT/PB5.rdf' => [ 'Samsung', 'Galaxy S7 Edge', 'Android', DeviceType::MOBILE ],
@@ -7456,6 +7507,7 @@ DeviceProfiles::$PROFILES = [
7456
  'http://wap.samsungmobile.com/uaprof/GT-P3110.xml' => [ 'Samsung', 'Galaxy Tab 2 (7.0)', 'Android', DeviceType::TABLET ],
7457
  'http://device.sprintpcs.com/Samsung/SPH-P500/LI6.rdf' => [ 'Samsung', 'Galaxy Tab 2 10.1', 'Android', DeviceType::TABLET ],
7458
  'http://device.sprintpcs.com/Samsung/SPH-P500/MB3.rdf' => [ 'Samsung', 'Galaxy Tab 2 10.1', 'Android', DeviceType::TABLET ],
 
7459
  'http://wap.samsungmobile.com/uaprof/GT-P5200.xml' => [ 'Samsung', 'Galaxy Tab 3 (10.1)', 'Android', DeviceType::TABLET ],
7460
  'http://wap.samsungmobile.com/uaprof/GT-P5210.xml' => [ 'Samsung', 'Galaxy Tab 3 (10.1)', 'Android', DeviceType::TABLET ],
7461
  'http://wap.samsungmobile.com/uaprof/GT-P5220.xml' => [ 'Samsung', 'Galaxy Tab 3 (10.1)', 'Android', DeviceType::TABLET ],
@@ -7566,6 +7618,7 @@ DeviceProfiles::$PROFILES = [
7566
  'http://wap.samsungmobile.com/uaprof/SM-T325.xml' => [ 'Samsung', 'Galaxy Tab Pro 8.4', 'Android', DeviceType::TABLET ],
7567
  'http://nmsc.ctvap.cn/uaprof/SCH/SCH_SM-T2519_1_20140428.xml' => [ 'Samsung', 'Galaxy Tab Q', 'Android', DeviceType::MOBILE ],
7568
  'http://device.sprintpcs.com/Samsung/SM-T807P-Chameleon/latest' => [ 'Samsung', 'Galaxy Tab S 10.5', 'Android', DeviceType::TABLET ],
 
7569
  'http://device.sprintpcs.com/Samsung/SM-T807P-SPRINT/NK1.rdf' => [ 'Samsung', 'Galaxy Tab S 10.5', 'Android', DeviceType::TABLET ],
7570
  'http://device.sprintpcs.com/Samsung/SM-T807P-SPRINT/OH1.rdf' => [ 'Samsung', 'Galaxy Tab S 10.5', 'Android', DeviceType::TABLET ],
7571
  'http://device.sprintpcs.com/Samsung/SM-T807P-SPRINT/OJ4.rdf' => [ 'Samsung', 'Galaxy Tab S 10.5', 'Android', DeviceType::TABLET ],
@@ -7729,6 +7782,7 @@ DeviceProfiles::$PROFILES = [
7729
  'http://wap.samsungmobile.com/uaprof/GT-C5510UAProf.xml' => [ 'Samsung', 'GT-C5510', null, DeviceType::MOBILE ],
7730
  'http://wap.samsungmobile.com/uaprof/GT-C5510UAProf3G.xml' => [ 'Samsung', 'GT-C5510', null, DeviceType::MOBILE ],
7731
  'http://wap.samsungmobile.com/uaprof/GT-E2152.xml' => [ 'Samsung', 'GT-E2152 Duos', null, DeviceType::MOBILE ],
 
7732
  'http://wap.samsungmobile.com/uaprof/GT-E2200.xml' => [ 'Samsung', 'GT-E2200', null, DeviceType::MOBILE ],
7733
  'http://wap.samsungmobile.com/uaprof/GT-E2230UAProf.xml' => [ 'Samsung', 'GT-E2230', null, DeviceType::MOBILE ],
7734
  'http://wap.samsungmobile.com/uaprof/GT-E2232UAProf.xml' => [ 'Samsung', 'GT-E2232', null, DeviceType::MOBILE ],
@@ -8827,6 +8881,7 @@ DeviceProfiles::$PROFILES = [
8827
  'http://uaprof.sonymobile.com/SGP341R1005.xml' => [ 'Sony', 'Xperia Tablet Z', 'Android', DeviceType::TABLET ],
8828
  'http://uaprof.sonymobile.com/SGP351R1002.xml' => [ 'Sony', 'Xperia Tablet Z', 'Android', DeviceType::TABLET ],
8829
  'http://uaprof.sonymobile.com/SO-03ER1002.xml' => [ 'Sony', 'Xperia Tablet Z', 'Android', DeviceType::TABLET ],
 
8830
  'http://uaprof.sonymobile.com/SGP412R1421.xml' => [ 'Sony', 'Xperia Tablet Z Ultra', 'Android', DeviceType::TABLET ],
8831
  'http://uaprof.sonymobile.com/SGP511R1701.xml' => [ 'Sony', 'Xperia Tablet Z2', 'Android', DeviceType::TABLET ],
8832
  'http://uaprof.sonymobile.com/SGP512R1701.xml' => [ 'Sony', 'Xperia Tablet Z2', 'Android', DeviceType::TABLET ],
@@ -9699,6 +9754,7 @@ DeviceProfiles::$PROFILES = [
9699
  'http://www.zte.com.cn/mobile/uaprof/ZTE_Kis3_max.xml' => [ 'ZTE', 'Kis 3 Max', 'Android', DeviceType::MOBILE ],
9700
  'http://www.zte.com.cn/mobile/uaprof/ZTE KIS LITE.xml' => [ 'ZTE', 'Kis Lite', 'Android', DeviceType::MOBILE ],
9701
  'http://www.zte.com.cn/mobile/uaprof/ZTE-KisPro.xml' => [ 'ZTE', 'Kis Pro', 'Android', DeviceType::MOBILE ],
 
9702
  'http://www.ztemt.com/mobile/uaprof/ZTE_LEO_M1.xml' => [ 'ZTE', 'LEO M1', 'Android', DeviceType::MOBILE ],
9703
  'http://www.zte.com.cn/mobile/uaprof/ZTE_V765M.xml' => [ 'ZTE', 'LEO Q1', 'Android', DeviceType::MOBILE ],
9704
  'http://www.ztemt.com/mobile/uaprof/V769M.xml' => [ 'ZTE', 'LEO Q2', 'Android', DeviceType::MOBILE ],
220
  'http://www-ccpp.tcl-ta.com/files/ALCATEL_ONETOUCH_Flash_Plus.xml' => [ 'Alcatel', 'One Touch Flash Plus', 'Android', DeviceType::MOBILE ],
221
  'http://www-ccpp.tcl-ta.com/files/7048A.xml' => [ 'Alcatel', 'One Touch Go Play', 'Android', DeviceType::MOBILE ],
222
  'http://www-ccpp.tcl-ta.com/files/7048X.xml' => [ 'Alcatel', 'One Touch Go Play', 'Android', DeviceType::MOBILE ],
223
+ 'http://www-ccpp.tcl-ta.com/files/ONE_TOUCH_8020A.xml' => [ 'Alcatel', 'One Touch Hero', 'Android', DeviceType::MOBILE ],
224
  'http://www-ccpp.tcl-ta.com/files/ONE_TOUCH_8020E.xml' => [ 'Alcatel', 'One Touch Hero', 'Android', DeviceType::MOBILE ],
225
  'http://www-ccpp.tcl-ta.com/files/7055A.xml' => [ 'Alcatel', 'One Touch Hero 2C', 'Android', DeviceType::MOBILE ],
226
  'http://www-ccpp.tcl-ta.com/files/ALCATEL_ONE_TOUCH_6030A.xml' => [ 'Alcatel', 'One Touch Idol', 'Android', DeviceType::MOBILE ],
419
  'http://www-ccpp.tcl-ta.com/files/ALCATEL_ONE_TOUCH_5035D.xml' => [ 'Alcatel', 'One Touch X\'Pop', 'Android', DeviceType::MOBILE ],
420
  'http://www-ccpp.tcl-ta.com/files/ALCATEL_ONE_TOUCH_5035E.xml' => [ 'Alcatel', 'One Touch X\'Pop', 'Android', DeviceType::MOBILE ],
421
  'http://www-ccpp.tcl-ta.com/files/ALCATEL_ONE_TOUCH_5035X.xml' => [ 'Alcatel', 'One Touch X\'Pop', 'Android', DeviceType::MOBILE ],
422
+ 'http://www-ccpp.tcl-ta.com/files/4044C.xml' => [ 'Alcatel', 'QUICKFLIP', 'KaiOS', DeviceType::MOBILE ],
423
  'http://www-ccpp.tcl-ta.com/files/ALCATEL_TRIBE_3075A.rdf' => [ 'Alcatel', 'Tribe 3075A', null, DeviceType::MOBILE ],
424
  'http://uaprof.vmobl.com/PCD/ADR2045-VMUB/1.0/UAProf.xml' => [ 'Alcatel', 'Venture', 'Android', DeviceType::MOBILE ],
425
  'http://pluto.alphacell.com/uaprof/m5p.xml' => [ 'AlphaCell', 'M5', null, DeviceType::MOBILE ],
747
  'http://wap.sonyericsson.com/UAprof/T68R503.xml' => [ 'Ericsson', 'T68', null, DeviceType::MOBILE ],
748
  'http://www.ztemt.com/mobile/uaprof/V6500_Etisalat_EG.xml' => [ 'Etisalat', 'Smartphone', 'Android', DeviceType::MOBILE ],
749
  'http://uaprof.qma.com.tw/BenQ-A3c.xml' => [ 'Ezcast', 'Dongle', 'Android', ],
750
+ 'http://mobiwire.com/uaprofile/Telekom_Austria_Group_FP1.xml' => [ 'Fairphone', '1', 'Android', DeviceType::MOBILE ],
751
  'http://www.msai.in/uaprof/Lava/Flair%20P2.xml' => [ 'Fairphone', '2', 'Android', DeviceType::MOBILE ],
752
  'http://www.c2dms.com/UAProfile/N26/FarEastone_Smart501.xml' => [ 'Fareastone', 'Smart 501', 'Android', DeviceType::MOBILE ],
753
  'http://www.wizdevice.com/support/rise/uaprof.xml' => [ 'Fareastone', 'Smart 701', 'Android', DeviceType::TABLET ],
1052
  'http://www.htcmms.com.tw/Android/Common/7QtMcMcyB2/ua-profile.xml' => [ 'HTC', 'Desire 816', 'Android', DeviceType::MOBILE ],
1053
  'http://www.htcmms.com.tw/Android/Common/geUXhkfboO/ua-profile.xml' => [ 'HTC', 'Desire 816', 'Android', DeviceType::MOBILE ],
1054
  'http://www.htcmms.com.tw/Android/Common/HRobRleNsO/ua-profile.xml' => [ 'HTC', 'Desire 816', 'Android', DeviceType::MOBILE ],
1055
+ 'http://www.htcmms.com.tw/Android/Common/Khlg9cPNZP/ua-profile.xml' => [ 'HTC', 'Desire 816', 'Android', DeviceType::MOBILE ],
1056
  'http://www.htcmms.com.tw/Android/Common/miKNCjjDHJ/ua-profile.xml' => [ 'HTC', 'Desire 816', 'Android', DeviceType::MOBILE ],
1057
  'http://www.htcmms.com.tw/Android/Common/rLgUe79qmx/ua-profile.xml' => [ 'HTC', 'Desire 816', 'Android', DeviceType::MOBILE ],
1058
  'http://www.htcmms.com.tw/Android/Common/rYMdtoVVAt/ua-profile.xml' => [ 'HTC', 'Desire 816', 'Android', DeviceType::MOBILE ],
1321
  'http://device.sprintpcs.com/HTC/2PQ93-SPRINT/1106511.rdf' => [ 'HTC', 'One (A9)', 'Android', DeviceType::MOBILE ],
1322
  'http://device.sprintpcs.com/HTC/2PQ93-SPRINT/1576511.rdf' => [ 'HTC', 'One (A9)', 'Android', DeviceType::MOBILE ],
1323
  'http://device.sprintpcs.com/HTC/2PQ93-SPRINT/1606514.rdf' => [ 'HTC', 'One (A9)', 'Android', DeviceType::MOBILE ],
1324
+ 'http://www.htcmms.com.tw/Android/Common/fJ1ZSlse0F/ua-profile.xml' => [ 'HTC', 'One (A9)', 'Android', DeviceType::MOBILE ],
1325
  'http://www.htcmms.com.tw/Android/Common/rjXLBq21RC/ua-profile.xml' => [ 'HTC', 'One (A9)', 'Android', DeviceType::MOBILE ],
1326
  'http://device.sprintpcs.com/HTC/0PAJ5-Chameleon/1116512.rdf' => [ 'HTC', 'One (E8)', 'Android', DeviceType::MOBILE ],
1327
  'http://device.sprintpcs.com/HTC/0PAJ5-Chameleon/1226511.rdf' => [ 'HTC', 'One (E8)', 'Android', DeviceType::MOBILE ],
1780
  'http://wap1.huawei.com/uaprof/HUAWEI_%s_UAProfile.xml' => [ 'Huawei', 'Ascend G7', 'Android', DeviceType::MOBILE ],
1781
  'http://wap1.huawei.com/uaprof/HUAWEI_G7-L01_OrangeUAProfile.xml' => [ 'Huawei', 'Ascend G7', 'Android', DeviceType::MOBILE ],
1782
  'http://wap1.huawei.com/uaprof/HUAWEI_G7-L01_UAProfile.xml' => [ 'Huawei', 'Ascend G7', 'Android', DeviceType::MOBILE ],
1783
+ 'http://wap1.huawei.com/uaprof/HUAWEI_G7-L02_UAProfile.xml' => [ 'Huawei', 'Ascend G7', 'Android', DeviceType::MOBILE ],
1784
  'http://wap1.huawei.com/uaprof/HUAWEI_G7-L03_DRMFL_UAProfile.xml' => [ 'Huawei', 'Ascend G7', 'Android', DeviceType::MOBILE ],
1785
  'http://wap1.huawei.com/uaprof/HUAWEI_G7-L03_UAProfile.xml' => [ 'Huawei', 'Ascend G7', 'Android', DeviceType::MOBILE ],
1786
  'http://wap1.huawei.com/uaprof/HUAWEI_G7-L11_UAProfile.xml' => [ 'Huawei', 'Ascend G7', 'Android', DeviceType::MOBILE ],
2087
  'http://wap1.huawei.com/uaprof/TIT-AL00C583_UAProfile.xml' => [ 'Huawei', 'Enjoy 5', 'Android', DeviceType::MOBILE ],
2088
  'http://wap1.huawei.com/uaprof/HUAWEI_TANGO_UAProfile.xml' => [ 'Huawei', 'Enjoy 5S', 'Android', DeviceType::MOBILE ],
2089
  'http://wap1.huawei.com/uaprof/HUAWEI_NCE-AL00_UAProfile.xml' => [ 'Huawei', 'Enjoy 6', 'Windows', DeviceType::MOBILE ],
2090
+ 'http://wap1.huawei.com/uaprof/HUAWEI_NCE-TL10_UAProfile.xml' => [ 'Huawei', 'Enjoy 6', 'Android', DeviceType::MOBILE ],
2091
  'http://wap1.huawei.com/uaprof/HUAWEI_SLA-TL10_UAProfile.xml' => [ 'Huawei', 'Enjoy 7', 'Android', DeviceType::MOBILE ],
2092
+ 'http://wap1.huawei.com/uaprof/HUAWEI_TRT-TL10A_UAProfile.xml' => [ 'Huawei', 'Enjoy 7 Plus', 'Android', DeviceType::MOBILE ],
2093
  'http://wap1.huawei.com/uaprof/HUAWEI_TRT-TL10_UAProfile.xml' => [ 'Huawei', 'Enjoy 7 Plus', 'Android', DeviceType::MOBILE ],
2094
  'http://wap1.huawei.com/uaprof/HW_HUAWEI_CM990_1_20130108.xml' => [ 'Huawei', 'Evolución 3', 'Android', DeviceType::MOBILE ],
2095
  'http://wap1.huawei.com/uaprof/HuaweiUM840v100GPRS.xml' => [ 'Huawei', 'Evolution', 'Android', DeviceType::MOBILE ],
2113
  'http://wap1.huawei.com/uaprof/HW_KII-L23_DRM_UAProfile.xml' => [ 'Huawei', 'GR5', 'Android', DeviceType::MOBILE ],
2114
  'http://wap1.huawei.com/uaprof/HW_KII-L23_UAProfile.xml' => [ 'Huawei', 'GR5', 'Android', DeviceType::MOBILE ],
2115
  'http://wap1.huawei.com/uaprof/HW_KII-L23_UAProfile_FL_Only.xml' => [ 'Huawei', 'GR5', 'Android', DeviceType::MOBILE ],
2116
+ 'http://wap1.huawei.com/uaprof/HW_KII-L23_UA_DRM_FL_Profile.xml' => [ 'Huawei', 'GR5', 'Android', DeviceType::MOBILE ],
2117
  'http://wap1.huawei.com/uaprof/HW_HUAWEI_H870C.xml' => [ 'Huawei', 'H870C', 'Android', DeviceType::MOBILE ],
2118
  'http://wap1.huawei.com/uaprof/HuaweiU8860-51GPRS-Normal.xml' => [ 'Huawei', 'Honor', 'Android', DeviceType::MOBILE ],
2119
  'http://wap1.huawei.com/uaprof/HuaweiU8860-51WCDMA-Normal.xml' => [ 'Huawei', 'Honor', 'Android', DeviceType::MOBILE ],
2252
  'http://wap1.huawei.com/uaprof/HUAWEI_ATH-UL01_DRM_Uaprofile.xml' => [ 'Huawei', 'Honor ShotX', 'Android', DeviceType::MOBILE ],
2253
  'http://wap1.huawei.com/uaprof/HUAWEI_ATH-UL01_Uaprofile.xml' => [ 'Huawei', 'Honor ShotX', 'Android', DeviceType::MOBILE ],
2254
  'http://wap1.huawei.com/uaprof/HUAWEI_ATH-UL06_Uaprofile.xml' => [ 'Huawei', 'Honor ShotX', 'Android', DeviceType::MOBILE ],
2255
+ 'http://wap1.huawei.com/uaprof/HUAWEI_HDN-L09_UAProfile.xml' => [ 'Huawei', 'Honor WaterPlay', 'Android', DeviceType::TABLET ],
2256
  'http://wap1.huawei.com/uaprof/HW_HUAWEI_C8950D_1_20120704.xml' => [ 'Huawei', 'Honor+', 'Android', DeviceType::MOBILE ],
2257
  'http://wap1.huawei.com/uaprof/HuaweiU8150v100WCDMA.xml' => [ 'Huawei', 'IDEOS', 'Android', DeviceType::MOBILE ],
2258
  'http://wap.huawei.com/uaprof/Huawei-S7.xml' => [ 'Huawei', 'IDEOS S7', 'Android', DeviceType::MOBILE ],
2379
  'http://provantage.cleartalk.csky.us/ua/huawei_M886.xml' => [ 'Huawei', 'Mercury', 'Android', DeviceType::MOBILE ],
2380
  'http://wap1.huawei.com/uaprof/HuaweiM886-Cricket.xml' => [ 'Huawei', 'Mercury', 'Android', DeviceType::MOBILE ],
2381
  'http://wap1.huawei.com/uaprof/HUAWEI_CAZ-TL10_UAProfile.xml' => [ 'Huawei', 'Nova', 'Android', DeviceType::MOBILE ],
2382
+ 'http://wap1.huawei.com/uaprof/HUAWEI_CAZ-TL20_UAProfile.xml' => [ 'Huawei', 'Nova', 'Android', DeviceType::MOBILE ],
2383
+ 'http://wap1.huawei.com/uaprof/HUAWEI_BAC-TL00_UAProfile.xml' => [ 'Huawei', 'Nova 2 Plus', 'Android', DeviceType::MOBILE ],
2384
+ 'http://wap1.huawei.com/uaprof/HUAWEI_VTR-TL00_UAProfile.xml' => [ 'Huawei', 'P10', 'Android', DeviceType::MOBILE ],
2385
  'http://wap1.huawei.com/uaprof/HUAWEI_WAS-TL10_UAProfile.xml' => [ 'Huawei', 'P10 Lite', 'Android', DeviceType::MOBILE ],
2386
  'http://wap1.huawei.com/uaprof/HUAWEI_VKY-TL00_UAProfile.xml' => [ 'Huawei', 'P10 Plus', 'Android', DeviceType::MOBILE ],
2387
  'http://wap1.huawei.com/uaprof/HW_GRA-CL10_1_20150105.xml' => [ 'Huawei', 'P8', 'Android', DeviceType::MOBILE ],
2396
  'http://wap1.huawei.com/uaprof/HW_EVA-CL00_3_20160226.xml' => [ 'Huawei', 'P9', 'Android', DeviceType::MOBILE ],
2397
  'http://wap1.huawei.com/uaprof/HUAWEI_VNS-TL00_UAProfile.xml' => [ 'Huawei', 'P9 Lite', 'Windows', DeviceType::MOBILE ],
2398
  'http://wap1.huawei.com/uaprof/HUAWEI_VNS_AL00_UAProfile.xml' => [ 'Huawei', 'P9 Lite', 'Android', DeviceType::MOBILE ],
2399
+ 'http://wap1.huawei.com/uaprof/HUAWEI_VNS_DL00_UAProfile.xml' => [ 'Huawei', 'P9 Lite', 'Android', DeviceType::MOBILE ],
2400
  'http://wap1.huawei.com/uaprof/HUAWEI_VIE-AL10_UAProfile.xml' => [ 'Huawei', 'P9 Plus', 'Android', DeviceType::MOBILE ],
2401
  'http://uaprof.metropcs.net/UAProf/Huawei-M931.xml' => [ 'Huawei', 'Premia 4G', 'Android', DeviceType::MOBILE ],
2402
  'http://wap1.huawei.com/uaprof/HW_HUAWEI_H891L.xml' => [ 'Huawei', 'Pronto', 'Android', DeviceType::MOBILE ],
2403
+ 'http://wap1.huawei.com/uaprof/HuaweiMediaPad_FDR-A04L.xml' => [ 'Huawei', 'Qua tab 02 HWT31', 'Android', DeviceType::MOBILE ],
2404
  'http://nmsc.ctvap.cn/uaprof/HW/HW_HUAWEI_S8520_1_20110819.xml' => [ 'Huawei', 'S8520', 'Android', DeviceType::MOBILE ],
2405
  'http://nmsc.ctvap.cn/uaprof/HW/HW_HUAWEI_S8600_1_20110825.xml' => [ 'Huawei', 'S8600', 'Android', DeviceType::MOBILE ],
2406
  'http://wap1.huawei.com/uaprof/HuaweiU8650GPRS-Normal.xml' => [ 'Huawei', 'Sonic', 'Android', DeviceType::MOBILE ],
2479
  'http://device.sprintpcs.com/Huawei/Y538-VIRGIN/Y538C237B150.rdf' => [ 'Huawei', 'Union', 'Android', DeviceType::MOBILE ],
2480
  'http://wap1.huawei.com/uaprof/HuaweiU8850v100WCDMA.xml' => [ 'Huawei', 'Vision', 'Android', DeviceType::MOBILE ],
2481
  'http://wap1.huawei.com/uaprof/HUAWEI_LUNA_UAProfile.xml' => [ 'Huawei', 'Y3 II', 'Android', DeviceType::MOBILE ],
2482
+ 'http://wap1.huawei.com/uaprof/LUA-U03_UAProfile.xml' => [ 'Huawei', 'Y3 II', 'Android', DeviceType::MOBILE ],
2483
  'http://wap1.huawei.com/uaprof/LUA-U22_UAProfile.xml' => [ 'Huawei', 'Y3 II', 'Android', DeviceType::MOBILE ],
2484
  'http://wap1.huawei.com/uaprof/LUA-U23_UAProfile.xml' => [ 'Huawei', 'Y3 II', 'Android', DeviceType::MOBILE ],
2485
  'http://wap1.huawei.com/uaprof/HUAWEI_CANCUN_UAProfile.xml,http://wap1.huawei.com/uaprof/HUAWEI_CUN_L_UAProfile.xml'=> [ 'Huawei', 'Y5 II', 'Android', DeviceType::MOBILE ],
2697
  'http://www.1066.cn/uaprof/prof/lava/LAVA_IRIS506Q.xml' => [ 'Lava', 'Iris 506Q', 'Android', DeviceType::MOBILE ],
2698
  'http://www.msai.in/uaprof/Lava/iris_alfa.xml' => [ 'Lava', 'Iris Alfa', 'Android', DeviceType::MOBILE ],
2699
  'http://www.msai.in/uaprof/Lava/Iris_Alfa_L.xml' => [ 'Lava', 'Iris Alfa L', 'Android', DeviceType::MOBILE ],
2700
+ 'http://www.msai.in/uaprof/Lava/iris_fuel_10.xml' => [ 'Lava', 'Iris fuel10', 'Android', DeviceType::MOBILE ],
2701
  'http://www.msai.in/uaprof/Lava/iris_Fuel20.xml' => [ 'Lava', 'Iris fuel20', 'Android', DeviceType::MOBILE ],
2702
  'http://www.1066.cn/uaprof/prof/Micromax/Micromax_A107.xml' => [ 'Lava', 'Iris fuel50', 'Android', DeviceType::MOBILE ],
2703
  'http://www.msai.in/uaprof/Lava/Iris%20Fuel60.xml' => [ 'Lava', 'Iris fuel60', 'Android', DeviceType::MOBILE ],
2937
  'http://gsm.lge.com/html/gsm/D950-M10-D1-KK.xml' => [ 'LG', 'G Flex', 'Android', DeviceType::MOBILE ],
2938
  'http://gsm.lge.com/html/gsm/D950-M10-D1.xml' => [ 'LG', 'G Flex', 'Android', DeviceType::MOBILE ],
2939
  'http://gsm.lge.com/html/gsm/D950-M3-D1.xml' => [ 'LG', 'G Flex', 'Android', DeviceType::MOBILE ],
2940
+ 'http://gsm.lge.com/html/gsm/D950G-M10-D1-KK.xml' => [ 'LG', 'G Flex', 'Android', DeviceType::MOBILE ],
2941
  'http://gsm.lge.com/html/gsm/D955-M10-D1.xml' => [ 'LG', 'G Flex', 'Android', DeviceType::MOBILE ],
2942
  'http://gsm.lge.com/html/gsm/D955-M3-D1-KK.xml' => [ 'LG', 'G Flex', 'Android', DeviceType::MOBILE ],
2943
  'http://gsm.lge.com/html/gsm/D955-M3-D1.xml' => [ 'LG', 'G Flex', 'Android', DeviceType::MOBILE ],
2959
  'http://device.sprintpcs.com/LG/LS996-SPRINT/LS996ZV8.rdf' => [ 'LG', 'G Flex 2', 'Android', DeviceType::MOBILE ],
2960
  'http://device.sprintpcs.com/LG/LS996-SPRINT/LS996ZV9.rdf' => [ 'LG', 'G Flex 2', 'Android', DeviceType::MOBILE ],
2961
  'http://device.sprintpcs.com/LG/LS996-SPRINT/LS996ZVB.rdf' => [ 'LG', 'G Flex 2', 'Android', DeviceType::MOBILE ],
2962
+ 'http://device.sprintpcs.com/LG/LS996-SPRINT/LS996ZVC.rdf' => [ 'LG', 'G Flex 2', 'Android', DeviceType::MOBILE ],
2963
  'http://gsm.lge.com/html/gsm/2D_2BD_BlBeXhXq5/H955-M3-D1.xml' => [ 'LG', 'G Flex 2', 'Android', DeviceType::MOBILE ],
2964
  'http://gsm.lge.com/html/gsm/2D_2BD_BlBeXhXq5/H955-M5-D1.xml' => [ 'LG', 'G Flex 2', 'Android', DeviceType::MOBILE ],
2965
  'http://gsm.lge.com/html/gsm/2D_2BD_BlBeXhXq5/H955-M6-D1.xml' => [ 'LG', 'G Flex 2', 'Android', DeviceType::MOBILE ],
2975
  'http://pix.cspire.com/UA/profile/lg/as995/as995.xml' => [ 'LG', 'G Flex 2', 'Android', DeviceType::MOBILE ],
2976
  'http://gsm.lge.com/html/gsm/V410-D1.xml' => [ 'LG', 'G Pad 7.0', 'Android', DeviceType::TABLET ],
2977
  'http://gsm.lge.com/html/gsm/V410-M10-D1.xml' => [ 'LG', 'G Pad 7.0', 'Android', DeviceType::TABLET ],
2978
+ 'http://gsm.lge.com/html/gsm/V410-M3-D1.xml' => [ 'LG', 'G Pad 7.0', 'Android', DeviceType::TABLET ],
2979
  'http://gsm.lge.com/html/gsm/V410GO-D1.xml' => [ 'LG', 'G Pad 7.0', 'Android', DeviceType::TABLET ],
2980
  'http://gsm.lge.com/html/gsm/V490-M3-D1.xml' => [ 'LG', 'G Pad 7.0', 'Android', DeviceType::TABLET ],
2981
  'http://device.sprintpcs.com/LG/LK430-Chameleon/latest' => [ 'LG', 'G Pad F 7.0', 'Android', DeviceType::TABLET ],
2985
  'http://device.sprintpcs.com/LG/LK430-SPRINT/LK430ZV6.rdf' => [ 'LG', 'G Pad F 7.0', 'Android', DeviceType::TABLET ],
2986
  'http://device.sprintpcs.com/LG/LK430-SPRINT/LK430ZV7.rdf' => [ 'LG', 'G Pad F 7.0', 'Android', DeviceType::TABLET ],
2987
  'http://gsm.lge.com/html/gsm/iBpgg_0u_ASxAV_F/V495-D1.xml' => [ 'LG', 'G Pad F 7.0', 'Android', DeviceType::TABLET ],
2988
+ 'http://gsm.lge.com/html/gsm/iBpgg_0u_ASxAV_F/V499-D1.xml' => [ 'LG', 'G Pad F 8.0', 'Android', DeviceType::TABLET ],
2989
  'http://gsm.lge.com/html/gsm/rGTs_Yxuw5wT0ZyW/V495-D1.xml' => [ 'LG', 'G Pad F 8.0', 'Android', DeviceType::TABLET ],
2990
  'http://gsm.lge.com/html/gsm/TksSP_-GkCHZ7K__/V930-D1.xml' => [ 'LG', 'G Pad X 10.1', 'Android', DeviceType::TABLET ],
2991
  'http://gsm.lge.com/html/gsm/_-0_bP_4P_s73ov-/V930-D1.xml' => [ 'LG', 'G Pad X 10.1', 'Android', DeviceType::TABLET ],
3035
  'http://device.sprintpcs.com/LG/LS770-VIRGIN/LS770ZVA.rdf' => [ 'LG', 'G Stylo', 'Android', DeviceType::MOBILE ],
3036
  'http://device.sprintpcs.com/LG/LS770-VIRGIN/LS770ZVB.rdf' => [ 'LG', 'G Stylo', 'Android', DeviceType::MOBILE ],
3037
  'http://gsm.lge.com/html/gsm/5uyruBAm__1ZuYMa/H631-M10-D1.xml' => [ 'LG', 'G Stylo', 'Android', DeviceType::MOBILE ],
3038
+ 'http://gsm.lge.com/html/gsm/b7_gceeg_u9fMBZq/H635-M10-D1.xml' => [ 'LG', 'G Stylo', 'Android', DeviceType::MOBILE ],
3039
  'http://gsm.lge.com/html/gsm/b7_gceeg_u9fMBZq/H635-M5-D1.xml' => [ 'LG', 'G Stylo', 'Android', DeviceType::MOBILE ],
3040
  'http://gsm.lge.com/html/gsm/b7_gceeg_u9fMBZq/H635-M6-D1.xml' => [ 'LG', 'G Stylo', 'Android', DeviceType::MOBILE ],
3041
  'http://gsm.lge.com/html/gsm/b7_gceeg_u9fMBZq/H636-M10-D1.xml' => [ 'LG', 'G Stylo', 'Android', DeviceType::MOBILE ],
3201
  'http://gsm.lge.com/html/gsm/HD_8T0W9FihEqY5S/D727-M10-D1.xml' => [ 'LG', 'G3 Beat', 'Android', DeviceType::MOBILE ],
3202
  'http://nmsc.ctvap.cn/uaprof/LG/LG_LG-D729_2_20140627.xml' => [ 'LG', 'G3 Beat', 'Android', DeviceType::MOBILE ],
3203
  'http://gsm.lge.com/html/gsm/F460K-M10-D1.xml' => [ 'LG', 'G3 Cat.6', 'Android', DeviceType::MOBILE ],
3204
+ 'http://gsm.lge.com/html/gsm/F460L-M9-D1.xml' => [ 'LG', 'G3 Cat.6', 'Android', DeviceType::MOBILE ],
3205
  'http://gsm.lge.com/html/gsm/F460S-M10-D1.xml' => [ 'LG', 'G3 Cat.6', 'Android', DeviceType::MOBILE ],
3206
  'http://device.sprintpcs.com/LG/LS885-Chameleon/latest' => [ 'LG', 'G3 mini', 'Android', DeviceType::MOBILE ],
3207
  'http://device.sprintpcs.com/LG/LS885-SPRINT/LS885ZV4.rdf' => [ 'LG', 'G3 mini', 'Android', DeviceType::MOBILE ],
3224
  'http://gsm.lge.com/html/gsm/D693-M3-D1.xml' => [ 'LG', 'G3 Stylus', 'Android', DeviceType::MOBILE ],
3225
  'http://gsm.lge.com/html/gsm/D693n-M10-D1.xml' => [ 'LG', 'G3 Stylus', 'Android', DeviceType::MOBILE ],
3226
  'http://gsm.lge.com/html/gsm/D693n-M3-D1.xml' => [ 'LG', 'G3 Stylus', 'Android', DeviceType::MOBILE ],
3227
+ 'http://gsm.lge.com/html/gsm/D693TR-M3-D1.xml' => [ 'LG', 'G3 Stylus', 'Android', DeviceType::MOBILE ],
3228
  'http://gsm.lge.com/html/gsm/D693TR-M5-D1.xml' => [ 'LG', 'G3 Stylus', 'Android', DeviceType::MOBILE ],
3229
  'http://gsm.lge.com/html/gsm/RNTp_ElEPgL_QrBQ/D690-M3-D1.xml' => [ 'LG', 'G3 Stylus', 'Android', DeviceType::MOBILE ],
3230
  'http://device.sprintpcs.com/LG/LS885-SPRINT/LS885ZV6.rdf' => [ 'LG', 'G3 Vigor', 'Android', DeviceType::MOBILE ],
3238
  'http://gsm.lge.com/html/gsm/YSdHbanpHC5h2R_E/H810-M10-D1.xml' => [ 'LG', 'G4', 'Android', DeviceType::MOBILE ],
3239
  'http://gsm.lge.com/html/gsm/YSdHbanpHC5h2R_E/H810-M3-D1.xml' => [ 'LG', 'G4', 'Android', DeviceType::MOBILE ],
3240
  'http://gsm.lge.com/html/gsm/YSdHbanpHC5h2R_E/H811-M10-D1.xml' => [ 'LG', 'G4', 'Android', DeviceType::MOBILE ],
3241
+ 'http://gsm.lge.com/html/gsm/YSdHbanpHC5h2R_E/H811-M3-D1.xml' => [ 'LG', 'G4', 'Android', DeviceType::MOBILE ],
3242
  'http://gsm.lge.com/html/gsm/YSdHbanpHC5h2R_E/H812-M10-D1.xml' => [ 'LG', 'G4', 'Android', DeviceType::MOBILE ],
3243
  'http://gsm.lge.com/html/gsm/YSdHbanpHC5h2R_E/H815-M10-D1.xml' => [ 'LG', 'G4', 'Android', DeviceType::MOBILE ],
3244
  'http://gsm.lge.com/html/gsm/YSdHbanpHC5h2R_E/H815-M20-D1.xml' => [ 'LG', 'G4', 'Android', DeviceType::MOBILE ],
3412
  'http://gsm.lge.com/html/gsm/D335-M3-D1.xml' => [ 'LG', 'L Bello', 'Android', DeviceType::MOBILE ],
3413
  'http://gsm.lge.com/html/gsm/D337-M3-D1.xml' => [ 'LG', 'L Bello', 'Android', DeviceType::MOBILE ],
3414
  'http://gsm.lge.com/html/gsm/RNTp_ElEPgL_QrBQ/D335-M3-D1.xml' => [ 'LG', 'L Bello', 'Android', DeviceType::MOBILE ],
3415
+ 'http://gsm.lge.com/html/gsm/RNTp_ElEPgL_QrBQ/D335-M5-D1.xml' => [ 'LG', 'L Bello', 'Android', DeviceType::MOBILE ],
3416
  'http://gsm.lge.com/html/gsm/U_EOJw1JxwmQJceD/31-M10-D1.xml' => [ 'LG', 'L Bello', 'Android', DeviceType::MOBILE ],
3417
  'http://gsm.lge.com/html/gsm/U_EOJw1JxwmQJceD/D331-M5-D1.xml' => [ 'LG', 'L Bello', 'Android', DeviceType::MOBILE ],
3418
  'http://gsm.lge.com/html/gsm/U_EOJw1JxwmQJceD/D335-M3-D1.xml' => [ 'LG', 'L Bello', 'Android', DeviceType::MOBILE ],
4006
  'http://gsm.lge.com/html/gsm/LG-U830.xml' => [ 'LG', 'U830 Chocolate', null, DeviceType::MOBILE ],
4007
  'http://gsm.lge.com/html/gsm/LG-U900.xml' => [ 'LG', 'U900', null, DeviceType::MOBILE ],
4008
  'http://gsm.lge.com/html/gsm/LG-U970.xml' => [ 'LG', 'U970 Shine', null, DeviceType::MOBILE ],
4009
+ 'http://gsm.lge.com/html/gsm/eNsCGw_apwMhnXPM/H901-M3-D1.xml' => [ 'LG', 'V10', 'Android', DeviceType::MOBILE ],
4010
  'http://gsm.lge.com/html/gsm/eNsCGw_apwMhnXPM/H960-M10-D1.xml' => [ 'LG', 'V10', 'Android', DeviceType::MOBILE ],
4011
  'http://gsm.lge.com/html/gsm/eNsCGw_apwMhnXPM/H960-M3-D1.xml' => [ 'LG', 'V10', 'Android', DeviceType::MOBILE ],
4012
  'http://gsm.lge.com/html/gsm/eNsCGw_apwMhnXPM/H961N-M3-D1.xml' => [ 'LG', 'V10', 'Android', DeviceType::MOBILE ],
4431
  'http://nds1.nds.nokia.com/uaprof/Nokia210.2r100.xml' => [ 'Nokia', '210', 'Series40', DeviceType::MOBILE ],
4432
  'http://nds1.nds.nokia.com/uaprof/Nokia220r100.xml' => [ 'Nokia', '220', 'Series30', DeviceType::MOBILE ],
4433
  'http://nds1.nds.nokia.com/uaprof/Nokia225r100.xml' => [ 'Nokia', '225', 'Series30', DeviceType::MOBILE ],
4434
+ 'http://useragentprofile.microsoft.com/uaprof/Nokia230r100.xml' => [ 'Nokia', '230', null, DeviceType::MOBILE ],
4435
  'http://nds1.nds.nokia.com/uaprof/N2322cr100.xml' => [ 'Nokia', '2322 classic', 'Series40', DeviceType::MOBILE ],
4436
  'http://nds1.nds.nokia.com/uaprof/N2600c-2r100.xml' => [ 'Nokia', '2600 classic', 'Series40', DeviceType::MOBILE ],
4437
  'http://nds1.nds.nokia.com/uaprof/N2600cr100.xml' => [ 'Nokia', '2600 classic', 'Series40', DeviceType::MOBILE ],
4438
  'http://nds.nokia.com/uaprof/N2610r100.xml' => [ 'Nokia', '2610', 'Series40', DeviceType::MOBILE ],
4439
+ 'http://nds1.nds.nokia.com/uaprof/N2610r100.xml' => [ 'Nokia', '2610', null, DeviceType::MOBILE ],
4440
  'http://nds.nokia.com/uaprof/N2626r100.xml' => [ 'Nokia', '2626', 'Series40', DeviceType::MOBILE ],
4441
  'http://nds1.nds.nokia.com/uaprof/N2626r100.xml' => [ 'Nokia', '2626', null, DeviceType::MOBILE ],
4442
  'http://nds.nokia.com/uaprof/N2630r100.xml' => [ 'Nokia', '2630', 'Series40', DeviceType::MOBILE ],
4497
  'http://nds.nokia.com/uaprof/N3300r100.xml' => [ 'Nokia', '3300', 'Series40', DeviceType::MOBILE ],
4498
  'http://nds.nokia.com/uaprof/N3300r200.xml' => [ 'Nokia', '3300', 'Series40', DeviceType::MOBILE ],
4499
  'http://useragentprofile.hmdglobal.com/uaprof/Nokia3310r100.xml' => [ 'Nokia', '3310 (2017)', null, DeviceType::MOBILE ],
4500
+ 'http://useragentprofile.hmdglobal.com/uaprof/Nokia33103Gr100.xml' => [ 'Nokia', '3310 3G', 'KaiOS', DeviceType::MOBILE ],
4501
  'http://nds.nokia.com/uaprof/N3330r100.xml' => [ 'Nokia', '3330', null, DeviceType::MOBILE ],
4502
  'http://nds.nokia.com/uaprof/N3350r100.xml' => [ 'Nokia', '3350', null, DeviceType::MOBILE ],
4503
  'http://nds.nokia.com/uaprof/N3360r100.xml' => [ 'Nokia', '3360', null, DeviceType::MOBILE ],
5001
  'http://nds.nokia.com/uaprof/N8801r301.xml' => [ 'Nokia', '8801', 'Series40', DeviceType::MOBILE ],
5002
  'http://nds.nokia.com/uaprof/N8801r400.xml' => [ 'Nokia', '8801', 'Series40', DeviceType::MOBILE ],
5003
  'http://nds.nokia.com/uaprof/N8801r401.xml' => [ 'Nokia', '8801', 'Series40', DeviceType::MOBILE ],
5004
+ 'http://useragentprofile.hmdglobal.com/uaprof/Nokia88104Gr100.xml' => [ 'Nokia', '8810 4G', 'KaiOS', DeviceType::MOBILE ],
5005
  'http://nds.nokia.com/uaprof/N8910r100.xml' => [ 'Nokia', '8910', null, DeviceType::MOBILE ],
5006
  'http://nds.nokia.com/uaprof/N8910ir100.xml' => [ 'Nokia', '8910i', null, DeviceType::MOBILE ],
5007
  'http://nds.nokia.com/uaprof/N9110r100.xml' => [ 'Nokia', '9110 Communicator', 'GOES', DeviceType::MOBILE ],
5385
  'http://ua.prof.oppo.com/resource/ua-PROF/OPPON1.xml' => [ 'Oppo', 'N1', 'Android', DeviceType::MOBILE ],
5386
  'http://ua.prof.oppo.com/resource/ua-PROF/OPPON5111.xml' => [ 'Oppo', 'N1 mini', 'Android', DeviceType::MOBILE ],
5387
  'http://ua.prof.oppo.com/resource/ua-PROF/OPPON5116.xml' => [ 'Oppo', 'N1 mini', 'Android', DeviceType::MOBILE ],
5388
+ 'http://www.oppo.com/resource/UA-PROF/OPPON5110.xml' => [ 'Oppo', 'N1 mini', 'Android', DeviceType::MOBILE ],
5389
  'http://www.oppo.com/resource/UA-PROF/OPPON5117.xml' => [ 'Oppo', 'N1 mini', 'Android', DeviceType::MOBILE ],
5390
  'http://www.oppo.com/resource/UA-PROF/OPPON5207.xml' => [ 'Oppo', 'N3', 'Android', DeviceType::MOBILE ],
5391
  'http://www.oppo.com/resource/UA-PROF/OPPON5209.xml' => [ 'Oppo', 'N3', 'Android', DeviceType::MOBILE ],
5800
  'http://www.blackberry.net/go/mobile/profiles/uaprof/8820/4.5.0.rdf' => [ 'RIM', 'BlackBerry 8820', 'BlackBerry OS', DeviceType::MOBILE ],
5801
  'http://www.blackberry.net/go/mobile/profiles/uaprof/8830/4.2.2.rdf' => [ 'RIM', 'BlackBerry 8830', 'BlackBerry OS', DeviceType::MOBILE ],
5802
  'http://www.blackberry.net/go/mobile/profiles/uaprof/9315_edge/7.1.0.rdf' => [ 'RIM', 'BlackBerry 9315', 'BlackBerry OS', DeviceType::MOBILE ],
5803
+ 'http://www.blackberry.net/go/mobile/profiles/uaprof/9570_80211g/6.0.0.rdf' => [ 'RIM', 'BlackBerry 9570', 'BlackBerry OS', DeviceType::MOBILE ],
5804
  'http://www.blackberry.net/go/mobile/profiles/uaprof/9620_80211g/7.1.0.rdf' => [ 'RIM', 'BlackBerry 9620', 'BlackBerry OS', DeviceType::MOBILE ],
5805
  'http://www.blackberry.net/go/mobile/profiles/uaprof/9620_edge/7.1.0.rdf' => [ 'RIM', 'BlackBerry 9620', 'BlackBerry OS', DeviceType::MOBILE ],
5806
  'http://www.blackberry.net/go/mobile/profiles/uaprof/9620_umts/7.1.0.rdf' => [ 'RIM', 'BlackBerry 9620', 'BlackBerry OS', DeviceType::MOBILE ],
6223
  'http://wap.samsungmobile.com/uaprof/GT-B5310.rdf' => [ 'Samsung', 'Corby Pro', 'Touchwiz', DeviceType::MOBILE ],
6224
  'http://wap.samsungmobile.com/uaprof/GT-B5310_3G.rdf' => [ 'Samsung', 'Corby Pro', 'Touchwiz', DeviceType::MOBILE ],
6225
  'http://wap.samsungmobile.com/uaprof/GT-B3210UAProf.xml' => [ 'Samsung', 'Corby TXT', null, DeviceType::MOBILE ],
6226
+ 'http://wap.samsungmobile.com/uaprof/SGH-D980.xml' => [ 'Samsung', 'D980 DuoS', null, DeviceType::MOBILE ],
6227
  'http://wap.samsungmobile.com/uaprof/SGH-T499.xml' => [ 'Samsung', 'Dart', 'Android', DeviceType::MOBILE ],
6228
  'http://wap.samsungmobile.com/uaprof/SGH-I857.xml' => [ 'Samsung', 'DoubleTime', 'Android', DeviceType::MOBILE ],
6229
  'http://wap.samsungmobile.com/uaprof/GT-I6712BR.xml' => [ 'Samsung', 'Duos TV', 'Touchwiz', DeviceType::MOBILE ],
6397
  'http://wap.samsungmobile.com/uaprof/SM-G350.xml' => [ 'Samsung', 'Galaxy Core Plus', 'Android', DeviceType::MOBILE ],
6398
  'http://wap.samsungmobile.com/uaprof/SM-G350BO.xml' => [ 'Samsung', 'Galaxy Core Plus', 'Android', DeviceType::MOBILE ],
6399
  'http://wap.samsungmobile.com/uaprof/SM-G350L.xml' => [ 'Samsung', 'Galaxy Core Plus', 'Android', DeviceType::MOBILE ],
6400
+ 'http://wap.samsungmobile.com/uaprof/SM-G350M.xml' => [ 'Samsung', 'Galaxy Core Plus', 'Android', DeviceType::MOBILE ],
6401
  'http://device.sprintpcs.com/Samsung/SM-G360P-2012071301/NL8.rdf' => [ 'Samsung', 'Galaxy Core Prime', 'Android', DeviceType::MOBILE ],
6402
  'http://device.sprintpcs.com/Samsung/SM-G360P-2012071301/OH1.rdf' => [ 'Samsung', 'Galaxy Core Prime', 'Android', DeviceType::MOBILE ],
6403
  'http://device.sprintpcs.com/Samsung/SM-G360P-BOOST/NL8.rdf' => [ 'Samsung', 'Galaxy Core Prime', 'Android', DeviceType::MOBILE ],
6485
  'http://wap.samsungmobile.com/uaprof/GT-I9060L.xml' => [ 'Samsung', 'Galaxy Grand Neo', 'Android', DeviceType::MOBILE ],
6486
  'http://wap.samsungmobile.com/uaprof/GT-I9060M.xml' => [ 'Samsung', 'Galaxy Grand Neo', 'Android', DeviceType::MOBILE ],
6487
  'http://wap.samsungmobile.com/uaprof/GT-I9063T.xml' => [ 'Samsung', 'Galaxy Grand Neo Duos', 'Android', DeviceType::MOBILE ],
6488
+ 'http://device.sprintpcs.com/Samsung/SM-G530P-MVNO/QF2.rdf' => [ 'Samsung', 'Galaxy Grand Prime', 'Android', DeviceType::MOBILE ],
6489
  'http://device.sprintpcs.com/Samsung/SM-G530P-SPRINT/OF8.rdf' => [ 'Samsung', 'Galaxy Grand Prime', 'Android', DeviceType::MOBILE ],
6490
  'http://device.sprintpcs.com/Samsung/SM-G530P-SPRINT/OG2.rdf' => [ 'Samsung', 'Galaxy Grand Prime', 'Android', DeviceType::MOBILE ],
6491
  'http://device.sprintpcs.com/Samsung/SM-G530P-SPRINT/OI1.rdf' => [ 'Samsung', 'Galaxy Grand Prime', 'Android', DeviceType::MOBILE ],
6542
  'http://device.sprintpcs.com/Samsung/SM-J320P-BOOST/PK2.rdf' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
6543
  'http://device.sprintpcs.com/Samsung/SM-J320P-BOOST/QD2.rdf' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
6544
  'http://device.sprintpcs.com/Samsung/SM-J320P-BOOST/QG3.rdf' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
6545
+ 'http://device.sprintpcs.com/Samsung/SM-J320P-BOOST/RA1.rdf' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
6546
  'http://device.sprintpcs.com/Samsung/SM-J320P-Chameleon/latest' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
6547
  'http://device.sprintpcs.com/Samsung/SM-J320P-SPRINT/OL2.rdf' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
6548
  'http://device.sprintpcs.com/Samsung/SM-J320P-SPRINT/PE1.rdf' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
6550
  'http://device.sprintpcs.com/Samsung/SM-J320P-SPRINT/PK2.rdf' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
6551
  'http://device.sprintpcs.com/Samsung/SM-J320P-SPRINT/QD2.rdf' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
6552
  'http://device.sprintpcs.com/Samsung/SM-J320P-SPRINT/QG3.rdf' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
6553
+ 'http://device.sprintpcs.com/Samsung/SM-J320P-SPRINT/RA1.rdf' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
6554
  'http://device.sprintpcs.com/Samsung/SM-J320P-VIRGIN/OL2.rdf' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
6555
  'http://device.sprintpcs.com/Samsung/SM-J320P-VIRGIN/PK2.rdf' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
6556
  'http://device.sprintpcs.com/Samsung/SM-J320P-VIRGIN/QG3.rdf' => [ 'Samsung', 'Galaxy J3', 'Android', DeviceType::MOBILE ],
6565
  'http://device.sprintpcs.com/Samsung/SM-J327P-BOOST/PL1.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
6566
  'http://device.sprintpcs.com/Samsung/SM-J327P-BOOST/QB6.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
6567
  'http://device.sprintpcs.com/Samsung/SM-J327P-BOOST/QF4.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
6568
+ 'http://device.sprintpcs.com/Samsung/SM-J327P-BOOST/QJ3.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
6569
+ 'http://device.sprintpcs.com/Samsung/SM-J327P-BOOST/QL3.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
6570
+ 'http://device.sprintpcs.com/Samsung/SM-J327P-BOOST/RC1.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
6571
+ 'http://device.sprintpcs.com/Samsung/SM-J327P-Chameleon/latest' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
6572
  'http://device.sprintpcs.com/Samsung/SM-J327P-SPRINT/PL1.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
6573
  'http://device.sprintpcs.com/Samsung/SM-J327P-SPRINT/QB6.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
6574
  'http://device.sprintpcs.com/Samsung/SM-J327P-SPRINT/QF4.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
6575
  'http://device.sprintpcs.com/Samsung/SM-J327P-SPRINT/QI2.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
6576
  'http://device.sprintpcs.com/Samsung/SM-J327P-SPRINT/QJ3.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
6577
+ 'http://device.sprintpcs.com/Samsung/SM-J327P-SPRINT/QL3.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
6578
+ 'http://device.sprintpcs.com/Samsung/SM-J327P-SPRINT/RC1.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
6579
  'http://device.sprintpcs.com/Samsung/SM-J327P-VIRGIN/QB6.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
6580
  'http://device.sprintpcs.com/Samsung/SM-J327P-VIRGIN/QF4.rdf' => [ 'Samsung', 'Galaxy J3 Emerge', 'Android', DeviceType::MOBILE ],
6581
  'http://wap.samsungmobile.com/uaprof/SM-J500F.xml' => [ 'Samsung', 'Galaxy J5', 'Android', DeviceType::MOBILE ],
6605
  'http://wap.samsungmobile.com/uaprof/SM-J710FPTR.xml' => [ 'Samsung', 'Galaxy J7 (2016)', 'Android', DeviceType::MOBILE ],
6606
  'http://wap.samsungmobile.com/uaprof/SM-J710GN.xml' => [ 'Samsung', 'Galaxy J7 (2016)', 'Android', DeviceType::MOBILE ],
6607
  'http://device.sprintpcs.com/Samsung/SM-J727P-BOOST/QF5.rdf' => [ 'Samsung', 'Galaxy J7 Perx', 'Android', DeviceType::MOBILE ],
6608
+ 'http://device.sprintpcs.com/Samsung/SM-J727P-BOOST/RC2.rdf' => [ 'Samsung', 'Galaxy J7 Perx', 'Android', DeviceType::MOBILE ],
6609
  'http://wap.samsungmobile.com/uaprof/SM-G610F.xml' => [ 'Samsung', 'Galaxy J7 Prime', 'Android', DeviceType::MOBILE ],
6610
  'http://wap.samsungmobile.com/uaprof/SM-G610Y.xml' => [ 'Samsung', 'Galaxy J7 Prime', 'Android', DeviceType::MOBILE ],
6611
  'http://wap.samsungmobile.com/uaprof/SGH-N075T.xml' => [ 'Samsung', 'GALAXY J SC-02F', 'Android', DeviceType::MOBILE ],
6623
  'http://nmsc.ctvap.cn/uaprof/SCH/SCH_SCH-P709E_1_20140113.xml' => [ 'Samsung', 'Galaxy Mega 5.8', 'Android', DeviceType::MOBILE ],
6624
  'http://wap.samsungmobile.com/uaprof/GT-I9150.xml' => [ 'Samsung', 'Galaxy Mega 5.8', 'Android', DeviceType::MOBILE ],
6625
  'http://wap.samsungmobile.com/uaprof/GT-I9152.xml' => [ 'Samsung', 'Galaxy Mega 5.8 Duos', 'Android', DeviceType::MOBILE ],
6626
+ 'http://device.sprintpcs.com/Samsung/SPH-L600-MVNO/QA1.rdf' => [ 'Samsung', 'Galaxy Mega 6.3', 'Android', DeviceType::MOBILE ],
6627
  'http://device.sprintpcs.com/Samsung/SPH-L600-SPRINT/MI6.rdf' => [ 'Samsung', 'Galaxy Mega 6.3', 'Android', DeviceType::MOBILE ],
6628
  'http://device.sprintpcs.com/Samsung/SPH-L600-SPRINT/MK1.rdf' => [ 'Samsung', 'Galaxy Mega 6.3', 'Android', DeviceType::MOBILE ],
6629
  'http://device.sprintpcs.com/Samsung/SPH-L600-SPRINT/NA7.rdf' => [ 'Samsung', 'Galaxy Mega 6.3', 'Android', DeviceType::MOBILE ],
6706
  'http://device.sprintpcs.com/Samsung/SM-N900P-SPRINT/OK2.rdf' => [ 'Samsung', 'Galaxy Note 3', 'Android', DeviceType::MOBILE ],
6707
  'http://device.sprintpcs.com/Samsung/SM-N900P-SPRINT/PH1.rdf' => [ 'Samsung', 'Galaxy Note 3', 'Android', DeviceType::MOBILE ],
6708
  'http://device.sprintpcs.com/Samsung/SM-N900P-SPRINT/PL1.rdf' => [ 'Samsung', 'Galaxy Note 3', 'Android', DeviceType::MOBILE ],
6709
+ 'http://device.sprintpcs.com/Samsung/SPH-L710-BOOSTNC5.rdf' => [ 'Samsung', 'Galaxy Note 3', 'Android', DeviceType::MOBILE ],
6710
  'http://nmsc.ctvap.cn/uaprof/SCH/SCH_SM-N9009_2_20130829.xml' => [ 'Samsung', 'Galaxy Note 3', 'Android', DeviceType::MOBILE ],
6711
  'http://wap.samsungmobile.com/uaprof/SAMSUNG-SM-N900A.xml' => [ 'Samsung', 'Galaxy Note 3', 'Android', DeviceType::MOBILE ],
6712
  'http://wap.samsungmobile.com/uaprof/SM-N900.xml' => [ 'Samsung', 'Galaxy Note 3', 'Android', DeviceType::MOBILE ],
6755
  'http://wap.samsungmobile.com/uaprof/SM-N9106W.xml' => [ 'Samsung', 'Galaxy Note 4', 'Android', DeviceType::MOBILE ],
6756
  'http://wap.samsungmobile.com/uaprof/SM-N910A.xml' => [ 'Samsung', 'Galaxy Note 4', 'Android', DeviceType::MOBILE ],
6757
  'http://wap.samsungmobile.com/uaprof/SM-N910C.xml' => [ 'Samsung', 'Galaxy Note 4', 'Android', DeviceType::MOBILE ],
6758
+ 'http://wap.samsungmobile.com/uaprof/SM-N910CPET.xml' => [ 'Samsung', 'Galaxy Note 4', 'Android', DeviceType::MOBILE ],
6759
  'http://wap.samsungmobile.com/uaprof/SM-N910F.xml' => [ 'Samsung', 'Galaxy Note 4', 'Android', DeviceType::MOBILE ],
6760
  'http://wap.samsungmobile.com/uaprof/SM-N910FPTR.xml' => [ 'Samsung', 'Galaxy Note 4', 'Android', DeviceType::MOBILE ],
6761
  'http://wap.samsungmobile.com/uaprof/SM-N910G.xml' => [ 'Samsung', 'Galaxy Note 4', 'Android', DeviceType::MOBILE ],
7134
  'http://device.sprintpcs.com/Samsung/SPH-L720-2011011301/OD2.rdf' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
7135
  'http://device.sprintpcs.com/Samsung/SPH-L720-2011011301/OH1.rdf' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
7136
  'http://device.sprintpcs.com/Samsung/SPH-L720-2012083001/NG2.rdf' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
7137
+ 'http://device.sprintpcs.com/Samsung/SPH-L720-2012083001/PL1.rdf' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
7138
  'http://device.sprintpcs.com/Samsung/SPH-L720-500002419/NAE.rdf' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
7139
  'http://device.sprintpcs.com/Samsung/SPH-L720-Chameleon/latest' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
7140
  'http://device.sprintpcs.com/Samsung/SPH-L720-Chameleon/MCI.rdf' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
7157
  'http://device.sprintpcs.com/Samsung/SPH-L720-SPRINT/PI2.rdf' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
7158
  'http://device.sprintpcs.com/Samsung/SPH-L720-SPRINT/PL1.rdf' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
7159
  'http://device.sprintpcs.com/Samsung/SPH-L720T-BOOST/OK3.rdf' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
7160
+ 'http://device.sprintpcs.com/Samsung/SPH-L720T-BOOST/PL1.rdf' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
7161
  'http://device.sprintpcs.com/Samsung/SPH-L720T-Chameleon/latest' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
7162
  'http://device.sprintpcs.com/Samsung/SPH-L720T-Chameleon/NG5.rdf' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
7163
  'http://device.sprintpcs.com/Samsung/SPH-L720T-MVNO/NC6.rdf' => [ 'Samsung', 'Galaxy S4', 'Android', DeviceType::MOBILE ],
7448
  'http://device.sprintpcs.com/Samsung/SM-G930P-SPRINT/QAA.rdf' => [ 'Samsung', 'Galaxy S7', 'Android', DeviceType::MOBILE ],
7449
  'http://device.sprintpcs.com/Samsung/SM-G930P-SPRINT/QC1.rdf' => [ 'Samsung', 'Galaxy S7', 'Android', DeviceType::MOBILE ],
7450
  'http://device.sprintpcs.com/Samsung/SM-G930P-SPRINT/QD2.rdf' => [ 'Samsung', 'Galaxy S7', 'Android', DeviceType::MOBILE ],
7451
+ 'http://device.sprintpcs.com/Samsung/SM-G930P-SPRINT/QE1.rdf' => [ 'Samsung', 'Galaxy S7', 'Android', DeviceType::MOBILE ],
7452
  'http://wap.samsungmobile.com/uaprof/SM-G930F.xml' => [ 'Samsung', 'Galaxy S7', 'Android', DeviceType::MOBILE ],
7453
  'http://device.sprintpcs.com/Samsung/SM-G935P-Chameleon/latest' => [ 'Samsung', 'Galaxy S7 Edge', 'Android', DeviceType::MOBILE ],
7454
  'http://device.sprintpcs.com/Samsung/SM-G935P-SPRINT/PB5.rdf' => [ 'Samsung', 'Galaxy S7 Edge', 'Android', DeviceType::MOBILE ],
7507
  'http://wap.samsungmobile.com/uaprof/GT-P3110.xml' => [ 'Samsung', 'Galaxy Tab 2 (7.0)', 'Android', DeviceType::TABLET ],
7508
  'http://device.sprintpcs.com/Samsung/SPH-P500/LI6.rdf' => [ 'Samsung', 'Galaxy Tab 2 10.1', 'Android', DeviceType::TABLET ],
7509
  'http://device.sprintpcs.com/Samsung/SPH-P500/MB3.rdf' => [ 'Samsung', 'Galaxy Tab 2 10.1', 'Android', DeviceType::TABLET ],
7510
+ 'http://wap.samsungmobile.com/uaprof/SGH-I497OYA.xml' => [ 'Samsung', 'Galaxy Tab 2 10.1', 'Android', DeviceType::TABLET ],
7511
  'http://wap.samsungmobile.com/uaprof/GT-P5200.xml' => [ 'Samsung', 'Galaxy Tab 3 (10.1)', 'Android', DeviceType::TABLET ],
7512
  'http://wap.samsungmobile.com/uaprof/GT-P5210.xml' => [ 'Samsung', 'Galaxy Tab 3 (10.1)', 'Android', DeviceType::TABLET ],
7513
  'http://wap.samsungmobile.com/uaprof/GT-P5220.xml' => [ 'Samsung', 'Galaxy Tab 3 (10.1)', 'Android', DeviceType::TABLET ],
7618
  'http://wap.samsungmobile.com/uaprof/SM-T325.xml' => [ 'Samsung', 'Galaxy Tab Pro 8.4', 'Android', DeviceType::TABLET ],
7619
  'http://nmsc.ctvap.cn/uaprof/SCH/SCH_SM-T2519_1_20140428.xml' => [ 'Samsung', 'Galaxy Tab Q', 'Android', DeviceType::MOBILE ],
7620
  'http://device.sprintpcs.com/Samsung/SM-T807P-Chameleon/latest' => [ 'Samsung', 'Galaxy Tab S 10.5', 'Android', DeviceType::TABLET ],
7621
+ 'http://device.sprintpcs.com/Samsung/SM-T807P-SPRINT/NH1.rdf' => [ 'Samsung', 'Galaxy Tab S 10.5', 'Android', DeviceType::TABLET ],
7622
  'http://device.sprintpcs.com/Samsung/SM-T807P-SPRINT/NK1.rdf' => [ 'Samsung', 'Galaxy Tab S 10.5', 'Android', DeviceType::TABLET ],
7623
  'http://device.sprintpcs.com/Samsung/SM-T807P-SPRINT/OH1.rdf' => [ 'Samsung', 'Galaxy Tab S 10.5', 'Android', DeviceType::TABLET ],
7624
  'http://device.sprintpcs.com/Samsung/SM-T807P-SPRINT/OJ4.rdf' => [ 'Samsung', 'Galaxy Tab S 10.5', 'Android', DeviceType::TABLET ],
7782
  'http://wap.samsungmobile.com/uaprof/GT-C5510UAProf.xml' => [ 'Samsung', 'GT-C5510', null, DeviceType::MOBILE ],
7783
  'http://wap.samsungmobile.com/uaprof/GT-C5510UAProf3G.xml' => [ 'Samsung', 'GT-C5510', null, DeviceType::MOBILE ],
7784
  'http://wap.samsungmobile.com/uaprof/GT-E2152.xml' => [ 'Samsung', 'GT-E2152 Duos', null, DeviceType::MOBILE ],
7785
+ 'http://wap.samsungmobile.com/uaprof/GT-E2152iUAProf.xml' => [ 'Samsung', 'GT-E2152i', null, DeviceType::MOBILE ],
7786
  'http://wap.samsungmobile.com/uaprof/GT-E2200.xml' => [ 'Samsung', 'GT-E2200', null, DeviceType::MOBILE ],
7787
  'http://wap.samsungmobile.com/uaprof/GT-E2230UAProf.xml' => [ 'Samsung', 'GT-E2230', null, DeviceType::MOBILE ],
7788
  'http://wap.samsungmobile.com/uaprof/GT-E2232UAProf.xml' => [ 'Samsung', 'GT-E2232', null, DeviceType::MOBILE ],
8881
  'http://uaprof.sonymobile.com/SGP341R1005.xml' => [ 'Sony', 'Xperia Tablet Z', 'Android', DeviceType::TABLET ],
8882
  'http://uaprof.sonymobile.com/SGP351R1002.xml' => [ 'Sony', 'Xperia Tablet Z', 'Android', DeviceType::TABLET ],
8883
  'http://uaprof.sonymobile.com/SO-03ER1002.xml' => [ 'Sony', 'Xperia Tablet Z', 'Android', DeviceType::TABLET ],
8884
+ 'http://uaprof.sonymobile.com/SGP412R1401.xml' => [ 'Sony', 'Xperia Tablet Z Ultra', 'Android', DeviceType::TABLET ],
8885
  'http://uaprof.sonymobile.com/SGP412R1421.xml' => [ 'Sony', 'Xperia Tablet Z Ultra', 'Android', DeviceType::TABLET ],
8886
  'http://uaprof.sonymobile.com/SGP511R1701.xml' => [ 'Sony', 'Xperia Tablet Z2', 'Android', DeviceType::TABLET ],
8887
  'http://uaprof.sonymobile.com/SGP512R1701.xml' => [ 'Sony', 'Xperia Tablet Z2', 'Android', DeviceType::TABLET ],
9754
  'http://www.zte.com.cn/mobile/uaprof/ZTE_Kis3_max.xml' => [ 'ZTE', 'Kis 3 Max', 'Android', DeviceType::MOBILE ],
9755
  'http://www.zte.com.cn/mobile/uaprof/ZTE KIS LITE.xml' => [ 'ZTE', 'Kis Lite', 'Android', DeviceType::MOBILE ],
9756
  'http://www.zte.com.cn/mobile/uaprof/ZTE-KisPro.xml' => [ 'ZTE', 'Kis Pro', 'Android', DeviceType::MOBILE ],
9757
+ 'http://www.zte.com.cn/mobile/uaprof/ZTE_Kis_Q.xml' => [ 'ZTE', 'Kis Q', 'Android', DeviceType::MOBILE ],
9758
  'http://www.ztemt.com/mobile/uaprof/ZTE_LEO_M1.xml' => [ 'ZTE', 'LEO M1', 'Android', DeviceType::MOBILE ],
9759
  'http://www.zte.com.cn/mobile/uaprof/ZTE_V765M.xml' => [ 'ZTE', 'LEO Q1', 'Android', DeviceType::MOBILE ],
9760
  'http://www.ztemt.com/mobile/uaprof/V769M.xml' => [ 'ZTE', 'LEO Q2', 'Android', DeviceType::MOBILE ],
integration/whichbrowser/data/regexes/applications-bots.php CHANGED
@@ -2,4 +2,4 @@
2
 
3
  namespace WhichBrowser\Data;
4
 
5
- Applications::$BOTS_REGEX = '/(008|360|a6|abound|muncher|adaxas|addthis|admantx|ahrefsbot|archiver|altavista|curious|cloudfront|amorank|archive|jeeves|astra|backlink|baidu|bazqux|bingbot|msnbot|msmobot|bing|blogbridge|bloglines|bloglovin|blogpulse|blogram|blogtrot|blogshares|boardreader|browsershots|bubing|butterfly|heritrix|cliqz|cloudflare|comodo|commafeed|cbot|watchdog|datasearch|daumoa|digg|domain|exabot|exactseek|ezooms|facebook|fast|flamingo|fastladder|feed|wrangler|validator|fever|friendica|robot|genieo|fetchor|google|gomez|ichiro|gooblog|goorss|grammarly|grub|hatena|capture|htdig|httpmon|hubpages|spider|crawler|kouio|larbin|linkedin|linkdex|livedoor|ltx71|magpie|mapion|socialstreams|mixi|mnogo|monitor|yeti|netcraft|netvibes|newsblur|newsgator|orange|pages|psbot|pingdom|pinterest|postrank|comment|rssbar|hunter|quora|safesearch|scrapy|shopwiki|reader|simplepie|site24|sogou|sophora|soso|spdycheck|spinn|detector|summify|telegram|twisted|twitter|tiny|tlsprober|typhoeus|vagabondo|voila|vocus|mcrawler|w3bot|jigsaw|w3c|wayback|webindexer|wordpress|mechanize|xerka|sitemap|yacy|yandex|yahoo|y\!j|slurp|httpclient|nutch|synapse|indy|wget|curl|package|java|simple|libwww|lwp|urllib|php|pear|zend|ruby)/i';
2
 
3
  namespace WhichBrowser\Data;
4
 
5
+ Applications::$BOTS_REGEX = '/(008|360|a6|abound|muncher|adaxas|addthis|admantx|adsbot|ahrefs|archiver|altavista|curious|cloudfront|amorank|apple|archive|jeeves|astra|backlink|baidu|barkrowler|bazqux|bingbot|msnbot|msmobot|bing|blex|blogbridge|blogger|bloglines|bloglovin|blogpulse|blogram|blogtrot|blogshares|boardreader|lddc|browsershots|bubing|buck|builtwith|butterfly|buzzsumo|bytespider|heritrix|clarabot|cliqz|cloudflare|coccoc|comodo|commafeed|cbot|cresearch|watchdog|datanyze|datasearch|dataprovider|daum|daumoa|digg|domaincrawl|domainstats|discord|domain|dmca|duckduck|embed|evc|exabot|exactseek|ezooms|facebook|fast|flamingo|fastladder|feed|wrangler|validator|fever|florienzh|friendica|robot|genieo|fetchor|google|gofeed|gomez|ichiro|gooblog|goorss|gowiki|grammarly|grub|hatena|capture|heureka|hootsuite|htdig|httpmon|hubpages|hubspot|spider|indeed|iodc|istellabot|crawler|kakao|kouio|larbin|letsearch|line|linkedin|linkpad|linkdex|livedoor|seeker|ltx71|magpie|mj12bot|mapion|mail\.ru|medium|megaindex|socialstreams|mixi|minds|mnogo|mojeek|monitor|dotbot|rogerbot|yeti|mxtoolbox|netcraft|netestate|netvibes|newsblur|newsgator|nimbostratus|odklbot|orange|pages|petal|aspiegel|psbot|pingdom|pinterest|plurk|pocket|postrank|comment|reddit|rssbar|hunter|quora|safesearch|scrapy|searchatlas|seekport|semrush|serpstat|seokicks|seznam|shopwiki|reader|simplepie|site24|skype|slack|sogou|sophora|soso|spaziodati|spdycheck|spinn|sputnik|detector|summify|telegram|twisted|twitter|tiny|tineye|tlsprober|trustedsite|typhoeus|vagabondo|velen|vkshare|voat|voila|vocus|mcrawler|vuhuv|w3bot|jigsaw|w3c|wappalyzer|wayback|webindexer|wordpress|mechanize|xenu|xerka|sitemap|yacy|yandex|yahoo|y\!j|slurp|yelp|yioop|yisou|zgrab|zmeu|httpclient|nutch|synapse|indy|go|httpunit|okhttp|node|wget|curl|package|java|simple|libwww|lwp|urllib|requests|php|pear|zend|ruby)/i';
integration/whichbrowser/data/regexes/applications-browsers.php CHANGED
@@ -2,4 +2,4 @@
2
 
3
  namespace WhichBrowser\Data;
4
 
5
- Applications::$BROWSERS_REGEX = '/(115|126|2345|qihu|7star|abrowse|acorn|acoo|aol|america|arachne|arora|aweb|avant|asw|aviator|flyflow|bdbrowser|bdspark|beamrise|blackwren|brave|byffox|camino|canure|charon|chromeplus|cometbird|comodo|dragon|conkeror|coolnovo|cunaguaro|cyberfox|daedalus|dillo|rhodonit|eudoraweb|flock|galeon|epiphany|ibrowse|icab|iceape|icecat|iceweasel|iridium|iron|kazehakase|kchrome|meleon|lbbrowser|lobo|lunascape|naenara|mxbrowser|mixshark|mlbrowser|netpositive|origyn|owb|orca|oregano|otter|palemoon|qtweb|qupzilla|rekonq|ryouko|saayaa|sleipnir|metasr|stainless|sunchrome|superbird|swing|tencent|tenfourfox|theworld|tungsten|vivaldi|voyager|waterfox|yabrowser|1password|3g explorer|4g explorer|atomiclite|au|awakening|baidu|bdmobile|bidu|baiduboxapp|browser|blazer|acheetahi|cornowser|coolmarket|cute|digia|doris|doroty|www browser|eui|go\.web|helium|huohoubrowser|surfboard|isurf|jig browser|jumanji|kiosk|lebrowser|liebao|macross|mammoth|mcent|mib|cmcs|motorola|netfrontlife|onebrowser|plink|polaris|openwave|up|km|quark|semc|stnc|sogou|symphony|ucpro|weblite|alti|aplix|awox|browserserver|isis|spyglass|oregan|viera|zetakey|bunjalloo|nwf|nuanti|wib|prince|demobrowser|dooble|dwb|evm|fireweb|hive|intermec|phantom|qt|roccat|raven|rockmelt|scope|slim|smbrowser|snowshoe|sputnik|surf|tao|taz|uzbl|villanova|vimb|wada|wavelink|webrender|webster|wyzo|yelang|yrcweb|linemode|lynx|links|w3m|nimbus|Webwasher|sankore|adapi|brightsign|coship)/i';
2
 
3
  namespace WhichBrowser\Data;
4
 
5
+ Applications::$BROWSERS_REGEX = '/(115|126|2345|37abc|qihu|1stbrowser|7star|abrowse|acorn|acoo|amigo|aol|america|apus|arachne|arora|aweb|avant|asw|avg|aviator|avira|flyflow|bdbrowser|bdspark|basilisk|beamrise|beonex|blackwren|blackhawk|bolt|blackbird|brave|brisk|browsex|browzar|byffox|camino|canure|ccleaner|cent|charon|chedot|cheshire|chimlac|chimera|chromeplus|colibri|columbus|cometbird|comodo|dragon|conkeror|coc|coolnovo|corom|crazy|crusta|cunaguaro|cyberdog|cyberfox|daedalus|degan|demeter|deskbrowse|diigo|dillo|doczilla|rhodonit|dplus|elements|eudoraweb|falkon|flamesky|flock|framafox|freeu|galeon|globalmojo|epiphany|greenbrowser|hola|hydra|ibrowse|icab|iceape|icecat|icedove|iceweasel|irider|iridium|iron|kapiko|kazehakase|kchrome|kinza|kkman|klondike|kylo|meleon|lbrowser|lbbrowser|light|lobo|lolifox|lovense|lunascape|naenara|netcaptor|madfox|mxbrowser|min|mini|mixshark|mlbrowser|mypal|multixp|netpositive|nichrome|origyn|owb|live|juzi|orca|oregano|otter|palemoon|patriott|perk|polarity|privacy|qiyu|qtweb|quicklook|qupzilla|qute|rekonq|ryouko|sylera|saayaa|salam|shiira|sielo|sitekiosk|sleipnir|slimjet|metasr|sparrow|sputnik|stainless|station|sunchrome|sundance|sundial|superbird|swiftweasel|swiftfox|swing|to-browser|tencent|tenfourfox|theworld|tulip|tungsten|ultrab|usejump|vimprobable|vivaldi|airwatch|vonkeror|voyager|waterfox|whale|winwap|xvast|yabrowser|zvu|zipzap|zombie|1password|3g explorer|4g explorer|aloha|atomiclite|au|awakening|baidu|bdmobile|bidu|baiduboxapp|browser|blazer|acheetahi|cornowser|coolmarket|cute|digia|doris|doroty|ecosia|www browser|epic|eui|go\.web|helium|heytap|huohoubrowser|surfboard|isurf|jig browser|jumanji|tnsbrowser|kiosk|kiwi|lebrowser|liebao|macross|mammoth|mcent|mint|mobicip|mib|cmcs|motorola|multizilla|netfrontlife|onebrowser|oneplus|plink|polaris|pure|openwave|up|km|oppo|quark|realme|semc|stnc|sogou|symphony|tenta|ucpro|vivo|weblite|wk|yaani|alti|aplix|awox|browserserver|isis|netbox|spyglass|oregan|viera|zetakey|bunjalloo|nwf|nuanti|wib|prince|demobrowser|dooble|dwb|evm|fireweb|hive|intermec|phantom|qt|roccat|raven|rockmelt|scope|slim|smbrowser|snowshoe|surf|tao|taz|uzbl|villanova|vimb|wada|wavelink|webrender|webster|wyzo|yelang|yrcweb|linemode|lynx|links|w3m|nimbus|Webwasher|sankore|adapi|brightsign|coship)/i';
integration/whichbrowser/data/regexes/applications-others.php CHANGED
@@ -2,4 +2,4 @@
2
 
3
  namespace WhichBrowser\Data;
4
 
5
- Applications::$OTHERS_REGEX = '/(itunes|qt|bluefish|nightingale|songbird|stagefright|substream|vlc|windows-media|coreplayer|flycast|boxee|kodi|xbmc|lightning|thunderbird|outlook|lotus|postbox|bat|yahoo|daum|flipboard|akregator|blogos|cococ|feed|liferea|news|jetbrains|rss|reeder|reedkit|rome|ziepod|messenger|kik|wire|yammer|fbios|fb4a|googleplus|instagram|pinterest|weibo|tumblr|twitter|wp-android|office|bingweb|hao123|gsa|naver|sogousearch|yandex|atom|golive|brackets|iweb|frontpage|amaya|websphere|download|tansodl|origin|secondlife|valve|raptr|alipay|cooliris|google|leechcraft|expeditor)/i';
2
 
3
  namespace WhichBrowser\Data;
4
 
5
+ Applications::$OTHERS_REGEX = '/(itunes|qt|bluefish|nightingale|songbird|stagefright|substream|vlc|windows-media|coreplayer|flycast|boxee|kodi|xbmc|lightning|thunderbird|outlook|lotus|postbox|bat|yahoo|daum|flipboard|akregator|blogos|cococ|feed|liferea|news|jetbrains|rss|reeder|reedkit|rome|ziepod|messenger|kakao|kik|line|slack|viber|whatsapp|wire|yammer|zalo|fbios|fb4a|googleplus|instagram|pinterest|weibo|tumblr|twitter|wp-android|yelp|office|bingweb|hao123|gsa|naver|sogousearch|yandex|atom|golive|brackets|iweb|frontpage|amaya|websphere|download|tansodl|origin|secondlife|valve|raptr|alipay|cooliris|google|leechcraft|expeditor)/i';
integration/whichbrowser/src/Analyser/Camouflage.php CHANGED
@@ -11,7 +11,6 @@ trait Camouflage
11
  private function &detectCamouflage()
12
  {
13
  if ($ua = $this->getHeader('User-Agent')) {
14
-
15
  $this
16
  ->detectCamouflagedAndroidBrowser($ua)
17
  ->detectCamouflagedAndroidAsusBrowser($ua)
@@ -125,7 +124,6 @@ trait Camouflage
125
  if (preg_match('/(?:Chrome|CrMo|CriOS)\//u', $ua)
126
  && !preg_match('/(?:Chrome|CrMo|CriOS)\/([0-9]{1,2}\.[0-9]\.[0-9]{3,4}\.[0-9]+)/u', $ua)
127
  ) {
128
-
129
  $this->data->features[] = 'wrongVersion';
130
  $this->data->camouflage = true;
131
  }
@@ -137,7 +135,6 @@ trait Camouflage
137
  private function &detectCamouflagedUCBrowser($ua)
138
  {
139
  if ($ua == 'Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.2.3.4) Gecko/') {
140
-
141
  if (!$this->data->isBrowser('UC Browser')) {
142
  $this->data->browser->name = 'UC Browser';
143
  $this->data->browser->version = null;
@@ -168,7 +165,6 @@ trait Camouflage
168
  private function &detectCamouflagedBasedOnEngines()
169
  {
170
  if (isset($this->data->engine->name) && $this->data->browser->mode != 'proxy') {
171
-
172
  /* If it claims not to be Trident, but it is probably Trident running camouflage mode */
173
  if ($this->options->engine & Constants\EngineType::TRIDENT) {
174
  $this->data->features[] = 'trident';
@@ -268,7 +264,6 @@ trait Camouflage
268
  {
269
  if (isset($this->data->browser->name) && isset($this->data->os->name)) {
270
  if ($this->data->os->name == 'iOS' && $this->data->browser->name != 'Opera Mini' && $this->data->browser->name != 'UC Browser' && isset($this->data->os->version)) {
271
-
272
  if ($this->data->os->version->toFloat() < 4.0 && $this->options->features & Constants\Feature::SANDBOX) {
273
  $this->data->features[] = 'foundSandbox';
274
  $this->data->camouflage = true;
@@ -286,7 +281,6 @@ trait Camouflage
286
  }
287
 
288
  if ($this->data->os->name != 'iOS' && $this->data->browser->name == 'Safari' && isset($this->data->browser->version)) {
289
-
290
  if ($this->data->browser->version->toFloat() < 4.0 && $this->options->features & Constants\Feature::APPCACHE) {
291
  $this->data->features[] = 'foundAppCache';
292
  $this->data->camouflage = true;
11
  private function &detectCamouflage()
12
  {
13
  if ($ua = $this->getHeader('User-Agent')) {
 
14
  $this
15
  ->detectCamouflagedAndroidBrowser($ua)
16
  ->detectCamouflagedAndroidAsusBrowser($ua)
124
  if (preg_match('/(?:Chrome|CrMo|CriOS)\//u', $ua)
125
  && !preg_match('/(?:Chrome|CrMo|CriOS)\/([0-9]{1,2}\.[0-9]\.[0-9]{3,4}\.[0-9]+)/u', $ua)
126
  ) {
 
127
  $this->data->features[] = 'wrongVersion';
128
  $this->data->camouflage = true;
129
  }
135
  private function &detectCamouflagedUCBrowser($ua)
136
  {
137
  if ($ua == 'Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.2.3.4) Gecko/') {
 
138
  if (!$this->data->isBrowser('UC Browser')) {
139
  $this->data->browser->name = 'UC Browser';
140
  $this->data->browser->version = null;
165
  private function &detectCamouflagedBasedOnEngines()
166
  {
167
  if (isset($this->data->engine->name) && $this->data->browser->mode != 'proxy') {
 
168
  /* If it claims not to be Trident, but it is probably Trident running camouflage mode */
169
  if ($this->options->engine & Constants\EngineType::TRIDENT) {
170
  $this->data->features[] = 'trident';
264
  {
265
  if (isset($this->data->browser->name) && isset($this->data->os->name)) {
266
  if ($this->data->os->name == 'iOS' && $this->data->browser->name != 'Opera Mini' && $this->data->browser->name != 'UC Browser' && isset($this->data->os->version)) {
 
267
  if ($this->data->os->version->toFloat() < 4.0 && $this->options->features & Constants\Feature::SANDBOX) {
268
  $this->data->features[] = 'foundSandbox';
269
  $this->data->camouflage = true;
281
  }
282
 
283
  if ($this->data->os->name != 'iOS' && $this->data->browser->name == 'Safari' && isset($this->data->browser->version)) {
 
284
  if ($this->data->browser->version->toFloat() < 4.0 && $this->options->features & Constants\Feature::APPCACHE) {
285
  $this->data->features[] = 'foundAppCache';
286
  $this->data->camouflage = true;
integration/whichbrowser/src/Analyser/Derive.php CHANGED
@@ -476,6 +476,18 @@ trait Derive
476
  if ($this->data->os->version->is('10.13')) {
477
  $this->data->os->version->nickname = 'High Sierra';
478
  }
 
 
 
 
 
 
 
 
 
 
 
 
479
  }
480
  }
481
  }
476
  if ($this->data->os->version->is('10.13')) {
477
  $this->data->os->version->nickname = 'High Sierra';
478
  }
479
+
480
+ if ($this->data->os->version->is('10.14')) {
481
+ $this->data->os->version->nickname = 'Mojave';
482
+ }
483
+
484
+ if ($this->data->os->version->is('10.15')) {
485
+ $this->data->os->version->nickname = 'Catalina';
486
+ }
487
+
488
+ if ($this->data->os->version->is('11.0')) {
489
+ $this->data->os->version->nickname = 'Big Sur';
490
+ }
491
  }
492
  }
493
  }
integration/whichbrowser/src/Analyser/Header.php CHANGED
@@ -82,7 +82,7 @@ trait Header
82
 
83
  private function analyseUserAgent($header)
84
  {
85
- new Header\Useragent($header, $this->data);
86
  }
87
 
88
  private function analyseBaiduHeader($header)
@@ -139,9 +139,11 @@ trait Header
139
 
140
  private function getHeader($h)
141
  {
 
142
  foreach ($this->headers as $k => $v) {
143
  if (strtolower($h) == strtolower($k)) {
144
- return $v;
 
145
  }
146
  }
147
  }
82
 
83
  private function analyseUserAgent($header)
84
  {
85
+ new Header\Useragent($header, $this->data, $this->options);
86
  }
87
 
88
  private function analyseBaiduHeader($header)
139
 
140
  private function getHeader($h)
141
  {
142
+ /* Find the header that matches */
143
  foreach ($this->headers as $k => $v) {
144
  if (strtolower($h) == strtolower($k)) {
145
+ /* And return the first 1024 bytes */
146
+ return substr($v, 0, 1024);
147
  }
148
  }
149
  }
integration/whichbrowser/src/Analyser/Header/Useragent.php CHANGED
@@ -6,9 +6,10 @@ class Useragent
6
  {
7
  use Useragent\Os, Useragent\Device, Useragent\Browser, Useragent\Application, Useragent\Using, Useragent\Engine, Useragent\Bot;
8
 
9
- public function __construct($header, &$data)
10
  {
11
  $this->data =& $data;
 
12
 
13
  /* Make sure we do not have a duplicate concatenated useragent string */
14
 
6
  {
7
  use Useragent\Os, Useragent\Device, Useragent\Browser, Useragent\Application, Useragent\Using, Useragent\Engine, Useragent\Bot;
8
 
9
+ public function __construct($header, &$data, &$options)
10
  {
11
  $this->data =& $data;
12
+ $this->options =& $options;
13
 
14
  /* Make sure we do not have a duplicate concatenated useragent string */
15
 
integration/whichbrowser/src/Analyser/Header/Useragent/Browser.php CHANGED
@@ -15,8 +15,8 @@ trait Browser
15
  /* Detect major browsers */
16
  $this->detectSafari($ua);
17
  $this->detectExplorer($ua);
18
- $this->detectFirefox($ua);
19
  $this->detectChrome($ua);
 
20
  $this->detectEdge($ua);
21
  $this->detectOpera($ua);
22
 
@@ -185,7 +185,6 @@ trait Browser
185
 
186
  /* Samsung Chromium based browsers */
187
  if (isset($this->data->device->manufacturer) && $this->data->device->manufacturer == 'Samsung') {
188
-
189
  /* Version 1.0 */
190
  if ($version == '18.0.1025.308' && preg_match('/Version\/1.0/u', $ua)) {
191
  $this->data->browser->name = "Samsung Internet";
@@ -243,7 +242,7 @@ trait Browser
243
 
244
  /* Oculus Chromium based browsers */
245
  if (preg_match('/OculusBrowser\/([0-9.]*)/u', $ua, $match)) {
246
- $this->data->browser->name = "Oculus Internet";
247
  $this->data->browser->channel = null;
248
  $this->data->browser->stock = true;
249
  $this->data->browser->version = new Version([ 'value' => $match[1], 'details' => 2 ]);
@@ -253,6 +252,12 @@ trait Browser
253
  $this->data->device->model = 'Gear VR';
254
  $this->data->device->type = Constants\DeviceType::HEADSET;
255
  }
 
 
 
 
 
 
256
  }
257
  } elseif (isset($this->data->os->name) && $this->data->os->name == 'Linux' && preg_match('/SamsungBrowser\/([0-9.]*)/u', $ua, $match)) {
258
  $this->data->browser->name = "Samsung Internet";
@@ -458,6 +463,19 @@ trait Browser
458
  }
459
  }
460
 
 
 
 
 
 
 
 
 
 
 
 
 
 
461
 
462
  /* Set the browser family */
463
 
@@ -485,6 +503,13 @@ trait Browser
485
  $this->data->browser->version = new Version([ 'value' => $match[2], 'details' => 1, 'hidden' => true ]);
486
  $this->data->browser->type = Constants\BrowserType::BROWSER;
487
  }
 
 
 
 
 
 
 
488
  }
489
 
490
 
@@ -492,7 +517,7 @@ trait Browser
492
 
493
  private function detectOpera($ua)
494
  {
495
- if (!preg_match('/(OPR|OMI|Opera|OPiOS|Coast|Oupeng)/ui', $ua)) {
496
  return;
497
  }
498
 
@@ -630,6 +655,16 @@ trait Browser
630
  $this->data->browser->type = Constants\BrowserType::BROWSER;
631
  }
632
 
 
 
 
 
 
 
 
 
 
 
633
  if (preg_match('/Coast\/([0-9.]*)/u', $ua, $match)) {
634
  $this->data->browser->stock = false;
635
  $this->data->browser->name = 'Coast by Opera';
@@ -643,6 +678,20 @@ trait Browser
643
  $this->data->browser->version = new Version([ 'value' => $match[1], 'details' => 2 ]);
644
  $this->data->browser->type = Constants\BrowserType::BROWSER;
645
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
646
  }
647
 
648
 
@@ -650,7 +699,7 @@ trait Browser
650
 
651
  private function detectFirefox($ua)
652
  {
653
- if (!preg_match('/(Firefox|GranParadiso|Namoroka|Shiretoko|Minefield|BonEcho|Fennec|Phoenix|Firebird|Minimo|FxiOS)/ui', $ua)) {
654
  return;
655
  }
656
 
@@ -714,8 +763,7 @@ trait Browser
714
  }
715
  }
716
 
717
-
718
- if (preg_match('/(GranParadiso|Namoroka|Shiretoko|Minefield|BonEcho)/u', $ua, $match)) {
719
  $this->data->browser->stock = false;
720
  $this->data->browser->name = 'Firefox';
721
  $this->data->browser->channel = str_replace('GranParadiso', 'Gran Paradiso', $match[1]);
@@ -754,6 +802,12 @@ trait Browser
754
  $this->data->browser->type = Constants\BrowserType::BROWSER;
755
  }
756
 
 
 
 
 
 
 
757
  if (preg_match('/Servo\/1.0 Firefox\//u', $ua)) {
758
  $this->data->browser->name = 'Servo Nightly Build';
759
  $this->data->browser->version = null;
@@ -1405,7 +1459,7 @@ trait Browser
1405
  }
1406
  }
1407
 
1408
- if (preg_match('/(Q)0?([0-9][A-Z])/u', $ua, $match)) {
1409
  $this->data->browser->name = 'Obigo ' . $match[1];
1410
  $this->data->browser->version = new Version($processObigoVersion($match[2]));
1411
  $this->data->browser->type = Constants\BrowserType::BROWSER;
@@ -1814,7 +1868,7 @@ trait Browser
1814
 
1815
  private function detectDesktopBrowsers($ua)
1816
  {
1817
- if (!preg_match('/(WebPositive|WebExplorer|WorldWideweb|Midori|Maxthon|Browse)/ui', $ua)) {
1818
  return;
1819
  }
1820
 
@@ -1911,6 +1965,21 @@ trait Browser
1911
  $this->data->browser->version = new Version([ 'value' => $match[1] ]);
1912
  $this->data->browser->type = Constants\BrowserType::BROWSER;
1913
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1914
  }
1915
 
1916
  private function detectMobileBrowsers($ua)
@@ -2414,7 +2483,6 @@ trait Browser
2414
  if (isset($match[1])) {
2415
  $this->data->browser->version = new Version([ 'value' => $match[1] ]);
2416
  }
2417
-
2418
  }
2419
 
2420
  if (preg_match('/WAP Browser\/MAUI/ui', $ua, $match)) {
15
  /* Detect major browsers */
16
  $this->detectSafari($ua);
17
  $this->detectExplorer($ua);
 
18
  $this->detectChrome($ua);
19
+ $this->detectFirefox($ua);
20
  $this->detectEdge($ua);
21
  $this->detectOpera($ua);
22
 
185
 
186
  /* Samsung Chromium based browsers */
187
  if (isset($this->data->device->manufacturer) && $this->data->device->manufacturer == 'Samsung') {
 
188
  /* Version 1.0 */
189
  if ($version == '18.0.1025.308' && preg_match('/Version\/1.0/u', $ua)) {
190
  $this->data->browser->name = "Samsung Internet";
242
 
243
  /* Oculus Chromium based browsers */
244
  if (preg_match('/OculusBrowser\/([0-9.]*)/u', $ua, $match)) {
245
+ $this->data->browser->name = "Oculus Browser";
246
  $this->data->browser->channel = null;
247
  $this->data->browser->stock = true;
248
  $this->data->browser->version = new Version([ 'value' => $match[1], 'details' => 2 ]);
252
  $this->data->device->model = 'Gear VR';
253
  $this->data->device->type = Constants\DeviceType::HEADSET;
254
  }
255
+
256
+ if (preg_match('/Pacific/', $ua)) {
257
+ $this->data->device->manufacturer = 'Oculus';
258
+ $this->data->device->model = 'Go';
259
+ $this->data->device->type = Constants\DeviceType::HEADSET;
260
+ }
261
  }
262
  } elseif (isset($this->data->os->name) && $this->data->os->name == 'Linux' && preg_match('/SamsungBrowser\/([0-9.]*)/u', $ua, $match)) {
263
  $this->data->browser->name = "Samsung Internet";
463
  }
464
  }
465
 
466
+ /* Microsoft Open Live Writer */
467
+
468
+ if (preg_match('/Open Live Writer ([0-9.]*)/u', $ua, $match)) {
469
+ $this->data->browser->type = Constants\BrowserType::BROWSER;
470
+ $this->data->browser->stock = false;
471
+ $this->data->browser->name = 'Open Live Writer';
472
+ $this->data->browser->version = new Version([ 'value' => $match[1] ]);
473
+ $this->data->browser->channel = null;
474
+
475
+ if (preg_match('/MSIE ([0-9.]*)/u', $ua, $match)) {
476
+ $this->data->browser->using = new Using([ 'name' => 'Internet Explorer', 'version' => new Version([ 'value' => $match[1] ]) ]);
477
+ }
478
+ }
479
 
480
  /* Set the browser family */
481
 
503
  $this->data->browser->version = new Version([ 'value' => $match[2], 'details' => 1, 'hidden' => true ]);
504
  $this->data->browser->type = Constants\BrowserType::BROWSER;
505
  }
506
+
507
+ if (preg_match('/Edg\/([0-9.]*)/u', $ua, $match)) {
508
+ $this->data->browser->name = 'Edge';
509
+ $this->data->browser->channel = '';
510
+ $this->data->browser->version = new Version([ 'value' => $match[1], 'details' => 1 ]);
511
+ $this->data->browser->type = Constants\BrowserType::BROWSER;
512
+ }
513
  }
514
 
515
 
517
 
518
  private function detectOpera($ua)
519
  {
520
+ if (!preg_match('/(OPR|OMI|Opera|OPiOS|OPT|Coast|Oupeng|OPRGX|MMS)/ui', $ua)) {
521
  return;
522
  }
523
 
655
  $this->data->browser->type = Constants\BrowserType::BROWSER;
656
  }
657
 
658
+ if (preg_match('/OPT\/([0-9]\.[0-9.]+)?/u', $ua, $match)) {
659
+ $this->data->browser->stock = false;
660
+ $this->data->browser->name = 'Opera Touch';
661
+ $this->data->browser->type = Constants\BrowserType::BROWSER;
662
+
663
+ if (isset($match[1])) {
664
+ $this->data->browser->version = new Version([ 'value' => $match[1], 'details' => 2 ]);
665
+ }
666
+ }
667
+
668
  if (preg_match('/Coast\/([0-9.]*)/u', $ua, $match)) {
669
  $this->data->browser->stock = false;
670
  $this->data->browser->name = 'Coast by Opera';
678
  $this->data->browser->version = new Version([ 'value' => $match[1], 'details' => 2 ]);
679
  $this->data->browser->type = Constants\BrowserType::BROWSER;
680
  }
681
+
682
+ if (preg_match('/\sMMS\/([0-9.]*)$/u', $ua, $match)) {
683
+ $this->data->browser->stock = false;
684
+ $this->data->browser->name = 'Opera Neon';
685
+ $this->data->browser->version = new Version([ 'value' => $match[1], 'details' => 2 ]);
686
+ $this->data->browser->type = Constants\BrowserType::BROWSER;
687
+ }
688
+
689
+ if (preg_match('/OPRGX\/([0-9.]*)$/u', $ua, $match)) {
690
+ $this->data->browser->stock = false;
691
+ $this->data->browser->name = 'Opera GX';
692
+ $this->data->browser->version = new Version([ 'value' => $match[1], 'details' => 2 ]);
693
+ $this->data->browser->type = Constants\BrowserType::BROWSER;
694
+ }
695
  }
696
 
697
 
699
 
700
  private function detectFirefox($ua)
701
  {
702
+ if (!preg_match('/(Firefox|Lorentz|GranParadiso|Namoroka|Shiretoko|Minefield|BonEcho|Fennec|Phoenix|Firebird|Minimo|FxiOS|Focus)/ui', $ua)) {
703
  return;
704
  }
705
 
763
  }
764
  }
765
 
766
+ if (preg_match('/(Lorentz|GranParadiso|Namoroka|Shiretoko|Minefield|BonEcho)/u', $ua, $match)) {
 
767
  $this->data->browser->stock = false;
768
  $this->data->browser->name = 'Firefox';
769
  $this->data->browser->channel = str_replace('GranParadiso', 'Gran Paradiso', $match[1]);
802
  $this->data->browser->type = Constants\BrowserType::BROWSER;
803
  }
804
 
805
+ if (preg_match('/Focus\/([0-9.]*)/u', $ua, $match)) {
806
+ $this->data->browser->name = 'Firefox Focus';
807
+ $this->data->browser->version = new Version([ 'value' => $match[1] ]);
808
+ $this->data->browser->type = Constants\BrowserType::BROWSER;
809
+ }
810
+
811
  if (preg_match('/Servo\/1.0 Firefox\//u', $ua)) {
812
  $this->data->browser->name = 'Servo Nightly Build';
813
  $this->data->browser->version = null;
1459
  }
1460
  }
1461
 
1462
+ if (preg_match('/[^A-Z](Q)0?([0-9][A-Z])/u', $ua, $match)) {
1463
  $this->data->browser->name = 'Obigo ' . $match[1];
1464
  $this->data->browser->version = new Version($processObigoVersion($match[2]));
1465
  $this->data->browser->type = Constants\BrowserType::BROWSER;
1868
 
1869
  private function detectDesktopBrowsers($ua)
1870
  {
1871
+ if (!preg_match('/(WebPositive|WebExplorer|WorldWideweb|Midori|Maxthon|Browse|Flow)/ui', $ua)) {
1872
  return;
1873
  }
1874
 
1965
  $this->data->browser->version = new Version([ 'value' => $match[1] ]);
1966
  $this->data->browser->type = Constants\BrowserType::BROWSER;
1967
  }
1968
+
1969
+ /* Browse for Flow */
1970
+
1971
+ if (preg_match('/ Flow\/([0-9.]+)/u', $ua, $match)) {
1972
+ $this->data->browser->name = 'Flow';
1973
+ $this->data->browser->channel = '';
1974
+ $this->data->browser->version = new Version([ 'value' => $match[1] ]);
1975
+ $this->data->browser->type = Constants\BrowserType::BROWSER;
1976
+ unset($this->data->browser->family);
1977
+
1978
+ if (preg_match('/EkiohFlow\/[0-9\.]+M/u', $ua)) {
1979
+ $this->data->browser->name = 'Flow Nightly Build';
1980
+ $this->data->browser->version = null;
1981
+ }
1982
+ }
1983
  }
1984
 
1985
  private function detectMobileBrowsers($ua)
2483
  if (isset($match[1])) {
2484
  $this->data->browser->version = new Version([ 'value' => $match[1] ]);
2485
  }
 
2486
  }
2487
 
2488
  if (preg_match('/WAP Browser\/MAUI/ui', $ua, $match)) {
integration/whichbrowser/src/Analyser/Header/Useragent/Device/Ereader.php CHANGED
@@ -132,7 +132,6 @@ trait Ereader
132
  'series' => 'Reader',
133
  'type' => Constants\DeviceType::EREADER
134
  ]);
135
-
136
  }
137
  }
138
 
132
  'series' => 'Reader',
133
  'type' => Constants\DeviceType::EREADER
134
  ]);
 
135
  }
136
  }
137
 
integration/whichbrowser/src/Analyser/Header/Useragent/Device/Mobile.php CHANGED
@@ -78,7 +78,6 @@ trait Mobile
78
  }
79
 
80
  if (preg_match('/Nokia[- \/]?([^\/\);]+)/ui', $ua, $match)) {
81
-
82
  if ($match[1] == 'Browser') {
83
  return;
84
  }
@@ -1149,7 +1148,7 @@ trait Mobile
1149
  }
1150
  }
1151
 
1152
- function identifyBasedOnIdentifier()
1153
  {
1154
  if ($this->data->device->identified & Constants\Id::MATCH_UA) {
1155
  return;
@@ -1182,10 +1181,9 @@ trait Mobile
1182
  }
1183
  }
1184
 
1185
- function identifyBasedOnIdUsingOs($id)
1186
  {
1187
  switch ($this->data->os->getFamily()) {
1188
-
1189
  case 'Android':
1190
  $device = Data\DeviceModels::identify('android', $id);
1191
  if ($device->identified) {
@@ -1236,7 +1234,7 @@ trait Mobile
1236
  }
1237
  }
1238
 
1239
- function identifyBasedOnId($id)
1240
  {
1241
  if ($this->data->device->type != 'mobile') {
1242
  return;
78
  }
79
 
80
  if (preg_match('/Nokia[- \/]?([^\/\);]+)/ui', $ua, $match)) {
 
81
  if ($match[1] == 'Browser') {
82
  return;
83
  }
1148
  }
1149
  }
1150
 
1151
+ private function identifyBasedOnIdentifier()
1152
  {
1153
  if ($this->data->device->identified & Constants\Id::MATCH_UA) {
1154
  return;
1181
  }
1182
  }
1183
 
1184
+ private function identifyBasedOnIdUsingOs($id)
1185
  {
1186
  switch ($this->data->os->getFamily()) {
 
1187
  case 'Android':
1188
  $device = Data\DeviceModels::identify('android', $id);
1189
  if ($device->identified) {
1234
  }
1235
  }
1236
 
1237
+ private function identifyBasedOnId($id)
1238
  {
1239
  if ($this->data->device->type != 'mobile') {
1240
  return;
integration/whichbrowser/src/Analyser/Header/Useragent/Device/Television.php CHANGED
@@ -610,29 +610,96 @@ trait Television
610
 
611
  /* Roku */
612
 
613
- if (preg_match('/^Roku\/DVP-(?:[0-9A-Z]+-)?[0-9\.]+ \(([0-9]{2,2})/u', $ua, $match)) {
614
  $this->data->os->reset();
615
 
616
  $this->data->device->manufacturer = 'Roku';
617
  $this->data->device->type = Constants\DeviceType::TELEVISION;
618
-
619
- switch ($match[1]) {
620
- case '02':
621
- $this->data->device->model = '2 XS';
622
- $this->data->device->generic = false;
623
- break;
624
- case '04':
625
- $this->data->device->model = '3';
626
- $this->data->device->generic = false;
627
- break;
628
- case '07':
629
- $this->data->device->model = 'LT';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
630
  $this->data->device->generic = false;
631
- break;
632
- case '09':
633
- $this->data->device->model = 'Streaming Stick';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
634
  $this->data->device->generic = false;
635
- break;
636
  }
637
 
638
  $this->data->device->identified |= Constants\Id::MATCH_UA;
@@ -1058,7 +1125,6 @@ trait Television
1058
 
1059
 
1060
  if (isset($this->data->device->model) && isset($this->data->device->manufacturer)) {
1061
-
1062
  if ($this->data->device->manufacturer == 'Dune HD') {
1063
  if (preg_match('/tv([0-9]+[a-z]?)/u', $this->data->device->model, $match)) {
1064
  $this->data->device->model = 'TV-' . strtoupper($match[1]);
610
 
611
  /* Roku */
612
 
613
+ if (preg_match('/Roku(?:([0-9]+)[A-Z]+)?\/DVP-(?:([0-9]+)[A-Z]+-)?[0-9\.]+/u', $ua, $match)) {
614
  $this->data->os->reset();
615
 
616
  $this->data->device->manufacturer = 'Roku';
617
  $this->data->device->type = Constants\DeviceType::TELEVISION;
618
+
619
+ $models = [
620
+ '2000' => 'HD',
621
+ '2050' => 'XD',
622
+ '2100' => 'XDS',
623
+ '2400' => 'LT',
624
+ '2450' => 'LT',
625
+ '2500' => 'HD',
626
+ '2700' => 'LT',
627
+ '2710' => '1 SE',
628
+ '2720' => '2',
629
+ '3000' => '2 HD',
630
+ '3050' => '2 XD',
631
+ '3100' => '2 XS',
632
+ '3400' => 'Streaming Stick, MHL',
633
+ '3420' => 'Streaming Stick, MHL',
634
+ '3500' => 'Streaming Stick, HDMI',
635
+ '3600' => 'Streaming Stick',
636
+ '3700' => 'Express',
637
+ '3710' => 'Express+',
638
+ '3800' => 'Streaming Stick',
639
+ '3810' => 'Streaming Stick+',
640
+ '3900' => 'Express',
641
+ '3910' => 'Express+',
642
+ '3920' => 'Premiere',
643
+ '3921' => 'Premiere+',
644
+ '3930' => 'Express',
645
+ '3931' => 'Express+',
646
+ '4200' => '3',
647
+ '4210' => '2',
648
+ '4230' => '3',
649
+ '4400' => '4',
650
+ '4620' => 'Premiere',
651
+ '4630' => 'Premiere+',
652
+ '4640' => 'Ultra',
653
+ '4660' => 'Ultra',
654
+ '4661' => 'Ultra',
655
+ '4662' => 'Ultra LT',
656
+ '4670' => 'Ultra',
657
+ '4800' => 'Ultra',
658
+ ];
659
+
660
+ if (!empty($match[1]) || !empty($match[2])) {
661
+ $model = !empty($match[1]) ? $match[1] : $match[2];
662
+
663
+ if (isset($models[$model])) {
664
+ $this->data->device->model = $models[$model];
665
  $this->data->device->generic = false;
666
+ }
667
+ }
668
+
669
+ $this->data->device->identified |= Constants\Id::MATCH_UA;
670
+ }
671
+
672
+ if (preg_match('/Roku\/DVP-[0-9\.]+ \(([0-9A-Z]{2,2})[0-9]+\./u', $ua, $match)) {
673
+ $this->data->os->reset();
674
+
675
+ $this->data->device->manufacturer = 'Roku';
676
+ $this->data->device->type = Constants\DeviceType::TELEVISION;
677
+
678
+ $models = [
679
+ '02' => '2 XS',
680
+ '03' => 'LT',
681
+ '04' => '3',
682
+ '07' => 'LT',
683
+ '09' => 'Streaming Stick',
684
+ '29' => 'Ultra',
685
+ '30' => [ 'TCL', '4K Roku TV' ],
686
+ '51' => 'Express',
687
+ 'AE' => 'Express',
688
+ ];
689
+
690
+ if (!empty($match[1])) {
691
+ $model = $match[1];
692
+
693
+ if (isset($models[$model])) {
694
+ if (is_array($models[$model])) {
695
+ $this->data->device->manufacturer = $models[$model][0];
696
+ $this->data->device->model = $models[$model][1];
697
+ } else {
698
+ $this->data->device->model = $models[$model];
699
+ }
700
+
701
  $this->data->device->generic = false;
702
+ }
703
  }
704
 
705
  $this->data->device->identified |= Constants\Id::MATCH_UA;
1125
 
1126
 
1127
  if (isset($this->data->device->model) && isset($this->data->device->manufacturer)) {
 
1128
  if ($this->data->device->manufacturer == 'Dune HD') {
1129
  if (preg_match('/tv([0-9]+[a-z]?)/u', $this->data->device->model, $match)) {
1130
  $this->data->device->model = 'TV-' . strtoupper($match[1]);
integration/whichbrowser/src/Analyser/Header/Useragent/Engine.php CHANGED
@@ -16,6 +16,7 @@ trait Engine
16
  $this->detectPresto($ua);
17
  $this->detectTrident($ua);
18
  $this->detectEdgeHTMLUseragent($ua);
 
19
 
20
  return $this;
21
  }
@@ -171,4 +172,14 @@ trait Engine
171
  $this->data->engine->version = new Version([ 'value' => $match[1], 'hidden' => true ]);
172
  }
173
  }
 
 
 
 
 
 
 
 
 
 
174
  }
16
  $this->detectPresto($ua);
17
  $this->detectTrident($ua);
18
  $this->detectEdgeHTMLUseragent($ua);
19
+ $this->detectFlow($ua);
20
 
21
  return $this;
22
  }
172
  $this->data->engine->version = new Version([ 'value' => $match[1], 'hidden' => true ]);
173
  }
174
  }
175
+
176
+ /* Flow */
177
+
178
+ private function detectFlow($ua)
179
+ {
180
+ if (preg_match('/EkiohFlow\/([0-9.]*)/u', $ua, $match)) {
181
+ $this->data->engine->name = 'EkiohFlow';
182
+ $this->data->engine->version = new Version([ 'value' => $match[1] ]);
183
+ }
184
+ }
185
  }
integration/whichbrowser/src/Analyser/Header/Useragent/Os.php CHANGED
@@ -74,6 +74,10 @@ trait Os
74
  $this->data->os->version = new Version([ 'value' => str_replace('_', '.', $match[1]) ]);
75
  }
76
 
 
 
 
 
77
  if (preg_match('/iPhone Simulator;/u', $ua)) {
78
  $this->data->device->type = Constants\DeviceType::EMULATOR;
79
  } else {
@@ -93,19 +97,23 @@ trait Os
93
  }
94
  }
95
  }
96
- } /* OS X */
97
-
98
- elseif (preg_match('/Mac OS X/u', $ua) || preg_match('/;os=Mac/u', $ua)) {
99
  $this->data->os->name = 'OS X';
100
 
101
- if (preg_match('/Mac OS X (10[0-9\._]*)/u', $ua, $match)) {
102
  $this->data->os->version = new Version([ 'value' => str_replace('_', '.', $match[1]), 'details' => 2 ]);
103
  }
104
 
105
- if (preg_match('/;os=Mac (10[0-9[\.,]*)/u', $ua, $match)) {
106
  $this->data->os->version = new Version([ 'value' => str_replace(',', '.', $match[1]), 'details' => 2 ]);
107
  }
108
 
 
 
 
 
109
  $this->data->device->type = Constants\DeviceType::DESKTOP;
110
  }
111
 
@@ -113,12 +121,10 @@ trait Os
113
 
114
  if (preg_match('/Darwin(?:\/([0-9]+).[0-9]+)?/u', $ua, $match)) {
115
  if (preg_match('/\(X11;/u', $ua)) {
116
-
117
  /* Darwin */
118
  $this->data->os->name = 'Darwin';
119
  $this->data->device->type = Constants\DeviceType::DESKTOP;
120
  } elseif (preg_match('/\((?:x86_64|i386|Power%20Macintosh)\)/u', $ua)) {
121
-
122
  /* OS X */
123
  $this->data->os->name = 'OS X';
124
  $this->data->device->type = Constants\DeviceType::DESKTOP;
@@ -137,7 +143,6 @@ trait Os
137
  }
138
  }
139
  } else {
140
-
141
  /* iOS */
142
  $this->data->os->name = 'iOS';
143
  $this->data->device->type = Constants\DeviceType::MOBILE;
@@ -241,8 +246,7 @@ trait Os
241
 
242
  $candidates = [];
243
 
244
- if (preg_match('/Build/ui', $ua)) {
245
-
246
  /* Normal Android useragent strings */
247
 
248
  if (preg_match('/; [a-z][a-zA-Z][-_][a-zA-Z][a-zA-Z] ([^;]*[^;\s])\s+(?:BUILD|Build|build)/u', $ua, $match)) {
@@ -257,7 +261,6 @@ trait Os
257
  $candidates[] = $match[1];
258
  }
259
  } elseif (preg_match('/Release\//ui', $ua)) {
260
-
261
  /* WAP style useragent strings */
262
 
263
  if (preg_match('/^(?U)([^\/]+)(?U)(?:(?:_CMCC_TD|_CMCC|_TD|_TDLTE|_LTE)?\/[^\/]*)? Linux\/[0-9.+]+ Android\/[0-9.]+/u', $this->removeKnownPrefixes($ua), $match)) {
@@ -268,16 +271,14 @@ trait Os
268
  $candidates[] = $match[1];
269
  }
270
  } elseif (preg_match('/Mozilla\//ui', $ua)) {
271
-
272
  /* Old Android useragent strings */
273
 
274
- if (preg_match('/Linux; (?:U; )?Android [^;]+; (?:[a-zA-Z][a-zA-Z](?:[-_][a-zA-Z][a-zA-Z])?; )?(?:[^;]+; ?)?([^)\/;]+)\)/u', $ua, $match)) {
275
  $candidates[] = $match[1];
276
  } elseif (preg_match('/\(([^;]+);U;Android\/[^;]+;[0-9]+\*[0-9]+;CTC\/2.0\)/u', $ua, $match)) {
277
  $candidates[] = $match[1];
278
  }
279
  } else {
280
-
281
  /* Other applications */
282
 
283
  if (preg_match('/[34]G Explorer\/[0-9.]+ \(Linux;Android [0-9.]+,([^\)]+)\)/u', $ua, $match)) {
@@ -2417,7 +2418,6 @@ trait Os
2417
  $count = count($patterns);
2418
  for ($b = 0; $b < $count; $b++) {
2419
  for ($r = 0; $r < count($patterns[$b]['regexp']); $r++) {
2420
-
2421
  if (preg_match($patterns[$b]['regexp'][$r], $ua, $match)) {
2422
  $this->data->os->name = $patterns[$b]['name'];
2423
 
74
  $this->data->os->version = new Version([ 'value' => str_replace('_', '.', $match[1]) ]);
75
  }
76
 
77
+ if (preg_match('/iOS ([0-9.]*);/u', $ua, $match)) {
78
+ $this->data->os->version = new Version([ 'value' => $match[1] ]);
79
+ }
80
+
81
  if (preg_match('/iPhone Simulator;/u', $ua)) {
82
  $this->data->device->type = Constants\DeviceType::EMULATOR;
83
  } else {
97
  }
98
  }
99
  }
100
+ } elseif (preg_match('/Mac OS X/u', $ua) || preg_match('/;os=Mac/u', $ua)) {
101
+ /* OS X */
102
+
103
  $this->data->os->name = 'OS X';
104
 
105
+ if (preg_match('/Mac OS X (1[0-9][0-9\._]*)/u', $ua, $match)) {
106
  $this->data->os->version = new Version([ 'value' => str_replace('_', '.', $match[1]), 'details' => 2 ]);
107
  }
108
 
109
+ if (preg_match('/;os=Mac (1[0-9][0-9[\.,]*)/u', $ua, $match)) {
110
  $this->data->os->version = new Version([ 'value' => str_replace(',', '.', $match[1]), 'details' => 2 ]);
111
  }
112
 
113
+ if ($this->data->os->version && $this->data->os->version->is('10.16')) {
114
+ $this->data->os->version = new Version([ 'value' => '11.0', 'details' => 2 ]);
115
+ }
116
+
117
  $this->data->device->type = Constants\DeviceType::DESKTOP;
118
  }
119
 
121
 
122
  if (preg_match('/Darwin(?:\/([0-9]+).[0-9]+)?/u', $ua, $match)) {
123
  if (preg_match('/\(X11;/u', $ua)) {
 
124
  /* Darwin */
125
  $this->data->os->name = 'Darwin';
126
  $this->data->device->type = Constants\DeviceType::DESKTOP;
127
  } elseif (preg_match('/\((?:x86_64|i386|Power%20Macintosh)\)/u', $ua)) {
 
128
  /* OS X */
129
  $this->data->os->name = 'OS X';
130
  $this->data->device->type = Constants\DeviceType::DESKTOP;
143
  }
144
  }
145
  } else {
 
146
  /* iOS */
147
  $this->data->os->name = 'iOS';
148
  $this->data->device->type = Constants\DeviceType::MOBILE;
246
 
247
  $candidates = [];
248
 
249
+ if (preg_match('/Build/ui', $ua) && (!preg_match('/AppleWebKit.*Build/ui', $ua) || preg_match('/Build.*AppleWebKit/ui', $ua))) {
 
250
  /* Normal Android useragent strings */
251
 
252
  if (preg_match('/; [a-z][a-zA-Z][-_][a-zA-Z][a-zA-Z] ([^;]*[^;\s])\s+(?:BUILD|Build|build)/u', $ua, $match)) {
261
  $candidates[] = $match[1];
262
  }
263
  } elseif (preg_match('/Release\//ui', $ua)) {
 
264
  /* WAP style useragent strings */
265
 
266
  if (preg_match('/^(?U)([^\/]+)(?U)(?:(?:_CMCC_TD|_CMCC|_TD|_TDLTE|_LTE)?\/[^\/]*)? Linux\/[0-9.+]+ Android\/[0-9.]+/u', $this->removeKnownPrefixes($ua), $match)) {
271
  $candidates[] = $match[1];
272
  }
273
  } elseif (preg_match('/Mozilla\//ui', $ua)) {
 
274
  /* Old Android useragent strings */
275
 
276
+ if (preg_match('/Linux; (?:arm; |arm_64; )?(?:U; )?Android [^;]+; (?:[a-zA-Z][a-zA-Z](?:[-_][a-zA-Z][a-zA-Z])?; )?(?:[^;]+; ?)?([^)\/;]+)\)/u', $ua, $match)) {
277
  $candidates[] = $match[1];
278
  } elseif (preg_match('/\(([^;]+);U;Android\/[^;]+;[0-9]+\*[0-9]+;CTC\/2.0\)/u', $ua, $match)) {
279
  $candidates[] = $match[1];
280
  }
281
  } else {
 
282
  /* Other applications */
283
 
284
  if (preg_match('/[34]G Explorer\/[0-9.]+ \(Linux;Android [0-9.]+,([^\)]+)\)/u', $ua, $match)) {
2418
  $count = count($patterns);
2419
  for ($b = 0; $b < $count; $b++) {
2420
  for ($r = 0; $r < count($patterns[$b]['regexp']); $r++) {
 
2421
  if (preg_match($patterns[$b]['regexp'][$r], $ua, $match)) {
2422
  $this->data->os->name = $patterns[$b]['name'];
2423
 
integration/whichbrowser/src/Data/Applications.php CHANGED
@@ -26,7 +26,6 @@ class Applications
26
 
27
  foreach (self::$BROWSERS as $type => $list) {
28
  foreach ($list as $i => $item) {
29
-
30
  if (preg_match($item['regexp'], $ua, $match)) {
31
  return [
32
  'browser' => [
@@ -57,7 +56,6 @@ class Applications
57
 
58
  foreach (self::$OTHERS as $type => $list) {
59
  foreach ($list as $i => $item) {
60
-
61
  if (preg_match($item['regexp'], $ua, $match)) {
62
  return [
63
  'browser' => [
26
 
27
  foreach (self::$BROWSERS as $type => $list) {
28
  foreach ($list as $i => $item) {
 
29
  if (preg_match($item['regexp'], $ua, $match)) {
30
  return [
31
  'browser' => [
56
 
57
  foreach (self::$OTHERS as $type => $list) {
58
  foreach ($list as $i => $item) {
 
59
  if (preg_match($item['regexp'], $ua, $match)) {
60
  return [
61
  'browser' => [
integration/whichbrowser/src/Model/Primitive/Base.php CHANGED
@@ -76,6 +76,6 @@ class Base
76
  }
77
  }
78
 
79
- return implode($lines, ", ");
80
  }
81
  }
76
  }
77
  }
78
 
79
+ return implode(", ", $lines);
80
  }
81
  }
integration/whichbrowser/src/Model/Primitive/NameVersion.php CHANGED
@@ -12,14 +12,19 @@ class NameVersion extends Base
12
  {
13
  /**
14
  * @var string $name The name
15
- * @var string $alias An alternative name that is used for readable strings
16
- * @var \WhichBrowser\Model\Version $version Version information
17
  */
18
  public $name;
 
 
 
 
19
  public $alias;
 
 
 
 
20
  public $version;
21
 
22
-
23
  /**
24
  * Set the properties to the default values
25
  *
12
  {
13
  /**
14
  * @var string $name The name
 
 
15
  */
16
  public $name;
17
+
18
+ /**
19
+ * @var string $alias An alternative name that is used for readable strings
20
+ */
21
  public $alias;
22
+
23
+ /**
24
+ * @var \WhichBrowser\Model\Version $version Version information
25
+ */
26
  public $version;
27
 
 
28
  /**
29
  * Set the properties to the default values
30
  *
integration/whichbrowser/src/Model/Version.php CHANGED
@@ -251,7 +251,7 @@ class Version extends Base
251
  }
252
  }
253
 
254
- $version .= implode($v, '.');
255
 
256
  if (array_key_exists(5, $match) && strlen($match[5])) {
257
  $version .= $match[5] . (!empty($match[6]) ? $match[6] : '');
251
  }
252
  }
253
 
254
+ $version .= implode('.', $v);
255
 
256
  if (array_key_exists(5, $match) && strlen($match[5])) {
257
  $version .= $match[5] . (!empty($match[6]) ? $match[6] : '');
integration/woocommerce.php CHANGED
@@ -1,1113 +1,1149 @@
1
- <?php
2
- define( 'GTM4WP_WPFILTER_EEC_PRODUCT_ARRAY', 'gtm4wp_eec_product_array' );
3
- define( 'GTM4WP_WPFILTER_EEC_CART_ITEM', 'gtm4wp_eec_cart_item' );
4
- define( 'GTM4WP_WPFILTER_EEC_ORDER_ITEM', 'gtm4wp_eec_order_item' );
5
-
6
- $gtm4wp_product_counter = 0;
7
- $gtm4wp_last_widget_title = 'Sidebar Products';
8
- if ( function_exists( 'WC' ) ) {
9
- $GLOBALS['gtm4wp_is_woocommerce3_7'] = version_compare( WC()->version, '3.7', '>=' );
10
- } else {
11
- $GLOBALS['gtm4wp_is_woocommerce3_7'] = false;
12
- }
13
- $GLOBALS['gtm4wp_grouped_product_ix'] = 1;
14
-
15
- // from https://snippets.webaware.com.au/ramblings/php-really-doesnt-unicode/
16
- function gtm4wp_untexturize( $fancy ) {
17
- $fixes = false;
18
-
19
- if ( $fixes === false ) {
20
- $fixes = array(
21
- json_decode( '"\u201C"' ) => '"', // left double quotation mark
22
- json_decode( '"\u201D"' ) => '"', // right double quotation mark
23
- json_decode( '"\u2018"' ) => "'", // left single quotation mark
24
- json_decode( '"\u2019"' ) => "'", // right single quotation mark
25
- json_decode( '"\u2032"' ) => "'", // prime (minutes, feet)
26
- json_decode( '"\u2033"' ) => '"', // double prime (seconds, inches)
27
- json_decode( '"\u2013"' ) => '-', // en dash
28
- json_decode( '"\u2014"' ) => '--', // em dash
29
- );
30
- }
31
-
32
- $normal = strtr( $fancy, $fixes );
33
-
34
- return $normal;
35
- }
36
-
37
- function gtm4wp_woocommerce_html_entity_decode( $val ) {
38
- return gtm4wp_untexturize( html_entity_decode( $val, ENT_QUOTES, 'utf-8' ) );
39
- }
40
-
41
- function gtm4wp_prefix_productid( $product_id ) {
42
- global $gtm4wp_options;
43
-
44
- if ( '' != $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMPRODIDPREFIX ] ) {
45
- return $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMPRODIDPREFIX ] . $product_id;
46
- } else {
47
- return $product_id;
48
- }
49
- }
50
-
51
- // from https://stackoverflow.com/questions/1252693/using-str-replace-so-that-it-only-acts-on-the-first-match
52
- function gtm4wp_str_replace_first( $from, $to, $subject ) {
53
- $from = '/' . preg_quote( $from, '/' ) . '/';
54
-
55
- return preg_replace( $from, $to, $subject, 1 );
56
- }
57
-
58
- function gtm4wp_get_product_category_hierarchy( $category_id ) {
59
- $cat_hierarchy = '';
60
-
61
- $category_parent_list = get_term_parents_list(
62
- $category_id,
63
- 'product_cat',
64
- array(
65
- 'format' => 'name',
66
- 'separator' => '/',
67
- 'link' => false,
68
- 'inclusive' => true,
69
- )
70
- );
71
-
72
- if ( is_string( $category_parent_list ) ) {
73
- $cat_hierarchy = trim( $category_parent_list, '/' );
74
- }
75
-
76
- return $cat_hierarchy;
77
- }
78
-
79
- function gtm4wp_get_product_category( $product_id, $fullpath = false ) {
80
- $product_cat = '';
81
-
82
- $_product_cats = get_the_terms( $product_id, 'product_cat' );
83
- if ( ( is_array( $_product_cats ) ) && ( count( $_product_cats ) > 0 ) ) {
84
- $first_product_cat = array_pop( $_product_cats );
85
- if ( $fullpath ) {
86
- $product_cat = gtm4wp_get_product_category_hierarchy( $first_product_cat->term_id );
87
- } else {
88
- $product_cat = $first_product_cat->name;
89
- }
90
- }
91
-
92
- return $product_cat;
93
- }
94
-
95
- function gtm4wp_woocommerce_getproductterm( $product_id, $taxonomy ) {
96
- $gtm4wp_product_terms = get_the_terms( $product_id, $taxonomy );
97
- if ( is_array( $gtm4wp_product_terms ) && ( count( $gtm4wp_product_terms ) > 0 ) ) {
98
- return $gtm4wp_product_terms[0]->name;
99
- }
100
-
101
- return "";
102
- }
103
-
104
- function gtm4wp_process_product( $product, $additional_product_attributes, $attributes_used_for ) {
105
- global $gtm4wp_options;
106
-
107
- if ( ! $product ) {
108
- return false;
109
- }
110
-
111
- if ( ! ( $product instanceof WC_Product ) ) {
112
- return false;
113
- }
114
-
115
- $product_id = $product->get_id();
116
- $product_type = $product->get_type();
117
- $remarketing_id = $product_id;
118
- $product_sku = $product->get_sku();
119
-
120
- if ( 'variation' == $product_type ) {
121
- $parent_product_id = $product->get_parent_id();
122
- $product_cat = gtm4wp_get_product_category( $parent_product_id, $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCUSEFULLCATEGORYPATH ] );
123
- } else {
124
- $product_cat = gtm4wp_get_product_category( $product_id, $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCUSEFULLCATEGORYPATH ] );
125
- }
126
-
127
- if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCUSESKU ] && ( '' != $product_sku ) ) {
128
- $remarketing_id = $product_sku;
129
- }
130
-
131
- $_temp_productdata = array(
132
- 'id' => $remarketing_id,
133
- 'name' => $product->get_title(),
134
- 'sku' => $product_sku ? $product_sku : $product_id,
135
- 'category' => $product_cat,
136
- 'price' => (float) wc_get_price_to_display( $product ),
137
- 'stocklevel' => $product->get_stock_quantity()
138
- );
139
-
140
- if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCEECBRANDTAXONOMY ] != "" ) {
141
- if ( isset( $parent_product_id ) && ( $parent_product_id !== 0 ) ) {
142
- $product_id_to_query = $parent_product_id;
143
- } else {
144
- $product_id_to_query = $product_id;
145
- }
146
-
147
- $_temp_productdata[ "brand" ] = gtm4wp_woocommerce_getproductterm( $product_id_to_query, $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCEECBRANDTAXONOMY ] );
148
- }
149
-
150
- if ( 'variation' == $product_type ) {
151
- $_temp_productdata['variant'] = implode( ',', $product->get_variation_attributes() );
152
- }
153
-
154
- $_temp_productdata = array_merge( $_temp_productdata, $additional_product_attributes );
155
-
156
- return apply_filters( GTM4WP_WPFILTER_EEC_PRODUCT_ARRAY, $_temp_productdata, $attributes_used_for );
157
- }
158
-
159
- function gtm4wp_map_eec_to_ga4( $productdata ) {
160
- if ( !is_array($productdata) ) {
161
- return;
162
- }
163
-
164
- $category_path = array_key_exists( "category", $productdata ) ? $productdata[ "category" ] : "";
165
- $category_parts = explode('/', $category_path);
166
-
167
- // default, required parameters
168
- $ga4_product = array(
169
- 'item_id' => array_key_exists( "id", $productdata ) ? $productdata[ "id" ] : "",
170
- 'item_name' => array_key_exists( "name", $productdata ) ? $productdata[ "name" ] : "",
171
- 'item_brand' => array_key_exists( "brand", $productdata ) ? $productdata[ "brand" ] : "",
172
- 'price' => array_key_exists( "price", $productdata ) ? $productdata[ "price" ] : ""
173
- );
174
-
175
- // category, also handle category path
176
- if ( 1 == count($category_parts) ) {
177
- $ga4_product[ "item_category" ] = $category_parts[0];
178
- } else if ( count($category_parts) > 1 ) {
179
- $ga4_product[ "item_category" ] = $category_parts[0];
180
- for( $i=1; $i < min( 5, count( $category_parts ) ); $i++ ) {
181
- $ga4_product[ "item_category_" . (string)($i+1) ] = $category_parts[$i];
182
- }
183
- }
184
-
185
- // optional parameters which should not be included in the array if not set
186
- if ( array_key_exists( "variant", $productdata ) ) {
187
- $ga4_product[ "item_variant" ] = $productdata[ "variant" ];
188
- }
189
- if ( array_key_exists( "listname", $productdata ) ) {
190
- $ga4_product[ "item_list_name" ] = $productdata[ "listname" ];
191
- }
192
- if ( array_key_exists( "listposition", $productdata ) ) {
193
- $ga4_product[ "index" ] = $productdata[ "listposition" ];
194
- }
195
- if ( array_key_exists( "quantity", $productdata ) ) {
196
- $ga4_product[ "quantity" ] = $productdata[ "quantity" ];
197
- }
198
- if ( array_key_exists( "coupon", $productdata ) ) {
199
- $ga4_product[ "coupon" ] = $productdata[ "coupon" ];
200
- }
201
-
202
- return $ga4_product;
203
- }
204
-
205
- function gtm4wp_process_order_items( $order ) {
206
- global $gtm4wp_options;
207
-
208
- $return_data = array(
209
- 'products' => [],
210
- 'sumprice' => 0,
211
- 'product_ids' => []
212
- );
213
-
214
- if ( ! $order ) {
215
- return $return_data;
216
- }
217
-
218
- $order_items = $order->get_items();
219
-
220
- if ( $order_items ) {
221
- foreach ( $order_items as $item ) {
222
- if ( ! apply_filters( GTM4WP_WPFILTER_EEC_ORDER_ITEM, true, $item ) ) {
223
- continue;
224
- }
225
-
226
- $product = $item->get_product();
227
- $inc_tax = ( 'incl' === get_option( 'woocommerce_tax_display_shop' ) );
228
- $product_price = (float) $order->get_item_total( $item, $inc_tax );
229
- $eec_product_array = gtm4wp_process_product( $product, array(
230
- 'quantity' => $item->get_quantity(),
231
- 'price' => $product_price
232
- ), 'purchase' );
233
-
234
- if ( $eec_product_array ) {
235
- $return_data['products'][] = $eec_product_array;
236
- $return_data['sumprice'] += $product_price * $eec_product_array['quantity'];
237
- $return_data['product_ids'][] = gtm4wp_prefix_productid( $eec_product_array['id'] );
238
- }
239
- }
240
- }
241
-
242
- return $return_data;
243
- }
244
-
245
- function gtm4wp_woocommerce_addglobalvars( $return = '' ) {
246
- global $gtm4wp_options;
247
-
248
- if ( function_exists( 'WC' ) && WC()->cart ) {
249
- $gtm4wp_needs_shipping_address = (bool) WC()->cart->needs_shipping_address();
250
- } else {
251
- $gtm4wp_needs_shipping_address = false;
252
- }
253
-
254
- $return .= '
255
- var gtm4wp_use_sku_instead = ' . (int) ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCUSESKU ] ) . ";
256
- var gtm4wp_id_prefix = '" . esc_js( gtm4wp_prefix_productid( '' ) ) . "';
257
- var gtm4wp_remarketing = " . gtm4wp_escjs_boolean( (bool) ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ] ) ) . ';
258
- var gtm4wp_eec = ' . gtm4wp_escjs_boolean( (bool) ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) ) . ';
259
- var gtm4wp_classicec = ' . gtm4wp_escjs_boolean( (bool) ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC ] ) ) . ";
260
- var gtm4wp_currency = '" . esc_js( get_woocommerce_currency() ) . "';
261
- var gtm4wp_product_per_impression = " . (int) ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCPRODPERIMPRESSION ] ) . ';
262
- var gtm4wp_needs_shipping_address = ' . gtm4wp_escjs_boolean( $gtm4wp_needs_shipping_address ) . ';';
263
-
264
- return $return;
265
- }
266
-
267
- function gtm4wp_woocommerce_datalayer_filter_items( $dataLayer ) {
268
- global $gtm4wp_options, $wp_query, $gtm4wp_datalayer_name, $gtm4wp_product_counter, $gtm4wp_is_woocommerce3_7;
269
-
270
- $woo = WC();
271
-
272
- if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCCUSTOMERDATA ] ) {
273
- if ( $woo->customer instanceof WC_Customer ) {
274
- // we need to use this instead of $woo->customer as this will load proper total order number and value from the database instead of the session
275
- $woo_customer = new WC_Customer( $woo->customer->get_id() );
276
-
277
- $dataLayer['customerTotalOrders'] = $woo_customer->get_order_count();
278
- $dataLayer['customerTotalOrderValue'] = $woo_customer->get_total_spent();
279
-
280
- $dataLayer['customerFirstName'] = $woo_customer->get_first_name();
281
- $dataLayer['customerLastName'] = $woo_customer->get_last_name();
282
-
283
- $dataLayer['customerBillingFirstName'] = $woo_customer->get_billing_first_name();
284
- $dataLayer['customerBillingLastName'] = $woo_customer->get_billing_last_name();
285
- $dataLayer['customerBillingCompany'] = $woo_customer->get_billing_company();
286
- $dataLayer['customerBillingAddress1'] = $woo_customer->get_billing_address_1();
287
- $dataLayer['customerBillingAddress2'] = $woo_customer->get_billing_address_2();
288
- $dataLayer['customerBillingCity'] = $woo_customer->get_billing_city();
289
- $dataLayer['customerBillingPostcode'] = $woo_customer->get_billing_postcode();
290
- $dataLayer['customerBillingCountry'] = $woo_customer->get_billing_country();
291
- $dataLayer['customerBillingEmail'] = $woo_customer->get_billing_email();
292
- $dataLayer['customerBillingPhone'] = $woo_customer->get_billing_phone();
293
-
294
- $dataLayer['customerShippingFirstName'] = $woo_customer->get_shipping_first_name();
295
- $dataLayer['customerShippingLastName'] = $woo_customer->get_shipping_last_name();
296
- $dataLayer['customerShippingCompany'] = $woo_customer->get_shipping_company();
297
- $dataLayer['customerShippingAddress1'] = $woo_customer->get_shipping_address_1();
298
- $dataLayer['customerShippingAddress2'] = $woo_customer->get_shipping_address_2();
299
- $dataLayer['customerShippingCity'] = $woo_customer->get_shipping_city();
300
- $dataLayer['customerShippingPostcode'] = $woo_customer->get_shipping_postcode();
301
- $dataLayer['customerShippingCountry'] = $woo_customer->get_shipping_country();
302
- }
303
- }
304
-
305
- if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCEINCLUDECARTINDL ] && version_compare( $woo->version, "3.2", ">=" ) ) {
306
- $current_cart = $woo->cart;
307
- $dataLayer["cartContent"] = array(
308
- "totals" => array(
309
- "applied_coupons" => $current_cart->get_applied_coupons(),
310
- "discount_total" => $current_cart->get_discount_total(),
311
- "subtotal" => $current_cart->get_subtotal(),
312
- "total" => $current_cart->get_cart_contents_total()
313
- ),
314
- "items" => array()
315
- );
316
-
317
- foreach( $current_cart->get_cart() as $cart_item_id => $cart_item_data) {
318
- $product = apply_filters( 'woocommerce_cart_item_product', $cart_item_data["data"], $cart_item_data, $cart_item_id );
319
- if (
320
- !apply_filters( GTM4WP_WPFILTER_EEC_CART_ITEM, true, $cart_item_data )
321
- || !apply_filters( 'woocommerce_widget_cart_item_visible', true, $cart_item_data, $cart_item_id )
322
- ) {
323
- continue;
324
- }
325
-
326
- $eec_product_array = gtm4wp_process_product( $product, array(
327
- 'quantity' => $cart_item_data["quantity"]
328
- ), 'cart' );
329
-
330
- $dataLayer["cartContent"]["items"][] = $eec_product_array;
331
- }
332
- }
333
-
334
- if ( is_product_category() || is_product_tag() || is_front_page() || is_shop() ) {
335
- $ecomm_pagetype = 'category';
336
- if ( is_front_page() ) {
337
- $ecomm_pagetype = 'home';
338
- } elseif ( is_search() ) {
339
- $ecomm_pagetype = 'searchresults';
340
- }
341
-
342
- if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ] ) {
343
- $dataLayer['ecomm_prodid'] = array();
344
- $dataLayer['ecomm_pagetype'] = $ecomm_pagetype;
345
- $dataLayer['ecomm_totalvalue'] = 0;
346
- }
347
- } elseif ( is_product() ) {
348
- if (
349
- $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ]
350
- || ( true === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] )
351
- ) {
352
- $postid = get_the_ID();
353
- $product = wc_get_product( $postid );
354
-
355
- $eec_product_array = gtm4wp_process_product( $product, array(), 'productdetail' );
356
-
357
- $dataLayer['productRatingCounts'] = $product->get_rating_counts();
358
- $dataLayer['productAverageRating'] = (float) $product->get_average_rating();
359
- $dataLayer['productReviewCount'] = (int) $product->get_review_count();
360
- $dataLayer['productType'] = $product->get_type();
361
-
362
- switch ( $dataLayer['productType'] ) {
363
- case 'variable': {
364
- $dataLayer['productIsVariable'] = 1;
365
-
366
- $dataLayer['ecomm_prodid'] = gtm4wp_prefix_productid( $eec_product_array[ 'id' ] );
367
- $dataLayer['ecomm_pagetype'] = 'product';
368
- $dataLayer['ecomm_totalvalue'] = $eec_product_array[ 'price' ];
369
-
370
- break;
371
- }
372
-
373
- case 'grouped': {
374
- $dataLayer['productIsVariable'] = 0;
375
-
376
- break;
377
- }
378
-
379
- default: {
380
- $dataLayer['productIsVariable'] = 0;
381
-
382
- if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ] ) {
383
- $dataLayer['ecomm_prodid'] = gtm4wp_prefix_productid( $eec_product_array[ 'id' ] );
384
- $dataLayer['ecomm_pagetype'] = 'product';
385
- $dataLayer['ecomm_totalvalue'] = $eec_product_array['price'];
386
- }
387
-
388
- if ( true === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) {
389
- $currencyCode = get_woocommerce_currency();
390
-
391
- $dataLayer['ecommerce'] = array(
392
- 'currencyCode' => $currencyCode,
393
- 'detail' => array(
394
- 'products' => array(
395
- $eec_product_array
396
- )
397
- )
398
- );
399
- }
400
- }
401
- }
402
- }
403
- } elseif ( is_cart() ) {
404
- if (
405
- $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ]
406
- || $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCEECCARTASFIRSTSTEP ]
407
- || $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ]
408
- ) {
409
- $gtm4wp_cart_products = array();
410
- $gtm4wp_cart_products_remarketing = array();
411
-
412
- $gtm4wp_currency = get_woocommerce_currency();
413
-
414
- foreach ( $woo->cart->get_cart() as $cart_item_id => $cart_item_data ) {
415
- $product = apply_filters( 'woocommerce_cart_item_product', $cart_item_data['data'], $cart_item_data, $cart_item_id );
416
-
417
- if ( ! apply_filters( GTM4WP_WPFILTER_EEC_CART_ITEM, true, $cart_item_data ) ) {
418
- continue;
419
- }
420
-
421
- $eec_product_array = gtm4wp_process_product( $product, array(
422
- 'quantity' => $cart_item_data['quantity']
423
- ), 'cart' );
424
-
425
- $gtm4wp_cart_products[] = $eec_product_array;
426
- $gtm4wp_cart_products_remarketing[] = gtm4wp_prefix_productid( $eec_product_array[ 'id' ] );
427
- }
428
-
429
- if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ] ) {
430
- $dataLayer['ecomm_prodid'] = $gtm4wp_cart_products_remarketing;
431
- $dataLayer['ecomm_pagetype'] = 'cart';
432
- if ( ! $woo->cart->prices_include_tax ) {
433
- $cart_total = $woo->cart->cart_contents_total;
434
- } else {
435
- $cart_total = $woo->cart->cart_contents_total + $woo->cart->tax_total;
436
- }
437
- $dataLayer['ecomm_totalvalue'] = (float) $cart_total;
438
- }
439
-
440
- if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) {
441
- if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCEECCARTASFIRSTSTEP ] ) {
442
- $dataLayer['ecommerce'] = array(
443
- 'currencyCode' => $gtm4wp_currency,
444
- 'checkout' => array(
445
- 'actionField' => array(
446
- 'step' => 1,
447
- ),
448
- 'products' => $gtm4wp_cart_products,
449
- )
450
- );
451
- } else {
452
- // add only ga4 products to populate view_cart event
453
- $dataLayer['ecommerce'] = array(
454
- 'cart' => $gtm4wp_cart_products
455
- );
456
- }
457
- }
458
- }
459
- } elseif ( is_order_received_page() ) {
460
- $do_not_flag_tracked_order = (bool) ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCNOORDERTRACKEDFLAG ] );
461
- $order_id = empty( $_GET['order'] ) ? ( $GLOBALS['wp']->query_vars['order-received'] ? $GLOBALS['wp']->query_vars['order-received'] : 0 ) : absint( $_GET['order'] );
462
- $order_id_filtered = apply_filters( 'woocommerce_thankyou_order_id', $order_id );
463
- if ( '' != $order_id_filtered ) {
464
- $order_id = $order_id_filtered;
465
- }
466
-
467
- $order_key = apply_filters( 'woocommerce_thankyou_order_key', empty( $_GET['key'] ) ? '' : wc_clean( $_GET['key'] ) );
468
-
469
- if ( $order_id > 0 ) {
470
- $order = wc_get_order( $order_id );
471
-
472
- if ( $order instanceof WC_Order ) {
473
- $this_order_key = $order->get_order_key();
474
-
475
- if ( $this_order_key != $order_key ) {
476
- unset( $order );
477
- }
478
- } else {
479
- unset( $order );
480
- }
481
- }
482
-
483
- if ( isset($order) && $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCORDERDATA ] ) {
484
- $order_items = gtm4wp_process_order_items( $order );
485
-
486
- $dataLayer['orderData'] = array(
487
- 'attributes' => array(
488
- 'date' => $order->get_date_created()->date( 'c' ),
489
-
490
- 'order_number' => $order->get_order_number(),
491
- 'order_key' => $order->get_order_key(),
492
-
493
- 'payment_method' => esc_js( $order->get_payment_method() ),
494
- 'payment_method_title' => esc_js( $order->get_payment_method_title() ),
495
-
496
- 'shipping_method' => esc_js( $order->get_shipping_method() ),
497
-
498
- 'status' => esc_js( $order->get_status() ),
499
-
500
- 'coupons' => implode( ', ', ( $gtm4wp_is_woocommerce3_7 ? $order->get_coupon_codes() : $order->get_used_coupons() ) )
501
- ),
502
- 'totals' => array(
503
- 'currency' => esc_js( $order->get_currency() ),
504
- 'discount_total' => esc_js( $order->get_discount_total() ),
505
- 'discount_tax' => esc_js( $order->get_discount_tax() ),
506
- 'shipping_total' => esc_js( $order->get_shipping_total() ),
507
- 'shipping_tax' => esc_js( $order->get_shipping_tax() ),
508
- 'cart_tax' => esc_js( $order->get_cart_tax() ),
509
- 'total' => esc_js( $order->get_total() ),
510
- 'total_tax' => esc_js( $order->get_total_tax() ),
511
- 'total_discount' => esc_js( $order->get_total_discount() ),
512
- 'subtotal' => esc_js( $order->get_subtotal() ),
513
- 'tax_totals' => $order->get_tax_totals()
514
- ),
515
- 'customer' => array(
516
- 'id' => $order->get_customer_id(),
517
-
518
- 'billing' => array(
519
- 'first_name' => esc_js( $order->get_billing_first_name() ),
520
- 'last_name' => esc_js( $order->get_billing_last_name() ),
521
- 'company' => esc_js( $order->get_billing_company() ),
522
- 'address_1' => esc_js( $order->get_billing_address_1() ),
523
- 'address_2' => esc_js( $order->get_billing_address_2() ),
524
- 'city' => esc_js( $order->get_billing_city() ),
525
- 'state' => esc_js( $order->get_billing_state() ),
526
- 'postcode' => esc_js( $order->get_billing_postcode() ),
527
- 'country' => esc_js( $order->get_billing_country() ),
528
- 'email' => esc_js( $order->get_billing_email() ),
529
- 'phone' => esc_js( $order->get_billing_phone() )
530
- ),
531
-
532
- 'shipping' => array(
533
- 'first_name' => esc_js( $order->get_shipping_first_name() ),
534
- 'last_name' => esc_js( $order->get_shipping_last_name() ),
535
- 'company' => esc_js( $order->get_shipping_company() ),
536
- 'address_1' => esc_js( $order->get_shipping_address_1() ),
537
- 'address_2' => esc_js( $order->get_shipping_address_2() ),
538
- 'city' => esc_js( $order->get_shipping_city() ),
539
- 'state' => esc_js( $order->get_shipping_state() ),
540
- 'postcode' => esc_js( $order->get_shipping_postcode() ),
541
- 'country' => esc_js( $order->get_shipping_country() )
542
- )
543
-
544
- ),
545
- 'items' => $order_items['products']
546
- );
547
- }
548
-
549
- if ( ( 1 == get_post_meta( $order_id, '_ga_tracked', true ) ) && ! $do_not_flag_tracked_order ) {
550
- unset( $order );
551
- }
552
-
553
- if ( isset( $_COOKIE[ 'gtm4wp_orderid_tracked' ] ) && ( $_COOKIE[ 'gtm4wp_orderid_tracked' ] == $order_id ) && ! $do_not_flag_tracked_order ) {
554
- unset( $order );
555
- }
556
-
557
- if ( isset( $order ) ) {
558
- if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCEXCLUDETAX ] ) {
559
- $order_revenue = (float)( $order->get_total() - $order->get_total_tax() );
560
- } else {
561
- $order_revenue = (float) $order->get_total();
562
- }
563
-
564
- $order_shipping_cost = (float) $order->get_shipping_total();
565
-
566
- if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCEXCLUDESHIPPING ] ) {
567
- $order_revenue -= $order_shipping_cost;
568
- }
569
-
570
- $order_currency = $order->get_currency();
571
-
572
- if ( true === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC ] ) {
573
- $dataLayer['event'] = 'gtm4wp.orderCompleted';
574
- $dataLayer['transactionId'] = $order->get_order_number();
575
- $dataLayer['transactionAffiliation'] = '';
576
- $dataLayer['transactionTotal'] = $order_revenue;
577
- $dataLayer['transactionShipping'] = $order_shipping_cost;
578
- $dataLayer['transactionTax'] = (float) $order->get_total_tax();
579
- $dataLayer['transactionCurrency'] = $order_currency;
580
- }
581
-
582
- if ( true === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) {
583
- $dataLayer['event'] = 'gtm4wp.orderCompletedEEC';
584
- $dataLayer['ecommerce'] = array(
585
- 'currencyCode' => $order_currency,
586
- 'purchase' => array(
587
- 'actionField' => array(
588
- 'id' => $order->get_order_number(),
589
- 'affiliation' => '',
590
- 'revenue' => $order_revenue,
591
- 'tax' => (float) $order->get_total_tax(),
592
- 'shipping' => (float)( $order->get_shipping_total() ),
593
- 'coupon' => implode( ', ', ( $gtm4wp_is_woocommerce3_7 ? $order->get_coupon_codes() : $order->get_used_coupons() ) ),
594
- )
595
- )
596
- );
597
- }
598
-
599
- if ( ! isset( $order_items ) ) {
600
- $order_items = gtm4wp_process_order_items( $order );
601
- }
602
-
603
- if ( true === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC ] ) {
604
- $dataLayer['transactionProducts'] = $order_items['products'];
605
- }
606
-
607
- if ( true === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) {
608
- $dataLayer['ecommerce']['purchase']['products'] = $order_items['products'];
609
- }
610
-
611
- if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ] ) {
612
- $dataLayer['ecomm_prodid'] = $order_items['product_ids'];
613
- $dataLayer['ecomm_pagetype'] = 'purchase';
614
- $dataLayer['ecomm_totalvalue'] = (float) $order_items['sumprice'];
615
- }
616
-
617
- if ( ! $do_not_flag_tracked_order ) {
618
- update_post_meta( $order_id, '_ga_tracked', 1 );
619
- }
620
- }
621
- } elseif ( is_checkout() ) {
622
- if (
623
- ( true === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] )
624
- || ( true === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ] )
625
- ) {
626
- $gtm4wp_checkout_products = array();
627
- $gtm4wp_checkout_products_remarketing = array();
628
- $gtm4wp_totalvalue = 0;
629
-
630
- foreach ( $woo->cart->get_cart() as $cart_item_id => $cart_item_data ) {
631
- $product = apply_filters( 'woocommerce_cart_item_product', $cart_item_data['data'], $cart_item_data, $cart_item_id );
632
-
633
- if ( ! apply_filters( GTM4WP_WPFILTER_EEC_CART_ITEM, true, $cart_item_data ) ) {
634
- continue;
635
- }
636
-
637
- $eec_product_array = gtm4wp_process_product( $product, array(
638
- 'quantity' => $cart_item_data['quantity']
639
- ), 'cart' );
640
-
641
- $gtm4wp_checkout_products[] = $eec_product_array;
642
-
643
- $gtm4wp_checkout_products_remarketing[] = gtm4wp_prefix_productid( $eec_product_array[ 'id' ] );
644
- $gtm4wp_totalvalue += $eec_product_array['quantity'] * $eec_product_array['price'];
645
- } // end foreach cart item
646
-
647
- if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ] ) {
648
- $dataLayer['ecomm_prodid'] = $gtm4wp_checkout_products_remarketing;
649
- $dataLayer['ecomm_pagetype'] = 'cart';
650
- $dataLayer['ecomm_totalvalue'] = (float) $gtm4wp_totalvalue;
651
- }
652
-
653
- if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) {
654
- $currencyCode = get_woocommerce_currency();
655
-
656
- $ga4_products = array();
657
- $sum_value = 0;
658
- foreach( $gtm4wp_checkout_products as $oneproduct ) {
659
- $ga4_products[] = gtm4wp_map_eec_to_ga4( $oneproduct );
660
- $sum_value += $oneproduct["price"] * $oneproduct["quantity"];
661
- }
662
-
663
- $dataLayer['ecommerce'] = array(
664
- 'currencyCode' => $currencyCode,
665
- 'checkout' => array(
666
- 'actionField' => array(
667
- 'step' => 1 + (int) $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCEECCARTASFIRSTSTEP ],
668
- ),
669
- 'products' => $gtm4wp_checkout_products,
670
- )
671
- );
672
-
673
- wc_enqueue_js('
674
- window.gtm4wp_checkout_products = ' . json_encode( $gtm4wp_checkout_products ) . ';
675
- window.gtm4wp_checkout_products_ga4 = ' . json_encode( $ga4_products ) . ';
676
- window.gtm4wp_checkout_value = ' . (float) $sum_value . ';
677
- window.gtm4wp_checkout_step_offset = ' . (int) $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCEECCARTASFIRSTSTEP ] . ';'
678
- );
679
- }
680
- }
681
- } else {
682
- if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ] ) {
683
- $dataLayer['ecomm_pagetype'] = 'other';
684
- }
685
- }
686
-
687
- if ( isset( $_COOKIE['gtm4wp_product_readded_to_cart'] ) ) {
688
- $cart_item = $woo->cart->get_cart_item( $_COOKIE['gtm4wp_product_readded_to_cart'] );
689
- if ( ! empty( $cart_item ) ) {
690
- $product = $cart_item['data'];
691
-
692
- $eec_product_array = gtm4wp_process_product( $product, array(
693
- 'quantity' => $cart_item['quantity']
694
- ), 'readdedtocart' );
695
-
696
- $currencyCode = get_woocommerce_currency();
697
-
698
- $dataLayer['event'] = 'gtm4wp.addProductToCartEEC';
699
- $dataLayer['ecommerce'] = array(
700
- 'currencyCode' => $currencyCode,
701
- 'add' => array(
702
- 'products' => array(
703
- $eec_product_array
704
- )
705
- )
706
- );
707
- }
708
-
709
- wc_enqueue_js( "document.cookie = 'gtm4wp_product_readded_to_cart=; expires=Thu, 01 Jan 1970 00:00:01 GMT;';" );
710
- unset( $_COOKIE['gtm4wp_product_readded_to_cart'] );
711
- }
712
-
713
- return $dataLayer;
714
- }
715
-
716
- function gtm4wp_woocommerce_single_add_to_cart_tracking() {
717
- global $product, $gtm4wp_datalayer_name, $gtm4wp_options;
718
-
719
- // exit early if there is nothing to do
720
- if ( ( false === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC ] ) && ( false === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) ) {
721
- return;
722
- }
723
-
724
- $eec_product_array = gtm4wp_process_product( $product, array(), 'addtocartsingle' );
725
-
726
- foreach ( $eec_product_array as $eec_product_array_key => $eec_product_array_value ) {
727
- echo '<input type="hidden" name="gtm4wp_' . esc_attr( $eec_product_array_key ) . '" value="' . esc_attr( $eec_product_array_value ) . '" />' . "\n";
728
- }
729
- }
730
-
731
- $GLOBALS['gtm4wp_cart_item_proddata'] = '';
732
- function gtm4wp_woocommerce_cart_item_product_filter( $product, $cart_item = '', $cart_id = '' ) {
733
- global $gtm4wp_options;
734
-
735
- $eec_product_array = gtm4wp_process_product( $product, array(
736
- 'productlink' => apply_filters( 'the_permalink', get_permalink(), 0 )
737
- ), 'cart' );
738
-
739
- $GLOBALS['gtm4wp_cart_item_proddata'] = $eec_product_array;
740
-
741
- return $product;
742
- }
743
-
744
- function gtm4wp_woocommerce_cart_item_remove_link_filter( $remove_from_cart_link ) {
745
- if ( ! isset( $GLOBALS['gtm4wp_cart_item_proddata'] ) ) {
746
- return $remove_from_cart_link;
747
- }
748
-
749
- if ( ! is_array( $GLOBALS['gtm4wp_cart_item_proddata'] ) ) {
750
- return $remove_from_cart_link;
751
- }
752
-
753
- if ( ! isset( $GLOBALS['gtm4wp_cart_item_proddata']['variant'] ) ) {
754
- $GLOBALS['gtm4wp_cart_item_proddata']['variant'] = '';
755
- }
756
-
757
- if ( ! isset( $GLOBALS['gtm4wp_cart_item_proddata']['brand'] ) ) {
758
- $GLOBALS['gtm4wp_cart_item_proddata']['brand'] = '';
759
- }
760
-
761
- $cartlink_with_data = sprintf(
762
- 'data-gtm4wp_product_id="%s" data-gtm4wp_product_name="%s" data-gtm4wp_product_price="%s" data-gtm4wp_product_cat="%s" data-gtm4wp_product_url="%s" data-gtm4wp_product_variant="%s" data-gtm4wp_product_stocklevel="%s" data-gtm4wp_product_brand="%s" href="',
763
- esc_attr( $GLOBALS['gtm4wp_cart_item_proddata']['id'] ),
764
- esc_attr( $GLOBALS['gtm4wp_cart_item_proddata']['name'] ),
765
- esc_attr( $GLOBALS['gtm4wp_cart_item_proddata']['price'] ),
766
- esc_attr( $GLOBALS['gtm4wp_cart_item_proddata']['category'] ),
767
- esc_url( $GLOBALS['gtm4wp_cart_item_proddata']['productlink'] ),
768
- esc_attr( $GLOBALS['gtm4wp_cart_item_proddata']['variant'] ),
769
- esc_attr( $GLOBALS['gtm4wp_cart_item_proddata']['stocklevel'] ),
770
- esc_attr( $GLOBALS['gtm4wp_cart_item_proddata']['brand'] )
771
- );
772
- $GLOBALS['gtm4wp_cart_item_proddata'] = '';
773
-
774
- return gtm4wp_str_replace_first( 'href="', $cartlink_with_data, $remove_from_cart_link );
775
- }
776
-
777
- function gtp4wp_woocommerce_reset_loop() {
778
- global $woocommerce_loop;
779
-
780
- $woocommerce_loop['listtype'] = '';
781
- }
782
-
783
- function gtm4wp_woocommerce_add_related_to_loop( $arg ) {
784
- global $woocommerce_loop;
785
-
786
- $woocommerce_loop['listtype'] = __( 'Related Products', 'duracelltomi-google-tag-manager' );
787
-
788
- return $arg;
789
- }
790
-
791
- function gtm4wp_woocommerce_add_cross_sell_to_loop( $arg ) {
792
- global $woocommerce_loop;
793
-
794
- $woocommerce_loop['listtype'] = __( 'Cross-Sell Products', 'duracelltomi-google-tag-manager' );
795
-
796
- return $arg;
797
- }
798
-
799
- function gtm4wp_woocommerce_add_upsells_to_loop( $arg ) {
800
- global $woocommerce_loop;
801
-
802
- $woocommerce_loop['listtype'] = __( 'Upsell Products', 'duracelltomi-google-tag-manager' );
803
-
804
- return $arg;
805
- }
806
-
807
- function gtm4wp_woocommerce_before_template_part( $template_name ) {
808
- ob_start();
809
- }
810
-
811
- function gtm4wp_woocommerce_after_template_part( $template_name ) {
812
- global $product, $gtm4wp_product_counter, $gtm4wp_last_widget_title, $gtm4wp_options;
813
-
814
- $productitem = ob_get_contents();
815
- ob_end_clean();
816
-
817
- if ( 'content-widget-product.php' == $template_name ) {
818
- $eec_product_array = gtm4wp_process_product( $product, array(
819
- 'productlink' => apply_filters( 'the_permalink', get_permalink(), 0 ),
820
- 'listname' => $gtm4wp_last_widget_title,
821
- 'listposition' => $gtm4wp_product_counter
822
- ), 'widgetproduct' );
823
-
824
- if ( ! isset( $eec_product_array[ 'brand' ] ) ) {
825
- $eec_product_array[ 'brand' ] = '';
826
- }
827
-
828
- $productlink_with_data = sprintf(
829
- 'data-gtm4wp_product_id="%s" data-gtm4wp_product_name="%s" data-gtm4wp_product_price="%s" data-gtm4wp_product_cat="%s" data-gtm4wp_product_url="%s" data-gtm4wp_productlist_name="%s" data-gtm4wp_product_listposition="%s" data-gtm4wp_product_stocklevel="%s" data-gtm4wp_product_brand="%s" href="',
830
- esc_attr( $eec_product_array['id'] ),
831
- esc_attr( $eec_product_array['name'] ),
832
- esc_attr( $eec_product_array['price'] ),
833
- esc_attr( $eec_product_array['category'] ),
834
- esc_url( $eec_product_array['productlink'] ),
835
- esc_attr( $eec_product_array['listname'] ),
836
- esc_attr( $eec_product_array['listposition'] ),
837
- esc_attr( $eec_product_array['stocklevel'] ),
838
- esc_attr( $eec_product_array[ "brand" ] )
839
- );
840
-
841
- $gtm4wp_product_counter++;
842
-
843
- $productitem = str_replace( 'href="', $productlink_with_data, $productitem );
844
- }
845
-
846
- echo $productitem;
847
- }
848
-
849
- function gtm4wp_widget_title_filter( $widget_title ) {
850
- global $gtm4wp_product_counter, $gtm4wp_last_widget_title;
851
-
852
- $gtm4wp_product_counter = 1;
853
- $gtm4wp_last_widget_title = $widget_title . __( ' (widget)', 'duracelltomi-google-tag-manager' );
854
-
855
- return $widget_title;
856
- }
857
-
858
- function gtm4wp_before_recent_products_loop() {
859
- global $woocommerce_loop;
860
-
861
- $woocommerce_loop['listtype'] = __( 'Recent Products', 'duracelltomi-google-tag-manager' );
862
- }
863
-
864
- function gtm4wp_before_sale_products_loop() {
865
- global $woocommerce_loop;
866
-
867
- $woocommerce_loop['listtype'] = __( 'Sale Products', 'duracelltomi-google-tag-manager' );
868
- }
869
-
870
- function gtm4wp_before_best_selling_products_loop() {
871
- global $woocommerce_loop;
872
-
873
- $woocommerce_loop['listtype'] = __( 'Best Selling Products', 'duracelltomi-google-tag-manager' );
874
- }
875
-
876
- function gtm4wp_before_top_rated_products_loop() {
877
- global $woocommerce_loop;
878
-
879
- $woocommerce_loop['listtype'] = __( 'Top Rated Products', 'duracelltomi-google-tag-manager' );
880
- }
881
-
882
- function gtm4wp_before_featured_products_loop() {
883
- global $woocommerce_loop;
884
-
885
- $woocommerce_loop['listtype'] = __( 'Featured Products', 'duracelltomi-google-tag-manager' );
886
- }
887
-
888
- function gtm4wp_before_related_products_loop() {
889
- global $woocommerce_loop;
890
-
891
- $woocommerce_loop['listtype'] = __( 'Related Products', 'duracelltomi-google-tag-manager' );
892
- }
893
-
894
- function gtm4wp_woocommerce_before_shop_loop_item() {
895
- global $product, $woocommerce_loop, $wp_query, $gtm4wp_options;
896
-
897
- if ( ! isset( $product ) ) {
898
- return;
899
- }
900
-
901
- $product_id = $product->get_id();
902
-
903
- $product_cat = '';
904
- if ( is_product_category() ) {
905
- global $wp_query;
906
- $cat_obj = $wp_query->get_queried_object();
907
- if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCUSEFULLCATEGORYPATH ] ) {
908
- $product_cat = gtm4wp_get_product_category_hierarchy( $cat_obj->term_id );
909
- } else {
910
- $product_cat = $cat_obj->name;
911
- }
912
- } else {
913
- $product_cat = gtm4wp_get_product_category( $product_id, $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCUSEFULLCATEGORYPATH ] );
914
- }
915
-
916
- if ( is_search() ) {
917
- $list_name = __( 'Search Results', 'duracelltomi-google-tag-manager' );
918
- } elseif ( isset( $woocommerce_loop['listtype'] ) && ( $woocommerce_loop['listtype'] != '' ) ) {
919
- $list_name = $woocommerce_loop['listtype'];
920
- } else {
921
- $list_name = __( 'General Product List', 'duracelltomi-google-tag-manager' );
922
- }
923
-
924
- $paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
925
- $posts_per_page = get_query_var( 'posts_per_page' );
926
- if ( $posts_per_page < 1 ) {
927
- $posts_per_page = 1;
928
- }
929
-
930
- $eec_product_array = gtm4wp_process_product( $product, array(
931
- 'productlink' => apply_filters( 'the_permalink', get_permalink(), 0 ),
932
- 'listname' => $list_name,
933
- 'listposition' => $woocommerce_loop['loop'] + ( $posts_per_page * ( $paged - 1 ) )
934
- ), 'productlist' );
935
-
936
- if ( ! isset( $eec_product_array[ 'brand' ] ) ) {
937
- $eec_product_array[ 'brand' ] = '';
938
- }
939
-
940
- printf(
941
- '<span class="gtm4wp_productdata" style="display:none; visibility:hidden;" data-gtm4wp_product_id="%s" data-gtm4wp_product_name="%s" data-gtm4wp_product_price="%s" data-gtm4wp_product_cat="%s" data-gtm4wp_product_url="%s" data-gtm4wp_product_listposition="%s" data-gtm4wp_productlist_name="%s" data-gtm4wp_product_stocklevel="%s" data-gtm4wp_product_brand="%s"></span>',
942
- esc_attr( $eec_product_array['id'] ),
943
- esc_attr( $eec_product_array['name'] ),
944
- esc_attr( $eec_product_array['price'] ),
945
- esc_attr( $eec_product_array['category'] ),
946
- esc_url( $eec_product_array['productlink'] ),
947
- esc_attr( $eec_product_array['listposition'] ),
948
- esc_attr( $eec_product_array['listname'] ),
949
- esc_attr( $eec_product_array['stocklevel'] ),
950
- esc_attr( $eec_product_array[ "brand" ] )
951
- );
952
- }
953
-
954
- function gtm4wp_woocommerce_cart_item_restored( $cart_item_key ) {
955
- setcookie( 'gtm4wp_product_readded_to_cart', $cart_item_key );
956
- }
957
-
958
- function gtm4wp_woocommerce_enqueue_scripts() {
959
- global $gtm4wp_options, $gtp4wp_plugin_url;
960
-
961
- if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC ] ) {
962
- $in_footer = apply_filters( 'gtm4wp_' . GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC, false );
963
- wp_enqueue_script( 'gtm4wp-woocommerce-classic', $gtp4wp_plugin_url . 'js/gtm4wp-woocommerce-classic.js', array( 'jquery' ), GTM4WP_VERSION, $in_footer );
964
- }
965
-
966
- if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) {
967
- $in_footer = apply_filters( 'gtm4wp_' . GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC, false );
968
- wp_enqueue_script( 'gtm4wp-woocommerce-enhanced', $gtp4wp_plugin_url . 'js/gtm4wp-woocommerce-enhanced.js', array( 'jquery' ), GTM4WP_VERSION, $in_footer );
969
- }
970
- }
971
-
972
- function gtm4wp_wc_quick_view_before_single_product() {
973
- global $gtm4wp_options, $gtm4wp_datalayer_name;
974
-
975
- $dataLayer = array(
976
- 'event' => 'gtm4wp.changeDetailViewEEC',
977
- );
978
-
979
- if ( ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ] ) || ( true === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) ) {
980
- $postid = get_the_ID();
981
- $product = wc_get_product( $postid );
982
-
983
- $eec_product_array = gtm4wp_process_product( $product, array(), 'productdetail' );
984
-
985
- $dataLayer['productRatingCounts'] = $product->get_rating_counts();
986
- $dataLayer['productAverageRating'] = (float) $product->get_average_rating();
987
- $dataLayer['productReviewCount'] = (int) $product->get_review_count();
988
- $dataLayer['productType'] = $product->get_type();
989
-
990
- switch ( $dataLayer['productType'] ) {
991
- case 'variable': {
992
- $dataLayer['productIsVariable'] = 1;
993
-
994
- $dataLayer['ecomm_prodid'] = gtm4wp_prefix_productid( $eec_product_array[ 'id' ] );
995
- $dataLayer['ecomm_pagetype'] = 'product';
996
- $dataLayer['ecomm_totalvalue'] = $eec_product_array[ 'price' ];
997
-
998
- break;
999
- }
1000
-
1001
- case 'grouped': {
1002
- $dataLayer['productIsVariable'] = 0;
1003
-
1004
- break;
1005
- }
1006
-
1007
- default: {
1008
- $dataLayer['productIsVariable'] = 0;
1009
-
1010
- if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ] ) {
1011
- $dataLayer['ecomm_prodid'] = gtm4wp_prefix_productid( $eec_product_array[ 'id' ] );
1012
- $dataLayer['ecomm_pagetype'] = 'product';
1013
- $dataLayer['ecomm_totalvalue'] = $eec_product_array['price'];
1014
- }
1015
-
1016
- if ( true === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) {
1017
- $currencyCode = get_woocommerce_currency();
1018
-
1019
- $dataLayer['ecommerce'] = array(
1020
- 'currencyCode' => $currencyCode,
1021
- 'detail' => array(
1022
- 'products' => array(
1023
- $eec_product_array
1024
- )
1025
- )
1026
- );
1027
- }
1028
- }
1029
- }
1030
- }
1031
-
1032
- echo '
1033
- <script>
1034
- ' . $gtm4wp_datalayer_name . '.push(' . json_encode( $dataLayer ) . ');
1035
- </script>';
1036
- }
1037
-
1038
- function gtm4wp_woocommerce_grouped_product_list_column_label( $labelvalue, $product ) {
1039
- global $gtm4wp_options, $gtm4wp_grouped_product_ix;
1040
-
1041
- if ( ! isset( $product ) ) {
1042
- return $labelvalue;
1043
- }
1044
-
1045
- $list_name = __( 'Grouped Product Detail Page', 'duracelltomi-google-tag-manager' );
1046
-
1047
- $eec_product_array = gtm4wp_process_product( $product, array(
1048
- 'productlink' => $product->get_permalink(),
1049
- 'listname' => $list_name,
1050
- 'listposition' => $gtm4wp_grouped_product_ix
1051
- ), 'groupedproductlist' );
1052
-
1053
- $gtm4wp_grouped_product_ix++;
1054
-
1055
- if ( ! isset( $eec_product_array[ 'brand' ] ) ) {
1056
- $eec_product_array[ 'brand' ] = '';
1057
- }
1058
-
1059
- $labelvalue .=
1060
- sprintf(
1061
- '<span class="gtm4wp_productdata" style="display:none; visibility:hidden;" data-gtm4wp_product_id="%s" data-gtm4wp_product_sku="%s" data-gtm4wp_product_name="%s" data-gtm4wp_product_price="%s" data-gtm4wp_product_cat="%s" data-gtm4wp_product_url="%s" data-gtm4wp_product_listposition="%s" data-gtm4wp_productlist_name="%s" data-gtm4wp_product_stocklevel="%s" data-gtm4wp_product_brand="%s"></span>',
1062
- esc_attr( $eec_product_array['id'] ),
1063
- esc_attr( $eec_product_array['sku'] ),
1064
- esc_attr( $eec_product_array['name'] ),
1065
- esc_attr( $eec_product_array['price'] ),
1066
- esc_attr( $eec_product_array['category'] ),
1067
- esc_url( $eec_product_array['productlink'] ),
1068
- esc_attr( $eec_product_array['listposition'] ),
1069
- esc_attr( $eec_product_array['listname'] ),
1070
- esc_attr( $eec_product_array['stocklevel'] ),
1071
- esc_attr( $eec_product_array['brand'] )
1072
- );
1073
-
1074
- return $labelvalue;
1075
- }
1076
-
1077
- // do not add filter if someone enabled WooCommerce integration without an activated WooCommerce plugin
1078
- if ( function_exists( 'WC' ) ) {
1079
- add_filter( GTM4WP_WPFILTER_COMPILE_DATALAYER, 'gtm4wp_woocommerce_datalayer_filter_items' );
1080
-
1081
- add_filter( 'loop_end', 'gtp4wp_woocommerce_reset_loop' );
1082
- add_action( 'woocommerce_before_shop_loop_item', 'gtm4wp_woocommerce_before_shop_loop_item' );
1083
- add_action( 'woocommerce_after_add_to_cart_button', 'gtm4wp_woocommerce_single_add_to_cart_tracking' );
1084
-
1085
- // add_action( "wp_footer", "gtm4wp_woocommerce_wp_footer" );
1086
- add_action( 'wp_enqueue_scripts', 'gtm4wp_woocommerce_enqueue_scripts' );
1087
- add_filter( GTM4WP_WPACTION_ADDGLOBALVARS, 'gtm4wp_woocommerce_addglobalvars' );
1088
-
1089
- if ( true === $GLOBALS['gtm4wp_options'][ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) {
1090
- // add_action( "wp_footer", "gtm4wp_woocommerce_enhanced_ecom_product_click" );
1091
- add_action( 'woocommerce_before_template_part', 'gtm4wp_woocommerce_before_template_part' );
1092
- add_action( 'woocommerce_after_template_part', 'gtm4wp_woocommerce_after_template_part' );
1093
- add_filter( 'widget_title', 'gtm4wp_widget_title_filter' );
1094
- add_action( 'wc_quick_view_before_single_product', 'gtm4wp_wc_quick_view_before_single_product' );
1095
- add_filter( 'woocommerce_grouped_product_list_column_label', 'gtm4wp_woocommerce_grouped_product_list_column_label', 10, 2 );
1096
-
1097
- add_filter( 'woocommerce_cart_item_product', 'gtm4wp_woocommerce_cart_item_product_filter' );
1098
- add_filter( 'woocommerce_cart_item_remove_link', 'gtm4wp_woocommerce_cart_item_remove_link_filter' );
1099
- add_action( 'woocommerce_cart_item_restored', 'gtm4wp_woocommerce_cart_item_restored' );
1100
-
1101
- add_filter( 'woocommerce_related_products_args', 'gtm4wp_woocommerce_add_related_to_loop' );
1102
- add_filter( 'woocommerce_related_products_columns', 'gtm4wp_woocommerce_add_related_to_loop' );
1103
- add_filter( 'woocommerce_cross_sells_columns', 'gtm4wp_woocommerce_add_cross_sell_to_loop' );
1104
- add_filter( 'woocommerce_upsells_columns', 'gtm4wp_woocommerce_add_upsells_to_loop' );
1105
-
1106
- add_action( 'woocommerce_shortcode_before_recent_products_loop', 'gtm4wp_before_recent_products_loop' );
1107
- add_action( 'woocommerce_shortcode_before_sale_products_loop', 'gtm4wp_before_sale_products_loop' );
1108
- add_action( 'woocommerce_shortcode_before_best_selling_products_loop', 'gtm4wp_before_best_selling_products_loop' );
1109
- add_action( 'woocommerce_shortcode_before_top_rated_products_loop', 'gtm4wp_before_top_rated_products_loop' );
1110
- add_action( 'woocommerce_shortcode_before_featured_products_loop', 'gtm4wp_before_featured_products_loop' );
1111
- add_action( 'woocommerce_shortcode_before_related_products_loop', 'gtm4wp_before_related_products_loop' );
1112
- }
1113
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ define( 'GTM4WP_WPFILTER_EEC_PRODUCT_ARRAY', 'gtm4wp_eec_product_array' );
3
+ define( 'GTM4WP_WPFILTER_EEC_CART_ITEM', 'gtm4wp_eec_cart_item' );
4
+ define( 'GTM4WP_WPFILTER_EEC_ORDER_ITEM', 'gtm4wp_eec_order_item' );
5
+
6
+ $gtm4wp_product_counter = 0;
7
+ $gtm4wp_last_widget_title = 'Sidebar Products';
8
+ if ( function_exists( 'WC' ) ) {
9
+ $GLOBALS['gtm4wp_is_woocommerce3_7'] = version_compare( WC()->version, '3.7', '>=' );
10
+ } else {
11
+ $GLOBALS['gtm4wp_is_woocommerce3_7'] = false;
12
+ }
13
+ $GLOBALS['gtm4wp_grouped_product_ix'] = 1;
14
+
15
+ // from https://snippets.webaware.com.au/ramblings/php-really-doesnt-unicode/
16
+ function gtm4wp_untexturize( $fancy ) {
17
+ $fixes = false;
18
+
19
+ if ( $fixes === false ) {
20
+ $fixes = array(
21
+ json_decode( '"\u201C"' ) => '"', // left double quotation mark
22
+ json_decode( '"\u201D"' ) => '"', // right double quotation mark
23
+ json_decode( '"\u2018"' ) => "'", // left single quotation mark
24
+ json_decode( '"\u2019"' ) => "'", // right single quotation mark
25
+ json_decode( '"\u2032"' ) => "'", // prime (minutes, feet)
26
+ json_decode( '"\u2033"' ) => '"', // double prime (seconds, inches)
27
+ json_decode( '"\u2013"' ) => '-', // en dash
28
+ json_decode( '"\u2014"' ) => '--', // em dash
29
+ );
30
+ }
31
+
32
+ $normal = strtr( $fancy, $fixes );
33
+
34
+ return $normal;
35
+ }
36
+
37
+ function gtm4wp_woocommerce_html_entity_decode( $val ) {
38
+ return gtm4wp_untexturize( html_entity_decode( $val, ENT_QUOTES, 'utf-8' ) );
39
+ }
40
+
41
+ function gtm4wp_prefix_productid( $product_id ) {
42
+ global $gtm4wp_options;
43
+
44
+ if ( '' != $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMPRODIDPREFIX ] ) {
45
+ return $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMPRODIDPREFIX ] . $product_id;
46
+ } else {
47
+ return $product_id;
48
+ }
49
+ }
50
+
51
+ // from https://stackoverflow.com/questions/1252693/using-str-replace-so-that-it-only-acts-on-the-first-match
52
+ function gtm4wp_str_replace_first( $from, $to, $subject ) {
53
+ $from = '/' . preg_quote( $from, '/' ) . '/';
54
+
55
+ return preg_replace( $from, $to, $subject, 1 );
56
+ }
57
+
58
+ function gtm4wp_get_product_category_hierarchy( $category_id ) {
59
+ $cat_hierarchy = '';
60
+
61
+ $category_parent_list = get_term_parents_list(
62
+ $category_id,
63
+ 'product_cat',
64
+ array(
65
+ 'format' => 'name',
66
+ 'separator' => '/',
67
+ 'link' => false,
68
+ 'inclusive' => true,
69
+ )
70
+ );
71
+
72
+ if ( is_string( $category_parent_list ) ) {
73
+ $cat_hierarchy = trim( $category_parent_list, '/' );
74
+ }
75
+
76
+ return $cat_hierarchy;
77
+ }
78
+
79
+ function gtm4wp_get_product_category( $product_id, $fullpath = false ) {
80
+ $product_cat = '';
81
+
82
+ $_product_cats = get_the_terms( $product_id, 'product_cat' );
83
+ if ( ( is_array( $_product_cats ) ) && ( count( $_product_cats ) > 0 ) ) {
84
+ $first_product_cat = array_pop( $_product_cats );
85
+ if ( $fullpath ) {
86
+ $product_cat = gtm4wp_get_product_category_hierarchy( $first_product_cat->term_id );
87
+ } else {
88
+ $product_cat = $first_product_cat->name;
89
+ }
90
+ }
91
+
92
+ return $product_cat;
93
+ }
94
+
95
+ function gtm4wp_woocommerce_getproductterm( $product_id, $taxonomy ) {
96
+ $gtm4wp_product_terms = get_the_terms( $product_id, $taxonomy );
97
+ if ( is_array( $gtm4wp_product_terms ) && ( count( $gtm4wp_product_terms ) > 0 ) ) {
98
+ return $gtm4wp_product_terms[0]->name;
99
+ }
100
+
101
+ return "";
102
+ }
103
+
104
+ function gtm4wp_process_product( $product, $additional_product_attributes, $attributes_used_for ) {
105
+ global $gtm4wp_options;
106
+
107
+ if ( ! $product ) {
108
+ return false;
109
+ }
110
+
111
+ if ( ! ( $product instanceof WC_Product ) ) {
112
+ return false;
113
+ }
114
+
115
+ $product_id = $product->get_id();
116
+ $product_type = $product->get_type();
117
+ $remarketing_id = $product_id;
118
+ $product_sku = $product->get_sku();
119
+
120
+ if ( 'variation' == $product_type ) {
121
+ $parent_product_id = $product->get_parent_id();
122
+ $product_cat = gtm4wp_get_product_category( $parent_product_id, $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCUSEFULLCATEGORYPATH ] );
123
+ } else {
124
+ $product_cat = gtm4wp_get_product_category( $product_id, $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCUSEFULLCATEGORYPATH ] );
125
+ }
126
+
127
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCUSESKU ] && ( '' != $product_sku ) ) {
128
+ $remarketing_id = $product_sku;
129
+ }
130
+
131
+ $_temp_productdata = array(
132
+ 'id' => $remarketing_id,
133
+ 'name' => $product->get_title(),
134
+ 'sku' => $product_sku ? $product_sku : $product_id,
135
+ 'category' => $product_cat,
136
+ 'price' => round( (float) wc_get_price_to_display( $product ), 2),
137
+ 'stocklevel' => $product->get_stock_quantity()
138
+ );
139
+
140
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCEECBRANDTAXONOMY ] != "" ) {
141
+ if ( isset( $parent_product_id ) && ( $parent_product_id !== 0 ) ) {
142
+ $product_id_to_query = $parent_product_id;
143
+ } else {
144
+ $product_id_to_query = $product_id;
145
+ }
146
+
147
+ $_temp_productdata[ "brand" ] = gtm4wp_woocommerce_getproductterm( $product_id_to_query, $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCEECBRANDTAXONOMY ] );
148
+ }
149
+
150
+ if ( 'variation' == $product_type ) {
151
+ $_temp_productdata['variant'] = implode( ',', $product->get_variation_attributes() );
152
+ }
153
+
154
+ $_temp_productdata = array_merge( $_temp_productdata, $additional_product_attributes );
155
+
156
+ return apply_filters( GTM4WP_WPFILTER_EEC_PRODUCT_ARRAY, $_temp_productdata, $attributes_used_for );
157
+ }
158
+
159
+ function gtm4wp_get_gads_product_id_variable_name( $vertical_id ) {
160
+ global $gtm4wp_business_verticals_ids;
161
+
162
+ if ( array_key_exists( $vertical_id, $gtm4wp_business_verticals_ids ) ) {
163
+ return $gtm4wp_business_verticals_ids[ $vertical_id ];
164
+ } else {
165
+ return "id";
166
+ }
167
+ }
168
+
169
+ function gtm4wp_map_eec_to_ga4( $productdata ) {
170
+ global $gtm4wp_options;
171
+
172
+ if ( !is_array($productdata) ) {
173
+ return;
174
+ }
175
+
176
+ $category_path = array_key_exists( "category", $productdata ) ? $productdata[ "category" ] : "";
177
+ $category_parts = explode('/', $category_path);
178
+
179
+ // default, required parameters
180
+ $ga4_product = array(
181
+ 'item_id' => array_key_exists( "id", $productdata ) ? $productdata[ "id" ] : "",
182
+ 'item_name' => array_key_exists( "name", $productdata ) ? $productdata[ "name" ] : "",
183
+ 'item_brand' => array_key_exists( "brand", $productdata ) ? $productdata[ "brand" ] : "",
184
+ 'price' => array_key_exists( "price", $productdata ) ? $productdata[ "price" ] : ""
185
+ );
186
+
187
+ // category, also handle category path
188
+ if ( 1 == count($category_parts) ) {
189
+ $ga4_product[ "item_category" ] = $category_parts[0];
190
+ } else if ( count($category_parts) > 1 ) {
191
+ $ga4_product[ "item_category" ] = $category_parts[0];
192
+ for( $i=1; $i < min( 5, count( $category_parts ) ); $i++ ) {
193
+ $ga4_product[ "item_category_" . (string)($i+1) ] = $category_parts[$i];
194
+ }
195
+ }
196
+
197
+ // optional parameters which should not be included in the array if not set
198
+ if ( array_key_exists( "variant", $productdata ) ) {
199
+ $ga4_product[ "item_variant" ] = $productdata[ "variant" ];
200
+ }
201
+ if ( array_key_exists( "listname", $productdata ) ) {
202
+ $ga4_product[ "item_list_name" ] = $productdata[ "listname" ];
203
+ }
204
+ if ( array_key_exists( "listposition", $productdata ) ) {
205
+ $ga4_product[ "index" ] = $productdata[ "listposition" ];
206
+ }
207
+ if ( array_key_exists( "quantity", $productdata ) ) {
208
+ $ga4_product[ "quantity" ] = $productdata[ "quantity" ];
209
+ }
210
+ if ( array_key_exists( "coupon", $productdata ) ) {
211
+ $ga4_product[ "coupon" ] = $productdata[ "coupon" ];
212
+ }
213
+
214
+ $ga4_product[ "google_business_vertical" ] = $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCBUSINESSVERTICAL ];
215
+ $ga4_product[ gtm4wp_get_gads_product_id_variable_name( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCBUSINESSVERTICAL ] ) ] = gtm4wp_prefix_productid( $ga4_product["item_id"] );
216
+
217
+ return $ga4_product;
218
+ }
219
+
220
+ function gtm4wp_process_order_items( $order ) {
221
+ global $gtm4wp_options;
222
+
223
+ $return_data = array(
224
+ 'products' => [],
225
+ 'sumprice' => 0,
226
+ 'product_ids' => []
227
+ );
228
+
229
+ if ( ! $order ) {
230
+ return $return_data;
231
+ }
232
+
233
+ $order_items = $order->get_items();
234
+
235
+ if ( $order_items ) {
236
+ foreach ( $order_items as $item ) {
237
+ if ( ! apply_filters( GTM4WP_WPFILTER_EEC_ORDER_ITEM, true, $item ) ) {
238
+ continue;
239
+ }
240
+
241
+ $product = $item->get_product();
242
+ $inc_tax = ( 'incl' === get_option( 'woocommerce_tax_display_shop' ) );
243
+ $product_price = round( (float) $order->get_item_total( $item, $inc_tax ), 2);
244
+ $eec_product_array = gtm4wp_process_product( $product, array(
245
+ 'quantity' => $item->get_quantity(),
246
+ 'price' => $product_price
247
+ ), 'purchase' );
248
+
249
+ if ( $eec_product_array ) {
250
+ $return_data['products'][] = $eec_product_array;
251
+ $return_data['sumprice'] += $product_price * $eec_product_array['quantity'];
252
+ $return_data['product_ids'][] = gtm4wp_prefix_productid( $eec_product_array['id'] );
253
+ }
254
+ }
255
+ }
256
+
257
+ return $return_data;
258
+ }
259
+
260
+ function gtm4wp_woocommerce_addglobalvars( $return = '' ) {
261
+ global $gtm4wp_options;
262
+
263
+ if ( function_exists( 'WC' ) && WC()->cart ) {
264
+ $gtm4wp_needs_shipping_address = (bool) WC()->cart->needs_shipping_address();
265
+ } else {
266
+ $gtm4wp_needs_shipping_address = false;
267
+ }
268
+
269
+ $return .= '
270
+ var gtm4wp_use_sku_instead = ' . (int) ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCUSESKU ] ) . ';
271
+ var gtm4wp_id_prefix = \'' . esc_js( gtm4wp_prefix_productid( '' ) ) . '\';
272
+ var gtm4wp_remarketing = ' . gtm4wp_escjs_boolean( (bool) ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ] ) ) . ';
273
+ var gtm4wp_eec = ' . gtm4wp_escjs_boolean( (bool) ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) ) . ';
274
+ var gtm4wp_classicec = ' . gtm4wp_escjs_boolean( (bool) ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC ] ) ) . ';
275
+ var gtm4wp_currency = \'' . esc_js( get_woocommerce_currency() ) . '\';
276
+ var gtm4wp_product_per_impression = ' . (int) ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCPRODPERIMPRESSION ] ) . ';
277
+ var gtm4wp_needs_shipping_address = ' . gtm4wp_escjs_boolean( $gtm4wp_needs_shipping_address ) . ';
278
+ var gtm4wp_business_vertical = \'' . esc_js( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCBUSINESSVERTICAL ] ) . '\';
279
+ var gtm4wp_business_vertical_id = \'' . gtm4wp_get_gads_product_id_variable_name( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCBUSINESSVERTICAL ] ) . '\';';
280
+
281
+ return $return;
282
+ }
283
+
284
+ function gtm4wp_woocommerce_datalayer_filter_items( $dataLayer ) {
285
+ global $gtm4wp_options, $wp_query, $gtm4wp_datalayer_name, $gtm4wp_product_counter, $gtm4wp_is_woocommerce3_7;
286
+
287
+ $woo = WC();
288
+
289
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCCUSTOMERDATA ] ) {
290
+ if ( $woo->customer instanceof WC_Customer ) {
291
+ // we need to use this instead of $woo->customer as this will load proper total order number and value from the database instead of the session
292
+ $woo_customer = new WC_Customer( $woo->customer->get_id() );
293
+
294
+ $dataLayer['customerTotalOrders'] = $woo_customer->get_order_count();
295
+ $dataLayer['customerTotalOrderValue'] = $woo_customer->get_total_spent();
296
+
297
+ $dataLayer['customerFirstName'] = $woo_customer->get_first_name();
298
+ $dataLayer['customerLastName'] = $woo_customer->get_last_name();
299
+
300
+ $dataLayer['customerBillingFirstName'] = $woo_customer->get_billing_first_name();
301
+ $dataLayer['customerBillingLastName'] = $woo_customer->get_billing_last_name();
302
+ $dataLayer['customerBillingCompany'] = $woo_customer->get_billing_company();
303
+ $dataLayer['customerBillingAddress1'] = $woo_customer->get_billing_address_1();
304
+ $dataLayer['customerBillingAddress2'] = $woo_customer->get_billing_address_2();
305
+ $dataLayer['customerBillingCity'] = $woo_customer->get_billing_city();
306
+ $dataLayer['customerBillingPostcode'] = $woo_customer->get_billing_postcode();
307
+ $dataLayer['customerBillingCountry'] = $woo_customer->get_billing_country();
308
+ $dataLayer['customerBillingEmail'] = $woo_customer->get_billing_email();
309
+ $dataLayer['customerBillingPhone'] = $woo_customer->get_billing_phone();
310
+
311
+ $dataLayer['customerShippingFirstName'] = $woo_customer->get_shipping_first_name();
312
+ $dataLayer['customerShippingLastName'] = $woo_customer->get_shipping_last_name();
313
+ $dataLayer['customerShippingCompany'] = $woo_customer->get_shipping_company();
314
+ $dataLayer['customerShippingAddress1'] = $woo_customer->get_shipping_address_1();
315
+ $dataLayer['customerShippingAddress2'] = $woo_customer->get_shipping_address_2();
316
+ $dataLayer['customerShippingCity'] = $woo_customer->get_shipping_city();
317
+ $dataLayer['customerShippingPostcode'] = $woo_customer->get_shipping_postcode();
318
+ $dataLayer['customerShippingCountry'] = $woo_customer->get_shipping_country();
319
+ }
320
+ }
321
+
322
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCEINCLUDECARTINDL ] && version_compare( $woo->version, "3.2", ">=" ) && isset($woo) && isset($woo->cart) ) {
323
+ $current_cart = $woo->cart;
324
+ $dataLayer["cartContent"] = array(
325
+ "totals" => array(
326
+ "applied_coupons" => $current_cart->get_applied_coupons(),
327
+ "discount_total" => $current_cart->get_discount_total(),
328
+ "subtotal" => $current_cart->get_subtotal(),
329
+ "total" => $current_cart->get_cart_contents_total()
330
+ ),
331
+ "items" => array()
332
+ );
333
+
334
+ foreach( $current_cart->get_cart() as $cart_item_id => $cart_item_data) {
335
+ $product = apply_filters( 'woocommerce_cart_item_product', $cart_item_data["data"], $cart_item_data, $cart_item_id );
336
+ if (
337
+ !apply_filters( GTM4WP_WPFILTER_EEC_CART_ITEM, true, $cart_item_data )
338
+ || !apply_filters( 'woocommerce_widget_cart_item_visible', true, $cart_item_data, $cart_item_id )
339
+ ) {
340
+ continue;
341
+ }
342
+
343
+ $eec_product_array = gtm4wp_process_product( $product, array(
344
+ 'quantity' => $cart_item_data["quantity"]
345
+ ), 'cart' );
346
+
347
+ $dataLayer["cartContent"]["items"][] = $eec_product_array;
348
+ }
349
+ }
350
+
351
+ if ( is_product_category() || is_product_tag() || is_front_page() || is_shop() ) {
352
+ $ecomm_pagetype = 'category';
353
+ if ( is_front_page() ) {
354
+ $ecomm_pagetype = 'home';
355
+ } elseif ( is_search() ) {
356
+ $ecomm_pagetype = 'searchresults';
357
+ }
358
+
359
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ] ) {
360
+ $dataLayer['ecomm_prodid'] = array();
361
+ $dataLayer['ecomm_pagetype'] = $ecomm_pagetype;
362
+ $dataLayer['ecomm_totalvalue'] = 0;
363
+ }
364
+ } elseif ( is_product() ) {
365
+ if (
366
+ $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ]
367
+ || ( true === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] )
368
+ ) {
369
+ $postid = get_the_ID();
370
+ $product = wc_get_product( $postid );
371
+
372
+ $eec_product_array = gtm4wp_process_product( $product, array(), 'productdetail' );
373
+
374
+ $dataLayer['productRatingCounts'] = $product->get_rating_counts();
375
+ $dataLayer['productAverageRating'] = (float) $product->get_average_rating();
376
+ $dataLayer['productReviewCount'] = (int) $product->get_review_count();
377
+ $dataLayer['productType'] = $product->get_type();
378
+
379
+ switch ( $dataLayer['productType'] ) {
380
+ case 'variable': {
381
+ $dataLayer['productIsVariable'] = 1;
382
+
383
+ $dataLayer['ecomm_prodid'] = gtm4wp_prefix_productid( $eec_product_array[ 'id' ] );
384
+ $dataLayer['ecomm_pagetype'] = 'product';
385
+ $dataLayer['ecomm_totalvalue'] = $eec_product_array[ 'price' ];
386
+
387
+ break;
388
+ }
389
+
390
+ case 'grouped': {
391
+ $dataLayer['productIsVariable'] = 0;
392
+
393
+ break;
394
+ }
395
+
396
+ default: {
397
+ $dataLayer['productIsVariable'] = 0;
398
+
399
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ] ) {
400
+ $dataLayer['ecomm_prodid'] = gtm4wp_prefix_productid( $eec_product_array[ 'id' ] );
401
+ $dataLayer['ecomm_pagetype'] = 'product';
402
+ $dataLayer['ecomm_totalvalue'] = $eec_product_array['price'];
403
+ }
404
+
405
+ if ( true === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) {
406
+ $currencyCode = get_woocommerce_currency();
407
+
408
+ $dataLayer['event'] = 'gtm4wp.changeDetailViewEEC';
409
+ $dataLayer['ecommerce'] = array(
410
+ 'currencyCode' => $currencyCode,
411
+ 'detail' => array(
412
+ 'products' => array(
413
+ $eec_product_array
414
+ )
415
+ )
416
+ );
417
+ }
418
+ }
419
+ }
420
+ }
421
+ } elseif ( is_cart() ) {
422
+ if (
423
+ $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ]
424
+ || $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCEECCARTASFIRSTSTEP ]
425
+ || $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ]
426
+ ) {
427
+ $gtm4wp_cart_products = array();
428
+ $gtm4wp_cart_products_remarketing = array();
429
+
430
+ $gtm4wp_currency = get_woocommerce_currency();
431
+
432
+ foreach ( $woo->cart->get_cart() as $cart_item_id => $cart_item_data ) {
433
+ $product = apply_filters( 'woocommerce_cart_item_product', $cart_item_data['data'], $cart_item_data, $cart_item_id );
434
+
435
+ if ( ! apply_filters( GTM4WP_WPFILTER_EEC_CART_ITEM, true, $cart_item_data ) ) {
436
+ continue;
437
+ }
438
+
439
+ $eec_product_array = gtm4wp_process_product( $product, array(
440
+ 'quantity' => $cart_item_data['quantity']
441
+ ), 'cart' );
442
+
443
+ $gtm4wp_cart_products[] = $eec_product_array;
444
+ $gtm4wp_cart_products_remarketing[] = gtm4wp_prefix_productid( $eec_product_array[ 'id' ] );
445
+ }
446
+
447
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ] ) {
448
+ $dataLayer['ecomm_prodid'] = $gtm4wp_cart_products_remarketing;
449
+ $dataLayer['ecomm_pagetype'] = 'cart';
450
+ if ( ! $woo->cart->prices_include_tax ) {
451
+ $cart_total = $woo->cart->cart_contents_total;
452
+ } else {
453
+ $cart_total = $woo->cart->cart_contents_total + $woo->cart->tax_total;
454
+ }
455
+ $dataLayer['ecomm_totalvalue'] = (float) $cart_total;
456
+ }
457
+
458
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) {
459
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCEECCARTASFIRSTSTEP ] ) {
460
+ $dataLayer['event'] = 'gtm4wp.checkoutStepEEC';
461
+ $dataLayer['ecommerce'] = array(
462
+ 'currencyCode' => $gtm4wp_currency,
463
+ 'checkout' => array(
464
+ 'actionField' => array(
465
+ 'step' => 1,
466
+ ),
467
+ 'products' => $gtm4wp_cart_products,
468
+ )
469
+ );
470
+ } else {
471
+ // add only ga4 products to populate view_cart event
472
+ $dataLayer['ecommerce'] = array(
473
+ 'cart' => $gtm4wp_cart_products
474
+ );
475
+ }
476
+ }
477
+ }
478
+ } elseif ( is_order_received_page() ) {
479
+ $do_not_flag_tracked_order = (bool) ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCNOORDERTRACKEDFLAG ] );
480
+ $order_id = empty( $_GET['order'] ) ? ( $GLOBALS['wp']->query_vars['order-received'] ? $GLOBALS['wp']->query_vars['order-received'] : 0 ) : absint( $_GET['order'] );
481
+ $order_id_filtered = apply_filters( 'woocommerce_thankyou_order_id', $order_id );
482
+ if ( '' != $order_id_filtered ) {
483
+ $order_id = $order_id_filtered;
484
+ }
485
+
486
+ $order_key = apply_filters( 'woocommerce_thankyou_order_key', empty( $_GET['key'] ) ? '' : wc_clean( $_GET['key'] ) );
487
+
488
+ if ( $order_id > 0 ) {
489
+ $order = wc_get_order( $order_id );
490
+
491
+ if ( $order instanceof WC_Order ) {
492
+ $this_order_key = $order->get_order_key();
493
+
494
+ if ( $this_order_key != $order_key ) {
495
+ unset( $order );
496
+ }
497
+ } else {
498
+ unset( $order );
499
+ }
500
+ }
501
+
502
+ if(isset($order) && $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCORDERMAXAGE ] ){
503
+
504
+ $now = new DateTime();
505
+ if($order->is_paid() && $order->get_date_paid()){
506
+ $diff = $now->diff($order->get_date_paid());
507
+ $minutes = ($diff->days * 24 * 60) + ($diff->h * 60) + $diff->i;
508
+ } else {
509
+ $diff = $now->diff($order->get_date_created());
510
+ $minutes = ($diff->days * 24 * 60) + ($diff->h * 60) + $diff->i;
511
+ }
512
+
513
+ if($minutes > $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCORDERMAXAGE ]) {
514
+ unset($order);
515
+ }
516
+ }
517
+
518
+ if ( isset($order) && $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCORDERDATA ] ) {
519
+ $order_items = gtm4wp_process_order_items( $order );
520
+
521
+ $dataLayer['orderData'] = array(
522
+ 'attributes' => array(
523
+ 'date' => $order->get_date_created()->date( 'c' ),
524
+
525
+ 'order_number' => $order->get_order_number(),
526
+ 'order_key' => $order->get_order_key(),
527
+
528
+ 'payment_method' => esc_js( $order->get_payment_method() ),
529
+ 'payment_method_title' => esc_js( $order->get_payment_method_title() ),
530
+
531
+ 'shipping_method' => esc_js( $order->get_shipping_method() ),
532
+
533
+ 'status' => esc_js( $order->get_status() ),
534
+
535
+ 'coupons' => implode( ', ', ( $gtm4wp_is_woocommerce3_7 ? $order->get_coupon_codes() : $order->get_used_coupons() ) )
536
+ ),
537
+ 'totals' => array(
538
+ 'currency' => esc_js( $order->get_currency() ),
539
+ 'discount_total' => esc_js( $order->get_discount_total() ),
540
+ 'discount_tax' => esc_js( $order->get_discount_tax() ),
541
+ 'shipping_total' => esc_js( $order->get_shipping_total() ),
542
+ 'shipping_tax' => esc_js( $order->get_shipping_tax() ),
543
+ 'cart_tax' => esc_js( $order->get_cart_tax() ),
544
+ 'total' => esc_js( $order->get_total() ),
545
+ 'total_tax' => esc_js( $order->get_total_tax() ),
546
+ 'total_discount' => esc_js( $order->get_total_discount() ),
547
+ 'subtotal' => esc_js( $order->get_subtotal() ),
548
+ 'tax_totals' => $order->get_tax_totals()
549
+ ),
550
+ 'customer' => array(
551
+ 'id' => $order->get_customer_id(),
552
+
553
+ 'billing' => array(
554
+ 'first_name' => esc_js( $order->get_billing_first_name() ),
555
+ 'last_name' => esc_js( $order->get_billing_last_name() ),
556
+ 'company' => esc_js( $order->get_billing_company() ),
557
+ 'address_1' => esc_js( $order->get_billing_address_1() ),
558
+ 'address_2' => esc_js( $order->get_billing_address_2() ),
559
+ 'city' => esc_js( $order->get_billing_city() ),
560
+ 'state' => esc_js( $order->get_billing_state() ),
561
+ 'postcode' => esc_js( $order->get_billing_postcode() ),
562
+ 'country' => esc_js( $order->get_billing_country() ),
563
+ 'email' => esc_js( $order->get_billing_email() ),
564
+ 'phone' => esc_js( $order->get_billing_phone() )
565
+ ),
566
+
567
+ 'shipping' => array(
568
+ 'first_name' => esc_js( $order->get_shipping_first_name() ),
569
+ 'last_name' => esc_js( $order->get_shipping_last_name() ),
570
+ 'company' => esc_js( $order->get_shipping_company() ),
571
+ 'address_1' => esc_js( $order->get_shipping_address_1() ),
572
+ 'address_2' => esc_js( $order->get_shipping_address_2() ),
573
+ 'city' => esc_js( $order->get_shipping_city() ),
574
+ 'state' => esc_js( $order->get_shipping_state() ),
575
+ 'postcode' => esc_js( $order->get_shipping_postcode() ),
576
+ 'country' => esc_js( $order->get_shipping_country() )
577
+ )
578
+
579
+ ),
580
+ 'items' => $order_items['products']
581
+ );
582
+ }
583
+
584
+ if ( ( 1 == get_post_meta( $order_id, '_ga_tracked', true ) ) && ! $do_not_flag_tracked_order ) {
585
+ unset( $order );
586
+ }
587
+
588
+ if ( isset( $_COOKIE[ 'gtm4wp_orderid_tracked' ] ) && ( $_COOKIE[ 'gtm4wp_orderid_tracked' ] == $order_id ) && ! $do_not_flag_tracked_order ) {
589
+ unset( $order );
590
+ }
591
+
592
+ if ( isset( $order ) ) {
593
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCEXCLUDETAX ] ) {
594
+ $order_revenue = (float)( $order->get_total() - $order->get_total_tax() );
595
+ } else {
596
+ $order_revenue = (float) $order->get_total();
597
+ }
598
+
599
+ $order_shipping_cost = (float) $order->get_shipping_total();
600
+
601
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCEXCLUDESHIPPING ] ) {
602
+ $order_revenue -= $order_shipping_cost;
603
+ }
604
+
605
+ $order_currency = $order->get_currency();
606
+
607
+ if ( true === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC ] ) {
608
+ $dataLayer['event'] = 'gtm4wp.orderCompleted';
609
+ $dataLayer['transactionId'] = $order->get_order_number();
610
+ $dataLayer['transactionAffiliation'] = '';
611
+ $dataLayer['transactionTotal'] = $order_revenue;
612
+ $dataLayer['transactionShipping'] = $order_shipping_cost;
613
+ $dataLayer['transactionTax'] = (float) $order->get_total_tax();
614
+ $dataLayer['transactionCurrency'] = $order_currency;
615
+ }
616
+
617
+ if ( true === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) {
618
+ $dataLayer['event'] = 'gtm4wp.orderCompletedEEC';
619
+ $dataLayer['ecommerce'] = array(
620
+ 'currencyCode' => $order_currency,
621
+ 'purchase' => array(
622
+ 'actionField' => array(
623
+ 'id' => $order->get_order_number(),
624
+ 'affiliation' => '',
625
+ 'revenue' => $order_revenue,
626
+ 'tax' => (float) $order->get_total_tax(),
627
+ 'shipping' => (float)( $order->get_shipping_total() ),
628
+ 'coupon' => implode( ', ', ( $gtm4wp_is_woocommerce3_7 ? $order->get_coupon_codes() : $order->get_used_coupons() ) ),
629
+ )
630
+ )
631
+ );
632
+ }
633
+
634
+ if ( ! isset( $order_items ) ) {
635
+ $order_items = gtm4wp_process_order_items( $order );
636
+ }
637
+
638
+ if ( true === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC ] ) {
639
+ $dataLayer['transactionProducts'] = $order_items['products'];
640
+ }
641
+
642
+ if ( true === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) {
643
+ $dataLayer['ecommerce']['purchase']['products'] = $order_items['products'];
644
+ }
645
+
646
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ] ) {
647
+ $dataLayer['ecomm_prodid'] = $order_items['product_ids'];
648
+ $dataLayer['ecomm_pagetype'] = 'purchase';
649
+ $dataLayer['ecomm_totalvalue'] = (float) $order_items['sumprice'];
650
+ }
651
+
652
+ if ( ! $do_not_flag_tracked_order ) {
653
+ update_post_meta( $order_id, '_ga_tracked', 1 );
654
+ }
655
+ }
656
+ } elseif ( is_checkout() ) {
657
+ if (
658
+ ( true === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] )
659
+ || ( true === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ] )
660
+ ) {
661
+ $gtm4wp_checkout_products = array();
662
+ $gtm4wp_checkout_products_remarketing = array();
663
+ $gtm4wp_totalvalue = 0;
664
+
665
+ foreach ( $woo->cart->get_cart() as $cart_item_id => $cart_item_data ) {
666
+ $product = apply_filters( 'woocommerce_cart_item_product', $cart_item_data['data'], $cart_item_data, $cart_item_id );
667
+
668
+ if ( ! apply_filters( GTM4WP_WPFILTER_EEC_CART_ITEM, true, $cart_item_data ) ) {
669
+ continue;
670
+ }
671
+
672
+ $eec_product_array = gtm4wp_process_product( $product, array(
673
+ 'quantity' => $cart_item_data['quantity']
674
+ ), 'cart' );
675
+
676
+ $gtm4wp_checkout_products[] = $eec_product_array;
677
+
678
+ $gtm4wp_checkout_products_remarketing[] = gtm4wp_prefix_productid( $eec_product_array[ 'id' ] );
679
+ $gtm4wp_totalvalue += $eec_product_array['quantity'] * $eec_product_array['price'];
680
+ } // end foreach cart item
681
+
682
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ] ) {
683
+ $dataLayer['ecomm_prodid'] = $gtm4wp_checkout_products_remarketing;
684
+ $dataLayer['ecomm_pagetype'] = 'cart';
685
+ $dataLayer['ecomm_totalvalue'] = (float) $gtm4wp_totalvalue;
686
+ }
687
+
688
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) {
689
+ $currencyCode = get_woocommerce_currency();
690
+
691
+ $ga4_products = array();
692
+ $sum_value = 0;
693
+ foreach( $gtm4wp_checkout_products as $oneproduct ) {
694
+ $ga4_products[] = gtm4wp_map_eec_to_ga4( $oneproduct );
695
+ $sum_value += $oneproduct["price"] * $oneproduct["quantity"];
696
+ }
697
+
698
+ $dataLayer['event'] = 'gtm4wp.checkoutStepEEC';
699
+ $dataLayer['ecommerce'] = array(
700
+ 'currencyCode' => $currencyCode,
701
+ 'checkout' => array(
702
+ 'actionField' => array(
703
+ 'step' => 1 + (int) $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCEECCARTASFIRSTSTEP ],
704
+ ),
705
+ 'products' => $gtm4wp_checkout_products,
706
+ )
707
+ );
708
+
709
+ wc_enqueue_js('
710
+ window.gtm4wp_checkout_products = ' . json_encode( $gtm4wp_checkout_products ) . ';
711
+ window.gtm4wp_checkout_products_ga4 = ' . json_encode( $ga4_products ) . ';
712
+ window.gtm4wp_checkout_value = ' . (float) $sum_value . ';
713
+ window.gtm4wp_checkout_step_offset = ' . (int) $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCEECCARTASFIRSTSTEP ] . ';'
714
+ );
715
+ }
716
+ }
717
+ } else {
718
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ] ) {
719
+ $dataLayer['ecomm_pagetype'] = 'other';
720
+ }
721
+ }
722
+
723
+ if ( isset( $_COOKIE['gtm4wp_product_readded_to_cart'] ) ) {
724
+ $cart_item = $woo->cart->get_cart_item( $_COOKIE['gtm4wp_product_readded_to_cart'] );
725
+ if ( ! empty( $cart_item ) ) {
726
+ $product = $cart_item['data'];
727
+
728
+ $eec_product_array = gtm4wp_process_product( $product, array(
729
+ 'quantity' => $cart_item['quantity']
730
+ ), 'readdedtocart' );
731
+
732
+ $currencyCode = get_woocommerce_currency();
733
+
734
+ $dataLayer['event'] = 'gtm4wp.addProductToCartEEC';
735
+ $dataLayer['ecommerce'] = array(
736
+ 'currencyCode' => $currencyCode,
737
+ 'add' => array(
738
+ 'products' => array(
739
+ $eec_product_array
740
+ )
741
+ )
742
+ );
743
+ }
744
+
745
+ wc_enqueue_js( "document.cookie = 'gtm4wp_product_readded_to_cart=; expires=Thu, 01 Jan 1970 00:00:01 GMT;';" );
746
+ unset( $_COOKIE['gtm4wp_product_readded_to_cart'] );
747
+ }
748
+
749
+ return $dataLayer;
750
+ }
751
+
752
+ function gtm4wp_woocommerce_single_add_to_cart_tracking() {
753
+ global $product, $gtm4wp_datalayer_name, $gtm4wp_options;
754
+
755
+ // exit early if there is nothing to do
756
+ if ( ( false === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC ] ) && ( false === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) ) {
757
+ return;
758
+ }
759
+
760
+ $eec_product_array = gtm4wp_process_product( $product, array(), 'addtocartsingle' );
761
+
762
+ foreach ( $eec_product_array as $eec_product_array_key => $eec_product_array_value ) {
763
+ echo '<input type="hidden" name="gtm4wp_' . esc_attr( $eec_product_array_key ) . '" value="' . esc_attr( $eec_product_array_value ) . '" />' . "\n";
764
+ }
765
+ }
766
+
767
+ $GLOBALS['gtm4wp_cart_item_proddata'] = '';
768
+ function gtm4wp_woocommerce_cart_item_product_filter( $product, $cart_item = '', $cart_id = '' ) {
769
+ global $gtm4wp_options;
770
+
771
+ $eec_product_array = gtm4wp_process_product( $product, array(
772
+ 'productlink' => apply_filters( 'the_permalink', get_permalink(), 0 )
773
+ ), 'cart' );
774
+
775
+ $GLOBALS['gtm4wp_cart_item_proddata'] = $eec_product_array;
776
+
777
+ return $product;
778
+ }
779
+
780
+ function gtm4wp_woocommerce_cart_item_remove_link_filter( $remove_from_cart_link ) {
781
+ if ( ! isset( $GLOBALS['gtm4wp_cart_item_proddata'] ) ) {
782
+ return $remove_from_cart_link;
783
+ }
784
+
785
+ if ( ! is_array( $GLOBALS['gtm4wp_cart_item_proddata'] ) ) {
786
+ return $remove_from_cart_link;
787
+ }
788
+
789
+ if ( ! isset( $GLOBALS['gtm4wp_cart_item_proddata']['variant'] ) ) {
790
+ $GLOBALS['gtm4wp_cart_item_proddata']['variant'] = '';
791
+ }
792
+
793
+ if ( ! isset( $GLOBALS['gtm4wp_cart_item_proddata']['brand'] ) ) {
794
+ $GLOBALS['gtm4wp_cart_item_proddata']['brand'] = '';
795
+ }
796
+
797
+ $cartlink_with_data = sprintf(
798
+ 'data-gtm4wp_product_id="%s" data-gtm4wp_product_name="%s" data-gtm4wp_product_price="%s" data-gtm4wp_product_cat="%s" data-gtm4wp_product_url="%s" data-gtm4wp_product_variant="%s" data-gtm4wp_product_stocklevel="%s" data-gtm4wp_product_brand="%s" href="',
799
+ esc_attr( $GLOBALS['gtm4wp_cart_item_proddata']['id'] ),
800
+ esc_attr( $GLOBALS['gtm4wp_cart_item_proddata']['name'] ),
801
+ esc_attr( $GLOBALS['gtm4wp_cart_item_proddata']['price'] ),
802
+ esc_attr( $GLOBALS['gtm4wp_cart_item_proddata']['category'] ),
803
+ esc_url( $GLOBALS['gtm4wp_cart_item_proddata']['productlink'] ),
804
+ esc_attr( $GLOBALS['gtm4wp_cart_item_proddata']['variant'] ),
805
+ esc_attr( $GLOBALS['gtm4wp_cart_item_proddata']['stocklevel'] ),
806
+ esc_attr( $GLOBALS['gtm4wp_cart_item_proddata']['brand'] )
807
+ );
808
+ $GLOBALS['gtm4wp_cart_item_proddata'] = '';
809
+
810
+ return gtm4wp_str_replace_first( 'href="', $cartlink_with_data, $remove_from_cart_link );
811
+ }
812
+
813
+ function gtp4wp_woocommerce_reset_loop() {
814
+ global $woocommerce_loop;
815
+
816
+ $woocommerce_loop['listtype'] = '';
817
+ }
818
+
819
+ function gtm4wp_woocommerce_add_related_to_loop( $arg ) {
820
+ global $woocommerce_loop;
821
+
822
+ $woocommerce_loop['listtype'] = __( 'Related Products', 'duracelltomi-google-tag-manager' );
823
+
824
+ return $arg;
825
+ }
826
+
827
+ function gtm4wp_woocommerce_add_cross_sell_to_loop( $arg ) {
828
+ global $woocommerce_loop;
829
+
830
+ $woocommerce_loop['listtype'] = __( 'Cross-Sell Products', 'duracelltomi-google-tag-manager' );
831
+
832
+ return $arg;
833
+ }
834
+
835
+ function gtm4wp_woocommerce_add_upsells_to_loop( $arg ) {
836
+ global $woocommerce_loop;
837
+
838
+ $woocommerce_loop['listtype'] = __( 'Upsell Products', 'duracelltomi-google-tag-manager' );
839
+
840
+ return $arg;
841
+ }
842
+
843
+ function gtm4wp_woocommerce_before_template_part( $template_name ) {
844
+ ob_start();
845
+ }
846
+
847
+ function gtm4wp_woocommerce_after_template_part( $template_name ) {
848
+ global $product, $gtm4wp_product_counter, $gtm4wp_last_widget_title, $gtm4wp_options;
849
+
850
+ $productitem = ob_get_contents();
851
+ ob_end_clean();
852
+
853
+ if ( 'content-widget-product.php' == $template_name ) {
854
+ $eec_product_array = gtm4wp_process_product( $product, array(
855
+ 'productlink' => apply_filters( 'the_permalink', get_permalink(), 0 ),
856
+ 'listname' => $gtm4wp_last_widget_title,
857
+ 'listposition' => $gtm4wp_product_counter
858
+ ), 'widgetproduct' );
859
+
860
+ if ( ! isset( $eec_product_array[ 'brand' ] ) ) {
861
+ $eec_product_array[ 'brand' ] = '';
862
+ }
863
+
864
+ $productlink_with_data = sprintf(
865
+ 'data-gtm4wp_product_id="%s" data-gtm4wp_product_name="%s" data-gtm4wp_product_price="%s" data-gtm4wp_product_cat="%s" data-gtm4wp_product_url="%s" data-gtm4wp_productlist_name="%s" data-gtm4wp_product_listposition="%s" data-gtm4wp_product_stocklevel="%s" data-gtm4wp_product_brand="%s" href="',
866
+ esc_attr( $eec_product_array['id'] ),
867
+ esc_attr( $eec_product_array['name'] ),
868
+ esc_attr( $eec_product_array['price'] ),
869
+ esc_attr( $eec_product_array['category'] ),
870
+ esc_url( $eec_product_array['productlink'] ),
871
+ esc_attr( $eec_product_array['listname'] ),
872
+ esc_attr( $eec_product_array['listposition'] ),
873
+ esc_attr( $eec_product_array['stocklevel'] ),
874
+ esc_attr( $eec_product_array[ "brand" ] )
875
+ );
876
+
877
+ $gtm4wp_product_counter++;
878
+
879
+ $productitem = str_replace( 'href="', $productlink_with_data, $productitem );
880
+ }
881
+
882
+ echo $productitem;
883
+ }
884
+
885
+ function gtm4wp_widget_title_filter( $widget_title ) {
886
+ global $gtm4wp_product_counter, $gtm4wp_last_widget_title;
887
+
888
+ $gtm4wp_product_counter = 1;
889
+ $gtm4wp_last_widget_title = $widget_title . __( ' (widget)', 'duracelltomi-google-tag-manager' );
890
+
891
+ return $widget_title;
892
+ }
893
+
894
+ function gtm4wp_before_recent_products_loop() {
895
+ global $woocommerce_loop;
896
+
897
+ $woocommerce_loop['listtype'] = __( 'Recent Products', 'duracelltomi-google-tag-manager' );
898
+ }
899
+
900
+ function gtm4wp_before_sale_products_loop() {
901
+ global $woocommerce_loop;
902
+
903
+ $woocommerce_loop['listtype'] = __( 'Sale Products', 'duracelltomi-google-tag-manager' );
904
+ }
905
+
906
+ function gtm4wp_before_best_selling_products_loop() {
907
+ global $woocommerce_loop;
908
+
909
+ $woocommerce_loop['listtype'] = __( 'Best Selling Products', 'duracelltomi-google-tag-manager' );
910
+ }
911
+
912
+ function gtm4wp_before_top_rated_products_loop() {
913
+ global $woocommerce_loop;
914
+
915
+ $woocommerce_loop['listtype'] = __( 'Top Rated Products', 'duracelltomi-google-tag-manager' );
916
+ }
917
+
918
+ function gtm4wp_before_featured_products_loop() {
919
+ global $woocommerce_loop;
920
+
921
+ $woocommerce_loop['listtype'] = __( 'Featured Products', 'duracelltomi-google-tag-manager' );
922
+ }
923
+
924
+ function gtm4wp_before_related_products_loop() {
925
+ global $woocommerce_loop;
926
+
927
+ $woocommerce_loop['listtype'] = __( 'Related Products', 'duracelltomi-google-tag-manager' );
928
+ }
929
+
930
+ function gtm4wp_woocommerce_before_shop_loop_item() {
931
+ global $product, $woocommerce_loop, $wp_query, $gtm4wp_options;
932
+
933
+ if ( ! isset( $product ) ) {
934
+ return;
935
+ }
936
+
937
+ $product_id = $product->get_id();
938
+
939
+ $product_cat = '';
940
+ if ( is_product_category() ) {
941
+ global $wp_query;
942
+ $cat_obj = $wp_query->get_queried_object();
943
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCUSEFULLCATEGORYPATH ] ) {
944
+ $product_cat = gtm4wp_get_product_category_hierarchy( $cat_obj->term_id );
945
+ } else {
946
+ $product_cat = $cat_obj->name;
947
+ }
948
+ } else {
949
+ $product_cat = gtm4wp_get_product_category( $product_id, $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCUSEFULLCATEGORYPATH ] );
950
+ }
951
+
952
+ if ( is_search() ) {
953
+ $list_name = __( 'Search Results', 'duracelltomi-google-tag-manager' );
954
+ } elseif ( isset( $woocommerce_loop['listtype'] ) && ( $woocommerce_loop['listtype'] != '' ) ) {
955
+ $list_name = $woocommerce_loop['listtype'];
956
+ } else {
957
+ $list_name = __( 'General Product List', 'duracelltomi-google-tag-manager' );
958
+ }
959
+
960
+ $paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
961
+ $posts_per_page = get_query_var( 'posts_per_page' );
962
+ if ( $posts_per_page < 1 ) {
963
+ $posts_per_page = 1;
964
+ }
965
+
966
+ $eec_product_array = gtm4wp_process_product( $product, array(
967
+ 'productlink' => apply_filters( 'the_permalink', get_permalink(), 0 ),
968
+ 'listname' => $list_name,
969
+ 'listposition' => $woocommerce_loop['loop'] + ( $posts_per_page * ( $paged - 1 ) )
970
+ ), 'productlist' );
971
+
972
+ if ( ! isset( $eec_product_array[ 'brand' ] ) ) {
973
+ $eec_product_array[ 'brand' ] = '';
974
+ }
975
+
976
+ printf(
977
+ '<span class="gtm4wp_productdata" style="display:none; visibility:hidden;" data-gtm4wp_product_id="%s" data-gtm4wp_product_name="%s" data-gtm4wp_product_price="%s" data-gtm4wp_product_cat="%s" data-gtm4wp_product_url="%s" data-gtm4wp_product_listposition="%s" data-gtm4wp_productlist_name="%s" data-gtm4wp_product_stocklevel="%s" data-gtm4wp_product_brand="%s"></span>',
978
+ esc_attr( $eec_product_array['id'] ),
979
+ esc_attr( $eec_product_array['name'] ),
980
+ esc_attr( $eec_product_array['price'] ),
981
+ esc_attr( $eec_product_array['category'] ),
982
+ esc_url( $eec_product_array['productlink'] ),
983
+ esc_attr( $eec_product_array['listposition'] ),
984
+ esc_attr( $eec_product_array['listname'] ),
985
+ esc_attr( $eec_product_array['stocklevel'] ),
986
+ esc_attr( $eec_product_array[ "brand" ] )
987
+ );
988
+ }
989
+
990
+ function gtm4wp_woocommerce_cart_item_restored( $cart_item_key ) {
991
+ setcookie( 'gtm4wp_product_readded_to_cart', $cart_item_key );
992
+ }
993
+
994
+ function gtm4wp_woocommerce_enqueue_scripts() {
995
+ global $gtm4wp_options, $gtp4wp_plugin_url;
996
+
997
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC ] ) {
998
+ $in_footer = apply_filters( 'gtm4wp_' . GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC, false );
999
+ wp_enqueue_script( 'gtm4wp-woocommerce-classic', $gtp4wp_plugin_url . 'js/gtm4wp-woocommerce-classic.js', array( 'jquery' ), GTM4WP_VERSION, $in_footer );
1000
+ }
1001
+
1002
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) {
1003
+ $in_footer = apply_filters( 'gtm4wp_' . GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC, false );
1004
+ wp_enqueue_script( 'gtm4wp-woocommerce-enhanced', $gtp4wp_plugin_url . 'js/gtm4wp-woocommerce-enhanced.js', array( 'jquery' ), GTM4WP_VERSION, $in_footer );
1005
+ }
1006
+ }
1007
+
1008
+ function gtm4wp_wc_quick_view_before_single_product() {
1009
+ global $gtm4wp_options, $gtm4wp_datalayer_name;
1010
+
1011
+ $dataLayer = array(
1012
+ 'event' => 'gtm4wp.changeDetailViewEEC',
1013
+ );
1014
+
1015
+ if ( ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ] ) || ( true === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) ) {
1016
+ $postid = get_the_ID();
1017
+ $product = wc_get_product( $postid );
1018
+
1019
+ $eec_product_array = gtm4wp_process_product( $product, array(), 'productdetail' );
1020
+
1021
+ $dataLayer['productRatingCounts'] = $product->get_rating_counts();
1022
+ $dataLayer['productAverageRating'] = (float) $product->get_average_rating();
1023
+ $dataLayer['productReviewCount'] = (int) $product->get_review_count();
1024
+ $dataLayer['productType'] = $product->get_type();
1025
+
1026
+ switch ( $dataLayer['productType'] ) {
1027
+ case 'variable': {
1028
+ $dataLayer['productIsVariable'] = 1;
1029
+
1030
+ $dataLayer['ecomm_prodid'] = gtm4wp_prefix_productid( $eec_product_array[ 'id' ] );
1031
+ $dataLayer['ecomm_pagetype'] = 'product';
1032
+ $dataLayer['ecomm_totalvalue'] = $eec_product_array[ 'price' ];
1033
+
1034
+ break;
1035
+ }
1036
+
1037
+ case 'grouped': {
1038
+ $dataLayer['productIsVariable'] = 0;
1039
+
1040
+ break;
1041
+ }
1042
+
1043
+ default: {
1044
+ $dataLayer['productIsVariable'] = 0;
1045
+
1046
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ] ) {
1047
+ $dataLayer['ecomm_prodid'] = gtm4wp_prefix_productid( $eec_product_array[ 'id' ] );
1048
+ $dataLayer['ecomm_pagetype'] = 'product';
1049
+ $dataLayer['ecomm_totalvalue'] = $eec_product_array['price'];
1050
+ }
1051
+
1052
+ if ( true === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) {
1053
+ $currencyCode = get_woocommerce_currency();
1054
+
1055
+ $dataLayer['ecommerce'] = array(
1056
+ 'currencyCode' => $currencyCode,
1057
+ 'detail' => array(
1058
+ 'products' => array(
1059
+ $eec_product_array
1060
+ )
1061
+ )
1062
+ );
1063
+ }
1064
+ }
1065
+ }
1066
+ }
1067
+
1068
+ echo '
1069
+ <script>
1070
+ ' . $gtm4wp_datalayer_name . '.push(' . json_encode( $dataLayer ) . ');
1071
+ </script>';
1072
+ }
1073
+
1074
+ function gtm4wp_woocommerce_grouped_product_list_column_label( $labelvalue, $product ) {
1075
+ global $gtm4wp_options, $gtm4wp_grouped_product_ix;
1076
+
1077
+ if ( ! isset( $product ) ) {
1078
+ return $labelvalue;
1079
+ }
1080
+
1081
+ $list_name = __( 'Grouped Product Detail Page', 'duracelltomi-google-tag-manager' );
1082
+
1083
+ $eec_product_array = gtm4wp_process_product( $product, array(
1084
+ 'productlink' => $product->get_permalink(),
1085
+ 'listname' => $list_name,
1086
+ 'listposition' => $gtm4wp_grouped_product_ix
1087
+ ), 'groupedproductlist' );
1088
+
1089
+ $gtm4wp_grouped_product_ix++;
1090
+
1091
+ if ( ! isset( $eec_product_array[ 'brand' ] ) ) {
1092
+ $eec_product_array[ 'brand' ] = '';
1093
+ }
1094
+
1095
+ $labelvalue .=
1096
+ sprintf(
1097
+ '<span class="gtm4wp_productdata" style="display:none; visibility:hidden;" data-gtm4wp_product_id="%s" data-gtm4wp_product_sku="%s" data-gtm4wp_product_name="%s" data-gtm4wp_product_price="%s" data-gtm4wp_product_cat="%s" data-gtm4wp_product_url="%s" data-gtm4wp_product_listposition="%s" data-gtm4wp_productlist_name="%s" data-gtm4wp_product_stocklevel="%s" data-gtm4wp_product_brand="%s"></span>',
1098
+ esc_attr( $eec_product_array['id'] ),
1099
+ esc_attr( $eec_product_array['sku'] ),
1100
+ esc_attr( $eec_product_array['name'] ),
1101
+ esc_attr( $eec_product_array['price'] ),
1102
+ esc_attr( $eec_product_array['category'] ),
1103
+ esc_url( $eec_product_array['productlink'] ),
1104
+ esc_attr( $eec_product_array['listposition'] ),
1105
+ esc_attr( $eec_product_array['listname'] ),
1106
+ esc_attr( $eec_product_array['stocklevel'] ),
1107
+ esc_attr( $eec_product_array['brand'] )
1108
+ );
1109
+
1110
+ return $labelvalue;
1111
+ }
1112
+
1113
+ // do not add filter if someone enabled WooCommerce integration without an activated WooCommerce plugin
1114
+ if ( function_exists( 'WC' ) ) {
1115
+ add_filter( GTM4WP_WPFILTER_COMPILE_DATALAYER, 'gtm4wp_woocommerce_datalayer_filter_items' );
1116
+
1117
+ add_filter( 'loop_end', 'gtp4wp_woocommerce_reset_loop' );
1118
+ add_action( 'woocommerce_before_shop_loop_item', 'gtm4wp_woocommerce_before_shop_loop_item' );
1119
+ add_action( 'woocommerce_after_add_to_cart_button', 'gtm4wp_woocommerce_single_add_to_cart_tracking' );
1120
+
1121
+ // add_action( "wp_footer", "gtm4wp_woocommerce_wp_footer" );
1122
+ add_action( 'wp_enqueue_scripts', 'gtm4wp_woocommerce_enqueue_scripts' );
1123
+ add_filter( GTM4WP_WPACTION_ADDGLOBALVARS, 'gtm4wp_woocommerce_addglobalvars' );
1124
+
1125
+ if ( true === $GLOBALS['gtm4wp_options'][ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) {
1126
+ // add_action( "wp_footer", "gtm4wp_woocommerce_enhanced_ecom_product_click" );
1127
+ add_action( 'woocommerce_before_template_part', 'gtm4wp_woocommerce_before_template_part' );
1128
+ add_action( 'woocommerce_after_template_part', 'gtm4wp_woocommerce_after_template_part' );
1129
+ add_filter( 'widget_title', 'gtm4wp_widget_title_filter' );
1130
+ add_action( 'wc_quick_view_before_single_product', 'gtm4wp_wc_quick_view_before_single_product' );
1131
+ add_filter( 'woocommerce_grouped_product_list_column_label', 'gtm4wp_woocommerce_grouped_product_list_column_label', 10, 2 );
1132
+
1133
+ add_filter( 'woocommerce_cart_item_product', 'gtm4wp_woocommerce_cart_item_product_filter' );
1134
+ add_filter( 'woocommerce_cart_item_remove_link', 'gtm4wp_woocommerce_cart_item_remove_link_filter' );
1135
+ add_action( 'woocommerce_cart_item_restored', 'gtm4wp_woocommerce_cart_item_restored' );
1136
+
1137
+ add_filter( 'woocommerce_related_products_args', 'gtm4wp_woocommerce_add_related_to_loop' );
1138
+ add_filter( 'woocommerce_related_products_columns', 'gtm4wp_woocommerce_add_related_to_loop' );
1139
+ add_filter( 'woocommerce_cross_sells_columns', 'gtm4wp_woocommerce_add_cross_sell_to_loop' );
1140
+ add_filter( 'woocommerce_upsells_columns', 'gtm4wp_woocommerce_add_upsells_to_loop' );
1141
+
1142
+ add_action( 'woocommerce_shortcode_before_recent_products_loop', 'gtm4wp_before_recent_products_loop' );
1143
+ add_action( 'woocommerce_shortcode_before_sale_products_loop', 'gtm4wp_before_sale_products_loop' );
1144
+ add_action( 'woocommerce_shortcode_before_best_selling_products_loop', 'gtm4wp_before_best_selling_products_loop' );
1145
+ add_action( 'woocommerce_shortcode_before_top_rated_products_loop', 'gtm4wp_before_top_rated_products_loop' );
1146
+ add_action( 'woocommerce_shortcode_before_featured_products_loop', 'gtm4wp_before_featured_products_loop' );
1147
+ add_action( 'woocommerce_shortcode_before_related_products_loop', 'gtm4wp_before_related_products_loop' );
1148
+ }
1149
+ }
js/admin-subtabs.js CHANGED
@@ -71,7 +71,7 @@ var adminsubtabs = {
71
  },
72
  "int-wc": {
73
  tabtext: gtm4wp.wctabtitle,
74
- numitems: 15
75
  },
76
  "int-google-optimize": {
77
  tabtext: gtm4wp.gotabtitle,
@@ -80,6 +80,10 @@ var adminsubtabs = {
80
  "int-amp": {
81
  tabtext: gtm4wp.amptabtitle,
82
  numitems: 1
 
 
 
 
83
  }
84
  }
85
  };
71
  },
72
  "int-wc": {
73
  tabtext: gtm4wp.wctabtitle,
74
+ numitems: 17
75
  },
76
  "int-google-optimize": {
77
  tabtext: gtm4wp.gotabtitle,
80
  "int-amp": {
81
  tabtext: gtm4wp.amptabtitle,
82
  numitems: 1
83
+ },
84
+ "int-cookiebot": {
85
+ tabtext: gtm4wp.cookiebottabtitle,
86
+ numitems: 1
87
  }
88
  }
89
  };
js/gtm4wp-woocommerce-enhanced.js CHANGED
@@ -7,7 +7,7 @@ function gtm4wp_map_eec_to_ga4( productdata ) {
7
  }
8
 
9
  var category_path = productdata.category ? productdata.category : '';
10
- var category_parts = category_path.split('/');
11
 
12
  // default, required parameters
13
  var ga4_product = {
@@ -44,6 +44,9 @@ function gtm4wp_map_eec_to_ga4( productdata ) {
44
  ga4_product.coupon = productdata.coupon;
45
  }
46
 
 
 
 
47
  return ga4_product;
48
  }
49
 
@@ -528,6 +531,11 @@ jQuery(function() {
528
  },
529
  'eventCallback': function() {
530
 
 
 
 
 
 
531
  // fire ga4 version
532
  window[ gtm4wp_datalayer_name ].push({
533
  'event': 'select_item',
@@ -547,6 +555,8 @@ jQuery(function() {
547
  'eventTimeout': 2000
548
  });
549
 
 
 
550
  },
551
  'eventTimeout': 2000
552
  });
@@ -894,7 +904,7 @@ jQuery(function() {
894
  'event': 'view_cart',
895
  'ecommerce': {
896
  'currency': gtm4wp_currency,
897
- 'value': sum_value,
898
  'items': ga4_products
899
  }
900
  });
7
  }
8
 
9
  var category_path = productdata.category ? productdata.category : '';
10
+ var category_parts = category_path.toString().split('/');
11
 
12
  // default, required parameters
13
  var ga4_product = {
44
  ga4_product.coupon = productdata.coupon;
45
  }
46
 
47
+ ga4_product.google_business_vertical = window.gtm4wp_business_vertical;
48
+ ga4_product[ window.gtm4wp_business_vertical_id ] = gtm4wp_id_prefix + ga4_product[ "item_id" ];
49
+
50
  return ga4_product;
51
  }
52
 
531
  },
532
  'eventCallback': function() {
533
 
534
+ // do not fire this event multiple times
535
+ if ( window[ "gtm4wp_select_item_" + product_data.id ] ) {
536
+ return;
537
+ }
538
+
539
  // fire ga4 version
540
  window[ gtm4wp_datalayer_name ].push({
541
  'event': 'select_item',
555
  'eventTimeout': 2000
556
  });
557
 
558
+ window[ "gtm4wp_select_item_" + product_data.id ] = true;
559
+
560
  },
561
  'eventTimeout': 2000
562
  });
904
  'event': 'view_cart',
905
  'ecommerce': {
906
  'currency': gtm4wp_currency,
907
+ 'value': sum_value.toFixed(2),
908
  'items': ga4_products
909
  }
910
  });
license.txt CHANGED
@@ -1,621 +1,621 @@
1
- GNU GENERAL PUBLIC LICENSE
2
- Version 3, 29 June 2007
3
-
4
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
5
- Everyone is permitted to copy and distribute verbatim copies
6
- of this license document, but changing it is not allowed.
7
-
8
- Preamble
9
-
10
- The GNU General Public License is a free, copyleft license for
11
- software and other kinds of works.
12
-
13
- The licenses for most software and other practical works are designed
14
- to take away your freedom to share and change the works. By contrast,
15
- the GNU General Public License is intended to guarantee your freedom to
16
- share and change all versions of a program--to make sure it remains free
17
- software for all its users. We, the Free Software Foundation, use the
18
- GNU General Public License for most of our software; it applies also to
19
- any other work released this way by its authors. You can apply it to
20
- your programs, too.
21
-
22
- When we speak of free software, we are referring to freedom, not
23
- price. Our General Public Licenses are designed to make sure that you
24
- have the freedom to distribute copies of free software (and charge for
25
- them if you wish), that you receive source code or can get it if you
26
- want it, that you can change the software or use pieces of it in new
27
- free programs, and that you know you can do these things.
28
-
29
- To protect your rights, we need to prevent others from denying you
30
- these rights or asking you to surrender the rights. Therefore, you have
31
- certain responsibilities if you distribute copies of the software, or if
32
- you modify it: responsibilities to respect the freedom of others.
33
-
34
- For example, if you distribute copies of such a program, whether
35
- gratis or for a fee, you must pass on to the recipients the same
36
- freedoms that you received. You must make sure that they, too, receive
37
- or can get the source code. And you must show them these terms so they
38
- know their rights.
39
-
40
- Developers that use the GNU GPL protect your rights with two steps:
41
- (1) assert copyright on the software, and (2) offer you this License
42
- giving you legal permission to copy, distribute and/or modify it.
43
-
44
- For the developers' and authors' protection, the GPL clearly explains
45
- that there is no warranty for this free software. For both users' and
46
- authors' sake, the GPL requires that modified versions be marked as
47
- changed, so that their problems will not be attributed erroneously to
48
- authors of previous versions.
49
-
50
- Some devices are designed to deny users access to install or run
51
- modified versions of the software inside them, although the manufacturer
52
- can do so. This is fundamentally incompatible with the aim of
53
- protecting users' freedom to change the software. The systematic
54
- pattern of such abuse occurs in the area of products for individuals to
55
- use, which is precisely where it is most unacceptable. Therefore, we
56
- have designed this version of the GPL to prohibit the practice for those
57
- products. If such problems arise substantially in other domains, we
58
- stand ready to extend this provision to those domains in future versions
59
- of the GPL, as needed to protect the freedom of users.
60
-
61
- Finally, every program is threatened constantly by software patents.
62
- States should not allow patents to restrict development and use of
63
- software on general-purpose computers, but in those that do, we wish to
64
- avoid the special danger that patents applied to a free program could
65
- make it effectively proprietary. To prevent this, the GPL assures that
66
- patents cannot be used to render the program non-free.
67
-
68
- The precise terms and conditions for copying, distribution and
69
- modification follow.
70
-
71
- TERMS AND CONDITIONS
72
-
73
- 0. Definitions.
74
-
75
- "This License" refers to version 3 of the GNU General Public License.
76
-
77
- "Copyright" also means copyright-like laws that apply to other kinds of
78
- works, such as semiconductor masks.
79
-
80
- "The Program" refers to any copyrightable work licensed under this
81
- License. Each licensee is addressed as "you". "Licensees" and
82
- "recipients" may be individuals or organizations.
83
-
84
- To "modify" a work means to copy from or adapt all or part of the work
85
- in a fashion requiring copyright permission, other than the making of an
86
- exact copy. The resulting work is called a "modified version" of the
87
- earlier work or a work "based on" the earlier work.
88
-
89
- A "covered work" means either the unmodified Program or a work based
90
- on the Program.
91
-
92
- To "propagate" a work means to do anything with it that, without
93
- permission, would make you directly or secondarily liable for
94
- infringement under applicable copyright law, except executing it on a
95
- computer or modifying a private copy. Propagation includes copying,
96
- distribution (with or without modification), making available to the
97
- public, and in some countries other activities as well.
98
-
99
- To "convey" a work means any kind of propagation that enables other
100
- parties to make or receive copies. Mere interaction with a user through
101
- a computer network, with no transfer of a copy, is not conveying.
102
-
103
- An interactive user interface displays "Appropriate Legal Notices"
104
- to the extent that it includes a convenient and prominently visible
105
- feature that (1) displays an appropriate copyright notice, and (2)
106
- tells the user that there is no warranty for the work (except to the
107
- extent that warranties are provided), that licensees may convey the
108
- work under this License, and how to view a copy of this License. If
109
- the interface presents a list of user commands or options, such as a
110
- menu, a prominent item in the list meets this criterion.
111
-
112
- 1. Source Code.
113
-
114
- The "source code" for a work means the preferred form of the work
115
- for making modifications to it. "Object code" means any non-source
116
- form of a work.
117
-
118
- A "Standard Interface" means an interface that either is an official
119
- standard defined by a recognized standards body, or, in the case of
120
- interfaces specified for a particular programming language, one that
121
- is widely used among developers working in that language.
122
-
123
- The "System Libraries" of an executable work include anything, other
124
- than the work as a whole, that (a) is included in the normal form of
125
- packaging a Major Component, but which is not part of that Major
126
- Component, and (b) serves only to enable use of the work with that
127
- Major Component, or to implement a Standard Interface for which an
128
- implementation is available to the public in source code form. A
129
- "Major Component", in this context, means a major essential component
130
- (kernel, window system, and so on) of the specific operating system
131
- (if any) on which the executable work runs, or a compiler used to
132
- produce the work, or an object code interpreter used to run it.
133
-
134
- The "Corresponding Source" for a work in object code form means all
135
- the source code needed to generate, install, and (for an executable
136
- work) run the object code and to modify the work, including scripts to
137
- control those activities. However, it does not include the work's
138
- System Libraries, or general-purpose tools or generally available free
139
- programs which are used unmodified in performing those activities but
140
- which are not part of the work. For example, Corresponding Source
141
- includes interface definition files associated with source files for
142
- the work, and the source code for shared libraries and dynamically
143
- linked subprograms that the work is specifically designed to require,
144
- such as by intimate data communication or control flow between those
145
- subprograms and other parts of the work.
146
-
147
- The Corresponding Source need not include anything that users
148
- can regenerate automatically from other parts of the Corresponding
149
- Source.
150
-
151
- The Corresponding Source for a work in source code form is that
152
- same work.
153
-
154
- 2. Basic Permissions.
155
-
156
- All rights granted under this License are granted for the term of
157
- copyright on the Program, and are irrevocable provided the stated
158
- conditions are met. This License explicitly affirms your unlimited
159
- permission to run the unmodified Program. The output from running a
160
- covered work is covered by this License only if the output, given its
161
- content, constitutes a covered work. This License acknowledges your
162
- rights of fair use or other equivalent, as provided by copyright law.
163
-
164
- You may make, run and propagate covered works that you do not
165
- convey, without conditions so long as your license otherwise remains
166
- in force. You may convey covered works to others for the sole purpose
167
- of having them make modifications exclusively for you, or provide you
168
- with facilities for running those works, provided that you comply with
169
- the terms of this License in conveying all material for which you do
170
- not control copyright. Those thus making or running the covered works
171
- for you must do so exclusively on your behalf, under your direction
172
- and control, on terms that prohibit them from making any copies of
173
- your copyrighted material outside their relationship with you.
174
-
175
- Conveying under any other circumstances is permitted solely under
176
- the conditions stated below. Sublicensing is not allowed; section 10
177
- makes it unnecessary.
178
-
179
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180
-
181
- No covered work shall be deemed part of an effective technological
182
- measure under any applicable law fulfilling obligations under article
183
- 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184
- similar laws prohibiting or restricting circumvention of such
185
- measures.
186
-
187
- When you convey a covered work, you waive any legal power to forbid
188
- circumvention of technological measures to the extent such circumvention
189
- is effected by exercising rights under this License with respect to
190
- the covered work, and you disclaim any intention to limit operation or
191
- modification of the work as a means of enforcing, against the work's
192
- users, your or third parties' legal rights to forbid circumvention of
193
- technological measures.
194
-
195
- 4. Conveying Verbatim Copies.
196
-
197
- You may convey verbatim copies of the Program's source code as you
198
- receive it, in any medium, provided that you conspicuously and
199
- appropriately publish on each copy an appropriate copyright notice;
200
- keep intact all notices stating that this License and any
201
- non-permissive terms added in accord with section 7 apply to the code;
202
- keep intact all notices of the absence of any warranty; and give all
203
- recipients a copy of this License along with the Program.
204
-
205
- You may charge any price or no price for each copy that you convey,
206
- and you may offer support or warranty protection for a fee.
207
-
208
- 5. Conveying Modified Source Versions.
209
-
210
- You may convey a work based on the Program, or the modifications to
211
- produce it from the Program, in the form of source code under the
212
- terms of section 4, provided that you also meet all of these conditions:
213
-
214
- a) The work must carry prominent notices stating that you modified
215
- it, and giving a relevant date.
216
-
217
- b) The work must carry prominent notices stating that it is
218
- released under this License and any conditions added under section
219
- 7. This requirement modifies the requirement in section 4 to
220
- "keep intact all notices".
221
-
222
- c) You must license the entire work, as a whole, under this
223
- License to anyone who comes into possession of a copy. This
224
- License will therefore apply, along with any applicable section 7
225
- additional terms, to the whole of the work, and all its parts,
226
- regardless of how they are packaged. This License gives no
227
- permission to license the work in any other way, but it does not
228
- invalidate such permission if you have separately received it.
229
-
230
- d) If the work has interactive user interfaces, each must display
231
- Appropriate Legal Notices; however, if the Program has interactive
232
- interfaces that do not display Appropriate Legal Notices, your
233
- work need not make them do so.
234
-
235
- A compilation of a covered work with other separate and independent
236
- works, which are not by their nature extensions of the covered work,
237
- and which are not combined with it such as to form a larger program,
238
- in or on a volume of a storage or distribution medium, is called an
239
- "aggregate" if the compilation and its resulting copyright are not
240
- used to limit the access or legal rights of the compilation's users
241
- beyond what the individual works permit. Inclusion of a covered work
242
- in an aggregate does not cause this License to apply to the other
243
- parts of the aggregate.
244
-
245
- 6. Conveying Non-Source Forms.
246
-
247
- You may convey a covered work in object code form under the terms
248
- of sections 4 and 5, provided that you also convey the
249
- machine-readable Corresponding Source under the terms of this License,
250
- in one of these ways:
251
-
252
- a) Convey the object code in, or embodied in, a physical product
253
- (including a physical distribution medium), accompanied by the
254
- Corresponding Source fixed on a durable physical medium
255
- customarily used for software interchange.
256
-
257
- b) Convey the object code in, or embodied in, a physical product
258
- (including a physical distribution medium), accompanied by a
259
- written offer, valid for at least three years and valid for as
260
- long as you offer spare parts or customer support for that product
261
- model, to give anyone who possesses the object code either (1) a
262
- copy of the Corresponding Source for all the software in the
263
- product that is covered by this License, on a durable physical
264
- medium customarily used for software interchange, for a price no
265
- more than your reasonable cost of physically performing this
266
- conveying of source, or (2) access to copy the
267
- Corresponding Source from a network server at no charge.
268
-
269
- c) Convey individual copies of the object code with a copy of the
270
- written offer to provide the Corresponding Source. This
271
- alternative is allowed only occasionally and noncommercially, and
272
- only if you received the object code with such an offer, in accord
273
- with subsection 6b.
274
-
275
- d) Convey the object code by offering access from a designated
276
- place (gratis or for a charge), and offer equivalent access to the
277
- Corresponding Source in the same way through the same place at no
278
- further charge. You need not require recipients to copy the
279
- Corresponding Source along with the object code. If the place to
280
- copy the object code is a network server, the Corresponding Source
281
- may be on a different server (operated by you or a third party)
282
- that supports equivalent copying facilities, provided you maintain
283
- clear directions next to the object code saying where to find the
284
- Corresponding Source. Regardless of what server hosts the
285
- Corresponding Source, you remain obligated to ensure that it is
286
- available for as long as needed to satisfy these requirements.
287
-
288
- e) Convey the object code using peer-to-peer transmission, provided
289
- you inform other peers where the object code and Corresponding
290
- Source of the work are being offered to the general public at no
291
- charge under subsection 6d.
292
-
293
- A separable portion of the object code, whose source code is excluded
294
- from the Corresponding Source as a System Library, need not be
295
- included in conveying the object code work.
296
-
297
- A "User Product" is either (1) a "consumer product", which means any
298
- tangible personal property which is normally used for personal, family,
299
- or household purposes, or (2) anything designed or sold for incorporation
300
- into a dwelling. In determining whether a product is a consumer product,
301
- doubtful cases shall be resolved in favor of coverage. For a particular
302
- product received by a particular user, "normally used" refers to a
303
- typical or common use of that class of product, regardless of the status
304
- of the particular user or of the way in which the particular user
305
- actually uses, or expects or is expected to use, the product. A product
306
- is a consumer product regardless of whether the product has substantial
307
- commercial, industrial or non-consumer uses, unless such uses represent
308
- the only significant mode of use of the product.
309
-
310
- "Installation Information" for a User Product means any methods,
311
- procedures, authorization keys, or other information required to install
312
- and execute modified versions of a covered work in that User Product from
313
- a modified version of its Corresponding Source. The information must
314
- suffice to ensure that the continued functioning of the modified object
315
- code is in no case prevented or interfered with solely because
316
- modification has been made.
317
-
318
- If you convey an object code work under this section in, or with, or
319
- specifically for use in, a User Product, and the conveying occurs as
320
- part of a transaction in which the right of possession and use of the
321
- User Product is transferred to the recipient in perpetuity or for a
322
- fixed term (regardless of how the transaction is characterized), the
323
- Corresponding Source conveyed under this section must be accompanied
324
- by the Installation Information. But this requirement does not apply
325
- if neither you nor any third party retains the ability to install
326
- modified object code on the User Product (for example, the work has
327
- been installed in ROM).
328
-
329
- The requirement to provide Installation Information does not include a
330
- requirement to continue to provide support service, warranty, or updates
331
- for a work that has been modified or installed by the recipient, or for
332
- the User Product in which it has been modified or installed. Access to a
333
- network may be denied when the modification itself materially and
334
- adversely affects the operation of the network or violates the rules and
335
- protocols for communication across the network.
336
-
337
- Corresponding Source conveyed, and Installation Information provided,
338
- in accord with this section must be in a format that is publicly
339
- documented (and with an implementation available to the public in
340
- source code form), and must require no special password or key for
341
- unpacking, reading or copying.
342
-
343
- 7. Additional Terms.
344
-
345
- "Additional permissions" are terms that supplement the terms of this
346
- License by making exceptions from one or more of its conditions.
347
- Additional permissions that are applicable to the entire Program shall
348
- be treated as though they were included in this License, to the extent
349
- that they are valid under applicable law. If additional permissions
350
- apply only to part of the Program, that part may be used separately
351
- under those permissions, but the entire Program remains governed by
352
- this License without regard to the additional permissions.
353
-
354
- When you convey a copy of a covered work, you may at your option
355
- remove any additional permissions from that copy, or from any part of
356
- it. (Additional permissions may be written to require their own
357
- removal in certain cases when you modify the work.) You may place
358
- additional permissions on material, added by you to a covered work,
359
- for which you have or can give appropriate copyright permission.
360
-
361
- Notwithstanding any other provision of this License, for material you
362
- add to a covered work, you may (if authorized by the copyright holders of
363
- that material) supplement the terms of this License with terms:
364
-
365
- a) Disclaiming warranty or limiting liability differently from the
366
- terms of sections 15 and 16 of this License; or
367
-
368
- b) Requiring preservation of specified reasonable legal notices or
369
- author attributions in that material or in the Appropriate Legal
370
- Notices displayed by works containing it; or
371
-
372
- c) Prohibiting misrepresentation of the origin of that material, or
373
- requiring that modified versions of such material be marked in
374
- reasonable ways as different from the original version; or
375
-
376
- d) Limiting the use for publicity purposes of names of licensors or
377
- authors of the material; or
378
-
379
- e) Declining to grant rights under trademark law for use of some
380
- trade names, trademarks, or service marks; or
381
-
382
- f) Requiring indemnification of licensors and authors of that
383
- material by anyone who conveys the material (or modified versions of
384
- it) with contractual assumptions of liability to the recipient, for
385
- any liability that these contractual assumptions directly impose on
386
- those licensors and authors.
387
-
388
- All other non-permissive additional terms are considered "further
389
- restrictions" within the meaning of section 10. If the Program as you
390
- received it, or any part of it, contains a notice stating that it is
391
- governed by this License along with a term that is a further
392
- restriction, you may remove that term. If a license document contains
393
- a further restriction but permits relicensing or conveying under this
394
- License, you may add to a covered work material governed by the terms
395
- of that license document, provided that the further restriction does
396
- not survive such relicensing or conveying.
397
-
398
- If you add terms to a covered work in accord with this section, you
399
- must place, in the relevant source files, a statement of the
400
- additional terms that apply to those files, or a notice indicating
401
- where to find the applicable terms.
402
-
403
- Additional terms, permissive or non-permissive, may be stated in the
404
- form of a separately written license, or stated as exceptions;
405
- the above requirements apply either way.
406
-
407
- 8. Termination.
408
-
409
- You may not propagate or modify a covered work except as expressly
410
- provided under this License. Any attempt otherwise to propagate or
411
- modify it is void, and will automatically terminate your rights under
412
- this License (including any patent licenses granted under the third
413
- paragraph of section 11).
414
-
415
- However, if you cease all violation of this License, then your
416
- license from a particular copyright holder is reinstated (a)
417
- provisionally, unless and until the copyright holder explicitly and
418
- finally terminates your license, and (b) permanently, if the copyright
419
- holder fails to notify you of the violation by some reasonable means
420
- prior to 60 days after the cessation.
421
-
422
- Moreover, your license from a particular copyright holder is
423
- reinstated permanently if the copyright holder notifies you of the
424
- violation by some reasonable means, this is the first time you have
425
- received notice of violation of this License (for any work) from that
426
- copyright holder, and you cure the violation prior to 30 days after
427
- your receipt of the notice.
428
-
429
- Termination of your rights under this section does not terminate the
430
- licenses of parties who have received copies or rights from you under
431
- this License. If your rights have been terminated and not permanently
432
- reinstated, you do not qualify to receive new licenses for the same
433
- material under section 10.
434
-
435
- 9. Acceptance Not Required for Having Copies.
436
-
437
- You are not required to accept this License in order to receive or
438
- run a copy of the Program. Ancillary propagation of a covered work
439
- occurring solely as a consequence of using peer-to-peer transmission
440
- to receive a copy likewise does not require acceptance. However,
441
- nothing other than this License grants you permission to propagate or
442
- modify any covered work. These actions infringe copyright if you do
443
- not accept this License. Therefore, by modifying or propagating a
444
- covered work, you indicate your acceptance of this License to do so.
445
-
446
- 10. Automatic Licensing of Downstream Recipients.
447
-
448
- Each time you convey a covered work, the recipient automatically
449
- receives a license from the original licensors, to run, modify and
450
- propagate that work, subject to this License. You are not responsible
451
- for enforcing compliance by third parties with this License.
452
-
453
- An "entity transaction" is a transaction transferring control of an
454
- organization, or substantially all assets of one, or subdividing an
455
- organization, or merging organizations. If propagation of a covered
456
- work results from an entity transaction, each party to that
457
- transaction who receives a copy of the work also receives whatever
458
- licenses to the work the party's predecessor in interest had or could
459
- give under the previous paragraph, plus a right to possession of the
460
- Corresponding Source of the work from the predecessor in interest, if
461
- the predecessor has it or can get it with reasonable efforts.
462
-
463
- You may not impose any further restrictions on the exercise of the
464
- rights granted or affirmed under this License. For example, you may
465
- not impose a license fee, royalty, or other charge for exercise of
466
- rights granted under this License, and you may not initiate litigation
467
- (including a cross-claim or counterclaim in a lawsuit) alleging that
468
- any patent claim is infringed by making, using, selling, offering for
469
- sale, or importing the Program or any portion of it.
470
-
471
- 11. Patents.
472
-
473
- A "contributor" is a copyright holder who authorizes use under this
474
- License of the Program or a work on which the Program is based. The
475
- work thus licensed is called the contributor's "contributor version".
476
-
477
- A contributor's "essential patent claims" are all patent claims
478
- owned or controlled by the contributor, whether already acquired or
479
- hereafter acquired, that would be infringed by some manner, permitted
480
- by this License, of making, using, or selling its contributor version,
481
- but do not include claims that would be infringed only as a
482
- consequence of further modification of the contributor version. For
483
- purposes of this definition, "control" includes the right to grant
484
- patent sublicenses in a manner consistent with the requirements of
485
- this License.
486
-
487
- Each contributor grants you a non-exclusive, worldwide, royalty-free
488
- patent license under the contributor's essential patent claims, to
489
- make, use, sell, offer for sale, import and otherwise run, modify and
490
- propagate the contents of its contributor version.
491
-
492
- In the following three paragraphs, a "patent license" is any express
493
- agreement or commitment, however denominated, not to enforce a patent
494
- (such as an express permission to practice a patent or covenant not to
495
- sue for patent infringement). To "grant" such a patent license to a
496
- party means to make such an agreement or commitment not to enforce a
497
- patent against the party.
498
-
499
- If you convey a covered work, knowingly relying on a patent license,
500
- and the Corresponding Source of the work is not available for anyone
501
- to copy, free of charge and under the terms of this License, through a
502
- publicly available network server or other readily accessible means,
503
- then you must either (1) cause the Corresponding Source to be so
504
- available, or (2) arrange to deprive yourself of the benefit of the
505
- patent license for this particular work, or (3) arrange, in a manner
506
- consistent with the requirements of this License, to extend the patent
507
- license to downstream recipients. "Knowingly relying" means you have
508
- actual knowledge that, but for the patent license, your conveying the
509
- covered work in a country, or your recipient's use of the covered work
510
- in a country, would infringe one or more identifiable patents in that
511
- country that you have reason to believe are valid.
512
-
513
- If, pursuant to or in connection with a single transaction or
514
- arrangement, you convey, or propagate by procuring conveyance of, a
515
- covered work, and grant a patent license to some of the parties
516
- receiving the covered work authorizing them to use, propagate, modify
517
- or convey a specific copy of the covered work, then the patent license
518
- you grant is automatically extended to all recipients of the covered
519
- work and works based on it.
520
-
521
- A patent license is "discriminatory" if it does not include within
522
- the scope of its coverage, prohibits the exercise of, or is
523
- conditioned on the non-exercise of one or more of the rights that are
524
- specifically granted under this License. You may not convey a covered
525
- work if you are a party to an arrangement with a third party that is
526
- in the business of distributing software, under which you make payment
527
- to the third party based on the extent of your activity of conveying
528
- the work, and under which the third party grants, to any of the
529
- parties who would receive the covered work from you, a discriminatory
530
- patent license (a) in connection with copies of the covered work
531
- conveyed by you (or copies made from those copies), or (b) primarily
532
- for and in connection with specific products or compilations that
533
- contain the covered work, unless you entered into that arrangement,
534
- or that patent license was granted, prior to 28 March 2007.
535
-
536
- Nothing in this License shall be construed as excluding or limiting
537
- any implied license or other defenses to infringement that may
538
- otherwise be available to you under applicable patent law.
539
-
540
- 12. No Surrender of Others' Freedom.
541
-
542
- If conditions are imposed on you (whether by court order, agreement or
543
- otherwise) that contradict the conditions of this License, they do not
544
- excuse you from the conditions of this License. If you cannot convey a
545
- covered work so as to satisfy simultaneously your obligations under this
546
- License and any other pertinent obligations, then as a consequence you may
547
- not convey it at all. For example, if you agree to terms that obligate you
548
- to collect a royalty for further conveying from those to whom you convey
549
- the Program, the only way you could satisfy both those terms and this
550
- License would be to refrain entirely from conveying the Program.
551
-
552
- 13. Use with the GNU Affero General Public License.
553
-
554
- Notwithstanding any other provision of this License, you have
555
- permission to link or combine any covered work with a work licensed
556
- under version 3 of the GNU Affero General Public License into a single
557
- combined work, and to convey the resulting work. The terms of this
558
- License will continue to apply to the part which is the covered work,
559
- but the special requirements of the GNU Affero General Public License,
560
- section 13, concerning interaction through a network will apply to the
561
- combination as such.
562
-
563
- 14. Revised Versions of this License.
564
-
565
- The Free Software Foundation may publish revised and/or new versions of
566
- the GNU General Public License from time to time. Such new versions will
567
- be similar in spirit to the present version, but may differ in detail to
568
- address new problems or concerns.
569
-
570
- Each version is given a distinguishing version number. If the
571
- Program specifies that a certain numbered version of the GNU General
572
- Public License "or any later version" applies to it, you have the
573
- option of following the terms and conditions either of that numbered
574
- version or of any later version published by the Free Software
575
- Foundation. If the Program does not specify a version number of the
576
- GNU General Public License, you may choose any version ever published
577
- by the Free Software Foundation.
578
-
579
- If the Program specifies that a proxy can decide which future
580
- versions of the GNU General Public License can be used, that proxy's
581
- public statement of acceptance of a version permanently authorizes you
582
- to choose that version for the Program.
583
-
584
- Later license versions may give you additional or different
585
- permissions. However, no additional obligations are imposed on any
586
- author or copyright holder as a result of your choosing to follow a
587
- later version.
588
-
589
- 15. Disclaimer of Warranty.
590
-
591
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592
- APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593
- HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594
- OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595
- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596
- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597
- IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598
- ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599
-
600
- 16. Limitation of Liability.
601
-
602
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603
- WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604
- THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605
- GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606
- USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607
- DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608
- PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609
- EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610
- SUCH DAMAGES.
611
-
612
- 17. Interpretation of Sections 15 and 16.
613
-
614
- If the disclaimer of warranty and limitation of liability provided
615
- above cannot be given local legal effect according to their terms,
616
- reviewing courts shall apply local law that most closely approximates
617
- an absolute waiver of all civil liability in connection with the
618
- Program, unless a warranty or assumption of liability accompanies a
619
- copy of the Program in return for a fee.
620
-
621
- END OF TERMS AND CONDITIONS
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 3, 29 June 2007
3
+
4
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
5
+ Everyone is permitted to copy and distribute verbatim copies
6
+ of this license document, but changing it is not allowed.
7
+
8
+ Preamble
9
+
10
+ The GNU General Public License is a free, copyleft license for
11
+ software and other kinds of works.
12
+
13
+ The licenses for most software and other practical works are designed
14
+ to take away your freedom to share and change the works. By contrast,
15
+ the GNU General Public License is intended to guarantee your freedom to
16
+ share and change all versions of a program--to make sure it remains free
17
+ software for all its users. We, the Free Software Foundation, use the
18
+ GNU General Public License for most of our software; it applies also to
19
+ any other work released this way by its authors. You can apply it to
20
+ your programs, too.
21
+
22
+ When we speak of free software, we are referring to freedom, not
23
+ price. Our General Public Licenses are designed to make sure that you
24
+ have the freedom to distribute copies of free software (and charge for
25
+ them if you wish), that you receive source code or can get it if you
26
+ want it, that you can change the software or use pieces of it in new
27
+ free programs, and that you know you can do these things.
28
+
29
+ To protect your rights, we need to prevent others from denying you
30
+ these rights or asking you to surrender the rights. Therefore, you have
31
+ certain responsibilities if you distribute copies of the software, or if
32
+ you modify it: responsibilities to respect the freedom of others.
33
+
34
+ For example, if you distribute copies of such a program, whether
35
+ gratis or for a fee, you must pass on to the recipients the same
36
+ freedoms that you received. You must make sure that they, too, receive
37
+ or can get the source code. And you must show them these terms so they
38
+ know their rights.
39
+
40
+ Developers that use the GNU GPL protect your rights with two steps:
41
+ (1) assert copyright on the software, and (2) offer you this License
42
+ giving you legal permission to copy, distribute and/or modify it.
43
+
44
+ For the developers' and authors' protection, the GPL clearly explains
45
+ that there is no warranty for this free software. For both users' and
46
+ authors' sake, the GPL requires that modified versions be marked as
47
+ changed, so that their problems will not be attributed erroneously to
48
+ authors of previous versions.
49
+
50
+ Some devices are designed to deny users access to install or run
51
+ modified versions of the software inside them, although the manufacturer
52
+ can do so. This is fundamentally incompatible with the aim of
53
+ protecting users' freedom to change the software. The systematic
54
+ pattern of such abuse occurs in the area of products for individuals to
55
+ use, which is precisely where it is most unacceptable. Therefore, we
56
+ have designed this version of the GPL to prohibit the practice for those
57
+ products. If such problems arise substantially in other domains, we
58
+ stand ready to extend this provision to those domains in future versions
59
+ of the GPL, as needed to protect the freedom of users.
60
+
61
+ Finally, every program is threatened constantly by software patents.
62
+ States should not allow patents to restrict development and use of
63
+ software on general-purpose computers, but in those that do, we wish to
64
+ avoid the special danger that patents applied to a free program could
65
+ make it effectively proprietary. To prevent this, the GPL assures that
66
+ patents cannot be used to render the program non-free.
67
+
68
+ The precise terms and conditions for copying, distribution and
69
+ modification follow.
70
+
71
+ TERMS AND CONDITIONS
72
+
73
+ 0. Definitions.
74
+
75
+ "This License" refers to version 3 of the GNU General Public License.
76
+
77
+ "Copyright" also means copyright-like laws that apply to other kinds of
78
+ works, such as semiconductor masks.
79
+
80
+ "The Program" refers to any copyrightable work licensed under this
81
+ License. Each licensee is addressed as "you". "Licensees" and
82
+ "recipients" may be individuals or organizations.
83
+
84
+ To "modify" a work means to copy from or adapt all or part of the work
85
+ in a fashion requiring copyright permission, other than the making of an
86
+ exact copy. The resulting work is called a "modified version" of the
87
+ earlier work or a work "based on" the earlier work.
88
+
89
+ A "covered work" means either the unmodified Program or a work based
90
+ on the Program.
91
+
92
+ To "propagate" a work means to do anything with it that, without
93
+ permission, would make you directly or secondarily liable for
94
+ infringement under applicable copyright law, except executing it on a
95
+ computer or modifying a private copy. Propagation includes copying,
96
+ distribution (with or without modification), making available to the
97
+ public, and in some countries other activities as well.
98
+
99
+ To "convey" a work means any kind of propagation that enables other
100
+ parties to make or receive copies. Mere interaction with a user through
101
+ a computer network, with no transfer of a copy, is not conveying.
102
+
103
+ An interactive user interface displays "Appropriate Legal Notices"
104
+ to the extent that it includes a convenient and prominently visible
105
+ feature that (1) displays an appropriate copyright notice, and (2)
106
+ tells the user that there is no warranty for the work (except to the
107
+ extent that warranties are provided), that licensees may convey the
108
+ work under this License, and how to view a copy of this License. If
109
+ the interface presents a list of user commands or options, such as a
110
+ menu, a prominent item in the list meets this criterion.
111
+
112
+ 1. Source Code.
113
+
114
+ The "source code" for a work means the preferred form of the work
115
+ for making modifications to it. "Object code" means any non-source
116
+ form of a work.
117
+
118
+ A "Standard Interface" means an interface that either is an official
119
+ standard defined by a recognized standards body, or, in the case of
120
+ interfaces specified for a particular programming language, one that
121
+ is widely used among developers working in that language.
122
+
123
+ The "System Libraries" of an executable work include anything, other
124
+ than the work as a whole, that (a) is included in the normal form of
125
+ packaging a Major Component, but which is not part of that Major
126
+ Component, and (b) serves only to enable use of the work with that
127
+ Major Component, or to implement a Standard Interface for which an
128
+ implementation is available to the public in source code form. A
129
+ "Major Component", in this context, means a major essential component
130
+ (kernel, window system, and so on) of the specific operating system
131
+ (if any) on which the executable work runs, or a compiler used to
132
+ produce the work, or an object code interpreter used to run it.
133
+
134
+ The "Corresponding Source" for a work in object code form means all
135
+ the source code needed to generate, install, and (for an executable
136
+ work) run the object code and to modify the work, including scripts to
137
+ control those activities. However, it does not include the work's
138
+ System Libraries, or general-purpose tools or generally available free
139
+ programs which are used unmodified in performing those activities but
140
+ which are not part of the work. For example, Corresponding Source
141
+ includes interface definition files associated with source files for
142
+ the work, and the source code for shared libraries and dynamically
143
+ linked subprograms that the work is specifically designed to require,
144
+ such as by intimate data communication or control flow between those
145
+ subprograms and other parts of the work.
146
+
147
+ The Corresponding Source need not include anything that users
148
+ can regenerate automatically from other parts of the Corresponding
149
+ Source.
150
+
151
+ The Corresponding Source for a work in source code form is that
152
+ same work.
153
+
154
+ 2. Basic Permissions.
155
+
156
+ All rights granted under this License are granted for the term of
157
+ copyright on the Program, and are irrevocable provided the stated
158
+ conditions are met. This License explicitly affirms your unlimited
159
+ permission to run the unmodified Program. The output from running a
160
+ covered work is covered by this License only if the output, given its
161
+ content, constitutes a covered work. This License acknowledges your
162
+ rights of fair use or other equivalent, as provided by copyright law.
163
+
164
+ You may make, run and propagate covered works that you do not
165
+ convey, without conditions so long as your license otherwise remains
166
+ in force. You may convey covered works to others for the sole purpose
167
+ of having them make modifications exclusively for you, or provide you
168
+ with facilities for running those works, provided that you comply with
169
+ the terms of this License in conveying all material for which you do
170
+ not control copyright. Those thus making or running the covered works
171
+ for you must do so exclusively on your behalf, under your direction
172
+ and control, on terms that prohibit them from making any copies of
173
+ your copyrighted material outside their relationship with you.
174
+
175
+ Conveying under any other circumstances is permitted solely under
176
+ the conditions stated below. Sublicensing is not allowed; section 10
177
+ makes it unnecessary.
178
+
179
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180
+
181
+ No covered work shall be deemed part of an effective technological
182
+ measure under any applicable law fulfilling obligations under article
183
+ 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184
+ similar laws prohibiting or restricting circumvention of such
185
+ measures.
186
+
187
+ When you convey a covered work, you waive any legal power to forbid
188
+ circumvention of technological measures to the extent such circumvention
189
+ is effected by exercising rights under this License with respect to
190
+ the covered work, and you disclaim any intention to limit operation or
191
+ modification of the work as a means of enforcing, against the work's
192
+ users, your or third parties' legal rights to forbid circumvention of
193
+ technological measures.
194
+
195
+ 4. Conveying Verbatim Copies.
196
+
197
+ You may convey verbatim copies of the Program's source code as you
198
+ receive it, in any medium, provided that you conspicuously and
199
+ appropriately publish on each copy an appropriate copyright notice;
200
+ keep intact all notices stating that this License and any
201
+ non-permissive terms added in accord with section 7 apply to the code;
202
+ keep intact all notices of the absence of any warranty; and give all
203
+ recipients a copy of this License along with the Program.
204
+
205
+ You may charge any price or no price for each copy that you convey,
206
+ and you may offer support or warranty protection for a fee.
207
+
208
+ 5. Conveying Modified Source Versions.
209
+
210
+ You may convey a work based on the Program, or the modifications to
211
+ produce it from the Program, in the form of source code under the
212
+ terms of section 4, provided that you also meet all of these conditions:
213
+
214
+ a) The work must carry prominent notices stating that you modified
215
+ it, and giving a relevant date.
216
+
217
+ b) The work must carry prominent notices stating that it is
218
+ released under this License and any conditions added under section
219
+ 7. This requirement modifies the requirement in section 4 to
220
+ "keep intact all notices".
221
+
222
+ c) You must license the entire work, as a whole, under this
223
+ License to anyone who comes into possession of a copy. This
224
+ License will therefore apply, along with any applicable section 7
225
+ additional terms, to the whole of the work, and all its parts,
226
+ regardless of how they are packaged. This License gives no
227
+ permission to license the work in any other way, but it does not
228
+ invalidate such permission if you have separately received it.
229
+
230
+ d) If the work has interactive user interfaces, each must display
231
+ Appropriate Legal Notices; however, if the Program has interactive
232
+ interfaces that do not display Appropriate Legal Notices, your
233
+ work need not make them do so.
234
+
235
+ A compilation of a covered work with other separate and independent
236
+ works, which are not by their nature extensions of the covered work,
237
+ and which are not combined with it such as to form a larger program,
238
+ in or on a volume of a storage or distribution medium, is called an
239
+ "aggregate" if the compilation and its resulting copyright are not
240
+ used to limit the access or legal rights of the compilation's users
241
+ beyond what the individual works permit. Inclusion of a covered work
242
+ in an aggregate does not cause this License to apply to the other
243
+ parts of the aggregate.
244
+
245
+ 6. Conveying Non-Source Forms.
246
+
247
+ You may convey a covered work in object code form under the terms
248
+ of sections 4 and 5, provided that you also convey the
249
+ machine-readable Corresponding Source under the terms of this License,
250
+ in one of these ways:
251
+
252
+ a) Convey the object code in, or embodied in, a physical product
253
+ (including a physical distribution medium), accompanied by the
254
+ Corresponding Source fixed on a durable physical medium
255
+ customarily used for software interchange.
256
+
257
+ b) Convey the object code in, or embodied in, a physical product
258
+ (including a physical distribution medium), accompanied by a
259
+ written offer, valid for at least three years and valid for as
260
+ long as you offer spare parts or customer support for that product
261
+ model, to give anyone who possesses the object code either (1) a
262
+ copy of the Corresponding Source for all the software in the
263
+ product that is covered by this License, on a durable physical
264
+ medium customarily used for software interchange, for a price no
265
+ more than your reasonable cost of physically performing this
266
+ conveying of source, or (2) access to copy the
267
+ Corresponding Source from a network server at no charge.
268
+
269
+ c) Convey individual copies of the object code with a copy of the
270
+ written offer to provide the Corresponding Source. This
271
+ alternative is allowed only occasionally and noncommercially, and
272
+ only if you received the object code with such an offer, in accord
273
+ with subsection 6b.
274
+
275
+ d) Convey the object code by offering access from a designated
276
+ place (gratis or for a charge), and offer equivalent access to the
277
+ Corresponding Source in the same way through the same place at no
278
+ further charge. You need not require recipients to copy the
279
+ Corresponding Source along with the object code. If the place to
280
+ copy the object code is a network server, the Corresponding Source
281
+ may be on a different server (operated by you or a third party)
282
+ that supports equivalent copying facilities, provided you maintain
283
+ clear directions next to the object code saying where to find the
284
+ Corresponding Source. Regardless of what server hosts the
285
+ Corresponding Source, you remain obligated to ensure that it is
286
+ available for as long as needed to satisfy these requirements.
287
+
288
+ e) Convey the object code using peer-to-peer transmission, provided
289
+ you inform other peers where the object code and Corresponding
290
+ Source of the work are being offered to the general public at no
291
+ charge under subsection 6d.
292
+
293
+ A separable portion of the object code, whose source code is excluded
294
+ from the Corresponding Source as a System Library, need not be
295
+ included in conveying the object code work.
296
+
297
+ A "User Product" is either (1) a "consumer product", which means any
298
+ tangible personal property which is normally used for personal, family,
299
+ or household purposes, or (2) anything designed or sold for incorporation
300
+ into a dwelling. In determining whether a product is a consumer product,
301
+ doubtful cases shall be resolved in favor of coverage. For a particular
302
+ product received by a particular user, "normally used" refers to a
303
+ typical or common use of that class of product, regardless of the status
304
+ of the particular user or of the way in which the particular user
305
+ actually uses, or expects or is expected to use, the product. A product
306
+ is a consumer product regardless of whether the product has substantial
307
+ commercial, industrial or non-consumer uses, unless such uses represent
308
+ the only significant mode of use of the product.
309
+
310
+ "Installation Information" for a User Product means any methods,
311
+ procedures, authorization keys, or other information required to install
312
+ and execute modified versions of a covered work in that User Product from
313
+ a modified version of its Corresponding Source. The information must
314
+ suffice to ensure that the continued functioning of the modified object
315
+ code is in no case prevented or interfered with solely because
316
+ modification has been made.
317
+
318
+ If you convey an object code work under this section in, or with, or
319
+ specifically for use in, a User Product, and the conveying occurs as
320
+ part of a transaction in which the right of possession and use of the
321
+ User Product is transferred to the recipient in perpetuity or for a
322
+ fixed term (regardless of how the transaction is characterized), the
323
+ Corresponding Source conveyed under this section must be accompanied
324
+ by the Installation Information. But this requirement does not apply
325
+ if neither you nor any third party retains the ability to install
326
+ modified object code on the User Product (for example, the work has
327
+ been installed in ROM).
328
+
329
+ The requirement to provide Installation Information does not include a
330
+ requirement to continue to provide support service, warranty, or updates
331
+ for a work that has been modified or installed by the recipient, or for
332
+ the User Product in which it has been modified or installed. Access to a
333
+ network may be denied when the modification itself materially and
334
+ adversely affects the operation of the network or violates the rules and
335
+ protocols for communication across the network.
336
+
337
+ Corresponding Source conveyed, and Installation Information provided,
338
+ in accord with this section must be in a format that is publicly
339
+ documented (and with an implementation available to the public in
340
+ source code form), and must require no special password or key for
341
+ unpacking, reading or copying.
342
+
343
+ 7. Additional Terms.
344
+
345
+ "Additional permissions" are terms that supplement the terms of this
346
+ License by making exceptions from one or more of its conditions.
347
+ Additional permissions that are applicable to the entire Program shall
348
+ be treated as though they were included in this License, to the extent
349
+ that they are valid under applicable law. If additional permissions
350
+ apply only to part of the Program, that part may be used separately
351
+ under those permissions, but the entire Program remains governed by
352
+ this License without regard to the additional permissions.
353
+
354
+ When you convey a copy of a covered work, you may at your option
355
+ remove any additional permissions from that copy, or from any part of
356
+ it. (Additional permissions may be written to require their own
357
+ removal in certain cases when you modify the work.) You may place
358
+ additional permissions on material, added by you to a covered work,
359
+ for which you have or can give appropriate copyright permission.
360
+
361
+ Notwithstanding any other provision of this License, for material you
362
+ add to a covered work, you may (if authorized by the copyright holders of
363
+ that material) supplement the terms of this License with terms:
364
+
365
+ a) Disclaiming warranty or limiting liability differently from the
366
+ terms of sections 15 and 16 of this License; or
367
+
368
+ b) Requiring preservation of specified reasonable legal notices or
369
+ author attributions in that material or in the Appropriate Legal
370
+ Notices displayed by works containing it; or
371
+
372
+ c) Prohibiting misrepresentation of the origin of that material, or
373
+ requiring that modified versions of such material be marked in
374
+ reasonable ways as different from the original version; or
375
+
376
+ d) Limiting the use for publicity purposes of names of licensors or
377
+ authors of the material; or
378
+
379
+ e) Declining to grant rights under trademark law for use of some
380
+ trade names, trademarks, or service marks; or
381
+
382
+ f) Requiring indemnification of licensors and authors of that
383
+ material by anyone who conveys the material (or modified versions of
384
+ it) with contractual assumptions of liability to the recipient, for
385
+ any liability that these contractual assumptions directly impose on
386
+ those licensors and authors.
387
+
388
+ All other non-permissive additional terms are considered "further
389
+ restrictions" within the meaning of section 10. If the Program as you
390
+ received it, or any part of it, contains a notice stating that it is
391
+ governed by this License along with a term that is a further
392
+ restriction, you may remove that term. If a license document contains
393
+ a further restriction but permits relicensing or conveying under this
394
+ License, you may add to a covered work material governed by the terms
395
+ of that license document, provided that the further restriction does
396
+ not survive such relicensing or conveying.
397
+
398
+ If you add terms to a covered work in accord with this section, you
399
+ must place, in the relevant source files, a statement of the
400
+ additional terms that apply to those files, or a notice indicating
401
+ where to find the applicable terms.
402
+
403
+ Additional terms, permissive or non-permissive, may be stated in the
404
+ form of a separately written license, or stated as exceptions;
405
+ the above requirements apply either way.
406
+
407
+ 8. Termination.
408
+
409
+ You may not propagate or modify a covered work except as expressly
410
+ provided under this License. Any attempt otherwise to propagate or
411
+ modify it is void, and will automatically terminate your rights under
412
+ this License (including any patent licenses granted under the third
413
+ paragraph of section 11).
414
+
415
+ However, if you cease all violation of this License, then your
416
+ license from a particular copyright holder is reinstated (a)
417
+ provisionally, unless and until the copyright holder explicitly and
418
+ finally terminates your license, and (b) permanently, if the copyright
419
+ holder fails to notify you of the violation by some reasonable means
420
+ prior to 60 days after the cessation.
421
+
422
+ Moreover, your license from a particular copyright holder is
423
+ reinstated permanently if the copyright holder notifies you of the
424
+ violation by some reasonable means, this is the first time you have
425
+ received notice of violation of this License (for any work) from that
426
+ copyright holder, and you cure the violation prior to 30 days after
427
+ your receipt of the notice.
428
+
429
+ Termination of your rights under this section does not terminate the
430
+ licenses of parties who have received copies or rights from you under
431
+ this License. If your rights have been terminated and not permanently
432
+ reinstated, you do not qualify to receive new licenses for the same
433
+ material under section 10.
434
+
435
+ 9. Acceptance Not Required for Having Copies.
436
+
437
+ You are not required to accept this License in order to receive or
438
+ run a copy of the Program. Ancillary propagation of a covered work
439
+ occurring solely as a consequence of using peer-to-peer transmission
440
+ to receive a copy likewise does not require acceptance. However,
441
+ nothing other than this License grants you permission to propagate or
442
+ modify any covered work. These actions infringe copyright if you do
443
+ not accept this License. Therefore, by modifying or propagating a
444
+ covered work, you indicate your acceptance of this License to do so.
445
+
446
+ 10. Automatic Licensing of Downstream Recipients.
447
+
448
+ Each time you convey a covered work, the recipient automatically
449
+ receives a license from the original licensors, to run, modify and
450
+ propagate that work, subject to this License. You are not responsible
451
+ for enforcing compliance by third parties with this License.
452
+
453
+ An "entity transaction" is a transaction transferring control of an
454
+ organization, or substantially all assets of one, or subdividing an
455
+ organization, or merging organizations. If propagation of a covered
456
+ work results from an entity transaction, each party to that
457
+ transaction who receives a copy of the work also receives whatever
458
+ licenses to the work the party's predecessor in interest had or could
459
+ give under the previous paragraph, plus a right to possession of the
460
+ Corresponding Source of the work from the predecessor in interest, if
461
+ the predecessor has it or can get it with reasonable efforts.
462
+
463
+ You may not impose any further restrictions on the exercise of the
464
+ rights granted or affirmed under this License. For example, you may
465
+ not impose a license fee, royalty, or other charge for exercise of
466
+ rights granted under this License, and you may not initiate litigation
467
+ (including a cross-claim or counterclaim in a lawsuit) alleging that
468
+ any patent claim is infringed by making, using, selling, offering for
469
+ sale, or importing the Program or any portion of it.
470
+
471
+ 11. Patents.
472
+
473
+ A "contributor" is a copyright holder who authorizes use under this
474
+ License of the Program or a work on which the Program is based. The
475
+ work thus licensed is called the contributor's "contributor version".
476
+
477
+ A contributor's "essential patent claims" are all patent claims
478
+ owned or controlled by the contributor, whether already acquired or
479
+ hereafter acquired, that would be infringed by some manner, permitted
480
+ by this License, of making, using, or selling its contributor version,
481
+ but do not include claims that would be infringed only as a
482
+ consequence of further modification of the contributor version. For
483
+ purposes of this definition, "control" includes the right to grant
484
+ patent sublicenses in a manner consistent with the requirements of
485
+ this License.
486
+
487
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
488
+ patent license under the contributor's essential patent claims, to
489
+ make, use, sell, offer for sale, import and otherwise run, modify and
490
+ propagate the contents of its contributor version.
491
+
492
+ In the following three paragraphs, a "patent license" is any express
493
+ agreement or commitment, however denominated, not to enforce a patent
494
+ (such as an express permission to practice a patent or covenant not to
495
+ sue for patent infringement). To "grant" such a patent license to a
496
+ party means to make such an agreement or commitment not to enforce a
497
+ patent against the party.
498
+
499
+ If you convey a covered work, knowingly relying on a patent license,
500
+ and the Corresponding Source of the work is not available for anyone
501
+ to copy, free of charge and under the terms of this License, through a
502
+ publicly available network server or other readily accessible means,
503
+ then you must either (1) cause the Corresponding Source to be so
504
+ available, or (2) arrange to deprive yourself of the benefit of the
505
+ patent license for this particular work, or (3) arrange, in a manner
506
+ consistent with the requirements of this License, to extend the patent
507
+ license to downstream recipients. "Knowingly relying" means you have
508
+ actual knowledge that, but for the patent license, your conveying the
509
+ covered work in a country, or your recipient's use of the covered work
510
+ in a country, would infringe one or more identifiable patents in that
511
+ country that you have reason to believe are valid.
512
+
513
+ If, pursuant to or in connection with a single transaction or
514
+ arrangement, you convey, or propagate by procuring conveyance of, a
515
+ covered work, and grant a patent license to some of the parties
516
+ receiving the covered work authorizing them to use, propagate, modify
517
+ or convey a specific copy of the covered work, then the patent license
518
+ you grant is automatically extended to all recipients of the covered
519
+ work and works based on it.
520
+
521
+ A patent license is "discriminatory" if it does not include within
522
+ the scope of its coverage, prohibits the exercise of, or is
523
+ conditioned on the non-exercise of one or more of the rights that are
524
+ specifically granted under this License. You may not convey a covered
525
+ work if you are a party to an arrangement with a third party that is
526
+ in the business of distributing software, under which you make payment
527
+ to the third party based on the extent of your activity of conveying
528
+ the work, and under which the third party grants, to any of the
529
+ parties who would receive the covered work from you, a discriminatory
530
+ patent license (a) in connection with copies of the covered work
531
+ conveyed by you (or copies made from those copies), or (b) primarily
532
+ for and in connection with specific products or compilations that
533
+ contain the covered work, unless you entered into that arrangement,
534
+ or that patent license was granted, prior to 28 March 2007.
535
+
536
+ Nothing in this License shall be construed as excluding or limiting
537
+ any implied license or other defenses to infringement that may
538
+ otherwise be available to you under applicable patent law.
539
+
540
+ 12. No Surrender of Others' Freedom.
541
+
542
+ If conditions are imposed on you (whether by court order, agreement or
543
+ otherwise) that contradict the conditions of this License, they do not
544
+ excuse you from the conditions of this License. If you cannot convey a
545
+ covered work so as to satisfy simultaneously your obligations under this
546
+ License and any other pertinent obligations, then as a consequence you may
547
+ not convey it at all. For example, if you agree to terms that obligate you
548
+ to collect a royalty for further conveying from those to whom you convey
549
+ the Program, the only way you could satisfy both those terms and this
550
+ License would be to refrain entirely from conveying the Program.
551
+
552
+ 13. Use with the GNU Affero General Public License.
553
+
554
+ Notwithstanding any other provision of this License, you have
555
+ permission to link or combine any covered work with a work licensed
556
+ under version 3 of the GNU Affero General Public License into a single
557
+ combined work, and to convey the resulting work. The terms of this
558
+ License will continue to apply to the part which is the covered work,
559
+ but the special requirements of the GNU Affero General Public License,
560
+ section 13, concerning interaction through a network will apply to the
561
+ combination as such.
562
+
563
+ 14. Revised Versions of this License.
564
+
565
+ The Free Software Foundation may publish revised and/or new versions of
566
+ the GNU General Public License from time to time. Such new versions will
567
+ be similar in spirit to the present version, but may differ in detail to
568
+ address new problems or concerns.
569
+
570
+ Each version is given a distinguishing version number. If the
571
+ Program specifies that a certain numbered version of the GNU General
572
+ Public License "or any later version" applies to it, you have the
573
+ option of following the terms and conditions either of that numbered
574
+ version or of any later version published by the Free Software
575
+ Foundation. If the Program does not specify a version number of the
576
+ GNU General Public License, you may choose any version ever published
577
+ by the Free Software Foundation.
578
+
579
+ If the Program specifies that a proxy can decide which future
580
+ versions of the GNU General Public License can be used, that proxy's
581
+ public statement of acceptance of a version permanently authorizes you
582
+ to choose that version for the Program.
583
+
584
+ Later license versions may give you additional or different
585
+ permissions. However, no additional obligations are imposed on any
586
+ author or copyright holder as a result of your choosing to follow a
587
+ later version.
588
+
589
+ 15. Disclaimer of Warranty.
590
+
591
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592
+ APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593
+ HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594
+ OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596
+ PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597
+ IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598
+ ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599
+
600
+ 16. Limitation of Liability.
601
+
602
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604
+ THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605
+ GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606
+ USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607
+ DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608
+ PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609
+ EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610
+ SUCH DAMAGES.
611
+
612
+ 17. Interpretation of Sections 15 and 16.
613
+
614
+ If the disclaimer of warranty and limitation of liability provided
615
+ above cannot be given local legal effect according to their terms,
616
+ reviewing courts shall apply local law that most closely approximates
617
+ an absolute waiver of all civil liability in connection with the
618
+ Program, unless a warranty or assumption of liability accompanies a
619
+ copy of the Program in return for a fee.
620
+
621
+ END OF TERMS AND CONDITIONS
public/frontend.php CHANGED
@@ -1,904 +1,915 @@
1
- <?php
2
- define( 'GTM4WP_WPFILTER_COMPILE_DATALAYER', 'gtm4wp_compile_datalayer' );
3
- define( 'GTM4WP_WPFILTER_COMPILE_REMARKTING', 'gtm4wp_compile_remarkering' );
4
- define( 'GTM4WP_WPFILTER_AFTER_DATALAYER', 'gtm4wp_after_datalayer' );
5
- define( 'GTM4WP_WPFILTER_GETTHEGTMTAG', 'gtm4wp_get_the_gtm_tag' );
6
- define( 'GTM4WP_WPACTION_ADDGLOBALVARS', 'gtm4wp_add_global_vars' );
7
-
8
- $GLOBALS['gtm4wp_container_code_written'] = false;
9
-
10
- // check for empty is needed to prevent error in WP CLI
11
- // bugfix by Patrick Holberg Hesselberg
12
- if ( empty( $GLOBALS['gtm4wp_options'] ) || ( $GLOBALS['gtm4wp_options'][ GTM4WP_OPTION_DATALAYER_NAME ] == '' ) ) {
13
- $GLOBALS['gtm4wp_datalayer_name'] = 'dataLayer';
14
- } else {
15
- $GLOBALS['gtm4wp_datalayer_name'] = $GLOBALS['gtm4wp_options'][ GTM4WP_OPTION_DATALAYER_NAME ];
16
- }
17
-
18
- // Setting Global Variable to Store JSON based Datalayer for Intergrations
19
- $GLOBALS['gtm4wp_datalayer_json'] = '';
20
- $GLOBALS['gtm4wp_datalayer_globalvars'] = '';
21
-
22
- // Moving include to top due to hierarchy of includes
23
- if ( isset( $GLOBALS['gtm4wp_options'] ) && ( '' != $GLOBALS['gtm4wp_options'][ GTM4WP_OPTION_INTEGRATE_AMPID ] ) ) {
24
- require_once dirname( __FILE__ ) . '/../integration/amp.php';
25
- }
26
- if ( ! function_exists( 'gtm4wp_amp_running' ) ) {
27
- function gtm4wp_amp_running() {
28
- return false;
29
- }
30
- }
31
-
32
- /**
33
- * Converts bool false to string false for JS
34
- *
35
- * @author Vincent Koc <https://github.com/koconder/>
36
- * @return mixed Returs object or string false
37
- */
38
- function gtm4wp_escjs_boolean( $obj ) {
39
- if ( empty( $obj ) || is_null( $obj ) || ! $obj ) {
40
- return 'false';
41
- } else {
42
- return $obj;
43
- }
44
- }
45
-
46
- /**
47
- * Original copyright:
48
- * By Grant Burton @ BURTONTECH.COM
49
- *
50
- * Code improved by Thomas Geiger
51
- */
52
- function gtm4wp_get_user_ip() {
53
- if ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
54
- foreach ( explode( ',', $_SERVER['HTTP_X_FORWARDED_FOR'] ) as $ip ) {
55
- if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) !== false ) {
56
- return $ip;
57
- }
58
- }
59
- }
60
-
61
- $possible_ip_variables = array(
62
- 'HTTP_CLIENT_IP',
63
- 'HTTP_X_FORWARDED',
64
- 'HTTP_X_CLUSTER_CLIENT_IP',
65
- 'HTTP_FORWARDED_FOR',
66
- 'HTTP_FORWARDED',
67
- 'REMOTE_ADDR'
68
- );
69
-
70
- foreach( $possible_ip_variables as $one_ip_variable ) {
71
- if (
72
- ! empty( $_SERVER[ $one_ip_variable ] )
73
- && ( filter_var( $_SERVER[ $one_ip_variable ], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) !== false )
74
- ) {
75
- return $_SERVER[ $one_ip_variable ];
76
- }
77
- }
78
-
79
- return '';
80
- }
81
-
82
- if ( ! function_exists( 'getallheaders' ) ) {
83
- function getallheaders() {
84
- $headers = array();
85
- foreach ( $_SERVER as $name => $value ) {
86
- if ( substr( $name, 0, 5 ) == 'HTTP_' ) {
87
- $headers[ str_replace( ' ', '-', ucwords( strtolower( str_replace( '_', ' ', substr( $name, 5 ) ) ) ) ) ] = $value;
88
- }
89
- }
90
-
91
- return $headers;
92
- }
93
- }
94
-
95
- function gtm4wp_add_basic_datalayer_data( $dataLayer ) {
96
- global $wp_query, $gtm4wp_options, $gtm4wp_entity_ids;
97
-
98
- if ( $gtm4wp_options[ GTM4WP_OPTION_DONOTTRACK ] ) {
99
- if ( ! empty( $_SERVER['HTTP_DNT'] ) ) {
100
- $dataLayer['visitorDoNotTrack'] = (int) ( $_SERVER['HTTP_DNT'] );
101
- } else {
102
- $dataLayer['visitorDoNotTrack'] = 0;
103
- }
104
- }
105
-
106
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_SITEID ] || $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_SITENAME ] ) {
107
- $dataLayer['siteID'] = 0;
108
- $dataLayer['siteName'] = '';
109
-
110
- if ( function_exists( 'get_blog_details' ) ) {
111
- $gtm4wp_blogdetails = get_blog_details();
112
-
113
- $dataLayer['siteID'] = $gtm4wp_blogdetails->blog_id;
114
- $dataLayer['siteName'] = $gtm4wp_blogdetails->blogname;
115
- }
116
- }
117
-
118
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_LOGGEDIN ] ) {
119
- if ( is_user_logged_in() ) {
120
- $dataLayer['visitorLoginState'] = 'logged-in';
121
- } else {
122
- $dataLayer['visitorLoginState'] = 'logged-out';
123
- }
124
- }
125
-
126
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_USERROLE ] || $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_USEREMAIL ] || $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_USERREGDATE ] ) {
127
- $current_user = wp_get_current_user();
128
-
129
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_USERROLE ] ) {
130
- $dataLayer['visitorType'] = ( empty( $current_user->roles[0] ) ? 'visitor-logged-out' : $current_user->roles[0] );
131
- }
132
-
133
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_USEREMAIL ] ) {
134
- $dataLayer['visitorEmail'] = ( empty( $current_user->user_email ) ? '' : $current_user->user_email );
135
- }
136
-
137
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_USERREGDATE ] ) {
138
- $dataLayer['visitorRegistrationDate'] = ( empty( $current_user->user_registered ) ? '' : strtotime( $current_user->user_registered ) );
139
- }
140
-
141
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_USERNAME ] ) {
142
- $dataLayer['visitorUsername'] = ( empty( $current_user->user_login ) ? '' : $current_user->user_login );
143
- }
144
- }
145
-
146
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_USERID ] ) {
147
- $_gtm4wp_userid = get_current_user_id();
148
- if ( $_gtm4wp_userid > 0 ) {
149
- $dataLayer['visitorId'] = $_gtm4wp_userid;
150
- }
151
- }
152
-
153
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_VISITOR_IP ] ) {
154
- $dataLayer['visitorIP'] = esc_js( gtm4wp_get_user_ip() );
155
- }
156
-
157
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTTITLE ] ) {
158
- $dataLayer['pageTitle'] = strip_tags( wp_title( '|', false, 'right' ) );
159
- }
160
-
161
- if ( is_singular() ) {
162
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTTYPE ] ) {
163
- $dataLayer['pagePostType'] = get_post_type();
164
- $dataLayer['pagePostType2'] = 'single-' . get_post_type();
165
- }
166
-
167
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_CATEGORIES ] ) {
168
- $_post_cats = get_the_category();
169
- if ( $_post_cats ) {
170
- $dataLayer['pageCategory'] = array();
171
- foreach ( $_post_cats as $_one_cat ) {
172
- $dataLayer['pageCategory'][] = $_one_cat->slug;
173
- }
174
- }
175
- }
176
-
177
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_TAGS ] ) {
178
- $_post_tags = get_the_tags();
179
- if ( $_post_tags ) {
180
- $dataLayer['pageAttributes'] = array();
181
- foreach ( $_post_tags as $_one_tag ) {
182
- $dataLayer['pageAttributes'][] = $_one_tag->slug;
183
- }
184
- }
185
- }
186
-
187
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_AUTHORID ] || $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_AUTHOR ] ) {
188
- $postuser = get_userdata( $GLOBALS['post']->post_author );
189
-
190
- if ( false !== $postuser ) {
191
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_AUTHORID ] ) {
192
- $dataLayer['pagePostAuthorID'] = $postuser->ID;
193
- }
194
-
195
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_AUTHOR ] ) {
196
- $dataLayer['pagePostAuthor'] = $postuser->display_name;
197
- }
198
- }
199
- }
200
-
201
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTDATE ] ) {
202
- $dataLayer['pagePostDate'] = get_the_date();
203
- $dataLayer['pagePostDateYear'] = get_the_date( 'Y' );
204
- $dataLayer['pagePostDateMonth'] = get_the_date( 'm' );
205
- $dataLayer['pagePostDateDay'] = get_the_date( 'd' );
206
- }
207
-
208
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTTERMLIST ] ) {
209
- $dataLayer["pagePostTerms"] = array();
210
- $object_taxonomies = get_object_taxonomies( get_post_type() );
211
- foreach( $object_taxonomies as $one_object_taxonomy ) {
212
- $post_taxonomy_values = get_the_terms( $GLOBALS[ "post" ]->ID, $one_object_taxonomy );
213
- if ( is_array( $post_taxonomy_values ) ) {
214
- $dataLayer["pagePostTerms"][$one_object_taxonomy] = array();
215
- foreach( $post_taxonomy_values as $one_taxonomy_value ) {
216
- $dataLayer["pagePostTerms"][$one_object_taxonomy][] = $one_taxonomy_value->name;
217
- }
218
- }
219
- }
220
- }
221
- }
222
-
223
- if ( is_archive() || is_post_type_archive() ) {
224
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTTYPE ] ) {
225
- $dataLayer['pagePostType'] = get_post_type();
226
-
227
- if ( is_category() ) {
228
- $dataLayer['pagePostType2'] = 'category-' . get_post_type();
229
- } elseif ( is_tag() ) {
230
- $dataLayer['pagePostType2'] = 'tag-' . get_post_type();
231
- } elseif ( is_tax() ) {
232
- $dataLayer['pagePostType2'] = 'tax-' . get_post_type();
233
- } elseif ( is_author() ) {
234
- $dataLayer['pagePostType2'] = 'author-' . get_post_type();
235
- } elseif ( is_year() ) {
236
- $dataLayer['pagePostType2'] = 'year-' . get_post_type();
237
-
238
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTDATE ] ) {
239
- $dataLayer['pagePostDateYear'] = get_the_date( 'Y' );
240
- }
241
- } elseif ( is_month() ) {
242
- $dataLayer['pagePostType2'] = 'month-' . get_post_type();
243
-
244
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTDATE ] ) {
245
- $dataLayer['pagePostDateYear'] = get_the_date( 'Y' );
246
- $dataLayer['pagePostDateMonth'] = get_the_date( 'm' );
247
- }
248
- } elseif ( is_day() ) {
249
- $dataLayer['pagePostType2'] = 'day-' . get_post_type();
250
-
251
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTDATE ] ) {
252
- $dataLayer['pagePostDate'] = get_the_date();
253
- $dataLayer['pagePostDateYear'] = get_the_date( 'Y' );
254
- $dataLayer['pagePostDateMonth'] = get_the_date( 'm' );
255
- $dataLayer['pagePostDateDay'] = get_the_date( 'd' );
256
- }
257
- } elseif ( is_time() ) {
258
- $dataLayer['pagePostType2'] = 'time-' . get_post_type();
259
- } elseif ( is_date() ) {
260
- $dataLayer['pagePostType2'] = 'date-' . get_post_type();
261
-
262
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTDATE ] ) {
263
- $dataLayer['pagePostDate'] = get_the_date();
264
- $dataLayer['pagePostDateYear'] = get_the_date( 'Y' );
265
- $dataLayer['pagePostDateMonth'] = get_the_date( 'm' );
266
- $dataLayer['pagePostDateDay'] = get_the_date( 'd' );
267
- }
268
- }
269
- }
270
-
271
- if ( ( is_tax() || is_category() ) && $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_CATEGORIES ] ) {
272
- $_post_cats = get_the_category();
273
- $dataLayer['pageCategory'] = array();
274
- foreach ( $_post_cats as $_one_cat ) {
275
- $dataLayer['pageCategory'][] = $_one_cat->slug;
276
- }
277
- }
278
-
279
- if ( ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_AUTHORID ] ) && ( is_author() ) ) {
280
- global $authordata;
281
- $dataLayer['pagePostAuthorID'] = isset( $authordata->ID ) ? $authordata->ID : 0;
282
- }
283
-
284
- if ( ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_AUTHOR ] ) && ( is_author() ) ) {
285
- $dataLayer['pagePostAuthor'] = get_the_author();
286
- }
287
- }
288
-
289
- if ( is_search() ) {
290
- $dataLayer['siteSearchTerm'] = get_search_query();
291
- $dataLayer['siteSearchFrom'] = '';
292
- if ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
293
- $referer_url_parts = explode( '?', $_SERVER['HTTP_REFERER'] );
294
- if ( count( $referer_url_parts ) > 1 ) {
295
- $dataLayer['siteSearchFrom'] = $referer_url_parts[0] . '?' . rawurlencode( $referer_url_parts[1] );
296
- } else {
297
- $dataLayer['siteSearchFrom'] = $referer_url_parts[0];
298
- }
299
- }
300
- $dataLayer['siteSearchResults'] = $wp_query->post_count;
301
- }
302
-
303
- if ( is_front_page() && $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTTYPE ] ) {
304
- $dataLayer['pagePostType'] = 'frontpage';
305
- }
306
-
307
- if ( ! is_front_page() && is_home() && $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTTYPE ] ) {
308
- $dataLayer['pagePostType'] = 'bloghome';
309
- }
310
-
311
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_BROWSERDATA ] || $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_OSDATA ] || $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_DEVICEDATA ] ) {
312
- spl_autoload_register(
313
- function( $class ) {
314
- $class_parts = explode( '\\', $class );
315
- if ( 'WhichBrowser' == $class_parts[0] ) {
316
- include dirname( __FILE__ ) . '/../integration/whichbrowser/' . str_replace( array( 'WhichBrowser', '\\' ), array( 'src', '/' ), $class ) . '.php';
317
- }
318
- }
319
- );
320
-
321
- require_once dirname( __FILE__ ) . '/../integration/whichbrowser/src/Parser.php';
322
-
323
- $gtp4wp_headers = getallheaders();
324
- if ( ( false === $gtp4wp_headers ) && isset( $_SERVER['HTTP_USER_AGENT'] ) ) {
325
- $gtp4wp_headers = $_SERVER['HTTP_USER_AGENT'];
326
- }
327
- if ( false !== $gtp4wp_headers ) {
328
- $detected = new WhichBrowser\Parser( $gtp4wp_headers );
329
-
330
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_BROWSERDATA ] ) {
331
- $dataLayer['browserName'] = isset( $detected->browser->name ) ? $detected->browser->name : '';
332
- $dataLayer['browserVersion'] = isset( $detected->browser->version->value ) ? $detected->browser->version->value : '';
333
-
334
- $dataLayer['browserEngineName'] = isset( $detected->engine->name ) ? $detected->engine->name : '';
335
- $dataLayer['browserEngineVersion'] = isset( $detected->engine->version->value ) ? $detected->engine->version->value : '';
336
- }
337
-
338
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_OSDATA ] ) {
339
- $dataLayer['osName'] = isset( $detected->os->name ) ? $detected->os->name : '';
340
- $dataLayer['osVersion'] = isset( $detected->os->version->value ) ? $detected->os->version->value : '';
341
- }
342
-
343
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_DEVICEDATA ] ) {
344
- $dataLayer['deviceType'] = isset( $detected->device->type ) ? $detected->device->type : '';
345
- $dataLayer['deviceManufacturer'] = isset( $detected->device->manufacturer ) ? $detected->device->manufacturer : '';
346
- $dataLayer['deviceModel'] = isset( $detected->device->model ) ? $detected->device->model : '';
347
- }
348
- }
349
- }
350
-
351
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTCOUNT ] ) {
352
- $dataLayer['postCountOnPage'] = (int) $wp_query->post_count;
353
- $dataLayer['postCountTotal'] = (int) $wp_query->found_posts;
354
- }
355
-
356
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTID ] && is_singular() === true ) {
357
- $dataLayer['postID'] = (int) get_the_ID();
358
- }
359
-
360
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTFORMAT ] && is_singular() === true ) {
361
- $dataLayer['postFormat'] = get_post_format() ?: 'standard';
362
- }
363
-
364
- if ( $gtm4wp_options[ GTM4WP_OPTION_BLACKLIST_ENABLE ] > 0 ) {
365
- $_gtmrestrictlistitems = array();
366
-
367
- // because of security reasons, we loop through each stored entity in the options and validate them
368
- // to make sure nobody has entered some 'funny' item manually
369
- $valid_entity_ids = array_merge(
370
- array_keys( $gtm4wp_entity_ids[ 'tags' ] ),
371
- array_keys( $gtm4wp_entity_ids[ 'triggers' ] ),
372
- array_keys( $gtm4wp_entity_ids[ 'variables' ] )
373
- );
374
- foreach( $gtm4wp_options[ GTM4WP_OPTION_BLACKLIST_STATUS ] as $listed_entity ) {
375
- if ( in_array( $listed_entity, $valid_entity_ids ) ) {
376
- $_gtmrestrictlistitems[] = $listed_entity;
377
- }
378
- }
379
-
380
- $_gtmwhitelist = array();
381
- $_gtmblacklist = array();
382
- if ( $gtm4wp_options[ GTM4WP_OPTION_BLACKLIST_ENABLE ] == 1 ) {
383
- $_gtmblacklist = array_merge( $_gtmblacklist, $_gtmrestrictlistitems );
384
- } else {
385
- $_gtmwhitelist = array_merge( $_gtmwhitelist, $_gtmrestrictlistitems );
386
- }
387
-
388
- $dataLayer['gtm.whitelist'] = $_gtmwhitelist;
389
- $dataLayer['gtm.blacklist'] = $_gtmblacklist;
390
- }
391
-
392
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_MISCGEOCF ] && isset( $_SERVER['HTTP_CF_IPCOUNTRY'] ) ) {
393
- $dataLayer['geoCloudflareCountryCode'] = $_SERVER['HTTP_CF_IPCOUNTRY'];
394
- }
395
-
396
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_WEATHER ] || $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_MISCGEO ] ) {
397
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_WEATHER ] ) {
398
- $dataLayer['weatherCategory'] = __( '(no weather data available)', 'duracelltomi-google-tag-manager' );
399
- $dataLayer['weatherDescription'] = __( '(no weather data available)', 'duracelltomi-google-tag-manager' );
400
- $dataLayer['weatherTemp'] = 0;
401
- $dataLayer['weatherPressure'] = 0;
402
- $dataLayer['weatherWindSpeed'] = 0;
403
- $dataLayer['weatherWindDeg'] = 0;
404
- $dataLayer['weatherDataStatus'] = 'Initialized with empty data';
405
- }
406
-
407
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_MISCGEO ] ) {
408
- $dataLayer['geoCountryCode'] = __( '(no geo data available)', 'duracelltomi-google-tag-manager' );
409
- $dataLayer['geoCountryName'] = __( '(no geo data available)', 'duracelltomi-google-tag-manager' );
410
- $dataLayer['geoRegionCode'] = __( '(no geo data available)', 'duracelltomi-google-tag-manager' );
411
- $dataLayer['geoRegionName'] = __( '(no geo data available)', 'duracelltomi-google-tag-manager' );
412
- $dataLayer['geoCity'] = __( '(no geo data available)', 'duracelltomi-google-tag-manager' );
413
- $dataLayer['geoZipcode'] = __( '(no geo data available)', 'duracelltomi-google-tag-manager' );
414
- $dataLayer['geoLatitude'] = __( '(no geo data available)', 'duracelltomi-google-tag-manager' );
415
- $dataLayer['geoLongitude'] = __( '(no geo data available)', 'duracelltomi-google-tag-manager' );
416
- }
417
-
418
- $client_ip = gtm4wp_get_user_ip();
419
-
420
- if ( '' !== $client_ip ) {
421
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_WEATHER ] ) {
422
- $weatherdata = get_transient( 'gtm4wp-weatherdata-' . esc_attr( $client_ip ) );
423
-
424
- if ( false !== $weatherdata ) {
425
- $dataLayer['weatherCategory'] = $weatherdata->weather[0]->main;
426
- $dataLayer['weatherDescription'] = $weatherdata->weather[0]->description;
427
- $dataLayer['weatherTemp'] = $weatherdata->main->temp;
428
- $dataLayer['weatherPressure'] = $weatherdata->main->pressure;
429
- $dataLayer['weatherWindSpeed'] = $weatherdata->wind->speed;
430
- $dataLayer['weatherWindDeg'] = ( isset($weatherdata->wind->deg) ? $weatherdata->wind->deg : '' );
431
- $dataLayer['weatherFullWeatherData'] = $weatherdata;
432
- $dataLayer['weatherDataStatus'] = 'Read from cache';
433
- } else {
434
- $dataLayer['weatherDataStatus'] = 'No weather data in cache (' . esc_attr( $client_ip ) . ')';
435
- }
436
- }
437
-
438
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_MISCGEO ] ) {
439
- $geodata = get_transient( 'gtm4wp-geodata-' . esc_attr( $client_ip ) );
440
-
441
- if ( false !== $geodata ) {
442
- $dataLayer['geoFullGeoData'] = $geodata;
443
-
444
- if ( isset( $geodata->latitude ) ) {
445
- $dataLayer['geoCountryCode'] = $geodata->country_code;
446
- $dataLayer['geoCountryName'] = $geodata->country_name;
447
- $dataLayer['geoRegionCode'] = $geodata->region_code;
448
- $dataLayer['geoRegionName'] = $geodata->region_name;
449
- $dataLayer['geoCity'] = $geodata->city;
450
- $dataLayer['geoZipcode'] = $geodata->zip;
451
- $dataLayer['geoLatitude'] = $geodata->latitude;
452
- $dataLayer['geoLongitude'] = $geodata->longitude;
453
- }
454
- }
455
- }
456
- }
457
- }
458
-
459
- return $dataLayer;
460
- }
461
-
462
- function gtm4wp_wp_loaded() {
463
- global $gtm4wp_options;
464
-
465
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_WEATHER ] || $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_MISCGEO ] ) {
466
- $client_ip = gtm4wp_get_user_ip();
467
- $geodata = get_transient( 'gtm4wp-geodata-' . esc_attr( $client_ip ) );
468
-
469
- if ( false === $geodata ) {
470
- $gtm4wp_geodata = @wp_remote_get( sprintf( 'http://api.ipstack.com/%s?access_key=%s&format=1', urlencode( $client_ip ), $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_MISCGEOAPI ] ) );
471
-
472
- if ( is_array( $gtm4wp_geodata ) && ( 200 == $gtm4wp_geodata['response']['code'] ) ) {
473
- $gtm4wp_geodata = @json_decode( $gtm4wp_geodata['body'] );
474
-
475
- if ( is_object( $gtm4wp_geodata ) ) {
476
- set_transient( 'gtm4wp-geodata-' . esc_attr( $client_ip ), $gtm4wp_geodata, 60 * 60 );
477
-
478
- $weatherdata = get_transient( 'gtm4wp-weatherdata-' . esc_attr( $client_ip ) );
479
- if ( false === $weatherdata && isset( $gtm4wp_geodata->latitude ) ) {
480
-
481
- $weatherdata = wp_remote_get( 'http://api.openweathermap.org/data/2.5/weather?appid=' . $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_WEATHEROWMAPI ] . '&lat=' . $gtm4wp_geodata->latitude . '&lon=' . $gtm4wp_geodata->longitude . '&units=' . ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_WEATHERUNITS ] == 0 ? 'metric' : 'imperial' ) );
482
-
483
- if ( is_array( $weatherdata ) && ( 200 == $weatherdata['response']['code'] ) ) {
484
- $weatherdata = @json_decode( $weatherdata['body'] );
485
-
486
- if ( is_object( $weatherdata ) ) {
487
- set_transient( 'gtm4wp-weatherdata-' . esc_attr( $client_ip ), $weatherdata, 60 * 60 );
488
- setcookie( 'gtm4wp_last_weatherstatus', 'Weather data loaded.' );
489
- } else {
490
- setcookie( 'gtm4wp_last_weatherstatus', 'Openweathermap.org did not return processable data: ' . var_export( $weatherdata, true ) );
491
- }
492
- } else {
493
- if ( is_wp_error( $weatherdata ) ) {
494
- setcookie( 'gtm4wp_last_weatherstatus', 'Openweathermap.org request error: ' . $weatherdata->get_error_message() );
495
- } else {
496
- setcookie( 'gtm4wp_last_weatherstatus', 'Openweathermap.org returned status code: ' . $weatherdata['response']['code'] );
497
- }
498
- }
499
- }
500
- } else {
501
- setcookie( 'gtm4wp_last_weatherstatus', 'ipstack.com did not return lat-lng data: ' . var_export( $gtm4wp_geodata, true ) );
502
- }
503
- } else {
504
- if ( is_wp_error( $gtm4wp_geodata ) ) {
505
- setcookie( 'gtm4wp_last_weatherstatus', 'ipstack.com request error: ' . $gtm4wp_geodata->get_error_message() );
506
- } else {
507
- setcookie( 'gtm4wp_last_weatherstatus', 'ipstack.com returned status code: ' . $gtm4wp_geodata['response']['code'] );
508
- }
509
- }
510
- }
511
- }
512
- }
513
-
514
- function gtm4wp_get_the_gtm_tag() {
515
- global $gtm4wp_options, $gtm4wp_datalayer_name, $gtm4wp_container_code_written;
516
-
517
- $_gtm_tag = '
518
- <!-- Google Tag Manager (noscript) -->';
519
-
520
- if ( GTM4WP_PLACEMENT_OFF == $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] ) {
521
- $gtm4wp_container_code_written = true;
522
- }
523
-
524
- if ( ( $gtm4wp_options[ GTM4WP_OPTION_GTM_CODE ] != '' ) && ( ! $gtm4wp_container_code_written ) ) {
525
- $_gtm_codes = explode( ',', str_replace( array( ';', ' ' ), array( ',', '' ), $gtm4wp_options[ GTM4WP_OPTION_GTM_CODE ] ) );
526
-
527
- if ( ( '' != $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_AUTH ] ) && ( '' != $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_PREVIEW ] ) ) {
528
- $_gtm_env = '&gtm_auth=' . $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_AUTH ] . '&gtm_preview=' . $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_PREVIEW ] . '&gtm_cookies_win=x';
529
- } else {
530
- $_gtm_env = '';
531
- }
532
-
533
- foreach ( $_gtm_codes as $one_gtm_code ) {
534
- $_gtm_tag .= '
535
- <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=' . $one_gtm_code . $_gtm_env . '"
536
- height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>';
537
- }
538
-
539
- $_gtm_tag .= '
540
- <!-- End Google Tag Manager (noscript) -->';
541
-
542
- $_gtm_tag = apply_filters( GTM4WP_WPFILTER_GETTHEGTMTAG, $_gtm_tag );
543
- $gtm4wp_container_code_written = true;
544
- }
545
-
546
- return $_gtm_tag;
547
- }
548
-
549
- function gtm4wp_the_gtm_tag() {
550
- echo gtm4wp_get_the_gtm_tag();
551
- }
552
-
553
- function gtm4wp_enqueue_scripts() {
554
- global $gtm4wp_options, $gtp4wp_plugin_url;
555
-
556
- if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WPCF7 ] ) {
557
- $in_footer = apply_filters( 'gtm4wp_' . GTM4WP_OPTION_INTEGRATE_WPCF7, false );
558
- wp_enqueue_script( 'gtm4wp-contact-form-7-tracker', $gtp4wp_plugin_url . 'js/gtm4wp-contact-form-7-tracker.js', array( 'jquery' ), GTM4WP_VERSION, $in_footer );
559
- }
560
-
561
- if ( $gtm4wp_options[ GTM4WP_OPTION_EVENTS_FORMMOVE ] ) {
562
- $in_footer = apply_filters( 'gtm4wp_' . GTM4WP_OPTION_EVENTS_FORMMOVE, false );
563
- wp_enqueue_script( 'gtm4wp-form-move-tracker', $gtp4wp_plugin_url . 'js/gtm4wp-form-move-tracker.js', array( 'jquery' ), GTM4WP_VERSION, $in_footer );
564
- }
565
-
566
- if ( $gtm4wp_options[ GTM4WP_OPTION_EVENTS_YOUTUBE ] ) {
567
- require_once dirname( __FILE__ ) . '/../integration/youtube.php';
568
- }
569
-
570
- if ( $gtm4wp_options[ GTM4WP_OPTION_EVENTS_VIMEO ] ) {
571
- require_once dirname( __FILE__ ) . '/../integration/vimeo.php';
572
- }
573
-
574
- if ( $gtm4wp_options[ GTM4WP_OPTION_EVENTS_SOUNDCLOUD ] ) {
575
- require_once dirname( __FILE__ ) . '/../integration/soundcloud.php';
576
- }
577
-
578
- if ( $gtm4wp_options[ GTM4WP_OPTION_SCROLLER_ENABLED ] ) {
579
- $in_footer = apply_filters( 'gtm4wp_' . GTM4WP_OPTION_SCROLLER_ENABLED, false );
580
- wp_enqueue_script( 'gtm4wp-scroll-tracking', $gtp4wp_plugin_url . 'js/analytics-talk-content-tracking.js', array( 'jquery' ), GTM4WP_VERSION, $in_footer );
581
- }
582
- }
583
-
584
- function gtm4wp_wp_footer() {
585
- global $gtm4wp_options;
586
-
587
- if ( GTM4WP_PLACEMENT_FOOTER == $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] ) {
588
- gtm4wp_the_gtm_tag();
589
- }
590
- }
591
-
592
- function gtm4wp_wp_body_open() {
593
- global $gtm4wp_options;
594
-
595
- if ( ( GTM4WP_PLACEMENT_BODYOPEN == $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] ) || ( GTM4WP_PLACEMENT_BODYOPEN_AUTO == $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] ) ) {
596
- gtm4wp_the_gtm_tag();
597
- }
598
- }
599
-
600
- function gtm4wp_filter_visitor_keys( $dataLayer ) {
601
- foreach ( $dataLayer as $dl_key => $dl_value ) {
602
- if ( strpos( $dl_key, 'visitor' ) !== false ) {
603
- unset( $dataLayer[ $dl_key ] );
604
- }
605
- }
606
-
607
- return $dataLayer;
608
- }
609
-
610
- /**
611
- * GTM4WP global JS variables WordPress filter
612
- *
613
- * @author Vincent Koc <https://github.com/koconder/>
614
- * @link https://github.com/duracelltomi/gtm4wp/issues/34
615
- * @return mixed returns the
616
- */
617
- function gtm4wp_add_global_vars( $vars, $return = false ) {
618
- if ( ! $return ) {
619
- if ( function_exists( $vars ) ) {
620
- $vars = $vars();
621
- }
622
- $GLOBALS['gtm4wp_datalayer_globalvars'] = $GLOBALS['gtm4wp_datalayer_globalvars'] . ' ' . $vars;
623
- }
624
- return $GLOBALS['gtm4wp_datalayer_globalvars'];
625
- }
626
-
627
- function gtm4wp_wp_header_top( $echo = true ) {
628
- global $gtm4wp_options, $gtm4wp_datalayer_name;
629
-
630
- $has_html5_support = current_theme_supports( 'html5' );
631
-
632
- $_gtm_top_content = '
633
- <!-- Google Tag Manager for WordPress by gtm4wp.com -->
634
- <script data-cfasync="false" data-pagespeed-no-defer' . ( $has_html5_support ? ' type="text/javascript"' : '' ) . '>//<![CDATA[
635
- var gtm4wp_datalayer_name = "' . $gtm4wp_datalayer_name . '";
636
- var ' . $gtm4wp_datalayer_name . ' = ' . $gtm4wp_datalayer_name . ' || [];';
637
-
638
- // Load in the global variables from gtm4wp_add_global_vars / GTM4WP_WPACTION_ADDGLOBALVARS filter
639
- $_gtm_top_content .= apply_filters( GTM4WP_WPACTION_ADDGLOBALVARS, '', true );
640
-
641
- if ( $gtm4wp_options[ GTM4WP_OPTION_SCROLLER_ENABLED ] ) {
642
- $_gtm_top_content .= '
643
-
644
- var gtm4wp_scrollerscript_debugmode = ' . ( $gtm4wp_options[ GTM4WP_OPTION_SCROLLER_DEBUGMODE ] ? 'true' : 'false' ) . ';
645
- var gtm4wp_scrollerscript_callbacktime = ' . (int) $gtm4wp_options[ GTM4WP_OPTION_SCROLLER_CALLBACKTIME ] . ';
646
- var gtm4wp_scrollerscript_readerlocation = ' . (int) $gtm4wp_options[ GTM4WP_OPTION_SCROLLER_DISTANCE ] . ';
647
- var gtm4wp_scrollerscript_contentelementid = "' . $gtm4wp_options[ GTM4WP_OPTION_SCROLLER_CONTENTID ] . '";
648
- var gtm4wp_scrollerscript_scannertime = ' . (int) $gtm4wp_options[ GTM4WP_OPTION_SCROLLER_READERTIME ] . ';';
649
- }
650
-
651
- $_gtm_top_content .= '
652
- //]]>
653
- </script>
654
- <!-- End Google Tag Manager for WordPress by gtm4wp.com -->';
655
-
656
- if ( ! gtm4wp_amp_running() ) {
657
- if ( $echo ) {
658
- echo $_gtm_top_content;
659
- } else {
660
- return $_gtm_top_content;
661
- }
662
- }
663
- }
664
-
665
- function gtm4wp_wp_header_begin( $echo = true ) {
666
- global $gtm4wp_datalayer_name, $gtm4wp_datalayer_json, $gtm4wp_options, $woocommerce;
667
-
668
- $has_html5_support = current_theme_supports( 'html5' );
669
-
670
- $_gtm_header_content = '
671
- <!-- Google Tag Manager for WordPress by gtm4wp.com -->
672
- <script data-cfasync="false" data-pagespeed-no-defer' . ( $has_html5_support ? ' type="text/javascript"' : '' ) . '>//<![CDATA[';
673
-
674
- if ( $gtm4wp_options[ GTM4WP_OPTION_GTM_CODE ] != '' ) {
675
- $gtm4wp_datalayer_data = array();
676
- $gtm4wp_datalayer_data = (array) apply_filters( GTM4WP_WPFILTER_COMPILE_DATALAYER, $gtm4wp_datalayer_data );
677
-
678
- if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_REMARKETING ] ) {
679
- // add Google Ads remarketing tags as suggested here:
680
- // https://support.google.com/tagmanager/answer/3002580?hl=en
681
- add_filter( GTM4WP_WPFILTER_COMPILE_REMARKTING, 'gtm4wp_filter_visitor_keys' );
682
- $gtm4wp_remarketing_tags = (array) apply_filters( GTM4WP_WPFILTER_COMPILE_REMARKTING, $gtm4wp_datalayer_data );
683
-
684
- $_gtm_header_content .= "\nvar google_tag_params = ";
685
- $_gtm_header_content .= json_encode( $gtm4wp_remarketing_tags );
686
- $_gtm_header_content .= ';';
687
- $gtm4wp_datalayer_data['google_tag_params'] = '-~-window.google_tag_params-~-';
688
- }
689
-
690
- if ( version_compare( PHP_VERSION, '5.4.0' ) >= 0 ) {
691
- $gtm4wp_datalayer_json = json_encode( $gtm4wp_datalayer_data, JSON_UNESCAPED_UNICODE );
692
- } else {
693
- $gtm4wp_datalayer_json = json_encode( $gtm4wp_datalayer_data );
694
- }
695
-
696
- // Clean up and then push datalayer to AMP
697
- $gtm4wp_datalayer_json = str_replace(
698
- array( '"-~-', '-~-"' ),
699
- array( '', '' ),
700
- str_replace( '–', '-', $gtm4wp_datalayer_json )
701
- );
702
-
703
- $_gtm_header_content .= '
704
- var dataLayer_content = ' . $gtm4wp_datalayer_json . ';';
705
-
706
- // fire WooCommerce order double tracking protection only if WooCommerce is active and user is on the order received page
707
- if ( isset( $gtm4wp_options ) && ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC ] || $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) && isset( $woocommerce ) && is_order_received_page() ) {
708
-
709
- $_gtm_header_content .= '
710
- // if dataLayer contains ecommerce purchase data, check whether it has been already tracked
711
- if ( dataLayer_content.transactionId || ( dataLayer_content.ecommerce && dataLayer_content.ecommerce.purchase ) ) {
712
- // read order id already tracked from cookies
713
- var gtm4wp_orderid_tracked = "";
714
-
715
- if ( !window.localStorage ) {
716
- var gtm4wp_cookie = "; " + document.cookie;
717
- var gtm4wp_cookie_parts = gtm4wp_cookie.split( "; gtm4wp_orderid_tracked=" );
718
- if ( gtm4wp_cookie_parts.length == 2 ) {
719
- gtm4wp_orderid_tracked = gtm4wp_cookie_parts.pop().split(";").shift();
720
- }
721
- } else {
722
- window.localStorage.getItem( "gtm4wp_orderid_tracked" );
723
- }
724
-
725
- // check enhanced ecommerce
726
- if ( dataLayer_content.ecommerce && dataLayer_content.ecommerce.purchase ) {
727
- if ( gtm4wp_orderid_tracked && ( dataLayer_content.ecommerce.purchase.actionField.id == gtm4wp_orderid_tracked ) ) {
728
- delete dataLayer_content.ecommerce.purchase;
729
- } else {
730
- gtm4wp_orderid_tracked = dataLayer_content.ecommerce.purchase.actionField.id;
731
- }
732
- }
733
-
734
- // check app+web ecommerce
735
- if ( dataLayer_content.ecommerce && dataLayer_content.ecommerce.items ) {
736
- if ( gtm4wp_orderid_tracked && ( dataLayer_content.ecommerce.transaction_id == gtm4wp_orderid_tracked ) ) {
737
- delete dataLayer_content.ecommerce.affiliation;
738
- delete dataLayer_content.ecommerce.value;
739
- delete dataLayer_content.ecommerce.currency;
740
- delete dataLayer_content.ecommerce.tax;
741
- delete dataLayer_content.ecommerce.shipping;
742
- delete dataLayer_content.ecommerce.transaction_id;
743
-
744
- delete dataLayer_content.ecommerce.items;
745
- } else {
746
- gtm4wp_orderid_tracked = dataLayer_content.ecommerce.purchase.actionField.id;
747
- }
748
- }
749
-
750
- // check standard ecommerce
751
- if ( dataLayer_content.transactionId ) {
752
- if ( gtm4wp_orderid_tracked && ( dataLayer_content.transactionId == gtm4wp_orderid_tracked ) ) {
753
- delete dataLayer_content.transactionId;
754
- delete dataLayer_content.transactionDate;
755
- delete dataLayer_content.transactionType;
756
- delete dataLayer_content.transactionAffiliation;
757
- delete dataLayer_content.transactionTotal;
758
- delete dataLayer_content.transactionShipping;
759
- delete dataLayer_content.transactionTax;
760
- delete dataLayer_content.transactionPaymentType;
761
- delete dataLayer_content.transactionCurrency;
762
- delete dataLayer_content.transactionShippingMethod;
763
- delete dataLayer_content.transactionPromoCode;
764
- delete dataLayer_content.transactionProducts;
765
- } else {
766
- gtm4wp_orderid_tracked = dataLayer_content.transactionId;
767
- }
768
- }
769
-
770
- if ( gtm4wp_orderid_tracked ) {
771
- if ( !window.localStorage ) {
772
- var gtm4wp_orderid_cookie_expire = new Date();
773
- gtm4wp_orderid_cookie_expire.setTime( gtm4wp_orderid_cookie_expire.getTime() + (365*24*60*60*1000) );
774
- var gtm4wp_orderid_cookie_expires_part = "expires=" + gtm4wp_orderid_cookie_expire.toUTCString();
775
- document.cookie = "gtm4wp_orderid_tracked=" + gtm4wp_orderid_tracked + ";" + gtm4wp_orderid_cookie_expires_part + ";path=/";
776
- } else {
777
- window.localStorage.setItem( "gtm4wp_orderid_tracked", gtm4wp_orderid_tracked );
778
- }
779
- }
780
-
781
- }';
782
- }
783
-
784
- $_gtm_header_content .= '
785
- ' . $gtm4wp_datalayer_name . '.push( dataLayer_content );';
786
- }
787
-
788
- $_gtm_header_content .= '//]]>
789
- </script>';
790
-
791
- $_gtm_header_content .= apply_filters( GTM4WP_WPFILTER_AFTER_DATALAYER, '' );
792
-
793
- if ( ( $gtm4wp_options[ GTM4WP_OPTION_GTM_CODE ] != '' ) && ( GTM4WP_PLACEMENT_OFF != $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] ) ) {
794
- $_gtm_codes = explode( ',', str_replace( array( ';', ' ' ), array( ',', '' ), $gtm4wp_options[ GTM4WP_OPTION_GTM_CODE ] ) );
795
-
796
- $_gtm_tag = '';
797
- foreach ( $_gtm_codes as $one_gtm_code ) {
798
- if ( ( '' != $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_AUTH ] ) && ( '' != $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_PREVIEW ] ) ) {
799
- $_gtm_env = "+'&gtm_auth=" . $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_AUTH ] . '&gtm_preview=' . $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_PREVIEW ] . "&gtm_cookies_win=x'";
800
- } else {
801
- $_gtm_env = '';
802
- }
803
-
804
- $_gtm_tag .= '
805
- <script data-cfasync="false">//<![CDATA[
806
- (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({\'gtm.start\':
807
- new Date().getTime(),event:\'gtm.js\'});var f=d.getElementsByTagName(s)[0],
808
- j=d.createElement(s),dl=l!=\'dataLayer\'?\'&l=\'+l:\'\';j.async=true;j.src=
809
- \'//www.googletagmanager.com/gtm.\'' . '+\'js?id=\'+i+dl' . $_gtm_env . ';f.parentNode.insertBefore(j,f);
810
- })(window,document,\'script\',\'' . $gtm4wp_datalayer_name . '\',\'' . $one_gtm_code . '\');//]]>
811
- </script>';
812
- }
813
-
814
- $_gtm_tag .= '
815
- <!-- End Google Tag Manager -->';
816
-
817
- $_gtm_tag = apply_filters( GTM4WP_WPFILTER_GETTHEGTMTAG, $_gtm_tag );
818
- $_gtm_header_content .= $_gtm_tag;
819
- }
820
-
821
- $_gtm_header_content .= '
822
- <!-- End Google Tag Manager for WordPress by gtm4wp.com -->';
823
-
824
- if ( ! gtm4wp_amp_running() ) {
825
- if ( $echo ) {
826
- echo $_gtm_header_content;
827
- } else {
828
- return $_gtm_header_content;
829
- }
830
- }
831
- }
832
-
833
- function gtm4wp_wp_login() {
834
- setcookie( 'gtm4wp_user_logged_in', '1', 0, '/' );
835
- }
836
-
837
- function gtm4wp_user_register() {
838
- setcookie( 'gtm4wp_user_registered', '1', 0, '/' );
839
- }
840
-
841
- function gtm4wp_user_reg_login_script() {
842
- global $gtp4wp_plugin_url;
843
-
844
- $in_footer = apply_filters( 'gtm4wp_user_reg_login_script', true );
845
- wp_enqueue_script( 'gtm4wp-user-reg-login-script', $gtp4wp_plugin_url . 'js/gtm4wp-users.js', array( 'jquery' ), GTM4WP_VERSION, $in_footer );
846
- }
847
-
848
- function gtm4wp_rocket_excluded_inline_js_content( $pattern ) {
849
- $pattern[] = 'dataLayer';
850
- $pattern[] = 'gtm4wp';
851
-
852
- return $pattern;
853
- }
854
-
855
- add_action( 'wp_enqueue_scripts', 'gtm4wp_enqueue_scripts' );
856
- $gtm4wp_header_begin_prior = 10;
857
- if ( isset( $GLOBALS['gtm4wp_options'] ) && $GLOBALS['gtm4wp_options'][ GTM4WP_OPTION_LOADEARLY ] ) {
858
- $gtm4wp_header_begin_prior = 2;
859
- }
860
- add_action( 'wp_head', 'gtm4wp_wp_header_begin', $gtm4wp_header_begin_prior, 0 );
861
- add_action( 'wp_head', 'gtm4wp_wp_header_top', 1, 0 );
862
- add_action( 'wp_footer', 'gtm4wp_wp_footer' );
863
- add_action( 'wp_loaded', 'gtm4wp_wp_loaded' );
864
- add_filter( GTM4WP_WPFILTER_COMPILE_DATALAYER, 'gtm4wp_add_basic_datalayer_data' );
865
-
866
- // to be able to easily migrate from other Google Tag Manager plugins
867
- add_action( 'body_open', 'gtm4wp_wp_body_open' );
868
-
869
- // compatibility with existing themes that natively support code injection after opening body tag
870
- add_action( 'genesis_before', 'gtm4wp_wp_body_open' ); // Genisis theme
871
- add_action( 'generate_before_header', 'gtm4wp_wp_body_open', 0 ); // GeneratePress theme
872
- add_action( 'elementor/page_templates/canvas/before_content', 'gtm4wp_wp_body_open' ); // Elementor
873
- add_action( 'ct_before_builder', 'gtm4wp_wp_body_open', 0 ); // Oxygen Builder
874
- add_action( 'fl_before_builder', 'gtm4wp_wp_body_open', 0 ); // Beaver Builder Theme
875
-
876
- // standard WP theme support for body open tags
877
- add_action( 'wp_body_open', 'gtm4wp_wp_body_open' );
878
-
879
- add_filter( 'rocket_excluded_inline_js_content', 'gtm4wp_rocket_excluded_inline_js_content' ); // WP Rocket
880
- if (
881
- isset( $GLOBALS['gtm4wp_options'] )
882
- && (
883
- $GLOBALS['gtm4wp_options'][ GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC ]
884
- || $GLOBALS['gtm4wp_options'][ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ]
885
- )
886
- && isset( $GLOBALS['woocommerce'] )
887
- && version_compare( WC()->version, '3.2', '>=' ) // only activate WooCommerce integration for minimum supported WooCommerce version
888
- ) {
889
- require_once dirname( __FILE__ ) . '/../integration/woocommerce.php';
890
- }
891
-
892
- if ( isset( $GLOBALS['gtm4wp_options'] ) && ( $GLOBALS['gtm4wp_options'][ GTM4WP_OPTION_INTEGRATE_GOOGLEOPTIMIZEIDS ] != '' ) ) {
893
- require_once dirname( __FILE__ ) . '/../integration/google-optimize.php';
894
- }
895
-
896
- if ( isset( $GLOBALS['gtm4wp_options'] ) && ( $GLOBALS['gtm4wp_options'][ GTM4WP_OPTION_EVENTS_USERLOGIN ] ) ) {
897
- add_action( 'wp_login', 'gtm4wp_wp_login' );
898
- add_action( 'wp_enqueue_scripts', 'gtm4wp_user_reg_login_script' );
899
- }
900
-
901
- if ( isset( $GLOBALS['gtm4wp_options'] ) && ( $GLOBALS['gtm4wp_options'][ GTM4WP_OPTION_EVENTS_NEWUSERREG ] ) ) {
902
- add_action( 'user_register', 'gtm4wp_user_register' );
903
- add_action( 'wp_enqueue_scripts', 'gtm4wp_user_reg_login_script' );
904
- }
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ define( 'GTM4WP_WPFILTER_COMPILE_DATALAYER', 'gtm4wp_compile_datalayer' );
3
+ define( 'GTM4WP_WPFILTER_COMPILE_REMARKTING', 'gtm4wp_compile_remarkering' );
4
+ define( 'GTM4WP_WPFILTER_AFTER_DATALAYER', 'gtm4wp_after_datalayer' );
5
+ define( 'GTM4WP_WPFILTER_GETTHEGTMTAG', 'gtm4wp_get_the_gtm_tag' );
6
+ define( 'GTM4WP_WPACTION_ADDGLOBALVARS', 'gtm4wp_add_global_vars' );
7
+
8
+ $GLOBALS['gtm4wp_container_code_written'] = false;
9
+
10
+ // check for empty is needed to prevent error in WP CLI
11
+ // bugfix by Patrick Holberg Hesselberg
12
+ if ( empty( $GLOBALS['gtm4wp_options'] ) || ( $GLOBALS['gtm4wp_options'][ GTM4WP_OPTION_DATALAYER_NAME ] == '' ) ) {
13
+ $GLOBALS['gtm4wp_datalayer_name'] = 'dataLayer';
14
+ } else {
15
+ $GLOBALS['gtm4wp_datalayer_name'] = $GLOBALS['gtm4wp_options'][ GTM4WP_OPTION_DATALAYER_NAME ];
16
+ }
17
+
18
+ // Setting Global Variable to Store JSON based Datalayer for Intergrations
19
+ $GLOBALS['gtm4wp_datalayer_json'] = '';
20
+ $GLOBALS['gtm4wp_datalayer_globalvars'] = '';
21
+
22
+ // Moving include to top due to hierarchy of includes
23
+ if ( isset( $GLOBALS['gtm4wp_options'] ) && ( '' != $GLOBALS['gtm4wp_options'][ GTM4WP_OPTION_INTEGRATE_AMPID ] ) ) {
24
+ require_once dirname( __FILE__ ) . '/../integration/amp.php';
25
+ }
26
+ if ( ! function_exists( 'gtm4wp_amp_running' ) ) {
27
+ function gtm4wp_amp_running() {
28
+ return false;
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Converts bool false to string false for JS
34
+ *
35
+ * @author Vincent Koc <https://github.com/koconder/>
36
+ * @return mixed Returs object or string false
37
+ */
38
+ function gtm4wp_escjs_boolean( $obj ) {
39
+ if ( empty( $obj ) || is_null( $obj ) || ! $obj ) {
40
+ return 'false';
41
+ } else {
42
+ return $obj;
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Original copyright:
48
+ * By Grant Burton @ BURTONTECH.COM
49
+ *
50
+ * Code improved by Thomas Geiger
51
+ */
52
+ function gtm4wp_get_user_ip() {
53
+ if ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
54
+ foreach ( explode( ',', $_SERVER['HTTP_X_FORWARDED_FOR'] ) as $ip ) {
55
+ if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) !== false ) {
56
+ return $ip;
57
+ }
58
+ }
59
+ }
60
+
61
+ $possible_ip_variables = array(
62
+ 'HTTP_CLIENT_IP',
63
+ 'HTTP_X_FORWARDED',
64
+ 'HTTP_X_CLUSTER_CLIENT_IP',
65
+ 'HTTP_FORWARDED_FOR',
66
+ 'HTTP_FORWARDED',
67
+ 'REMOTE_ADDR'
68
+ );
69
+
70
+ foreach( $possible_ip_variables as $one_ip_variable ) {
71
+ if (
72
+ ! empty( $_SERVER[ $one_ip_variable ] )
73
+ && ( filter_var( $_SERVER[ $one_ip_variable ], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) !== false )
74
+ ) {
75
+ return $_SERVER[ $one_ip_variable ];
76
+ }
77
+ }
78
+
79
+ return '';
80
+ }
81
+
82
+ if ( ! function_exists( 'getallheaders' ) ) {
83
+ function getallheaders() {
84
+ $headers = array();
85
+ foreach ( $_SERVER as $name => $value ) {
86
+ if ( substr( $name, 0, 5 ) == 'HTTP_' ) {
87
+ $headers[ str_replace( ' ', '-', ucwords( strtolower( str_replace( '_', ' ', substr( $name, 5 ) ) ) ) ) ] = $value;
88
+ }
89
+ }
90
+
91
+ return $headers;
92
+ }
93
+ }
94
+
95
+ function gtm4wp_add_basic_datalayer_data( $dataLayer ) {
96
+ global $wp_query, $gtm4wp_options, $gtm4wp_entity_ids;
97
+
98
+ if ( $gtm4wp_options[ GTM4WP_OPTION_DONOTTRACK ] ) {
99
+ if ( ! empty( $_SERVER['HTTP_DNT'] ) ) {
100
+ $dataLayer['visitorDoNotTrack'] = (int) ( $_SERVER['HTTP_DNT'] );
101
+ } else {
102
+ $dataLayer['visitorDoNotTrack'] = 0;
103
+ }
104
+ }
105
+
106
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_SITEID ] || $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_SITENAME ] ) {
107
+ $dataLayer['siteID'] = 0;
108
+ $dataLayer['siteName'] = '';
109
+
110
+ if ( function_exists( 'get_blog_details' ) ) {
111
+ $gtm4wp_blogdetails = get_blog_details();
112
+
113
+ $dataLayer['siteID'] = $gtm4wp_blogdetails->blog_id;
114
+ $dataLayer['siteName'] = $gtm4wp_blogdetails->blogname;
115
+ }
116
+ }
117
+
118
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_LOGGEDIN ] ) {
119
+ if ( is_user_logged_in() ) {
120
+ $dataLayer['visitorLoginState'] = 'logged-in';
121
+ } else {
122
+ $dataLayer['visitorLoginState'] = 'logged-out';
123
+ }
124
+ }
125
+
126
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_USERROLE ] || $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_USEREMAIL ] || $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_USERREGDATE ] ) {
127
+ $current_user = wp_get_current_user();
128
+
129
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_USERROLE ] ) {
130
+ $dataLayer['visitorType'] = ( empty( $current_user->roles[0] ) ? 'visitor-logged-out' : $current_user->roles[0] );
131
+ }
132
+
133
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_USEREMAIL ] ) {
134
+ $dataLayer['visitorEmail'] = ( empty( $current_user->user_email ) ? '' : $current_user->user_email );
135
+ }
136
+
137
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_USERREGDATE ] ) {
138
+ $dataLayer['visitorRegistrationDate'] = ( empty( $current_user->user_registered ) ? '' : strtotime( $current_user->user_registered ) );
139
+ }
140
+
141
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_USERNAME ] ) {
142
+ $dataLayer['visitorUsername'] = ( empty( $current_user->user_login ) ? '' : $current_user->user_login );
143
+ }
144
+ }
145
+
146
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_USERID ] ) {
147
+ $_gtm4wp_userid = get_current_user_id();
148
+ if ( $_gtm4wp_userid > 0 ) {
149
+ $dataLayer['visitorId'] = $_gtm4wp_userid;
150
+ }
151
+ }
152
+
153
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_VISITOR_IP ] ) {
154
+ $dataLayer['visitorIP'] = esc_js( gtm4wp_get_user_ip() );
155
+ }
156
+
157
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTTITLE ] ) {
158
+ $dataLayer['pageTitle'] = strip_tags( wp_title( '|', false, 'right' ) );
159
+ }
160
+
161
+ if ( is_singular() ) {
162
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTTYPE ] ) {
163
+ $dataLayer['pagePostType'] = get_post_type();
164
+ $dataLayer['pagePostType2'] = 'single-' . get_post_type();
165
+ }
166
+
167
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_CATEGORIES ] ) {
168
+ $_post_cats = get_the_category();
169
+ if ( $_post_cats ) {
170
+ $dataLayer['pageCategory'] = array();
171
+ foreach ( $_post_cats as $_one_cat ) {
172
+ $dataLayer['pageCategory'][] = $_one_cat->slug;
173
+ }
174
+ }
175
+ }
176
+
177
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_TAGS ] ) {
178
+ $_post_tags = get_the_tags();
179
+ if ( $_post_tags ) {
180
+ $dataLayer['pageAttributes'] = array();
181
+ foreach ( $_post_tags as $_one_tag ) {
182
+ $dataLayer['pageAttributes'][] = $_one_tag->slug;
183
+ }
184
+ }
185
+ }
186
+
187
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_AUTHORID ] || $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_AUTHOR ] ) {
188
+ $postuser = get_userdata( $GLOBALS['post']->post_author );
189
+
190
+ if ( false !== $postuser ) {
191
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_AUTHORID ] ) {
192
+ $dataLayer['pagePostAuthorID'] = $postuser->ID;
193
+ }
194
+
195
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_AUTHOR ] ) {
196
+ $dataLayer['pagePostAuthor'] = $postuser->display_name;
197
+ }
198
+ }
199
+ }
200
+
201
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTDATE ] ) {
202
+ $dataLayer['pagePostDate'] = get_the_date();
203
+ $dataLayer['pagePostDateYear'] = get_the_date( 'Y' );
204
+ $dataLayer['pagePostDateMonth'] = get_the_date( 'm' );
205
+ $dataLayer['pagePostDateDay'] = get_the_date( 'd' );
206
+ }
207
+
208
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTTERMLIST ] ) {
209
+ $dataLayer["pagePostTerms"] = array();
210
+ $object_taxonomies = get_object_taxonomies( get_post_type() );
211
+ foreach( $object_taxonomies as $one_object_taxonomy ) {
212
+ $post_taxonomy_values = get_the_terms( $GLOBALS[ "post" ]->ID, $one_object_taxonomy );
213
+ if ( is_array( $post_taxonomy_values ) ) {
214
+ $dataLayer["pagePostTerms"][$one_object_taxonomy] = array();
215
+ foreach( $post_taxonomy_values as $one_taxonomy_value ) {
216
+ $dataLayer["pagePostTerms"][$one_object_taxonomy][] = $one_taxonomy_value->name;
217
+ }
218
+ }
219
+ }
220
+ }
221
+ }
222
+
223
+ if ( is_archive() || is_post_type_archive() ) {
224
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTTYPE ] ) {
225
+ $dataLayer['pagePostType'] = get_post_type();
226
+
227
+ if ( is_category() ) {
228
+ $dataLayer['pagePostType2'] = 'category-' . get_post_type();
229
+ } elseif ( is_tag() ) {
230
+ $dataLayer['pagePostType2'] = 'tag-' . get_post_type();
231
+ } elseif ( is_tax() ) {
232
+ $dataLayer['pagePostType2'] = 'tax-' . get_post_type();
233
+ } elseif ( is_author() ) {
234
+ $dataLayer['pagePostType2'] = 'author-' . get_post_type();
235
+ } elseif ( is_year() ) {
236
+ $dataLayer['pagePostType2'] = 'year-' . get_post_type();
237
+
238
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTDATE ] ) {
239
+ $dataLayer['pagePostDateYear'] = get_the_date( 'Y' );
240
+ }
241
+ } elseif ( is_month() ) {
242
+ $dataLayer['pagePostType2'] = 'month-' . get_post_type();
243
+
244
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTDATE ] ) {
245
+ $dataLayer['pagePostDateYear'] = get_the_date( 'Y' );
246
+ $dataLayer['pagePostDateMonth'] = get_the_date( 'm' );
247
+ }
248
+ } elseif ( is_day() ) {
249
+ $dataLayer['pagePostType2'] = 'day-' . get_post_type();
250
+
251
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTDATE ] ) {
252
+ $dataLayer['pagePostDate'] = get_the_date();
253
+ $dataLayer['pagePostDateYear'] = get_the_date( 'Y' );
254
+ $dataLayer['pagePostDateMonth'] = get_the_date( 'm' );
255
+ $dataLayer['pagePostDateDay'] = get_the_date( 'd' );
256
+ }
257
+ } elseif ( is_time() ) {
258
+ $dataLayer['pagePostType2'] = 'time-' . get_post_type();
259
+ } elseif ( is_date() ) {
260
+ $dataLayer['pagePostType2'] = 'date-' . get_post_type();
261
+
262
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTDATE ] ) {
263
+ $dataLayer['pagePostDate'] = get_the_date();
264
+ $dataLayer['pagePostDateYear'] = get_the_date( 'Y' );
265
+ $dataLayer['pagePostDateMonth'] = get_the_date( 'm' );
266
+ $dataLayer['pagePostDateDay'] = get_the_date( 'd' );
267
+ }
268
+ }
269
+ }
270
+
271
+ if ( ( is_tax() || is_category() ) && $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_CATEGORIES ] ) {
272
+ $_post_cats = get_the_category();
273
+ $dataLayer['pageCategory'] = array();
274
+ foreach ( $_post_cats as $_one_cat ) {
275
+ $dataLayer['pageCategory'][] = $_one_cat->slug;
276
+ }
277
+ }
278
+
279
+ if ( ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_AUTHORID ] ) && ( is_author() ) ) {
280
+ global $authordata;
281
+ $dataLayer['pagePostAuthorID'] = isset( $authordata->ID ) ? $authordata->ID : 0;
282
+ }
283
+
284
+ if ( ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_AUTHOR ] ) && ( is_author() ) ) {
285
+ $dataLayer['pagePostAuthor'] = get_the_author();
286
+ }
287
+ }
288
+
289
+ if ( is_search() ) {
290
+ $dataLayer['siteSearchTerm'] = get_search_query();
291
+ $dataLayer['siteSearchFrom'] = '';
292
+ if ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
293
+ $referer_url_parts = explode( '?', $_SERVER['HTTP_REFERER'] );
294
+ if ( count( $referer_url_parts ) > 1 ) {
295
+ $dataLayer['siteSearchFrom'] = $referer_url_parts[0] . '?' . rawurlencode( $referer_url_parts[1] );
296
+ } else {
297
+ $dataLayer['siteSearchFrom'] = $referer_url_parts[0];
298
+ }
299
+ }
300
+ $dataLayer['siteSearchResults'] = $wp_query->post_count;
301
+ }
302
+
303
+ if ( is_front_page() && $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTTYPE ] ) {
304
+ $dataLayer['pagePostType'] = 'frontpage';
305
+ }
306
+
307
+ if ( ! is_front_page() && is_home() && $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTTYPE ] ) {
308
+ $dataLayer['pagePostType'] = 'bloghome';
309
+ }
310
+
311
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_BROWSERDATA ] || $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_OSDATA ] || $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_DEVICEDATA ] ) {
312
+ spl_autoload_register(
313
+ function( $class ) {
314
+ $class_parts = explode( '\\', $class );
315
+ if ( 'WhichBrowser' == $class_parts[0] ) {
316
+ include dirname( __FILE__ ) . '/../integration/whichbrowser/' . str_replace( array( 'WhichBrowser', '\\' ), array( 'src', '/' ), $class ) . '.php';
317
+ }
318
+ }
319
+ );
320
+
321
+ require_once dirname( __FILE__ ) . '/../integration/whichbrowser/src/Parser.php';
322
+
323
+ $gtp4wp_headers = getallheaders();
324
+ if ( ( false === $gtp4wp_headers ) && isset( $_SERVER['HTTP_USER_AGENT'] ) ) {
325
+ $gtp4wp_headers = $_SERVER['HTTP_USER_AGENT'];
326
+ }
327
+ if ( false !== $gtp4wp_headers ) {
328
+ $detected = new WhichBrowser\Parser( $gtp4wp_headers );
329
+
330
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_BROWSERDATA ] ) {
331
+ $dataLayer['browserName'] = isset( $detected->browser->name ) ? $detected->browser->name : '';
332
+ $dataLayer['browserVersion'] = isset( $detected->browser->version->value ) ? $detected->browser->version->value : '';
333
+
334
+ $dataLayer['browserEngineName'] = isset( $detected->engine->name ) ? $detected->engine->name : '';
335
+ $dataLayer['browserEngineVersion'] = isset( $detected->engine->version->value ) ? $detected->engine->version->value : '';
336
+ }
337
+
338
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_OSDATA ] ) {
339
+ $dataLayer['osName'] = isset( $detected->os->name ) ? $detected->os->name : '';
340
+ $dataLayer['osVersion'] = isset( $detected->os->version->value ) ? $detected->os->version->value : '';
341
+ }
342
+
343
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_DEVICEDATA ] ) {
344
+ $dataLayer['deviceType'] = isset( $detected->device->type ) ? $detected->device->type : '';
345
+ $dataLayer['deviceManufacturer'] = isset( $detected->device->manufacturer ) ? $detected->device->manufacturer : '';
346
+ $dataLayer['deviceModel'] = isset( $detected->device->model ) ? $detected->device->model : '';
347
+ }
348
+ }
349
+ }
350
+
351
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTCOUNT ] ) {
352
+ $dataLayer['postCountOnPage'] = (int) $wp_query->post_count;
353
+ $dataLayer['postCountTotal'] = (int) $wp_query->found_posts;
354
+ }
355
+
356
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTID ] && is_singular() === true ) {
357
+ $dataLayer['postID'] = (int) get_the_ID();
358
+ }
359
+
360
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_POSTFORMAT ] && is_singular() === true ) {
361
+ $dataLayer['postFormat'] = get_post_format() ?: 'standard';
362
+ }
363
+
364
+ if ( $gtm4wp_options[ GTM4WP_OPTION_BLACKLIST_ENABLE ] > 0 ) {
365
+ $_gtmrestrictlistitems = array();
366
+
367
+ // because of security reasons, we loop through each stored entity in the options and validate them
368
+ // to make sure nobody has entered some 'funny' item manually
369
+ $valid_entity_ids = array_merge(
370
+ array_keys( $gtm4wp_entity_ids[ 'tags' ] ),
371
+ array_keys( $gtm4wp_entity_ids[ 'triggers' ] ),
372
+ array_keys( $gtm4wp_entity_ids[ 'variables' ] )
373
+ );
374
+ foreach( $gtm4wp_options[ GTM4WP_OPTION_BLACKLIST_STATUS ] as $listed_entity ) {
375
+ if ( in_array( $listed_entity, $valid_entity_ids ) ) {
376
+ $_gtmrestrictlistitems[] = $listed_entity;
377
+ }
378
+ }
379
+
380
+ $_gtmwhitelist = array();
381
+ $_gtmblacklist = array();
382
+ if ( $gtm4wp_options[ GTM4WP_OPTION_BLACKLIST_ENABLE ] == 1 ) {
383
+ $_gtmblacklist = array_merge( $_gtmblacklist, $_gtmrestrictlistitems );
384
+ } else {
385
+ $_gtmwhitelist = array_merge( $_gtmwhitelist, $_gtmrestrictlistitems );
386
+ }
387
+
388
+ $dataLayer['gtm.whitelist'] = $_gtmwhitelist;
389
+ $dataLayer['gtm.blacklist'] = $_gtmblacklist;
390
+ }
391
+
392
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_MISCGEOCF ] && isset( $_SERVER['HTTP_CF_IPCOUNTRY'] ) ) {
393
+ $dataLayer['geoCloudflareCountryCode'] = $_SERVER['HTTP_CF_IPCOUNTRY'];
394
+ }
395
+
396
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_WEATHER ] || $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_MISCGEO ] ) {
397
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_WEATHER ] ) {
398
+ $dataLayer['weatherCategory'] = __( '(no weather data available)', 'duracelltomi-google-tag-manager' );
399
+ $dataLayer['weatherDescription'] = __( '(no weather data available)', 'duracelltomi-google-tag-manager' );
400
+ $dataLayer['weatherTemp'] = 0;
401
+ $dataLayer['weatherPressure'] = 0;
402
+ $dataLayer['weatherWindSpeed'] = 0;
403
+ $dataLayer['weatherWindDeg'] = 0;
404
+ $dataLayer['weatherDataStatus'] = 'Initialized with empty data';
405
+ }
406
+
407
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_MISCGEO ] ) {
408
+ $dataLayer['geoCountryCode'] = __( '(no geo data available)', 'duracelltomi-google-tag-manager' );
409
+ $dataLayer['geoCountryName'] = __( '(no geo data available)', 'duracelltomi-google-tag-manager' );
410
+ $dataLayer['geoRegionCode'] = __( '(no geo data available)', 'duracelltomi-google-tag-manager' );
411
+ $dataLayer['geoRegionName'] = __( '(no geo data available)', 'duracelltomi-google-tag-manager' );
412
+ $dataLayer['geoCity'] = __( '(no geo data available)', 'duracelltomi-google-tag-manager' );
413
+ $dataLayer['geoZipcode'] = __( '(no geo data available)', 'duracelltomi-google-tag-manager' );
414
+ $dataLayer['geoLatitude'] = __( '(no geo data available)', 'duracelltomi-google-tag-manager' );
415
+ $dataLayer['geoLongitude'] = __( '(no geo data available)', 'duracelltomi-google-tag-manager' );
416
+ }
417
+
418
+ $client_ip = gtm4wp_get_user_ip();
419
+
420
+ if ( '' !== $client_ip ) {
421
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_WEATHER ] ) {
422
+ $weatherdata = get_transient( 'gtm4wp-weatherdata-' . esc_attr( $client_ip ) );
423
+
424
+ if ( false !== $weatherdata ) {
425
+ $dataLayer['weatherCategory'] = $weatherdata->weather[0]->main;
426
+ $dataLayer['weatherDescription'] = $weatherdata->weather[0]->description;
427
+ $dataLayer['weatherTemp'] = $weatherdata->main->temp;
428
+ $dataLayer['weatherPressure'] = $weatherdata->main->pressure;
429
+ $dataLayer['weatherWindSpeed'] = $weatherdata->wind->speed;
430
+ $dataLayer['weatherWindDeg'] = ( isset($weatherdata->wind->deg) ? $weatherdata->wind->deg : '' );
431
+ $dataLayer['weatherFullWeatherData'] = $weatherdata;
432
+ $dataLayer['weatherDataStatus'] = 'Read from cache';
433
+ } else {
434
+ $dataLayer['weatherDataStatus'] = 'No weather data in cache (' . esc_attr( $client_ip ) . ')';
435
+ }
436
+ }
437
+
438
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_MISCGEO ] ) {
439
+ $geodata = get_transient( 'gtm4wp-geodata-' . esc_attr( $client_ip ) );
440
+
441
+ if ( false !== $geodata ) {
442
+ $dataLayer['geoFullGeoData'] = $geodata;
443
+
444
+ if ( isset( $geodata->latitude ) ) {
445
+ $dataLayer['geoCountryCode'] = $geodata->country_code;
446
+ $dataLayer['geoCountryName'] = $geodata->country_name;
447
+ $dataLayer['geoRegionCode'] = $geodata->region_code;
448
+ $dataLayer['geoRegionName'] = $geodata->region_name;
449
+ $dataLayer['geoCity'] = $geodata->city;
450
+ $dataLayer['geoZipcode'] = $geodata->zip;
451
+ $dataLayer['geoLatitude'] = $geodata->latitude;
452
+ $dataLayer['geoLongitude'] = $geodata->longitude;
453
+ }
454
+ }
455
+ }
456
+ }
457
+ }
458
+
459
+ return $dataLayer;
460
+ }
461
+
462
+ function gtm4wp_wp_loaded() {
463
+ global $gtm4wp_options;
464
+
465
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_WEATHER ] || $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_MISCGEO ] ) {
466
+ $client_ip = gtm4wp_get_user_ip();
467
+ $geodata = get_transient( 'gtm4wp-geodata-' . esc_attr( $client_ip ) );
468
+
469
+ if ( false === $geodata ) {
470
+ $gtm4wp_geodata = @wp_remote_get( sprintf( 'http://api.ipstack.com/%s?access_key=%s&format=1', urlencode( $client_ip ), $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_MISCGEOAPI ] ) );
471
+
472
+ if ( is_array( $gtm4wp_geodata ) && ( 200 == $gtm4wp_geodata['response']['code'] ) ) {
473
+ $gtm4wp_geodata = @json_decode( $gtm4wp_geodata['body'] );
474
+
475
+ if ( is_object( $gtm4wp_geodata ) ) {
476
+ set_transient( 'gtm4wp-geodata-' . esc_attr( $client_ip ), $gtm4wp_geodata, 60 * 60 );
477
+
478
+ $weatherdata = get_transient( 'gtm4wp-weatherdata-' . esc_attr( $client_ip ) );
479
+ if ( false === $weatherdata && isset( $gtm4wp_geodata->latitude ) ) {
480
+
481
+ $weatherdata = wp_remote_get( 'http://api.openweathermap.org/data/2.5/weather?appid=' . $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_WEATHEROWMAPI ] . '&lat=' . $gtm4wp_geodata->latitude . '&lon=' . $gtm4wp_geodata->longitude . '&units=' . ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_WEATHERUNITS ] == 0 ? 'metric' : 'imperial' ) );
482
+
483
+ if ( is_array( $weatherdata ) && ( 200 == $weatherdata['response']['code'] ) ) {
484
+ $weatherdata = @json_decode( $weatherdata['body'] );
485
+
486
+ if ( is_object( $weatherdata ) ) {
487
+ set_transient( 'gtm4wp-weatherdata-' . esc_attr( $client_ip ), $weatherdata, 60 * 60 );
488
+ setcookie( 'gtm4wp_last_weatherstatus', 'Weather data loaded.' );
489
+ } else {
490
+ setcookie( 'gtm4wp_last_weatherstatus', 'Openweathermap.org did not return processable data: ' . var_export( $weatherdata, true ) );
491
+ }
492
+ } else {
493
+ if ( is_wp_error( $weatherdata ) ) {
494
+ setcookie( 'gtm4wp_last_weatherstatus', 'Openweathermap.org request error: ' . $weatherdata->get_error_message() );
495
+ } else {
496
+ setcookie( 'gtm4wp_last_weatherstatus', 'Openweathermap.org returned status code: ' . $weatherdata['response']['code'] );
497
+ }
498
+ }
499
+ }
500
+ } else {
501
+ setcookie( 'gtm4wp_last_weatherstatus', 'ipstack.com did not return lat-lng data: ' . var_export( $gtm4wp_geodata, true ) );
502
+ }
503
+ } else {
504
+ if ( is_wp_error( $gtm4wp_geodata ) ) {
505
+ setcookie( 'gtm4wp_last_weatherstatus', 'ipstack.com request error: ' . $gtm4wp_geodata->get_error_message() );
506
+ } else {
507
+ setcookie( 'gtm4wp_last_weatherstatus', 'ipstack.com returned status code: ' . $gtm4wp_geodata['response']['code'] );
508
+ }
509
+ }
510
+ }
511
+ }
512
+ }
513
+
514
+ function gtm4wp_get_the_gtm_tag() {
515
+ global $gtm4wp_options, $gtm4wp_datalayer_name, $gtm4wp_container_code_written;
516
+
517
+ $_gtm_tag = '
518
+ <!-- Google Tag Manager (noscript) -->';
519
+
520
+ if ( GTM4WP_PLACEMENT_OFF == $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] ) {
521
+ $gtm4wp_container_code_written = true;
522
+ }
523
+
524
+ if ( ( $gtm4wp_options[ GTM4WP_OPTION_GTM_CODE ] != '' ) && ( ! $gtm4wp_container_code_written ) ) {
525
+ $_gtm_codes = explode( ',', str_replace( array( ';', ' ' ), array( ',', '' ), $gtm4wp_options[ GTM4WP_OPTION_GTM_CODE ] ) );
526
+
527
+ if ( ( '' != $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_AUTH ] ) && ( '' != $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_PREVIEW ] ) ) {
528
+ $_gtm_env = '&gtm_auth=' . $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_AUTH ] . '&gtm_preview=' . $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_PREVIEW ] . '&gtm_cookies_win=x';
529
+ } else {
530
+ $_gtm_env = '';
531
+ }
532
+
533
+ $_gtm_domain_name = 'www.googletagmanager.com';
534
+ if ( $gtm4wp_options[ GTM4WP_OPTION_GTMDOMAIN ] != '' ) {
535
+ $_gtm_domain_name = $gtm4wp_options[ GTM4WP_OPTION_GTMDOMAIN ];
536
+ }
537
+
538
+ foreach ( $_gtm_codes as $one_gtm_code ) {
539
+ $_gtm_tag .= '
540
+ <noscript><iframe src="https://' . $_gtm_domain_name . '/ns.html?id=' . $one_gtm_code . $_gtm_env . '"
541
+ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>';
542
+ }
543
+
544
+ $_gtm_tag .= '
545
+ <!-- End Google Tag Manager (noscript) -->';
546
+
547
+ $_gtm_tag = apply_filters( GTM4WP_WPFILTER_GETTHEGTMTAG, $_gtm_tag );
548
+ $gtm4wp_container_code_written = true;
549
+ }
550
+
551
+ return $_gtm_tag;
552
+ }
553
+
554
+ function gtm4wp_the_gtm_tag() {
555
+ echo gtm4wp_get_the_gtm_tag();
556
+ }
557
+
558
+ function gtm4wp_enqueue_scripts() {
559
+ global $gtm4wp_options, $gtp4wp_plugin_url;
560
+
561
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WPCF7 ] ) {
562
+ $in_footer = apply_filters( 'gtm4wp_' . GTM4WP_OPTION_INTEGRATE_WPCF7, false );
563
+ wp_enqueue_script( 'gtm4wp-contact-form-7-tracker', $gtp4wp_plugin_url . 'js/gtm4wp-contact-form-7-tracker.js', array( 'jquery' ), GTM4WP_VERSION, $in_footer );
564
+ }
565
+
566
+ if ( $gtm4wp_options[ GTM4WP_OPTION_EVENTS_FORMMOVE ] ) {
567
+ $in_footer = apply_filters( 'gtm4wp_' . GTM4WP_OPTION_EVENTS_FORMMOVE, false );
568
+ wp_enqueue_script( 'gtm4wp-form-move-tracker', $gtp4wp_plugin_url . 'js/gtm4wp-form-move-tracker.js', array( 'jquery' ), GTM4WP_VERSION, $in_footer );
569
+ }
570
+
571
+ if ( $gtm4wp_options[ GTM4WP_OPTION_EVENTS_YOUTUBE ] ) {
572
+ require_once dirname( __FILE__ ) . '/../integration/youtube.php';
573
+ }
574
+
575
+ if ( $gtm4wp_options[ GTM4WP_OPTION_EVENTS_VIMEO ] ) {
576
+ require_once dirname( __FILE__ ) . '/../integration/vimeo.php';
577
+ }
578
+
579
+ if ( $gtm4wp_options[ GTM4WP_OPTION_EVENTS_SOUNDCLOUD ] ) {
580
+ require_once dirname( __FILE__ ) . '/../integration/soundcloud.php';
581
+ }
582
+
583
+ if ( $gtm4wp_options[ GTM4WP_OPTION_SCROLLER_ENABLED ] ) {
584
+ $in_footer = apply_filters( 'gtm4wp_' . GTM4WP_OPTION_SCROLLER_ENABLED, false );
585
+ wp_enqueue_script( 'gtm4wp-scroll-tracking', $gtp4wp_plugin_url . 'js/analytics-talk-content-tracking.js', array( 'jquery' ), GTM4WP_VERSION, $in_footer );
586
+ }
587
+ }
588
+
589
+ function gtm4wp_wp_footer() {
590
+ global $gtm4wp_options;
591
+
592
+ if ( GTM4WP_PLACEMENT_FOOTER == $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] ) {
593
+ gtm4wp_the_gtm_tag();
594
+ }
595
+ }
596
+
597
+ function gtm4wp_wp_body_open() {
598
+ global $gtm4wp_options;
599
+
600
+ if ( ( GTM4WP_PLACEMENT_BODYOPEN == $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] ) || ( GTM4WP_PLACEMENT_BODYOPEN_AUTO == $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] ) ) {
601
+ gtm4wp_the_gtm_tag();
602
+ }
603
+ }
604
+
605
+ function gtm4wp_filter_visitor_keys( $dataLayer ) {
606
+ foreach ( $dataLayer as $dl_key => $dl_value ) {
607
+ if ( strpos( $dl_key, 'visitor' ) !== false ) {
608
+ unset( $dataLayer[ $dl_key ] );
609
+ }
610
+ }
611
+
612
+ return $dataLayer;
613
+ }
614
+
615
+ /**
616
+ * GTM4WP global JS variables WordPress filter
617
+ *
618
+ * @author Vincent Koc <https://github.com/koconder/>
619
+ * @link https://github.com/duracelltomi/gtm4wp/issues/34
620
+ * @return mixed returns the
621
+ */
622
+ function gtm4wp_add_global_vars( $vars, $return = false ) {
623
+ if ( ! $return ) {
624
+ if ( function_exists( $vars ) ) {
625
+ $vars = $vars();
626
+ }
627
+ $GLOBALS['gtm4wp_datalayer_globalvars'] = $GLOBALS['gtm4wp_datalayer_globalvars'] . ' ' . $vars;
628
+ }
629
+ return $GLOBALS['gtm4wp_datalayer_globalvars'];
630
+ }
631
+
632
+ function gtm4wp_wp_header_top( $echo = true ) {
633
+ global $gtm4wp_options, $gtm4wp_datalayer_name;
634
+
635
+ $has_html5_support = current_theme_supports( 'html5' );
636
+
637
+ $_gtm_top_content = '
638
+ <!-- Google Tag Manager for WordPress by gtm4wp.com -->
639
+ <script data-cfasync="false" data-pagespeed-no-defer' . ( $has_html5_support ? ' type="text/javascript"' : '' ) . '>//<![CDATA[
640
+ var gtm4wp_datalayer_name = "' . $gtm4wp_datalayer_name . '";
641
+ var ' . $gtm4wp_datalayer_name . ' = ' . $gtm4wp_datalayer_name . ' || [];';
642
+
643
+ // Load in the global variables from gtm4wp_add_global_vars / GTM4WP_WPACTION_ADDGLOBALVARS filter
644
+ $_gtm_top_content .= apply_filters( GTM4WP_WPACTION_ADDGLOBALVARS, '', true );
645
+
646
+ if ( $gtm4wp_options[ GTM4WP_OPTION_SCROLLER_ENABLED ] ) {
647
+ $_gtm_top_content .= '
648
+
649
+ var gtm4wp_scrollerscript_debugmode = ' . ( $gtm4wp_options[ GTM4WP_OPTION_SCROLLER_DEBUGMODE ] ? 'true' : 'false' ) . ';
650
+ var gtm4wp_scrollerscript_callbacktime = ' . (int) $gtm4wp_options[ GTM4WP_OPTION_SCROLLER_CALLBACKTIME ] . ';
651
+ var gtm4wp_scrollerscript_readerlocation = ' . (int) $gtm4wp_options[ GTM4WP_OPTION_SCROLLER_DISTANCE ] . ';
652
+ var gtm4wp_scrollerscript_contentelementid = "' . $gtm4wp_options[ GTM4WP_OPTION_SCROLLER_CONTENTID ] . '";
653
+ var gtm4wp_scrollerscript_scannertime = ' . (int) $gtm4wp_options[ GTM4WP_OPTION_SCROLLER_READERTIME ] . ';';
654
+ }
655
+
656
+ $_gtm_top_content .= '
657
+ //]]>
658
+ </script>
659
+ <!-- End Google Tag Manager for WordPress by gtm4wp.com -->';
660
+
661
+ if ( ! gtm4wp_amp_running() ) {
662
+ if ( $echo ) {
663
+ echo $_gtm_top_content;
664
+ } else {
665
+ return $_gtm_top_content;
666
+ }
667
+ }
668
+ }
669
+
670
+ function gtm4wp_wp_header_begin( $echo = true ) {
671
+ global $gtm4wp_datalayer_name, $gtm4wp_datalayer_json, $gtm4wp_options, $woocommerce;
672
+
673
+ $has_html5_support = current_theme_supports( 'html5' );
674
+
675
+ $_gtm_header_content = '
676
+ <!-- Google Tag Manager for WordPress by gtm4wp.com -->
677
+ <script data-cfasync="false" data-pagespeed-no-defer' . ( $has_html5_support ? ' type="text/javascript"' : '' ) . '>//<![CDATA[';
678
+
679
+ if ( $gtm4wp_options[ GTM4WP_OPTION_GTM_CODE ] != '' ) {
680
+ $gtm4wp_datalayer_data = array();
681
+ $gtm4wp_datalayer_data = (array) apply_filters( GTM4WP_WPFILTER_COMPILE_DATALAYER, $gtm4wp_datalayer_data );
682
+
683
+ if ( $gtm4wp_options[ GTM4WP_OPTION_INCLUDE_REMARKETING ] ) {
684
+ // add Google Ads remarketing tags as suggested here:
685
+ // https://support.google.com/tagmanager/answer/3002580?hl=en
686
+ add_filter( GTM4WP_WPFILTER_COMPILE_REMARKTING, 'gtm4wp_filter_visitor_keys' );
687
+ $gtm4wp_remarketing_tags = (array) apply_filters( GTM4WP_WPFILTER_COMPILE_REMARKTING, $gtm4wp_datalayer_data );
688
+
689
+ $_gtm_header_content .= "\nvar google_tag_params = ";
690
+ $_gtm_header_content .= json_encode( $gtm4wp_remarketing_tags );
691
+ $_gtm_header_content .= ';';
692
+ $gtm4wp_datalayer_data['google_tag_params'] = '-~-window.google_tag_params-~-';
693
+ }
694
+
695
+ if ( version_compare( PHP_VERSION, '5.4.0' ) >= 0 ) {
696
+ $gtm4wp_datalayer_json = json_encode( $gtm4wp_datalayer_data, JSON_UNESCAPED_UNICODE );
697
+ } else {
698
+ $gtm4wp_datalayer_json = json_encode( $gtm4wp_datalayer_data );
699
+ }
700
+
701
+ // Clean up and then push datalayer to AMP
702
+ $gtm4wp_datalayer_json = str_replace(
703
+ array( '"-~-', '-~-"' ),
704
+ array( '', '' ),
705
+ str_replace( '–', '-', $gtm4wp_datalayer_json )
706
+ );
707
+
708
+ $_gtm_header_content .= '
709
+ var dataLayer_content = ' . $gtm4wp_datalayer_json . ';';
710
+
711
+ // fire WooCommerce order double tracking protection only if WooCommerce is active and user is on the order received page
712
+ if ( isset( $gtm4wp_options ) && ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC ] || $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) && isset( $woocommerce ) && is_order_received_page() ) {
713
+
714
+ $_gtm_header_content .= '
715
+ // if dataLayer contains ecommerce purchase data, check whether it has been already tracked
716
+ if ( dataLayer_content.transactionId || ( dataLayer_content.ecommerce && dataLayer_content.ecommerce.purchase ) ) {
717
+ // read order id already tracked from cookies
718
+ var gtm4wp_orderid_tracked = "";
719
+
720
+ if ( !window.localStorage ) {
721
+ var gtm4wp_cookie = "; " + document.cookie;
722
+ var gtm4wp_cookie_parts = gtm4wp_cookie.split( "; gtm4wp_orderid_tracked=" );
723
+ if ( gtm4wp_cookie_parts.length == 2 ) {
724
+ gtm4wp_orderid_tracked = gtm4wp_cookie_parts.pop().split(";").shift();
725
+ }
726
+ } else {
727
+ gtm4wp_orderid_tracked = window.localStorage.getItem( "gtm4wp_orderid_tracked" );
728
+ }
729
+
730
+ // check enhanced ecommerce
731
+ if ( dataLayer_content.ecommerce && dataLayer_content.ecommerce.purchase ) {
732
+ if ( gtm4wp_orderid_tracked && ( dataLayer_content.ecommerce.purchase.actionField.id == gtm4wp_orderid_tracked ) ) {
733
+ delete dataLayer_content.ecommerce.purchase;
734
+ } else {
735
+ gtm4wp_orderid_tracked = dataLayer_content.ecommerce.purchase.actionField.id;
736
+ }
737
+ }
738
+
739
+ // check app+web ecommerce
740
+ if ( dataLayer_content.ecommerce && dataLayer_content.ecommerce.items ) {
741
+ if ( gtm4wp_orderid_tracked && ( dataLayer_content.ecommerce.transaction_id == gtm4wp_orderid_tracked ) ) {
742
+ delete dataLayer_content.ecommerce.affiliation;
743
+ delete dataLayer_content.ecommerce.value;
744
+ delete dataLayer_content.ecommerce.currency;
745
+ delete dataLayer_content.ecommerce.tax;
746
+ delete dataLayer_content.ecommerce.shipping;
747
+ delete dataLayer_content.ecommerce.transaction_id;
748
+
749
+ delete dataLayer_content.ecommerce.items;
750
+ } else {
751
+ gtm4wp_orderid_tracked = dataLayer_content.ecommerce.purchase.actionField.id;
752
+ }
753
+ }
754
+
755
+ // check standard ecommerce
756
+ if ( dataLayer_content.transactionId ) {
757
+ if ( gtm4wp_orderid_tracked && ( dataLayer_content.transactionId == gtm4wp_orderid_tracked ) ) {
758
+ delete dataLayer_content.transactionId;
759
+ delete dataLayer_content.transactionDate;
760
+ delete dataLayer_content.transactionType;
761
+ delete dataLayer_content.transactionAffiliation;
762
+ delete dataLayer_content.transactionTotal;
763
+ delete dataLayer_content.transactionShipping;
764
+ delete dataLayer_content.transactionTax;
765
+ delete dataLayer_content.transactionPaymentType;
766
+ delete dataLayer_content.transactionCurrency;
767
+ delete dataLayer_content.transactionShippingMethod;
768
+ delete dataLayer_content.transactionPromoCode;
769
+ delete dataLayer_content.transactionProducts;
770
+ } else {
771
+ gtm4wp_orderid_tracked = dataLayer_content.transactionId;
772
+ }
773
+ }
774
+
775
+ if ( gtm4wp_orderid_tracked ) {
776
+ if ( !window.localStorage ) {
777
+ var gtm4wp_orderid_cookie_expire = new Date();
778
+ gtm4wp_orderid_cookie_expire.setTime( gtm4wp_orderid_cookie_expire.getTime() + (365*24*60*60*1000) );
779
+ var gtm4wp_orderid_cookie_expires_part = "expires=" + gtm4wp_orderid_cookie_expire.toUTCString();
780
+ document.cookie = "gtm4wp_orderid_tracked=" + gtm4wp_orderid_tracked + ";" + gtm4wp_orderid_cookie_expires_part + ";path=/";
781
+ } else {
782
+ window.localStorage.setItem( "gtm4wp_orderid_tracked", gtm4wp_orderid_tracked );
783
+ }
784
+ }
785
+
786
+ }';
787
+ }
788
+
789
+ $_gtm_header_content .= '
790
+ ' . $gtm4wp_datalayer_name . '.push( dataLayer_content );';
791
+ }
792
+
793
+ $_gtm_header_content .= '//]]>
794
+ </script>';
795
+
796
+ $_gtm_header_content .= apply_filters( GTM4WP_WPFILTER_AFTER_DATALAYER, '' );
797
+
798
+ if ( ( $gtm4wp_options[ GTM4WP_OPTION_GTM_CODE ] != '' ) && ( GTM4WP_PLACEMENT_OFF != $gtm4wp_options[ GTM4WP_OPTION_GTM_PLACEMENT ] ) ) {
799
+ $_gtm_codes = explode( ',', str_replace( array( ';', ' ' ), array( ',', '' ), $gtm4wp_options[ GTM4WP_OPTION_GTM_CODE ] ) );
800
+ $add_cookiebot_ignore = $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_COOKIEBOT ];
801
+
802
+ $_gtm_tag = '';
803
+ foreach ( $_gtm_codes as $one_gtm_code ) {
804
+ if ( ( '' != $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_AUTH ] ) && ( '' != $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_PREVIEW ] ) ) {
805
+ $_gtm_env = "+'&gtm_auth=" . $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_AUTH ] . '&gtm_preview=' . $gtm4wp_options[ GTM4WP_OPTION_ENV_GTM_PREVIEW ] . "&gtm_cookies_win=x'";
806
+ } else {
807
+ $_gtm_env = '';
808
+ }
809
+
810
+ $_gtm_domain_name = 'www.googletagmanager.com';
811
+ if ( $gtm4wp_options[ GTM4WP_OPTION_GTMDOMAIN ] != '' ) {
812
+ $_gtm_domain_name = $gtm4wp_options[ GTM4WP_OPTION_GTMDOMAIN ];
813
+ }
814
+
815
+ $_gtm_tag .= '
816
+ <script data-cfasync="false"' . ( $add_cookiebot_ignore ? ' data-cookieconsent="ignore"' : '' ) . '>//<![CDATA[
817
+ (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({\'gtm.start\':
818
+ new Date().getTime(),event:\'gtm.js\'});var f=d.getElementsByTagName(s)[0],
819
+ j=d.createElement(s),dl=l!=\'dataLayer\'?\'&l=\'+l:\'\';j.async=true;j.src=
820
+ \'//' . $_gtm_domain_name . '/gtm.\'' . '+\'js?id=\'+i+dl' . $_gtm_env . ';f.parentNode.insertBefore(j,f);
821
+ })(window,document,\'script\',\'' . $gtm4wp_datalayer_name . '\',\'' . $one_gtm_code . '\');//]]>
822
+ </script>';
823
+ }
824
+
825
+ $_gtm_tag .= '
826
+ <!-- End Google Tag Manager -->';
827
+
828
+ $_gtm_tag = apply_filters( GTM4WP_WPFILTER_GETTHEGTMTAG, $_gtm_tag );
829
+ $_gtm_header_content .= $_gtm_tag;
830
+ }
831
+
832
+ $_gtm_header_content .= '
833
+ <!-- End Google Tag Manager for WordPress by gtm4wp.com -->';
834
+
835
+ if ( ! gtm4wp_amp_running() ) {
836
+ if ( $echo ) {
837
+ echo $_gtm_header_content;
838
+ } else {
839
+ return $_gtm_header_content;
840
+ }
841
+ }
842
+ }
843
+
844
+ function gtm4wp_wp_login() {
845
+ setcookie( 'gtm4wp_user_logged_in', '1', 0, '/' );
846
+ }
847
+
848
+ function gtm4wp_user_register() {
849
+ setcookie( 'gtm4wp_user_registered', '1', 0, '/' );
850
+ }
851
+
852
+ function gtm4wp_user_reg_login_script() {
853
+ global $gtp4wp_plugin_url;
854
+
855
+ $in_footer = apply_filters( 'gtm4wp_user_reg_login_script', true );
856
+ wp_enqueue_script( 'gtm4wp-user-reg-login-script', $gtp4wp_plugin_url . 'js/gtm4wp-users.js', array( 'jquery' ), GTM4WP_VERSION, $in_footer );
857
+ }
858
+
859
+ function gtm4wp_rocket_excluded_inline_js_content( $pattern ) {
860
+ $pattern[] = 'dataLayer';
861
+ $pattern[] = 'gtm4wp';
862
+
863
+ return $pattern;
864
+ }
865
+
866
+ add_action( 'wp_enqueue_scripts', 'gtm4wp_enqueue_scripts' );
867
+ $gtm4wp_header_begin_prior = 10;
868
+ if ( isset( $GLOBALS['gtm4wp_options'] ) && $GLOBALS['gtm4wp_options'][ GTM4WP_OPTION_LOADEARLY ] ) {
869
+ $gtm4wp_header_begin_prior = 2;
870
+ }
871
+ add_action( 'wp_head', 'gtm4wp_wp_header_begin', $gtm4wp_header_begin_prior, 0 );
872
+ add_action( 'wp_head', 'gtm4wp_wp_header_top', 1, 0 );
873
+ add_action( 'wp_footer', 'gtm4wp_wp_footer' );
874
+ add_action( 'wp_loaded', 'gtm4wp_wp_loaded' );
875
+ add_filter( GTM4WP_WPFILTER_COMPILE_DATALAYER, 'gtm4wp_add_basic_datalayer_data' );
876
+
877
+ // to be able to easily migrate from other Google Tag Manager plugins
878
+ add_action( 'body_open', 'gtm4wp_wp_body_open' );
879
+
880
+ // compatibility with existing themes that natively support code injection after opening body tag
881
+ add_action( 'genesis_before', 'gtm4wp_wp_body_open' ); // Genisis theme
882
+ add_action( 'generate_before_header', 'gtm4wp_wp_body_open', 0 ); // GeneratePress theme
883
+ add_action( 'elementor/page_templates/canvas/before_content', 'gtm4wp_wp_body_open' ); // Elementor
884
+ add_action( 'ct_before_builder', 'gtm4wp_wp_body_open', 0 ); // Oxygen Builder
885
+ add_action( 'fl_before_builder', 'gtm4wp_wp_body_open', 0 ); // Beaver Builder Theme
886
+
887
+ // standard WP theme support for body open tags
888
+ add_action( 'wp_body_open', 'gtm4wp_wp_body_open' );
889
+
890
+ add_filter( 'rocket_excluded_inline_js_content', 'gtm4wp_rocket_excluded_inline_js_content' ); // WP Rocket
891
+ if (
892
+ isset( $GLOBALS['gtm4wp_options'] )
893
+ && (
894
+ $GLOBALS['gtm4wp_options'][ GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC ]
895
+ || $GLOBALS['gtm4wp_options'][ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ]
896
+ )
897
+ && isset( $GLOBALS['woocommerce'] )
898
+ && version_compare( WC()->version, '3.2', '>=' ) // only activate WooCommerce integration for minimum supported WooCommerce version
899
+ ) {
900
+ require_once dirname( __FILE__ ) . '/../integration/woocommerce.php';
901
+ }
902
+
903
+ if ( isset( $GLOBALS['gtm4wp_options'] ) && ( $GLOBALS['gtm4wp_options'][ GTM4WP_OPTION_INTEGRATE_GOOGLEOPTIMIZEIDS ] != '' ) ) {
904
+ require_once dirname( __FILE__ ) . '/../integration/google-optimize.php';
905
+ }
906
+
907
+ if ( isset( $GLOBALS['gtm4wp_options'] ) && ( $GLOBALS['gtm4wp_options'][ GTM4WP_OPTION_EVENTS_USERLOGIN ] ) ) {
908
+ add_action( 'wp_login', 'gtm4wp_wp_login' );
909
+ add_action( 'wp_enqueue_scripts', 'gtm4wp_user_reg_login_script' );
910
+ }
911
+
912
+ if ( isset( $GLOBALS['gtm4wp_options'] ) && ( $GLOBALS['gtm4wp_options'][ GTM4WP_OPTION_EVENTS_NEWUSERREG ] ) ) {
913
+ add_action( 'user_register', 'gtm4wp_user_register' );
914
+ add_action( 'wp_enqueue_scripts', 'gtm4wp_user_reg_login_script' );
915
+ }
readme.txt CHANGED
@@ -1,877 +1,906 @@
1
- === Google Tag Manager for WordPress ===
2
- Contributors: duracelltomi
3
- Donate link: https://gtm4wp.com/
4
- Tags: google tag manager, tag manager, gtm, google, adwords, google adwords, google ads, adwords remarketing, google ads remarketing, remarketing, google analytics, analytics, facebook ads, facebook remarketing, facebook pixel, google optimize, personalisation
5
- Requires at least: 3.4.0
6
- Requires PHP: 5.6
7
- Tested up to: 5.7
8
- Stable tag: 1.12.3
9
- License: GPLv3
10
- License URI: http://www.gnu.org/licenses/gpl.html
11
-
12
- Advanced measurement/advertising tag management and site personalisation for WordPress with Google Tag Manager and Google Optimize
13
-
14
- == Description ==
15
-
16
- Google Tag Manager (GTM) is Google's free tool for everyone to manage and deploy analytics and marketing tags as well as other code snippets
17
- using an intuitive web UI. To learn more about this tool, visit the [official website](https://www.google.com/analytics/tag-manager/).
18
-
19
- This plugin places the GTM container code snippets onto your wordpress website so that you do not need to add this manually.
20
- Multiple containers are also supported!
21
-
22
- The plugin complements your GTM setup by pushing page meta data and user information into the so called data layer.
23
- Google's official help pages includes [more details about the data layer](https://developers.google.com/tag-manager/devguide#datalayer).
24
-
25
- You can also add your Google Optimize container with the [recommended code setup](https://support.google.com/optimize/answer/7359264?hl=en)
26
-
27
- **Some parts of the plugin require PHP 5.6 newer.
28
- PHP 7.0 or newer is recommended.**
29
-
30
- Please note that PHP versions 7.2 or older already reached their end of life cycle thus it is recommended to upgrade. If you are not sure which version you are using, please contact your hosting provider for support.
31
-
32
- = GTM container code placement =
33
-
34
- The original GTM container code is divided into two parts:
35
-
36
- The first part is a javascript code snippet that is added to the `<head>` section of every page of the website.
37
- This part is critical to enable all features of GTM, and this plugin helps to place this part
38
- correctly on your site.
39
-
40
- The second part is an iframe snippet that acts as a failsafe/fallback should users' JavaScript be disabled.
41
- Google recommends – for best performance – to place this code snippet directly after the opening `<body>` tag on each page.
42
-
43
- Albeit not ideal, it will work when placed lower in the code. This plugin provides a code placement option for the second code snippet.
44
-
45
- If your WordPress theme is compatible with the additions of WordPress 5.2 then this plugin will place this second code to the right place.
46
- Users of the Genisis theme, GeneratePress theme, Elementor, Oxygen Builder and Beaver Builder Theme will also have this placed correctly.
47
- To utilize this, use the "Codeless" placement option.
48
-
49
- All other users can place this second code snippet using a custom PHP code ("Custom" placement option) or select the so called "Footer" option to
50
- add the code lower in the code (it is not the recommended way but will work)
51
-
52
-
53
- = Basic data included =
54
-
55
- * post/page titles
56
- * post/page dates
57
- * post/page category names
58
- * post/page tag names
59
- * post/page author ID and name
60
- * post/page ID
61
- * post types
62
- * post count on the current page + in the current category/tag/taxonomy
63
- * custom terms associated with any post type
64
- * logged in status
65
- * logged in user role
66
- * logged in user ID (to track cross device behaviour in Google Analytics)
67
- * logged in user email address (to comply with [GTM terms of service](https://www.google.com/analytics/tag-manager/use-policy/) do not pass this on to Google tags)
68
- * logger in user creation date
69
- * site search data
70
- * site name and id (for WordPress multisite instances)
71
- * IP address of the visitor (please use the explicit consent of the visitor to utilize this)
72
-
73
- = Browser / OS / Device data =
74
-
75
- * browser data (name, version, engine)
76
- * OS data (name, version)
77
- * device data (type, manufacturer, model)
78
-
79
- Data is provided using the WhichBrowser library: http://whichbrowser.net/
80
-
81
- = Weather data =
82
-
83
- (beta)
84
-
85
- Push data about users' current weather conditions into the dataLayer. This can be used to generate weather-related
86
- audience/remarketing lists on ad platforms and allows for user segmentation in your web analytics solutions:
87
-
88
- * weather category (clouds, rain, snow, etc.)
89
- * weather description: more detailed data
90
- * temperature in Celsius or Fahrenheit
91
- * air pressure
92
- * wind speed and degrees
93
-
94
- Weather data is queried from Open Weather Map. Depending on your websites traffic, additional fees may apply:
95
- http://openweathermap.org/price
96
-
97
- An (free) API key from OpenWeatherMap is required for this feature to work.
98
-
99
- ipstack.com is used to determine the site visitor's location. A (free) API key from IPStack.com is required for this feature to work:
100
- https://ipstack.com/product
101
-
102
- = Media player events =
103
-
104
- (experimental)
105
-
106
- Track users' interaction with any embedded media:
107
-
108
- * YouTube
109
- * Vimeo
110
- * Soundcloud
111
-
112
- DataLayer events can be chosen to fire upon media player load, media is being played, paused/stopped and optionally when
113
- the user reaches 10, 20, 30, ..., 90, 100% of the media duration.
114
-
115
- Tracking is supported for embedded media using the built-in oEmbed feature of WordPress as well as most other media plugins
116
- and copy/pasted codes. Players injected into the website after page load are not currently supported.
117
-
118
- = Scroll tracking =
119
-
120
- Fire tags based on how the visitor scrolls from the top to the bottom of a page.
121
- An example would be to separate "readers" (who spend a specified amount of time on a page) from "scrollers"
122
- (who only scroll through within seconds). You can use these events to fire Analytics tags and/or remarketing/conversion tags
123
- (for micro conversions).
124
-
125
- Scroll tracking is based on the solution originally created by
126
-
127
- * Nick Mihailovski
128
- * Thomas Baekdal
129
- * Avinash Kaushik
130
- * Joost de Valk
131
- * Eivind Savio
132
- * Justin Cutroni
133
-
134
- Original script:
135
- http://cutroni.com/blog/2012/02/21/advanced-content-tracking-with-google-analytics-part-1/
136
-
137
- = Google Ads remarketing =
138
-
139
- Google Tag Manager for WordPress can add each dataLayer variable as a Google Ads remarketing custom parameter list.
140
- This enables you to build sophisticated remarketing lists.
141
-
142
- NOTE: the current implementation can be used to populate Google ads in an old fashioned way, codes will be updated soon in this plugin.
143
-
144
- = Blacklist & Whitelist Tag Manager tags, triggers and variables =
145
-
146
- To increase website security, you have the option to white- and blacklist tags/triggers/variables.
147
- You can prevent specific tags from firing or the use of certain variable types regardless of your GTM setup.
148
-
149
- If the Google account associated with your GTM account is being hacked, an attacker could easily
150
- execute malware on your website without accessing its code on your hosting server. By blacklisting custom HTML tags
151
- and/or custom JavaScript variables you can secure the Tag Manager container.
152
-
153
- = Integration =
154
-
155
- Google Tag Manager for WordPress integrates with several popular plugins. More integration to come!
156
-
157
- * Contact Form 7: fire an event upon successful form submission
158
- * WooCommerce:
159
- * Classic e-commerce (deprecated):
160
- * fire an event when visitors add products to their cart
161
- * capture transaction data to be passed to your ad platforms and/or Analytics
162
- * capture necessary remarketing parameters for Google Ads Dynamic Remarketing
163
- * Enhanced e-commerce:
164
- * implementation of [Enhanced E-commerce GA3](https://developers.google.com/tag-manager/enhanced-ecommerce)
165
- * implementation of [Enhanced E-commerce GA4](https://developers.google.com/tag-manager/ecommerce-ga4)
166
- * Does not support promotions since WooCommerce does not have such a feature (yet)
167
- * Does not support refunds
168
-
169
- == Installation ==
170
-
171
- 1. Upload `duracelltomi-google-tag-manager-for-wordpress` to the `/wp-content/plugins/` directory
172
- 1. Activate the plugin through the 'Plugins' menu in WordPress
173
- 1. Go to Settings / Google Tag Manager and enter your Google Tag Manager container ID and set additional options
174
-
175
- == Frequently Asked Questions ==
176
-
177
- = How can I ... =
178
-
179
- Tutorials for various Google Tag Manager settings and implementation are available on my website:
180
- https://gtm4wp.com/how-to-articles/
181
-
182
- = PayPal / 3rd party payment gateway transactions in WooCommerce are not being tracked in Google Analytics =
183
-
184
- PayPal and some other 3rd party payment gateways do not redirect users back to your website upon successful transaction by default.
185
- It offers the route back for your customer but it can happen that users close the browser before arriving at your thankyou page
186
- (aka. order received page). This means that neither Google Analytics tags or any other tags have the chance to fire.
187
-
188
- Enable auto-return in your payment gateway settings. This will instruct them to show a quick info page after payment
189
- and redirect the user back to your site. This will improve the accuracy and frequency of tracked transactions.
190
-
191
- = Why isn't there an option to blacklist tag/variable classes =
192
-
193
- Although Google recommends to blacklist tags and variables using classes, people struggle to know
194
- which tags/variables gets affected. Therefore I opted for individual tags and variables rather than classes
195
- on the blacklist tabs.
196
-
197
- Regarding variables; ensure they are not part of any critical tags as blacklisting such variables will render said tags useless.
198
-
199
- = How can I track scroll events in Google Tag Manager? =
200
-
201
- Google Tag Manager supports basic scroll depth tracking based on percentage or pixels natively. This plugin adds
202
- additional scroll tracking events, more focused on capturing the users' intent and/or engagement.
203
-
204
- There are five dataLayer events you can use in your rule definitions:
205
-
206
- * gtm4wp.reading.articleLoaded: the content has been loaded
207
- * gtm4wp.reading.startReading: the visitor started to scroll. The `timeToScroll` dataLayer variable stores duration since the article loaded (in seconds)
208
- * gtm4wp.reading.contentBottom: the visitor reached the end of the content (not the page!). `timeToScroll` dataLayer variable updated
209
- * gtm4wp.reading.pagebottom: the visitor reached the end of the page. `timeToScroll` dataLayer variable updated
210
- * gtm4wp.reading.readerType: based on time spent since article loaded we determine whether the user is a 'scanner' or 'reader' and store this in the `readerType` dataLayer variable
211
-
212
- Example use cases: using these events as triggers, you can fire Google Universal Analytics and/or Google Ads remarketing/conversion tags
213
- to report micro conversions and/or to serve ads only to visitors who spend more time reading your content.
214
-
215
- = Can I exclude certain user roles from being tracked? =
216
-
217
- This is easily managed through GTM itself. If you want to exclude logged in users or users with certain user roles,
218
- use the corresponding dataLayer variable (visitorType) and an exclude filter in Google Tag Manager.
219
-
220
- https://gtm4wp.com/how-to-articles/how-to-exclude-admin-users-from-being-tracked/
221
-
222
- == Screenshots ==
223
-
224
- 1. Admin panel
225
- 2. Basic settings
226
- 3. Events
227
- 4. Integration panel
228
- 5. Advanced settings
229
- 6. Scroll tracking
230
-
231
- == Changelog ==
232
-
233
- = 1.12.3 =
234
-
235
- No new or updated functionality, but updated WooCommerce compatibility.
236
-
237
- IMPORTANT!
238
- If you are using the WooCommerce integration and enhanced ecommerce, please update your ecommerce event trigger to include gtm4wp.orderCompletedEEC as well.
239
- https://gtm4wp.com/how-to-articles/how-to-setup-enhanced-ecommerce-tracking
240
-
241
- = 1.12.2 =
242
-
243
- If you are upgrading from 1.11.x, please read the previous changelog entry for v1.12
244
-
245
- * Fixed: error message in WooCommerce integration on PHP 8 hosts
246
- * Fixed: PHP notice about non existing blacklist-enable array key
247
-
248
- = 1.12.1 =
249
-
250
- If you are upgrading from 1.11.x, please read the previous changelog entry for v1.12
251
-
252
- * Fixed: PHP notice while saving admin options
253
-
254
- = 1.12 =
255
-
256
- WARNING!
257
- If you are using the blacklist/whitelist feature of the plugin, review these options after upgrade as they could break because of a fundamental rework of this feature.
258
-
259
- * Added: support for Google Analytics 4 version of ecommerce data layer
260
- * Fixed: safer IP address validation in geo and weather data features
261
- * Updated: removed deprecated events: download links, email links, social links -> such can be now tracked with native Google Tag Manager triggers
262
- * Updated: removed support for WooCommerce versions before v3.2
263
- * Updated: 'Blacklist tags' tab renamed to 'Security'
264
- * Updated: complete rework of blacklist/whitelist feature to use the latest tag/trigger/variable list of Google
265
- * Deprecated: classic ecommerce tracking will be removed later this year, please upgrade to enhanced ecommerce tracking
266
- * Deprecated: standard Google Ads remarketing variable will be removed soon as the Google Ads remarketing tag template can easily use any of your Google Tag Manager variables
267
- * Deprecated: the old fashioned way of using Google Ads remarketing with the ecomm_ prefixed data layer variables will be removed soon. Instructions for upgrade will be published on gtm4wp.com once this feature gets updated in an upcoming plugin version
268
-
269
- = 1.11.6 =
270
-
271
- * Fixed: do not track hidden products in the cart in WooCommerce shops
272
- * Fixed: do not fire add to cart event if button is in a disabled state
273
- * Fixed: fixed translation of an admin text
274
- * Fixed: needs_shipping_address() calls were sometimes broken in WooCommerce shops, added additional checks to prevent
275
- * Updated: removed the body_class method of adding the iframe/noscript container code (page builders and the standard wp_body_open hook remains supported)
276
-
277
- = 1.11.5 =
278
-
279
- * Fixed: new Google Optimize container ID format accepted now
280
-
281
- = 1.11.4 =
282
-
283
- * Fixed: fire gtm4wp.checkoutStepEEC and gtm4wp.checkoutOptionEEC events if there is only one shipping method available and it is hidden from the user
284
- * Fixed: decrease checkout step numbers 3 and 4 if shipping destination is set to 'Force shipping to the customer billing address' in WooCommerce. This way there will be no gap in Checkout behaviour report in Google Analytics.
285
- * Updated: tested version number for WooCommerce
286
-
287
- = 1.11.3 =
288
-
289
- * Fixed: use var_export instead of var_dump in some debug code,
290
- * Fixed: apply WooCommerce option for tax inclusion on the order received page as well
291
- * Fixed: JavaScript errors in Vimeo player
292
- * Updated: do not add type attribute to script elements if theme suppors HTML5
293
- * Updated: tested version numbers for WordPress and WooCommerce
294
-
295
- = 1.11.2 =
296
-
297
- WARNING!
298
- If you are upgrading directly from v1.10.x, please read the changelog of v1.11 since it includes many important notices!
299
-
300
- No change in plugin code, WP.org deployment of v1.11.1 included wrong directories
301
-
302
- = 1.11.1 =
303
-
304
- WARNING!
305
- If you are upgrading directly from v1.10.x, please read the changelog of v1.11 since it includes many important notices!
306
-
307
- * Fixed: PHP notice about undefined order_items variable if the new 'Order data in data layer' is turned off
308
- * Fixed: PHP notice about missing brand array key if no brand taxonomy is selected in GTM4WP options
309
-
310
- = 1.11 =
311
-
312
- WARNING!
313
- Please read the changelog very carefully as there are many important changes and removed features which could need your attention before updating!
314
-
315
- * Added Oxygen Builder and Beaver Builder Theme support - you can now use the codeless placement option without issues
316
- * Added ability to fix the Google Tag Manager ID and GTM Environment parameters in wp-config.php. To use it, create PHP constants with the names
317
- ** GTM4WP_HARDCODED_GTM_ID
318
- ** GTM4WP_HARDCODED_GTM_ENV_AUTH
319
- ** GTM4WP_HARDCODED_GTM_ENV_PREVIEW
320
- * Added support for WooCommerce Grouped Products
321
- * Added new WooCommerce option to add all order data into the data layer on the order reveived page
322
- ** This includes personal data of the customer -> you need to ensure this is used in a privacy friendly and compliant way!
323
- ** This order data will be always present on the order received page, even if the page is reloaded or later revisited!
324
- * Removed several unofficial data layer variables on the WooCommerce order received page as they can be read using the new order data option
325
- ** transactionDate
326
- ** transactionType
327
- ** transactionPaymentType
328
- ** transactionShippingMethod
329
- ** transactionPromoCode
330
- * Improved: price reporting with the WooCommerce enhanced ecommerce integration now follows the option set with the 'Display prices in the shop' option of WooCommerce
331
- * Improved: from WooCommerce 3.7 WC_Abstract_Order::get_used_coupons() was replaced with WC_Abstract_Order::get_coupon_codes() which is now used if WC 3.7+ is detected
332
- * Improved: use localStorage for WooCommerce duplicate transaction tracking prevention if available. Should be work with Safari at least for now.
333
- * Fixed: WooCommerce duplicate transaction tracking prevention's cookie was set to expire on session end, now adds 1 year.
334
- * Deprecated data layer variable productIsVariable. Use the new productType data layer variable which will equal to simple, variable, grouped or external depending on the type of the product shown
335
- * Fixed: Wrong lookup for product brand name if Use SKU instead of product ID option was turned on
336
- * Fixed: Wrong lookup for product brand name for variable products
337
- * Fixed: check if $woo->customer is initialized
338
- * Fixed: no checkout step reported on WooCommerce checkout page if the user has accepted the default selection of the payment and shipping methods
339
-
340
- ! Planned deprecation of support for WooCommerce 2.x-3.1.x with next plugin version !
341
- ! Planned deprecation of support for WordPress 4.x with next plugin version !
342
-
343
- = 1.10.1 =
344
-
345
- * Fixed: wrong cookie name was used with the newly introduced double transaction tracking protection while setting the cookie
346
- * Fixed: double transaction tracking JavaScript code is now only included on the order received page
347
- * Fixed: product impressions not properly reported if Products per impressions were set to 0
348
- * Fixed: replaced all references to AdWords to Google Ads
349
-
350
- = 1.10 =
351
-
352
- * Added: Automatically add the noscript part of the container code after the opening body tag for WordPress 5.2+ sites where themes support the new wp_body_open action
353
- * Added: add associated taxonomy values for post type
354
- * Added: select brand taxonomy for WooCommerce products to populate "Product brand" dimension in enhanced ecommerce
355
- * Added: add cart content into data layer so that you can personalize your site experience using Google Optimize
356
- * Added: option to remove shipping costs from revenue data on order received page of WooCommerce
357
- * Added: if you enable either enhanced ecommerce or just Google Ads remarketing variables, 3 new data layer variables will be also available about the product on a detail page
358
- * Product rating details (productRatingCounts)
359
- * Average product rating (productAverageRating)
360
- * Review count (productReviewCount)
361
- * Added: if you are using Cloudflare, you can now add the country code HTTP header value into the data layer and read from it with the geoCloudflareCountryCode variable name
362
- * Fixed: better compatibility with Google's mod_pagespeed
363
- * Fixed: missing product quantity while adding a variable product into the cart
364
- * Fixed: prevent multiple tracking of WooCommerce orders on mobile devices where the mobile browser reloads the order received page from local cache executing GTM tracking again
365
-
366
- = 1.9.2 =
367
-
368
- * Fixed: possible PHP warning if geo data or weather data feature is turned on
369
-
370
- = 1.9.1 =
371
-
372
- * Fixed: handle out of quota cases with ipstack queries properly
373
- * Fixed: proper YouTube tracking for WordPress sites and WordPress multisites installed in a subdirectory
374
- * Fixed: properly detect client IP address and also properly escape this data while using it
375
- * Fixed: WooCommerce checkout steps after page load did not include products in the cart
376
- * Fixed: checkout step events for payment mode and shipping type not always fired
377
- * Fixed: the CMD on Mac will be treated just like the Ctrl key on Windows while processing the product click event in the WooCommerce integration (thy for luzinis)
378
- * Fixed: add currencyCode to every ecommerce action in WooCommerce integration
379
- * Fixed: better WooCommere Quick View integration
380
- * Fixed: possible cross site scripting vulnerability if site search tracking was enabled due to not properly escaped referrer url tracking
381
- * Changed: code cleanup in WooCommerce integration
382
-
383
- = 1.9 =
384
-
385
- * Added: initial support for AMP plugin from Automattic (thx koconder for the contribution!)
386
- * Added: option to remove tax from revenue data on order received page of WooCommerce
387
- * Added: WooCommerce enhanced ecommerce datasets now include stock levels
388
- * Added: new productIsVariable data layer variable is set to 1 on variable WooCommerce product pages
389
- * Added: product impressions can now be split into multiple chunks to prevent data loss on large product category and site home pages (thx Tim Zook for the contribution!)
390
- * IMPORTANT! You will need to update your GTM setup, please read the new Step 9 section of the [setup tutorial page](https://gtm4wp.com/how-to-articles/how-to-setup-enhanced-ecommerce-tracking).
391
- * Added: you can now disable flagging of WooCommerce orders as being already tracked once. In same cases (with iDeal for example) you may need this to make purchase tracking to work.
392
- * Added: uninstalling the plugin will now remove configured plugin options from database
393
- * Added: new advanced plugin option: data layer variable visitorDoNotTrack will include 1 if the user has set the [do not track flag](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/DNT) in his/her browser
394
- * Added: new data layer event when a user has logged in on the frontend: gtm4wp.userLoggedIn
395
- * Added: new data layer event when a new user has registered on the frontend: gtm4wp.userRegistered
396
- * Added: new advanced plugin option: move data layer declaration and Google Tag Manager container as close as possible to the beginning of the HTML document
397
- * Added: better WP Rocket support
398
- * Updated: Full Google Optimize support. Now the plugin can load your Google Optimize container with the [recommended code placement](https://support.google.com/optimize/answer/7359264?hl=en)
399
- * Updated: moved most of the inline JavaScript codes into separate .js files which should help cache plugins to do their job much better when my plugin is active
400
- * Fixed: wrong ecomm_pagetype on product search result pages
401
- * Fixed: PHP notice in some cases when geo data was not loaded properly
402
- * Fixed / Added: freegeoip.net was rebranded to ipstack.com and an API key is needed now even for free usage. You can now add your API key so that weather data and geo data can be added into the data layer
403
- * Warning: some plugin features will be remove from v1.10, most of them can be tracked now using pure Google Tag Manager triggers:
404
- * Social actions
405
- * Outbound link click events
406
- * Download click events
407
- * Email click events
408
- * Warning: PHP 5.6 is now the minimum recommended version to use this plugin. I advise to move to PHP 7.x
409
-
410
- = 1.8.1 =
411
-
412
- * Added: new visitorIP data layer variable to support post-GDPR implementations where for example internal traffic exclusion has to be made inside the browser
413
- * Fixed: JavaScript error around the variable gtm4wp_use_sku_instead
414
- * Fixed: added _ as a valid character for gtm_auth GTM environment variable
415
- * Fixed: corrected typo - gtm4wp.checkoutStepE**E**C
416
- * Fixed: two strings were not recognized by WordPress Translate on the admin page
417
- * Fixed: some other plugins call found_variation event of WooCommerce without product variation data being included
418
- * Fixed: product name included variation name on order received page which broke GA product reports
419
- * Fixed: in some cases, no contact form 7 data was being passed to the gtm4wp.contactForm7Submitted event
420
- * Updated: added CDATA markup around container code for better DOM compatibility
421
- * Updated: removed 'SKU:' prefix text from classic ecommerce dimension as it broke some enhanced ecommerce reports
422
-
423
- = 1.8 =
424
-
425
- * Fixed: weather data tracking codes could result in fatal PHP error
426
- * Fixed: cart events did to fire while user pressed the Enter key in quantity fields
427
- * Fixed: contact form 7 changed some code which prevented successful form submission tracking
428
- * Changed: links to plugin website updated
429
- * Changed: gtm4wp.cf7formid data layer variable now includes the ID of the form in WordPress
430
- * Added: gtm4wp.cf7inputs includes data that has been filled in the form
431
- * Added: [WooCommerce compatibility headers](https://docs.woocommerce.com/document/create-a-plugin/#section-10)
432
- * Added: admin warning for WooCommerce 2.x users. This plugin will drop support for WooCommerce 2.x soon
433
- * Added: postFormat data layer variable on singular pages
434
- * Added: customer* data layer variables with stored billing and shipping data, total number of orders and total value of those orders (needs WooCommerce 3.x)
435
- * Added: geo* data layer variables to get country, city, lat-lon coordinates of the visitor
436
- * Added: visitorUsername data layer variable with the username of the logged in user
437
- * Added: more detailed checkout reporting for WooCommerce sites
438
- * Add gtm4wp.checkoutStepEEC to your Ecommerce Helper trigger
439
- * Change a typo: gtm4wp.checkoutOptionE**C**C => gtm4wp.checkoutOptionE**E**C
440
- * Added: option to include full product category path in enhanced ecommerce reporting (can cause performance issues on large sites!)
441
- * Added: initial support for [Google Tag Manager Environments](https://support.google.com/tagmanager/answer/6311518?hl=en)
442
- * Added: support for [WooCommerce Quick View plugin](https://woocommerce.com/products/woocommerce-quick-view/)
443
- * Updated: description of code placement options to clarify what this option does
444
- * Updated: cleanup of readme.txt, spelling and grammar improvements
445
- * Updated: bundled WhichBrowser lib v2.0.32
446
-
447
-
448
- = 1.7.2 =
449
-
450
- * Fixed: in some cases, the remove item from cart link in a WooCommerce cart was not altered properly with additional tracking codes
451
- * Fixed: product categories were empty in the cart, on the checkout pages and on the order received page for product variations
452
- * Fixed: checkout option data included checkout step #1 if cart page was setup to be the first
453
- * Fixed: even more WooCommerce 3.x compatibility
454
- * Added: registration date of the logged in user can be added to the data layer
455
- * Updated: geoplugin.net has been replaced by freegeoip.net for weather tracking which has far better quota for free usage
456
- * Updated: Google Ads dynamic remarketing data layer items on a WooCommerce product page will be shown for the root product as well on variable product pages
457
- * Updated: Selecting a product variation will include the price of the product in Google Ads dynamic remarketing data layer items
458
- * Updated: minor code cleanup
459
-
460
- = 1.7.1 =
461
-
462
- * Fixed: PHP 5.3 compatible syntax in frontend.php
463
- * Fixed: PHP error using classic ecommerce with WooCommerce 2.6.x
464
- * Updated: Added data-cfasync='false' to all <script> elements to prevent CloudFlare to load scripts async
465
- * Added: Warning for users of PHP 5.4 or older to consider upgrade (FYI: PHP 5.5 and older versions do not get even security fixes)
466
-
467
- = 1.7 =
468
-
469
- * Updated: even better WooCommerce 3.0 compatibility (WooCommerce 2.6 still supported but this support ends with the next plugin version)
470
- * Fixed: properly escaping product category name on variable product detail pages
471
- * Fixed: proper data layer stucture in the gtm4wp.changeDetailViewEEC event
472
- * Added: Google Optimize page hiding snippet under Integrations tab
473
- * Added: add to cart data for WooCommerce enhanced ecommerce tracking if user undos a cart item removal (no need to update GTM tags)
474
- * Added: you can now enter a product ID prefix so that IDs can match with IDs in some product feeds generated by other plugins
475
- * Added: option to track cart page as step 1 in enhanced ecommerce checkout funnel
476
-
477
- = 1.6.1 =
478
-
479
- * Fixed: PHP warning message on WooCommerce cart page
480
- * Fixed: Better compatibility with WooCommerce 2.6.x :-)
481
-
482
- = 1.6 =
483
-
484
- * Fixed: do not block product list item clicks if ad blocker is enabled
485
- * Fixed: only track product clicks in product lists if link points to the product detail page URL
486
- * Fixed: PHP warning in backlogs 'Undefined variable: gtm4wp_options'
487
- * Added: product variation support in WooCommerce integration (enhanced ecommerce implementations should add the GTM event gtm4wp.changeDetailViewEEC to the ecommerce event trigger)
488
- * Updated: better WooCommerce 3.0 compatibility
489
-
490
- = 1.5.1 =
491
-
492
- * Fixed: clicks on products in product list pages redirected to undefined URLs with some themes.
493
-
494
- = 1.5 =
495
-
496
- Lots of WooCommerce ecommerce codes has been changed and extended, please double check your measurement after upgrading to this version!
497
-
498
- * Added: warning message if you are using PHP 5.3 or older. Browser/OS/Device tracking needs 5.4 or newer
499
- * Added: Email address of the logged in user into the visitorEmail dataLayer variable. Remember: to comply with GTM TOS you are not allowed to pass this data towards any Google tag but you can use this in any other 3rd party tag.
500
- * Added: gtm4wp_eec_product_array WordPress filter so that plugin and theme authors can add their own data for enhanced ecommere product arrays
501
- * Fixed: JavaScript error in WooCommerce stores when enhanced ecommerce enabled and a product being clicked in a widget area
502
- * Fixed: Order data not present in some cases on the order received page
503
- * Changed: Extended "User SKUs instead of IDs for remarketing" option to be also applied to ecommerce product data arrays
504
- * Changed: Use wc_clean instead of the deprecated function woocommerce_clean
505
- * Changed: New, divided GTM container implemented - a fixed part in the <head> and an iframe part placed using the container placement option you've set earlier
506
-
507
- = 1.4 =
508
-
509
- * Fixed: WP CLI error message
510
- * Fixed: wrong dynamic remarketing tagging on cart and checkout pages
511
- * Updated: WhichBrowser library to 2.0.22
512
- * Updated: slightly changed container code snippet to prevent W3 Total Cache to alter the code which breaks proper code execution
513
- * Updated: replaced file_get_contents() usage in weather tracking to wp_remote_get() so that it is more compatible with several WP instances
514
- * Updated: YouTube/Video/Soundcloud tracking now tracks videos not embedded using oEmbed (like videos in a widget area)
515
- * Updated: new Vimeo Player API implemented which should solve several issues
516
- * Changed: adapted W3C HTML5 media player event names which changes some events (needs updating your existing GTM setup):
517
- * Soundcloud: finish => ended, seek => seeked
518
- * YouTube: playing => play, paused => pause, playback-rate-change => ratechange
519
- * Vimeo: seek => seeked
520
- * Added: new placement option - 'off'. This will only generate the data layer but you will need to add the proper GTM container code snippet by hand
521
- * Added: new data layer variable: authorID
522
- * Added: new data layer variable: siteID to be able to track based on blog ID in a multisite environment
523
- * Added: new data layer variable: siteName to be able to track in a multisite environment
524
-
525
- = 1.3.2 =
526
-
527
- * Fixed: remove cart event not fired in WooCommerce 2.6
528
- * Fixed: ecomm_prodid.push error message on product detail pages
529
- * Fixed: proper tracking of cart actions on the cart page for WooCommerce 2.6
530
- * Fixed: 'Illegal string offset' errors in some cases in the cart
531
- * Fixed: OpenWeatherMap requires a (free) API key now, you can now enter this to use weather data in data layer
532
-
533
- = 1.3.1 =
534
-
535
- * Fixed: "json_encode() expects parameter 2 to be long, string given" on PHP 5.3 instances
536
- * Fixed: Fatal PHP error in cart if you enabled taxes to be included in your cart
537
-
538
- = 1.3 =
539
-
540
- Major changes to the Enhanced Ecommerce implementation of the WooCommerce integration!
541
-
542
- * Fixed: proper tracking of list positions
543
- * Fixed: opening product detail page in a new window/tab when user pressed the CTRL key
544
- * Fixed: ecomm_totalvalue included the total price of the cart without taxes
545
- * Fixed: ecomm_totalvalue does not take into account the quantity of ordered products on the order received page
546
- * Fixed: php error message on product lists when Google Ads dynamic remarketing was enabled on WooCommerce 2.6
547
- * Fixed: added data-cfasync="false" to the GTM container code for better compatibility with CloudFlare
548
- * Added: introducing tracking of list names (general product list, recent products list, featured products list, etc.)
549
- * Some list names (like cross-sells) will be shown as 'General Product List'. A proposed change in WooCommerce 2.6 will solve that issue
550
- * Added: tracking product lists in widgets
551
- * Added: tracking checkout options (payment and shipment)
552
- * Updated: better add-to-cart / remove-from-cart management in mini cart and while updating cart content
553
- * Updated: added currency code to each enhanced ecommerce call so that currency reporting is OK for multi currency sites
554
- * Updated: replaced usage of get_currentuser() to keep compatibility with WordPress 4.5
555
-
556
- = 1.2 =
557
-
558
- * Fixed: subtabs on admin page now showing in certain cases
559
- * Fixed: error message when running the site using WP CLI (thanks Patrick Holberg Hesselberg)
560
- * Fixed: some typos on admin page
561
- * Fixed: dismissable notices did not disappear in some cases
562
- * Fixed: tracking of Twitter event cased sometimes JS errors
563
- * Fixed: site search tracking caused sometimes PHP errors when HTTP_REFERER was not set
564
- * Updated: preparation for translate.wordpress.org
565
- * Added: support for multiple container IDs
566
- * Added: added form ID when sending a Contact Form 7 form. Variable name: gtm4wp.cf7formid
567
-
568
- = 1.1.1 =
569
-
570
- * Fixed: PHP errors in frontend.php and admin.php
571
-
572
- = 1.1 =
573
-
574
- * Added: track embedded YouTube/Vimeo/Soundcloud videos (experimental)
575
- * Added: new checkbox - use product SKU for Google Ads Dynamic Remarketing variables instead of product ID (experimental)
576
- * Added: place your container code after the opening body tag without modifying your theme files (thx Yaniv Friedensohn)
577
- * Added: automatic codeless container code injection for Genesis framework users
578
- * Fixed: Possible PHP error with custom payment gateway (QuickPay) on the checkout page (thx Damiel for findig this)
579
-
580
- = 1.0 =
581
-
582
- The plugin itself is now declared as stable. This means that it should work with most WordPress instances.
583
- From now on each version will include features labeled as:
584
-
585
- * Beta: the feature has been proven to work for several users but it can still have some bugs
586
- * Experimental: new feature that needs proper testing with more users
587
- * Deprecated: this feature will be removed in a future version
588
-
589
- If you see any issue with beta or experimental functions just disable the checkbox. Using this error messages should disappear.
590
- Please report all bugs found in my plugin using the [contact form on my website](https://gtm4wp.com/contact).
591
-
592
- * Fixed: wrong GTM container code when renaming default dataLayer variable name (thx Vassilis Papavassiliou)
593
- * Fixed: Enhanced Ecommerce product click data was "undefined" in some cases (thx Sergio Alen)
594
- * Fixed: wrong user role detection while adding visitorType to the dataLayer (thx Philippe Vachon-Rivard)
595
- * Changed: only add visitorId to the dataLayer if there is a logged in user
596
- * Added: feature labels so that you can see beta, experimental and deprecated features
597
- * Deprecated: outbound click, email click and download click events. You should use GTM trigger events instead
598
-
599
- = 0.9.1 =
600
-
601
- * Fixed: PHP error message: missing get_shipping function using WooCommerce 2.3.x
602
-
603
- = 0.9 =
604
-
605
- * Added: visitorId dataLayer variable with the ID of the currently logged in user to track userID in Google Analytics
606
- * Added: WordPress filter hook so that other templates and plugins can get access to the GTM container code before outputting it
607
- * Fixed: 'variation incorrect' issue by Sharken03
608
- * Fixed: error messages in WooCommerce integration when product has no categories
609
- * Fixed: add_inline_js errors in newer versions of WooCommerce
610
- * Fixed: error message when some device/browser/OS data could not be set
611
- * Fixed: tracking Twitter events was broken
612
-
613
- = 0.8.2 =
614
-
615
- * Fixed: broken links when listing subcategories instead of products (thanks Jon)
616
- * Fixed: wheather/weather typo (thanks John Hockaday)
617
- * Fixed: wrong usage of get_the_permalink() instead of get_permalink() (thanks Szepe Viktor)
618
-
619
- = 0.8.1 =
620
-
621
- * Fixed: PHP error in enhanced ecommerce implementation when using layered nav widget
622
-
623
- = 0.8 =
624
-
625
- * Updated: Added subtabs to the admin UI to make room for new features :-)
626
- * Updated: WhichBrowser library to the latest version
627
- * Added: You can now dismiss plugin notices permanently for each user
628
- * Added: weather data. See updated plugin description for details
629
- * Added: Enhanced E-commerce for WooCommerce (experimental!)
630
- * Fixed: PHP notice in frontend.php script. Credit to Daniel Sousa
631
-
632
- = 0.7.1 =
633
-
634
- * Fixed: WooCommerce 2.1.x compatibility
635
-
636
- = 0.7 =
637
-
638
- * Updated/Fixed: dataLayer variables are now populated at the end of the head section. Using this the container code can appear just after the opening body tag, thus Webmaster Tools verification using Tag Manager option will work
639
- * Added: blacklist or whitelist tags and macros to increase security of your Tag Manager setup
640
-
641
-
642
- = 0.6 =
643
-
644
- * Updated: better add-to-cart events for WooCommerce, it includes now product name, SKU and ID
645
- * Added: browser, OS and device data to dataLayer variables
646
- * Added: postCountOnPage and postCountTotal dataLayer variables to track empty categories/tags/taxonomies
647
-
648
- = 0.5.1 =
649
-
650
- * Fixed: WooCommerce integration did not work on some environments
651
-
652
- = 0.5 =
653
- * Added: scroll tracking
654
- * Fixed: social tracking option on the admin panel was being shown as an edit box instead of a checkbox
655
- * Fixed: WooCommerce transaction data was not included in the dataLayer if you selected "Custom" code placement
656
- * Fixed: do not do anything if you enabled WooCommerce integration but did not activate WooCommerce plugin itself
657
- * Updated: do not re-declare dataLayer variable if it already exists (because another script already created it before my plugin was run)
658
-
659
- = 0.4 =
660
- * Added: you can now select container code placement. This way you can insert the code snippet after the opening body tag. Please read FAQ for details
661
- * Added: initial support for social event tracking for Facebook and Twitter buttons. Please read FAQ for details
662
- * Updated: event name on successful WooCommerce transaction: OrderCompleted -> gtm4wp.orderCompleted
663
- * Fixed: frontend JS codes did not load on some WordPress installs
664
-
665
- = 0.3 =
666
- * Updated: admin page does not show an alert box if Tag Manager ID or dataLayer variable name is incorrect. Instead it shows a warning line below the input field.
667
- * Updated: rewritten the code for WooCommerce dynamic remarketing. Added tag for homepage and order completed page.
668
-
669
- = 0.2 =
670
- * ! BACKWARD INCOMPATIBLE CHANGE ! - Names of Tag Manager click events has been changed to comply with naming conventions:
671
- * ContactFormSubmitted -> gtm4wp.contactForm7Submitted
672
- * DownloadClick -> gtm4wp.downloadClick
673
- * EmailClick -> gtm4wp.emailClick
674
- * OutboundClick -> gtm4wp.outboundClick
675
- * AddProductToCart -> gtm4wp.addProductToCart
676
- * Updated: click events are now disabled by default to reflect recently released Tag Manager auto events. I do not plan to remove this functionality. You can decide which solution you would like to use :-)
677
- * Updated: language template (pot) file and Hungarian translation
678
- * Added: new form move events to track how visitors interact with your (comment, contact, etc.) forms
679
- * Added: event names to admin options page so that you know what events to use in Google Tag Manager
680
- * Added: Google Tag Manager icon to admin settings page
681
- * Added: Settings link to admin plugins page
682
- * Fixed: null value in visitorType dataLayer variable if no logged in user exists (now 'visitor-logged-out')
683
-
684
- = 0.1 =
685
- * First beta release
686
-
687
- == Upgrade Notice ==
688
-
689
- = 1.12.3 =
690
-
691
- Updated compatible WooCommerce version and added an important message to the changelog for WooCommerce users
692
-
693
- = 1.12.2 =
694
-
695
- Bugfix release + read changelog for important v1.12.x changes
696
-
697
- = 1.12.1 =
698
-
699
- Bugfix release + read changelog for important v1.12.x changes
700
-
701
- = 1.12 =
702
-
703
- Removed several deprecated features, dropped support for WooCommerce versions before 3.2, introduced GA4 data layer variables, deprecated classic ecommerce and Google Ads remarketing varibale
704
-
705
- = 1.11.6 =
706
-
707
- Bugfix release
708
-
709
- = 1.11.5 =
710
-
711
- Fixed: new Google Optimize container ID format accepted now
712
-
713
- = 1.11.4 =
714
-
715
- Bugfix and updated tested version number for WooCommerce
716
-
717
- = 1.11.3 =
718
-
719
- Some bugfixes and adding support for the latest WordPress and WooCommerce version
720
-
721
- = 1.11.2 =
722
-
723
- Replaces v1.11.1
724
-
725
- = 1.11.1 =
726
-
727
- WooCommerce integration related fixes.
728
-
729
- = 1.11 =
730
-
731
- Please read the changelog very carefully as there are many important changes and removed features which could need your attention before updating!
732
-
733
- = 1.10.1 =
734
-
735
- Bugfix release
736
-
737
- = 1.10 =
738
-
739
- Better WordPress 5.2 integration, support for brands in WooCommerce, access cart content in data layer, more stable double transaction tracking prevention on mobiles and more!
740
-
741
- = 1.9.2 =
742
-
743
- Fixed possible PHP warning if geo data or weather data feature is turned on
744
-
745
- = 1.9.1 =
746
-
747
- Bugfix version
748
-
749
- = 1.9 =
750
-
751
- New AMP GTM support, full Google Optimize support, lots of WooCommerce tracking improvements.
752
-
753
- = 1.8.1 =
754
-
755
- Bugfix version fixing some issues around WooCommerce tracking and GTM environments. Also adds IP address into the data layer.
756
-
757
- = 1.8 =
758
-
759
- Lots of new features and some important changes, please read the changelog to ensure your measurement does not break
760
-
761
- = 1.7.2 =
762
-
763
- Bugfix release: many little fixes, event better WooCommerce 3.x compatibility
764
-
765
- = 1.7.1 =
766
-
767
- Bugfix release: better PHP 5.3 and WooCommerce 2.6.x compatibility
768
-
769
- = 1.7 =
770
-
771
- Better WooCommerce 3.x compatibility and new features
772
-
773
- = 1.6.1 =
774
-
775
- Bugfix release.
776
-
777
- = 1.6 =
778
-
779
- If you are using WooCommerce and enhanced ecommerce, please add gtm4wp.changeDetailViewEEC to the ecommerce helper trigger
780
-
781
- = 1.5.1 =
782
-
783
- Fixed: clicks on products in product list pages redirected to undefined URLs with some themes.
784
-
785
- = 1.5 =
786
-
787
- Lots of WooCommerce ecommerce codes has been changed and extended, please double check your measurement after upgrading to this version!
788
-
789
- = 1.4 =
790
-
791
- Several additions and fixes, breaking changes on media player tracking, please read changelog before upgrade
792
-
793
- = 1.3.2 =
794
-
795
- Quickfix release for 1.3.x: major changes and improvements in the enhanced ecommerce implementation for WooCommerce. If you are already using this beta feature, please read the changelog before upgrading!
796
-
797
- = 1.3.1 =
798
-
799
- Quickfix release for 1.3: major changes and improvements in the enhanced ecommerce implementation for WooCommerce. If you are already using this beta feature, please read the changelog before upgrading!
800
-
801
- = 1.3 =
802
-
803
- Major changes and improvements in the enhanced ecommerce implementation for WooCommerce. If you are already using this beta feature, please read the changelog before upgrading!
804
-
805
- = 1.2 =
806
-
807
- New release with lots of fixes from the past months and new features like multiple container support!
808
-
809
- = 1.1.1 =
810
-
811
- This is a bugfix release to address some issues with v1.1
812
-
813
- = 1.1 =
814
-
815
- New! Track popular media players embedded into your website!
816
-
817
- = 1.0 =
818
-
819
- First stable release, please read changelog for details!
820
-
821
- = 0.9.1 =
822
-
823
- Bugfix release for WooCommerce users with ecommerce tracking enabled
824
-
825
- = 0.9 =
826
-
827
- Many bug fixes, important fixes for WooCommerce users
828
-
829
- = 0.8.2 =
830
-
831
- Another bugfix release for WooCommerce users with Enhanced Ecommerce enabled
832
-
833
- = 0.8.1 =
834
-
835
- Bugfix release for WooCommerce users with Enhanced Ecommerce enabled
836
-
837
- = 0.8 =
838
-
839
- This version introduces Enhanced E-commerce implementation for WooCommerce. Please note that this
840
- feature of the plugin is still experimental and the feature of Google Analytics is still in beta.
841
- Read the plugin FAQ for details.
842
-
843
- = 0.7.1 =
844
-
845
- If you are using WooCommerce and updated to 2.1.x you SHOULD update immediately.
846
- This release includes a fix so that transaction data can be passed to GTM.
847
-
848
- = 0.7 =
849
-
850
- Improved code so that Webmaster Tools verification can work using your GTM container tag.
851
- Blacklist or whitelist tags and macros to increase security of your Tag Manager setup.
852
- Fixed: WhichBrowser library was missing from 0.6
853
-
854
- = 0.6 =
855
-
856
- Improved add-to-cart events for WooCommerce, added browser/OS/device infos and post count infos.
857
-
858
- = 0.5.1 =
859
-
860
- Bug fix release for WooCommerce users.
861
-
862
- = 0.5 =
863
- Besides of some fixes this version includes scroll tracking events for Google Tag Manager.
864
-
865
- = 0.4 =
866
- Important change: Tag Manager event name of a WooCommerce successful order has been changed.
867
- See changelog for details.
868
-
869
- = 0.3 =
870
- This is a minor release. If you are using WooCommerce you should update to include more accurate Google Ads dynamic remarketing feature.
871
-
872
- = 0.2 =
873
- BACKWARD INCOMPATIBLE CHANGE: Names of Tag Manager click events has been changed to comply with naming conventions.
874
- See changelog for details. Do not forget to update your Tag Manager container setup after upgrading this plugin!
875
-
876
- = 0.1 =
877
- This is the first public beta, no upgrade is needed.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Google Tag Manager for WordPress ===
2
+ Contributors: duracelltomi
3
+ Donate link: https://gtm4wp.com/
4
+ Tags: google tag manager, tag manager, gtm, google, adwords, google adwords, google ads, adwords remarketing, google ads remarketing, remarketing, google analytics, analytics, facebook ads, facebook remarketing, facebook pixel, google optimize, personalisation
5
+ Requires at least: 3.4.0
6
+ Requires PHP: 5.6
7
+ Tested up to: 5.7.2
8
+ Stable tag: 1.13
9
+ License: GPLv3
10
+ License URI: http://www.gnu.org/licenses/gpl.html
11
+
12
+ Advanced measurement/advertising tag management and site personalisation for WordPress with Google Tag Manager and Google Optimize
13
+
14
+ == Description ==
15
+
16
+ Google Tag Manager (GTM) is Google's free tool for everyone to manage and deploy analytics and marketing tags as well as other code snippets
17
+ using an intuitive web UI. To learn more about this tool, visit the [official website](https://www.google.com/analytics/tag-manager/).
18
+
19
+ This plugin places the GTM container code snippets onto your wordpress website so that you do not need to add this manually.
20
+ Multiple containers are also supported!
21
+
22
+ The plugin complements your GTM setup by pushing page meta data and user information into the so called data layer.
23
+ Google's official help pages includes [more details about the data layer](https://developers.google.com/tag-manager/devguide#datalayer).
24
+
25
+ You can also add your Google Optimize container with the [recommended code setup](https://support.google.com/optimize/answer/7359264?hl=en)
26
+
27
+ **Some parts of the plugin require PHP 5.6 newer.
28
+ PHP 7.0 or newer is recommended.**
29
+
30
+ Please note that PHP versions 7.2 or older already reached their end of life cycle thus it is recommended to upgrade. If you are not sure which version you are using, please contact your hosting provider for support.
31
+
32
+ = GTM container code placement =
33
+
34
+ The original GTM container code is divided into two parts:
35
+
36
+ The first part is a javascript code snippet that is added to the `<head>` section of every page of the website.
37
+ This part is critical to enable all features of GTM, and this plugin helps to place this part
38
+ correctly on your site.
39
+
40
+ The second part is an iframe snippet that acts as a failsafe/fallback should users' JavaScript be disabled.
41
+ Google recommends – for best performance – to place this code snippet directly after the opening `<body>` tag on each page.
42
+
43
+ Albeit not ideal, it will work when placed lower in the code. This plugin provides a code placement option for the second code snippet.
44
+
45
+ If your WordPress theme is compatible with the additions of WordPress 5.2 then this plugin will place this second code to the right place.
46
+ Users of the Genisis theme, GeneratePress theme, Elementor, Oxygen Builder and Beaver Builder Theme will also have this placed correctly.
47
+ To utilize this, use the "Codeless" placement option.
48
+
49
+ All other users can place this second code snippet using a custom PHP code ("Custom" placement option) or select the so called "Footer" option to
50
+ add the code lower in the code (it is not the recommended way but will work)
51
+
52
+
53
+ = Basic data included =
54
+
55
+ * post/page titles
56
+ * post/page dates
57
+ * post/page category names
58
+ * post/page tag names
59
+ * post/page author ID and name
60
+ * post/page ID
61
+ * post types
62
+ * post count on the current page + in the current category/tag/taxonomy
63
+ * custom terms associated with any post type
64
+ * logged in status
65
+ * logged in user role
66
+ * logged in user ID (to track cross device behaviour in Google Analytics)
67
+ * logged in user email address (to comply with [GTM terms of service](https://www.google.com/analytics/tag-manager/use-policy/) do not pass this on to Google tags)
68
+ * logger in user creation date
69
+ * site search data
70
+ * site name and id (for WordPress multisite instances)
71
+ * IP address of the visitor (please use the explicit consent of the visitor to utilize this)
72
+
73
+ = Browser / OS / Device data =
74
+
75
+ * browser data (name, version, engine)
76
+ * OS data (name, version)
77
+ * device data (type, manufacturer, model)
78
+
79
+ Data is provided using the WhichBrowser library: http://whichbrowser.net/
80
+
81
+ = Weather data =
82
+
83
+ (beta)
84
+
85
+ Push data about users' current weather conditions into the dataLayer. This can be used to generate weather-related
86
+ audience/remarketing lists on ad platforms and allows for user segmentation in your web analytics solutions:
87
+
88
+ * weather category (clouds, rain, snow, etc.)
89
+ * weather description: more detailed data
90
+ * temperature in Celsius or Fahrenheit
91
+ * air pressure
92
+ * wind speed and degrees
93
+
94
+ Weather data is queried from Open Weather Map. Depending on your websites traffic, additional fees may apply:
95
+ http://openweathermap.org/price
96
+
97
+ An (free) API key from OpenWeatherMap is required for this feature to work.
98
+
99
+ ipstack.com is used to determine the site visitor's location. A (free) API key from IPStack.com is required for this feature to work:
100
+ https://ipstack.com/product
101
+
102
+ = Media player events =
103
+
104
+ (experimental)
105
+
106
+ Track users' interaction with any embedded media:
107
+
108
+ * YouTube
109
+ * Vimeo
110
+ * Soundcloud
111
+
112
+ DataLayer events can be chosen to fire upon media player load, media is being played, paused/stopped and optionally when
113
+ the user reaches 10, 20, 30, ..., 90, 100% of the media duration.
114
+
115
+ Tracking is supported for embedded media using the built-in oEmbed feature of WordPress as well as most other media plugins
116
+ and copy/pasted codes. Players injected into the website after page load are not currently supported.
117
+
118
+ = Scroll tracking =
119
+
120
+ Fire tags based on how the visitor scrolls from the top to the bottom of a page.
121
+ An example would be to separate "readers" (who spend a specified amount of time on a page) from "scrollers"
122
+ (who only scroll through within seconds). You can use these events to fire Analytics tags and/or remarketing/conversion tags
123
+ (for micro conversions).
124
+
125
+ Scroll tracking is based on the solution originally created by
126
+
127
+ * Nick Mihailovski
128
+ * Thomas Baekdal
129
+ * Avinash Kaushik
130
+ * Joost de Valk
131
+ * Eivind Savio
132
+ * Justin Cutroni
133
+
134
+ Original script:
135
+ http://cutroni.com/blog/2012/02/21/advanced-content-tracking-with-google-analytics-part-1/
136
+
137
+ = Google Ads remarketing =
138
+
139
+ Google Tag Manager for WordPress can add each dataLayer variable as a Google Ads remarketing custom parameter list.
140
+ This enables you to build sophisticated remarketing lists.
141
+
142
+ = Blacklist & Whitelist Tag Manager tags, triggers and variables =
143
+
144
+ To increase website security, you have the option to white- and blacklist tags/triggers/variables.
145
+ You can prevent specific tags from firing or the use of certain variable types regardless of your GTM setup.
146
+
147
+ If the Google account associated with your GTM account is being hacked, an attacker could easily
148
+ execute malware on your website without accessing its code on your hosting server. By blacklisting custom HTML tags
149
+ and/or custom JavaScript variables you can secure the Tag Manager container.
150
+
151
+ = Integration =
152
+
153
+ Google Tag Manager for WordPress integrates with several popular plugins. More integration to come!
154
+
155
+ * Contact Form 7: fire an event upon successful form submission
156
+ * WooCommerce:
157
+ * Classic e-commerce (deprecated):
158
+ * fire an event when visitors add products to their cart
159
+ * capture transaction data to be passed to your ad platforms and/or Analytics
160
+ * capture necessary remarketing parameters for Google Ads Dynamic Remarketing
161
+ * Enhanced e-commerce:
162
+ * implementation of [Enhanced E-commerce GA3](https://developers.google.com/tag-manager/enhanced-ecommerce)
163
+ * implementation of [Enhanced E-commerce GA4](https://developers.google.com/tag-manager/ecommerce-ga4)
164
+ * Does not support promotions since WooCommerce does not have such a feature (yet)
165
+ * Does not support refunds
166
+
167
+ = Server side containers =
168
+
169
+ If you are using a [server side container](https://developers.google.com/tag-manager/serverside/send-data#update_the_gtmjs_source_domain)
170
+ you can enter your custom domain name to load gtm.js from your there.
171
+
172
+ == Installation ==
173
+
174
+ 1. Upload `duracelltomi-google-tag-manager-for-wordpress` to the `/wp-content/plugins/` directory
175
+ 1. Activate the plugin through the 'Plugins' menu in WordPress
176
+ 1. Go to Settings / Google Tag Manager and enter your Google Tag Manager container ID and set additional options
177
+
178
+ == Frequently Asked Questions ==
179
+
180
+ = How can I ... =
181
+
182
+ Tutorials for various Google Tag Manager settings and implementation are available on my website:
183
+ https://gtm4wp.com/how-to-articles/
184
+
185
+ = PayPal / 3rd party payment gateway transactions in WooCommerce are not being tracked in Google Analytics =
186
+
187
+ PayPal and some other 3rd party payment gateways do not redirect users back to your website upon successful transaction by default.
188
+ It offers the route back for your customer but it can happen that users close the browser before arriving at your thankyou page
189
+ (aka. order received page). This means that neither Google Analytics tags or any other tags have the chance to fire.
190
+
191
+ Enable auto-return in your payment gateway settings. This will instruct them to show a quick info page after payment
192
+ and redirect the user back to your site. This will improve the accuracy and frequency of tracked transactions.
193
+
194
+ = Why isn't there an option to blacklist tag/variable classes =
195
+
196
+ Although Google recommends to blacklist tags and variables using classes, people struggle to know
197
+ which tags/variables gets affected. Therefore I opted for individual tags and variables rather than classes
198
+ on the blacklist tabs.
199
+
200
+ Regarding variables; ensure they are not part of any critical tags as blacklisting such variables will render said tags useless.
201
+
202
+ = How can I track scroll events in Google Tag Manager? =
203
+
204
+ Google Tag Manager supports basic scroll depth tracking based on percentage or pixels natively. This plugin adds
205
+ additional scroll tracking events, more focused on capturing the users' intent and/or engagement.
206
+
207
+ There are five dataLayer events you can use in your rule definitions:
208
+
209
+ * gtm4wp.reading.articleLoaded: the content has been loaded
210
+ * gtm4wp.reading.startReading: the visitor started to scroll. The `timeToScroll` dataLayer variable stores duration since the article loaded (in seconds)
211
+ * gtm4wp.reading.contentBottom: the visitor reached the end of the content (not the page!). `timeToScroll` dataLayer variable updated
212
+ * gtm4wp.reading.pagebottom: the visitor reached the end of the page. `timeToScroll` dataLayer variable updated
213
+ * gtm4wp.reading.readerType: based on time spent since article loaded we determine whether the user is a 'scanner' or 'reader' and store this in the `readerType` dataLayer variable
214
+
215
+ Example use cases: using these events as triggers, you can fire Google Universal Analytics and/or Google Ads remarketing/conversion tags
216
+ to report micro conversions and/or to serve ads only to visitors who spend more time reading your content.
217
+
218
+ = Can I exclude certain user roles from being tracked? =
219
+
220
+ This is easily managed through GTM itself. If you want to exclude logged in users or users with certain user roles,
221
+ use the corresponding dataLayer variable (visitorType) and an exclude filter in Google Tag Manager.
222
+
223
+ https://gtm4wp.com/how-to-articles/how-to-exclude-admin-users-from-being-tracked/
224
+
225
+ == Screenshots ==
226
+
227
+ 1. Admin panel
228
+ 2. Basic settings
229
+ 3. Events
230
+ 4. Integration panel
231
+ 5. Advanced settings
232
+ 6. Scroll tracking
233
+
234
+ == Changelog ==
235
+
236
+ = 1.13 =
237
+
238
+ WARNING!
239
+ If you are using the geo or weather options of this plugin, make sure your hosting is using PHP 7.0 or newer!
240
+
241
+ If you are using the WooCommerce integration with enhanced ecommerce, once again you will need to update your GTM container.
242
+ Please check the [setup article](https://gtm4wp.com/how-to-articles/how-to-setup-enhanced-ecommerce-tracking) to see what needs to be changed.
243
+ The goal is to keep this setup in the upcoming versions.
244
+
245
+ * Added: Google Business Vertical option to populate Google Ads dynamic remarketing
246
+ * Added: Make automatic cookie blocking mode of Cookiebot to work with your Google Tag Manager container (new option in the Integration tab)
247
+ * Added: support for [server side containers with custom domains](https://developers.google.com/tag-manager/serverside/send-data#update_the_gtmjs_source_domain)
248
+ * Added: improved duplacate WooCommerce order tracking prevention by also checking the age of the order. You can adjust the value in minutes on the plugin options page - by [Code-Craze](https://github.com/Code-Craze)
249
+ * Fixed: prices rounded to 2 decimals in the data layer (WooCommerce integration)
250
+ * Fixed: select_item event fired multiple times (at least twice)
251
+ * Fixed: frontend protection to preveent double tracking transactions had a bug
252
+ * Fixed: missing product detail and first checkout step tracking in WooCommerce shops with Enhanced Ecommerce
253
+ * Fixed: JavaScript type error if product category is a number
254
+ * Updated: WhichBrowser v2.1.1 (requires PHP 7.0 or newer)
255
+ * Updated: descriptions of WooCommerce tracking methods to emphasize the importance to migrate from standard to enhanced ecommerce
256
+ * Updated: added links to enhanced ecommerce setup guides (GA3 and GA4)
257
+
258
+ = 1.12.3 =
259
+
260
+ No new or updated functionality, but updated WooCommerce compatibility.
261
+
262
+ IMPORTANT!
263
+ If you are using the WooCommerce integration and enhanced ecommerce, please update your ecommerce event trigger to include gtm4wp.orderCompletedEEC as well.
264
+ https://gtm4wp.com/how-to-articles/how-to-setup-enhanced-ecommerce-tracking
265
+
266
+ = 1.12.2 =
267
+
268
+ If you are upgrading from 1.11.x, please read the previous changelog entry for v1.12
269
+
270
+ * Fixed: error message in WooCommerce integration on PHP 8 hosts
271
+ * Fixed: PHP notice about non existing blacklist-enable array key
272
+
273
+ = 1.12.1 =
274
+
275
+ If you are upgrading from 1.11.x, please read the previous changelog entry for v1.12
276
+
277
+ * Fixed: PHP notice while saving admin options
278
+
279
+ = 1.12 =
280
+
281
+ WARNING!
282
+ If you are using the blacklist/whitelist feature of the plugin, review these options after upgrade as they could break because of a fundamental rework of this feature.
283
+
284
+ * Added: support for Google Analytics 4 version of ecommerce data layer
285
+ * Fixed: safer IP address validation in geo and weather data features
286
+ * Updated: removed deprecated events: download links, email links, social links -> such can be now tracked with native Google Tag Manager triggers
287
+ * Updated: removed support for WooCommerce versions before v3.2
288
+ * Updated: 'Blacklist tags' tab renamed to 'Security'
289
+ * Updated: complete rework of blacklist/whitelist feature to use the latest tag/trigger/variable list of Google
290
+ * Deprecated: classic ecommerce tracking will be removed later this year, please upgrade to enhanced ecommerce tracking
291
+ * Deprecated: standard Google Ads remarketing variable will be removed soon as the Google Ads remarketing tag template can easily use any of your Google Tag Manager variables
292
+ * Deprecated: the old fashioned way of using Google Ads remarketing with the ecomm_ prefixed data layer variables will be removed soon. Instructions for upgrade will be published on gtm4wp.com once this feature gets updated in an upcoming plugin version
293
+
294
+ = 1.11.6 =
295
+
296
+ * Fixed: do not track hidden products in the cart in WooCommerce shops
297
+ * Fixed: do not fire add to cart event if button is in a disabled state
298
+ * Fixed: fixed translation of an admin text
299
+ * Fixed: needs_shipping_address() calls were sometimes broken in WooCommerce shops, added additional checks to prevent
300
+ * Updated: removed the body_class method of adding the iframe/noscript container code (page builders and the standard wp_body_open hook remains supported)
301
+
302
+ = 1.11.5 =
303
+
304
+ * Fixed: new Google Optimize container ID format accepted now
305
+
306
+ = 1.11.4 =
307
+
308
+ * Fixed: fire gtm4wp.checkoutStepEEC and gtm4wp.checkoutOptionEEC events if there is only one shipping method available and it is hidden from the user
309
+ * Fixed: decrease checkout step numbers 3 and 4 if shipping destination is set to 'Force shipping to the customer billing address' in WooCommerce. This way there will be no gap in Checkout behaviour report in Google Analytics.
310
+ * Updated: tested version number for WooCommerce
311
+
312
+ = 1.11.3 =
313
+
314
+ * Fixed: use var_export instead of var_dump in some debug code,
315
+ * Fixed: apply WooCommerce option for tax inclusion on the order received page as well
316
+ * Fixed: JavaScript errors in Vimeo player
317
+ * Updated: do not add type attribute to script elements if theme suppors HTML5
318
+ * Updated: tested version numbers for WordPress and WooCommerce
319
+
320
+ = 1.11.2 =
321
+
322
+ WARNING!
323
+ If you are upgrading directly from v1.10.x, please read the changelog of v1.11 since it includes many important notices!
324
+
325
+ No change in plugin code, WP.org deployment of v1.11.1 included wrong directories
326
+
327
+ = 1.11.1 =
328
+
329
+ WARNING!
330
+ If you are upgrading directly from v1.10.x, please read the changelog of v1.11 since it includes many important notices!
331
+
332
+ * Fixed: PHP notice about undefined order_items variable if the new 'Order data in data layer' is turned off
333
+ * Fixed: PHP notice about missing brand array key if no brand taxonomy is selected in GTM4WP options
334
+
335
+ = 1.11 =
336
+
337
+ WARNING!
338
+ Please read the changelog very carefully as there are many important changes and removed features which could need your attention before updating!
339
+
340
+ * Added Oxygen Builder and Beaver Builder Theme support - you can now use the codeless placement option without issues
341
+ * Added ability to fix the Google Tag Manager ID and GTM Environment parameters in wp-config.php. To use it, create PHP constants with the names
342
+ ** GTM4WP_HARDCODED_GTM_ID
343
+ ** GTM4WP_HARDCODED_GTM_ENV_AUTH
344
+ ** GTM4WP_HARDCODED_GTM_ENV_PREVIEW
345
+ * Added support for WooCommerce Grouped Products
346
+ * Added new WooCommerce option to add all order data into the data layer on the order reveived page
347
+ ** This includes personal data of the customer -> you need to ensure this is used in a privacy friendly and compliant way!
348
+ ** This order data will be always present on the order received page, even if the page is reloaded or later revisited!
349
+ * Removed several unofficial data layer variables on the WooCommerce order received page as they can be read using the new order data option
350
+ ** transactionDate
351
+ ** transactionType
352
+ ** transactionPaymentType
353
+ ** transactionShippingMethod
354
+ ** transactionPromoCode
355
+ * Improved: price reporting with the WooCommerce enhanced ecommerce integration now follows the option set with the 'Display prices in the shop' option of WooCommerce
356
+ * Improved: from WooCommerce 3.7 WC_Abstract_Order::get_used_coupons() was replaced with WC_Abstract_Order::get_coupon_codes() which is now used if WC 3.7+ is detected
357
+ * Improved: use localStorage for WooCommerce duplicate transaction tracking prevention if available. Should be work with Safari at least for now.
358
+ * Fixed: WooCommerce duplicate transaction tracking prevention's cookie was set to expire on session end, now adds 1 year.
359
+ * Deprecated data layer variable productIsVariable. Use the new productType data layer variable which will equal to simple, variable, grouped or external depending on the type of the product shown
360
+ * Fixed: Wrong lookup for product brand name if Use SKU instead of product ID option was turned on
361
+ * Fixed: Wrong lookup for product brand name for variable products
362
+ * Fixed: check if $woo->customer is initialized
363
+ * Fixed: no checkout step reported on WooCommerce checkout page if the user has accepted the default selection of the payment and shipping methods
364
+
365
+ ! Planned deprecation of support for WooCommerce 2.x-3.1.x with next plugin version !
366
+ ! Planned deprecation of support for WordPress 4.x with next plugin version !
367
+
368
+ = 1.10.1 =
369
+
370
+ * Fixed: wrong cookie name was used with the newly introduced double transaction tracking protection while setting the cookie
371
+ * Fixed: double transaction tracking JavaScript code is now only included on the order received page
372
+ * Fixed: product impressions not properly reported if Products per impressions were set to 0
373
+ * Fixed: replaced all references to AdWords to Google Ads
374
+
375
+ = 1.10 =
376
+
377
+ * Added: Automatically add the noscript part of the container code after the opening body tag for WordPress 5.2+ sites where themes support the new wp_body_open action
378
+ * Added: add associated taxonomy values for post type
379
+ * Added: select brand taxonomy for WooCommerce products to populate "Product brand" dimension in enhanced ecommerce
380
+ * Added: add cart content into data layer so that you can personalize your site experience using Google Optimize
381
+ * Added: option to remove shipping costs from revenue data on order received page of WooCommerce
382
+ * Added: if you enable either enhanced ecommerce or just Google Ads remarketing variables, 3 new data layer variables will be also available about the product on a detail page
383
+ * Product rating details (productRatingCounts)
384
+ * Average product rating (productAverageRating)
385
+ * Review count (productReviewCount)
386
+ * Added: if you are using Cloudflare, you can now add the country code HTTP header value into the data layer and read from it with the geoCloudflareCountryCode variable name
387
+ * Fixed: better compatibility with Google's mod_pagespeed
388
+ * Fixed: missing product quantity while adding a variable product into the cart
389
+ * Fixed: prevent multiple tracking of WooCommerce orders on mobile devices where the mobile browser reloads the order received page from local cache executing GTM tracking again
390
+
391
+ = 1.9.2 =
392
+
393
+ * Fixed: possible PHP warning if geo data or weather data feature is turned on
394
+
395
+ = 1.9.1 =
396
+
397
+ * Fixed: handle out of quota cases with ipstack queries properly
398
+ * Fixed: proper YouTube tracking for WordPress sites and WordPress multisites installed in a subdirectory
399
+ * Fixed: properly detect client IP address and also properly escape this data while using it
400
+ * Fixed: WooCommerce checkout steps after page load did not include products in the cart
401
+ * Fixed: checkout step events for payment mode and shipping type not always fired
402
+ * Fixed: the CMD on Mac will be treated just like the Ctrl key on Windows while processing the product click event in the WooCommerce integration (thy for luzinis)
403
+ * Fixed: add currencyCode to every ecommerce action in WooCommerce integration
404
+ * Fixed: better WooCommere Quick View integration
405
+ * Fixed: possible cross site scripting vulnerability if site search tracking was enabled due to not properly escaped referrer url tracking
406
+ * Changed: code cleanup in WooCommerce integration
407
+
408
+ = 1.9 =
409
+
410
+ * Added: initial support for AMP plugin from Automattic (thx koconder for the contribution!)
411
+ * Added: option to remove tax from revenue data on order received page of WooCommerce
412
+ * Added: WooCommerce enhanced ecommerce datasets now include stock levels
413
+ * Added: new productIsVariable data layer variable is set to 1 on variable WooCommerce product pages
414
+ * Added: product impressions can now be split into multiple chunks to prevent data loss on large product category and site home pages (thx Tim Zook for the contribution!)
415
+ * IMPORTANT! You will need to update your GTM setup, please read the new Step 9 section of the [setup tutorial page](https://gtm4wp.com/how-to-articles/how-to-setup-enhanced-ecommerce-tracking).
416
+ * Added: you can now disable flagging of WooCommerce orders as being already tracked once. In same cases (with iDeal for example) you may need this to make purchase tracking to work.
417
+ * Added: uninstalling the plugin will now remove configured plugin options from database
418
+ * Added: new advanced plugin option: data layer variable visitorDoNotTrack will include 1 if the user has set the [do not track flag](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/DNT) in his/her browser
419
+ * Added: new data layer event when a user has logged in on the frontend: gtm4wp.userLoggedIn
420
+ * Added: new data layer event when a new user has registered on the frontend: gtm4wp.userRegistered
421
+ * Added: new advanced plugin option: move data layer declaration and Google Tag Manager container as close as possible to the beginning of the HTML document
422
+ * Added: better WP Rocket support
423
+ * Updated: Full Google Optimize support. Now the plugin can load your Google Optimize container with the [recommended code placement](https://support.google.com/optimize/answer/7359264?hl=en)
424
+ * Updated: moved most of the inline JavaScript codes into separate .js files which should help cache plugins to do their job much better when my plugin is active
425
+ * Fixed: wrong ecomm_pagetype on product search result pages
426
+ * Fixed: PHP notice in some cases when geo data was not loaded properly
427
+ * Fixed / Added: freegeoip.net was rebranded to ipstack.com and an API key is needed now even for free usage. You can now add your API key so that weather data and geo data can be added into the data layer
428
+ * Warning: some plugin features will be remove from v1.10, most of them can be tracked now using pure Google Tag Manager triggers:
429
+ * Social actions
430
+ * Outbound link click events
431
+ * Download click events
432
+ * Email click events
433
+ * Warning: PHP 5.6 is now the minimum recommended version to use this plugin. I advise to move to PHP 7.x
434
+
435
+ = 1.8.1 =
436
+
437
+ * Added: new visitorIP data layer variable to support post-GDPR implementations where for example internal traffic exclusion has to be made inside the browser
438
+ * Fixed: JavaScript error around the variable gtm4wp_use_sku_instead
439
+ * Fixed: added _ as a valid character for gtm_auth GTM environment variable
440
+ * Fixed: corrected typo - gtm4wp.checkoutStepE**E**C
441
+ * Fixed: two strings were not recognized by WordPress Translate on the admin page
442
+ * Fixed: some other plugins call found_variation event of WooCommerce without product variation data being included
443
+ * Fixed: product name included variation name on order received page which broke GA product reports
444
+ * Fixed: in some cases, no contact form 7 data was being passed to the gtm4wp.contactForm7Submitted event
445
+ * Updated: added CDATA markup around container code for better DOM compatibility
446
+ * Updated: removed 'SKU:' prefix text from classic ecommerce dimension as it broke some enhanced ecommerce reports
447
+
448
+ = 1.8 =
449
+
450
+ * Fixed: weather data tracking codes could result in fatal PHP error
451
+ * Fixed: cart events did to fire while user pressed the Enter key in quantity fields
452
+ * Fixed: contact form 7 changed some code which prevented successful form submission tracking
453
+ * Changed: links to plugin website updated
454
+ * Changed: gtm4wp.cf7formid data layer variable now includes the ID of the form in WordPress
455
+ * Added: gtm4wp.cf7inputs includes data that has been filled in the form
456
+ * Added: [WooCommerce compatibility headers](https://docs.woocommerce.com/document/create-a-plugin/#section-10)
457
+ * Added: admin warning for WooCommerce 2.x users. This plugin will drop support for WooCommerce 2.x soon
458
+ * Added: postFormat data layer variable on singular pages
459
+ * Added: customer* data layer variables with stored billing and shipping data, total number of orders and total value of those orders (needs WooCommerce 3.x)
460
+ * Added: geo* data layer variables to get country, city, lat-lon coordinates of the visitor
461
+ * Added: visitorUsername data layer variable with the username of the logged in user
462
+ * Added: more detailed checkout reporting for WooCommerce sites
463
+ * Add gtm4wp.checkoutStepEEC to your Ecommerce Helper trigger
464
+ * Change a typo: gtm4wp.checkoutOptionE**C**C => gtm4wp.checkoutOptionE**E**C
465
+ * Added: option to include full product category path in enhanced ecommerce reporting (can cause performance issues on large sites!)
466
+ * Added: initial support for [Google Tag Manager Environments](https://support.google.com/tagmanager/answer/6311518?hl=en)
467
+ * Added: support for [WooCommerce Quick View plugin](https://woocommerce.com/products/woocommerce-quick-view/)
468
+ * Updated: description of code placement options to clarify what this option does
469
+ * Updated: cleanup of readme.txt, spelling and grammar improvements
470
+ * Updated: bundled WhichBrowser lib v2.0.32
471
+
472
+
473
+ = 1.7.2 =
474
+
475
+ * Fixed: in some cases, the remove item from cart link in a WooCommerce cart was not altered properly with additional tracking codes
476
+ * Fixed: product categories were empty in the cart, on the checkout pages and on the order received page for product variations
477
+ * Fixed: checkout option data included checkout step #1 if cart page was setup to be the first
478
+ * Fixed: even more WooCommerce 3.x compatibility
479
+ * Added: registration date of the logged in user can be added to the data layer
480
+ * Updated: geoplugin.net has been replaced by freegeoip.net for weather tracking which has far better quota for free usage
481
+ * Updated: Google Ads dynamic remarketing data layer items on a WooCommerce product page will be shown for the root product as well on variable product pages
482
+ * Updated: Selecting a product variation will include the price of the product in Google Ads dynamic remarketing data layer items
483
+ * Updated: minor code cleanup
484
+
485
+ = 1.7.1 =
486
+
487
+ * Fixed: PHP 5.3 compatible syntax in frontend.php
488
+ * Fixed: PHP error using classic ecommerce with WooCommerce 2.6.x
489
+ * Updated: Added data-cfasync='false' to all <script> elements to prevent CloudFlare to load scripts async
490
+ * Added: Warning for users of PHP 5.4 or older to consider upgrade (FYI: PHP 5.5 and older versions do not get even security fixes)
491
+
492
+ = 1.7 =
493
+
494
+ * Updated: even better WooCommerce 3.0 compatibility (WooCommerce 2.6 still supported but this support ends with the next plugin version)
495
+ * Fixed: properly escaping product category name on variable product detail pages
496
+ * Fixed: proper data layer stucture in the gtm4wp.changeDetailViewEEC event
497
+ * Added: Google Optimize page hiding snippet under Integrations tab
498
+ * Added: add to cart data for WooCommerce enhanced ecommerce tracking if user undos a cart item removal (no need to update GTM tags)
499
+ * Added: you can now enter a product ID prefix so that IDs can match with IDs in some product feeds generated by other plugins
500
+ * Added: option to track cart page as step 1 in enhanced ecommerce checkout funnel
501
+
502
+ = 1.6.1 =
503
+
504
+ * Fixed: PHP warning message on WooCommerce cart page
505
+ * Fixed: Better compatibility with WooCommerce 2.6.x :-)
506
+
507
+ = 1.6 =
508
+
509
+ * Fixed: do not block product list item clicks if ad blocker is enabled
510
+ * Fixed: only track product clicks in product lists if link points to the product detail page URL
511
+ * Fixed: PHP warning in backlogs 'Undefined variable: gtm4wp_options'
512
+ * Added: product variation support in WooCommerce integration (enhanced ecommerce implementations should add the GTM event gtm4wp.changeDetailViewEEC to the ecommerce event trigger)
513
+ * Updated: better WooCommerce 3.0 compatibility
514
+
515
+ = 1.5.1 =
516
+
517
+ * Fixed: clicks on products in product list pages redirected to undefined URLs with some themes.
518
+
519
+ = 1.5 =
520
+
521
+ Lots of WooCommerce ecommerce codes has been changed and extended, please double check your measurement after upgrading to this version!
522
+
523
+ * Added: warning message if you are using PHP 5.3 or older. Browser/OS/Device tracking needs 5.4 or newer
524
+ * Added: Email address of the logged in user into the visitorEmail dataLayer variable. Remember: to comply with GTM TOS you are not allowed to pass this data towards any Google tag but you can use this in any other 3rd party tag.
525
+ * Added: gtm4wp_eec_product_array WordPress filter so that plugin and theme authors can add their own data for enhanced ecommere product arrays
526
+ * Fixed: JavaScript error in WooCommerce stores when enhanced ecommerce enabled and a product being clicked in a widget area
527
+ * Fixed: Order data not present in some cases on the order received page
528
+ * Changed: Extended "User SKUs instead of IDs for remarketing" option to be also applied to ecommerce product data arrays
529
+ * Changed: Use wc_clean instead of the deprecated function woocommerce_clean
530
+ * Changed: New, divided GTM container implemented - a fixed part in the <head> and an iframe part placed using the container placement option you've set earlier
531
+
532
+ = 1.4 =
533
+
534
+ * Fixed: WP CLI error message
535
+ * Fixed: wrong dynamic remarketing tagging on cart and checkout pages
536
+ * Updated: WhichBrowser library to 2.0.22
537
+ * Updated: slightly changed container code snippet to prevent W3 Total Cache to alter the code which breaks proper code execution
538
+ * Updated: replaced file_get_contents() usage in weather tracking to wp_remote_get() so that it is more compatible with several WP instances
539
+ * Updated: YouTube/Video/Soundcloud tracking now tracks videos not embedded using oEmbed (like videos in a widget area)
540
+ * Updated: new Vimeo Player API implemented which should solve several issues
541
+ * Changed: adapted W3C HTML5 media player event names which changes some events (needs updating your existing GTM setup):
542
+ * Soundcloud: finish => ended, seek => seeked
543
+ * YouTube: playing => play, paused => pause, playback-rate-change => ratechange
544
+ * Vimeo: seek => seeked
545
+ * Added: new placement option - 'off'. This will only generate the data layer but you will need to add the proper GTM container code snippet by hand
546
+ * Added: new data layer variable: authorID
547
+ * Added: new data layer variable: siteID to be able to track based on blog ID in a multisite environment
548
+ * Added: new data layer variable: siteName to be able to track in a multisite environment
549
+
550
+ = 1.3.2 =
551
+
552
+ * Fixed: remove cart event not fired in WooCommerce 2.6
553
+ * Fixed: ecomm_prodid.push error message on product detail pages
554
+ * Fixed: proper tracking of cart actions on the cart page for WooCommerce 2.6
555
+ * Fixed: 'Illegal string offset' errors in some cases in the cart
556
+ * Fixed: OpenWeatherMap requires a (free) API key now, you can now enter this to use weather data in data layer
557
+
558
+ = 1.3.1 =
559
+
560
+ * Fixed: "json_encode() expects parameter 2 to be long, string given" on PHP 5.3 instances
561
+ * Fixed: Fatal PHP error in cart if you enabled taxes to be included in your cart
562
+
563
+ = 1.3 =
564
+
565
+ Major changes to the Enhanced Ecommerce implementation of the WooCommerce integration!
566
+
567
+ * Fixed: proper tracking of list positions
568
+ * Fixed: opening product detail page in a new window/tab when user pressed the CTRL key
569
+ * Fixed: ecomm_totalvalue included the total price of the cart without taxes
570
+ * Fixed: ecomm_totalvalue does not take into account the quantity of ordered products on the order received page
571
+ * Fixed: php error message on product lists when Google Ads dynamic remarketing was enabled on WooCommerce 2.6
572
+ * Fixed: added data-cfasync="false" to the GTM container code for better compatibility with CloudFlare
573
+ * Added: introducing tracking of list names (general product list, recent products list, featured products list, etc.)
574
+ * Some list names (like cross-sells) will be shown as 'General Product List'. A proposed change in WooCommerce 2.6 will solve that issue
575
+ * Added: tracking product lists in widgets
576
+ * Added: tracking checkout options (payment and shipment)
577
+ * Updated: better add-to-cart / remove-from-cart management in mini cart and while updating cart content
578
+ * Updated: added currency code to each enhanced ecommerce call so that currency reporting is OK for multi currency sites
579
+ * Updated: replaced usage of get_currentuser() to keep compatibility with WordPress 4.5
580
+
581
+ = 1.2 =
582
+
583
+ * Fixed: subtabs on admin page now showing in certain cases
584
+ * Fixed: error message when running the site using WP CLI (thanks Patrick Holberg Hesselberg)
585
+ * Fixed: some typos on admin page
586
+ * Fixed: dismissable notices did not disappear in some cases
587
+ * Fixed: tracking of Twitter event cased sometimes JS errors
588
+ * Fixed: site search tracking caused sometimes PHP errors when HTTP_REFERER was not set
589
+ * Updated: preparation for translate.wordpress.org
590
+ * Added: support for multiple container IDs
591
+ * Added: added form ID when sending a Contact Form 7 form. Variable name: gtm4wp.cf7formid
592
+
593
+ = 1.1.1 =
594
+
595
+ * Fixed: PHP errors in frontend.php and admin.php
596
+
597
+ = 1.1 =
598
+
599
+ * Added: track embedded YouTube/Vimeo/Soundcloud videos (experimental)
600
+ * Added: new checkbox - use product SKU for Google Ads Dynamic Remarketing variables instead of product ID (experimental)
601
+ * Added: place your container code after the opening body tag without modifying your theme files (thx Yaniv Friedensohn)
602
+ * Added: automatic codeless container code injection for Genesis framework users
603
+ * Fixed: Possible PHP error with custom payment gateway (QuickPay) on the checkout page (thx Damiel for findig this)
604
+
605
+ = 1.0 =
606
+
607
+ The plugin itself is now declared as stable. This means that it should work with most WordPress instances.
608
+ From now on each version will include features labeled as:
609
+
610
+ * Beta: the feature has been proven to work for several users but it can still have some bugs
611
+ * Experimental: new feature that needs proper testing with more users
612
+ * Deprecated: this feature will be removed in a future version
613
+
614
+ If you see any issue with beta or experimental functions just disable the checkbox. Using this error messages should disappear.
615
+ Please report all bugs found in my plugin using the [contact form on my website](https://gtm4wp.com/contact).
616
+
617
+ * Fixed: wrong GTM container code when renaming default dataLayer variable name (thx Vassilis Papavassiliou)
618
+ * Fixed: Enhanced Ecommerce product click data was "undefined" in some cases (thx Sergio Alen)
619
+ * Fixed: wrong user role detection while adding visitorType to the dataLayer (thx Philippe Vachon-Rivard)
620
+ * Changed: only add visitorId to the dataLayer if there is a logged in user
621
+ * Added: feature labels so that you can see beta, experimental and deprecated features
622
+ * Deprecated: outbound click, email click and download click events. You should use GTM trigger events instead
623
+
624
+ = 0.9.1 =
625
+
626
+ * Fixed: PHP error message: missing get_shipping function using WooCommerce 2.3.x
627
+
628
+ = 0.9 =
629
+
630
+ * Added: visitorId dataLayer variable with the ID of the currently logged in user to track userID in Google Analytics
631
+ * Added: WordPress filter hook so that other templates and plugins can get access to the GTM container code before outputting it
632
+ * Fixed: 'variation incorrect' issue by Sharken03
633
+ * Fixed: error messages in WooCommerce integration when product has no categories
634
+ * Fixed: add_inline_js errors in newer versions of WooCommerce
635
+ * Fixed: error message when some device/browser/OS data could not be set
636
+ * Fixed: tracking Twitter events was broken
637
+
638
+ = 0.8.2 =
639
+
640
+ * Fixed: broken links when listing subcategories instead of products (thanks Jon)
641
+ * Fixed: wheather/weather typo (thanks John Hockaday)
642
+ * Fixed: wrong usage of get_the_permalink() instead of get_permalink() (thanks Szepe Viktor)
643
+
644
+ = 0.8.1 =
645
+
646
+ * Fixed: PHP error in enhanced ecommerce implementation when using layered nav widget
647
+
648
+ = 0.8 =
649
+
650
+ * Updated: Added subtabs to the admin UI to make room for new features :-)
651
+ * Updated: WhichBrowser library to the latest version
652
+ * Added: You can now dismiss plugin notices permanently for each user
653
+ * Added: weather data. See updated plugin description for details
654
+ * Added: Enhanced E-commerce for WooCommerce (experimental!)
655
+ * Fixed: PHP notice in frontend.php script. Credit to Daniel Sousa
656
+
657
+ = 0.7.1 =
658
+
659
+ * Fixed: WooCommerce 2.1.x compatibility
660
+
661
+ = 0.7 =
662
+
663
+ * Updated/Fixed: dataLayer variables are now populated at the end of the head section. Using this the container code can appear just after the opening body tag, thus Webmaster Tools verification using Tag Manager option will work
664
+ * Added: blacklist or whitelist tags and macros to increase security of your Tag Manager setup
665
+
666
+
667
+ = 0.6 =
668
+
669
+ * Updated: better add-to-cart events for WooCommerce, it includes now product name, SKU and ID
670
+ * Added: browser, OS and device data to dataLayer variables
671
+ * Added: postCountOnPage and postCountTotal dataLayer variables to track empty categories/tags/taxonomies
672
+
673
+ = 0.5.1 =
674
+
675
+ * Fixed: WooCommerce integration did not work on some environments
676
+
677
+ = 0.5 =
678
+ * Added: scroll tracking
679
+ * Fixed: social tracking option on the admin panel was being shown as an edit box instead of a checkbox
680
+ * Fixed: WooCommerce transaction data was not included in the dataLayer if you selected "Custom" code placement
681
+ * Fixed: do not do anything if you enabled WooCommerce integration but did not activate WooCommerce plugin itself
682
+ * Updated: do not re-declare dataLayer variable if it already exists (because another script already created it before my plugin was run)
683
+
684
+ = 0.4 =
685
+ * Added: you can now select container code placement. This way you can insert the code snippet after the opening body tag. Please read FAQ for details
686
+ * Added: initial support for social event tracking for Facebook and Twitter buttons. Please read FAQ for details
687
+ * Updated: event name on successful WooCommerce transaction: OrderCompleted -> gtm4wp.orderCompleted
688
+ * Fixed: frontend JS codes did not load on some WordPress installs
689
+
690
+ = 0.3 =
691
+ * Updated: admin page does not show an alert box if Tag Manager ID or dataLayer variable name is incorrect. Instead it shows a warning line below the input field.
692
+ * Updated: rewritten the code for WooCommerce dynamic remarketing. Added tag for homepage and order completed page.
693
+
694
+ = 0.2 =
695
+ * ! BACKWARD INCOMPATIBLE CHANGE ! - Names of Tag Manager click events has been changed to comply with naming conventions:
696
+ * ContactFormSubmitted -> gtm4wp.contactForm7Submitted
697
+ * DownloadClick -> gtm4wp.downloadClick
698
+ * EmailClick -> gtm4wp.emailClick
699
+ * OutboundClick -> gtm4wp.outboundClick
700
+ * AddProductToCart -> gtm4wp.addProductToCart
701
+ * Updated: click events are now disabled by default to reflect recently released Tag Manager auto events. I do not plan to remove this functionality. You can decide which solution you would like to use :-)
702
+ * Updated: language template (pot) file and Hungarian translation
703
+ * Added: new form move events to track how visitors interact with your (comment, contact, etc.) forms
704
+ * Added: event names to admin options page so that you know what events to use in Google Tag Manager
705
+ * Added: Google Tag Manager icon to admin settings page
706
+ * Added: Settings link to admin plugins page
707
+ * Fixed: null value in visitorType dataLayer variable if no logged in user exists (now 'visitor-logged-out')
708
+
709
+ = 0.1 =
710
+ * First beta release
711
+
712
+ == Upgrade Notice ==
713
+
714
+ = 1.3 =
715
+
716
+ Updated support for Google Ads dynamic remarketing with WooCommerce, added support for server side containers and Cookiebot + fixes
717
+
718
+ = 1.12.3 =
719
+
720
+ Updated compatible WooCommerce version and added an important message to the changelog for WooCommerce users
721
+
722
+ = 1.12.2 =
723
+
724
+ Bugfix release + read changelog for important v1.12.x changes
725
+
726
+ = 1.12.1 =
727
+
728
+ Bugfix release + read changelog for important v1.12.x changes
729
+
730
+ = 1.12 =
731
+
732
+ Removed several deprecated features, dropped support for WooCommerce versions before 3.2, introduced GA4 data layer variables, deprecated classic ecommerce and Google Ads remarketing varibale
733
+
734
+ = 1.11.6 =
735
+
736
+ Bugfix release
737
+
738
+ = 1.11.5 =
739
+
740
+ Fixed: new Google Optimize container ID format accepted now
741
+
742
+ = 1.11.4 =
743
+
744
+ Bugfix and updated tested version number for WooCommerce
745
+
746
+ = 1.11.3 =
747
+
748
+ Some bugfixes and adding support for the latest WordPress and WooCommerce version
749
+
750
+ = 1.11.2 =
751
+
752
+ Replaces v1.11.1
753
+
754
+ = 1.11.1 =
755
+
756
+ WooCommerce integration related fixes.
757
+
758
+ = 1.11 =
759
+
760
+ Please read the changelog very carefully as there are many important changes and removed features which could need your attention before updating!
761
+
762
+ = 1.10.1 =
763
+
764
+ Bugfix release
765
+
766
+ = 1.10 =
767
+
768
+ Better WordPress 5.2 integration, support for brands in WooCommerce, access cart content in data layer, more stable double transaction tracking prevention on mobiles and more!
769
+
770
+ = 1.9.2 =
771
+
772
+ Fixed possible PHP warning if geo data or weather data feature is turned on
773
+
774
+ = 1.9.1 =
775
+
776
+ Bugfix version
777
+
778
+ = 1.9 =
779
+
780
+ New AMP GTM support, full Google Optimize support, lots of WooCommerce tracking improvements.
781
+
782
+ = 1.8.1 =
783
+
784
+ Bugfix version fixing some issues around WooCommerce tracking and GTM environments. Also adds IP address into the data layer.
785
+
786
+ = 1.8 =
787
+
788
+ Lots of new features and some important changes, please read the changelog to ensure your measurement does not break
789
+
790
+ = 1.7.2 =
791
+
792
+ Bugfix release: many little fixes, event better WooCommerce 3.x compatibility
793
+
794
+ = 1.7.1 =
795
+
796
+ Bugfix release: better PHP 5.3 and WooCommerce 2.6.x compatibility
797
+
798
+ = 1.7 =
799
+
800
+ Better WooCommerce 3.x compatibility and new features
801
+
802
+ = 1.6.1 =
803
+
804
+ Bugfix release.
805
+
806
+ = 1.6 =
807
+
808
+ If you are using WooCommerce and enhanced ecommerce, please add gtm4wp.changeDetailViewEEC to the ecommerce helper trigger
809
+
810
+ = 1.5.1 =
811
+
812
+ Fixed: clicks on products in product list pages redirected to undefined URLs with some themes.
813
+
814
+ = 1.5 =
815
+
816
+ Lots of WooCommerce ecommerce codes has been changed and extended, please double check your measurement after upgrading to this version!
817
+
818
+ = 1.4 =
819
+
820
+ Several additions and fixes, breaking changes on media player tracking, please read changelog before upgrade
821
+
822
+ = 1.3.2 =
823
+
824
+ Quickfix release for 1.3.x: major changes and improvements in the enhanced ecommerce implementation for WooCommerce. If you are already using this beta feature, please read the changelog before upgrading!
825
+
826
+ = 1.3.1 =
827
+
828
+ Quickfix release for 1.3: major changes and improvements in the enhanced ecommerce implementation for WooCommerce. If you are already using this beta feature, please read the changelog before upgrading!
829
+
830
+ = 1.3 =
831
+
832
+ Major changes and improvements in the enhanced ecommerce implementation for WooCommerce. If you are already using this beta feature, please read the changelog before upgrading!
833
+
834
+ = 1.2 =
835
+
836
+ New release with lots of fixes from the past months and new features like multiple container support!
837
+
838
+ = 1.1.1 =
839
+
840
+ This is a bugfix release to address some issues with v1.1
841
+
842
+ = 1.1 =
843
+
844
+ New! Track popular media players embedded into your website!
845
+
846
+ = 1.0 =
847
+
848
+ First stable release, please read changelog for details!
849
+
850
+ = 0.9.1 =
851
+
852
+ Bugfix release for WooCommerce users with ecommerce tracking enabled
853
+
854
+ = 0.9 =
855
+
856
+ Many bug fixes, important fixes for WooCommerce users
857
+
858
+ = 0.8.2 =
859
+
860
+ Another bugfix release for WooCommerce users with Enhanced Ecommerce enabled
861
+
862
+ = 0.8.1 =
863
+
864
+ Bugfix release for WooCommerce users with Enhanced Ecommerce enabled
865
+
866
+ = 0.8 =
867
+
868
+ This version introduces Enhanced E-commerce implementation for WooCommerce. Please note that this
869
+ feature of the plugin is still experimental and the feature of Google Analytics is still in beta.
870
+ Read the plugin FAQ for details.
871
+
872
+ = 0.7.1 =
873
+
874
+ If you are using WooCommerce and updated to 2.1.x you SHOULD update immediately.
875
+ This release includes a fix so that transaction data can be passed to GTM.
876
+
877
+ = 0.7 =
878
+
879
+ Improved code so that Webmaster Tools verification can work using your GTM container tag.
880
+ Blacklist or whitelist tags and macros to increase security of your Tag Manager setup.
881
+ Fixed: WhichBrowser library was missing from 0.6
882
+
883
+ = 0.6 =
884
+
885
+ Improved add-to-cart events for WooCommerce, added browser/OS/device infos and post count infos.
886
+
887
+ = 0.5.1 =
888
+
889
+ Bug fix release for WooCommerce users.
890
+
891
+ = 0.5 =
892
+ Besides of some fixes this version includes scroll tracking events for Google Tag Manager.
893
+
894
+ = 0.4 =
895
+ Important change: Tag Manager event name of a WooCommerce successful order has been changed.
896
+ See changelog for details.
897
+
898
+ = 0.3 =
899
+ This is a minor release. If you are using WooCommerce you should update to include more accurate Google Ads dynamic remarketing feature.
900
+
901
+ = 0.2 =
902
+ BACKWARD INCOMPATIBLE CHANGE: Names of Tag Manager click events has been changed to comply with naming conventions.
903
+ See changelog for details. Do not forget to update your Tag Manager container setup after upgrading this plugin!
904
+
905
+ = 0.1 =
906
+ This is the first public beta, no upgrade is needed.
uninstall.php CHANGED
@@ -1,9 +1,9 @@
1
- <?php
2
- // if uninstall.php is not called by WordPress, die
3
- if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
4
- die;
5
- }
6
-
7
- require_once dirname( __FILE__ ) . '/common/readoptions.php';
8
-
9
- delete_option( GTM4WP_OPTIONS );
1
+ <?php
2
+ // if uninstall.php is not called by WordPress, die
3
+ if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
4
+ die;
5
+ }
6
+
7
+ require_once dirname( __FILE__ ) . '/common/readoptions.php';
8
+
9
+ delete_option( GTM4WP_OPTIONS );