├── LICENSE.txt ├── assets ├── css │ ├── acf-field-group-osm.css │ ├── acf-field-group-osm.css.map │ ├── acf-input-osm.css │ ├── acf-input-osm.css.map │ ├── acf-osm-leaflet.css │ ├── acf-osm-leaflet.css.map │ ├── acf-osm-settings.css │ ├── acf-osm-settings.css.map │ └── images │ │ ├── geocoder.png │ │ ├── layers-2x.png │ │ ├── layers.png │ │ ├── marker-icon-2x.png │ │ ├── marker-icon.png │ │ ├── marker-shadow.png │ │ └── throbber.gif ├── js │ ├── acf-field-group-osm.js │ ├── acf-field-group-osm.js.LICENSE.txt │ ├── acf-field-group-osm.js.map │ ├── acf-input-osm.js │ ├── acf-input-osm.js.LICENSE.txt │ ├── acf-input-osm.js.map │ ├── acf-osm-frontend.js │ ├── acf-osm-frontend.js.LICENSE.txt │ ├── acf-osm-frontend.js.map │ ├── acf-osm-settings.js │ ├── acf-osm-settings.js.LICENSE.txt │ └── acf-osm-settings.js.map ├── location-arrow-solid.svg └── spinner-solid.svg ├── etc ├── leaflet-control-geocoders.json └── leaflet-providers.json ├── include ├── ACFFieldOpenstreetmap │ ├── Compat │ │ └── ACF.php │ ├── Core │ │ ├── Core.php │ │ ├── LeafletGeocoders.php │ │ ├── LeafletProviders.php │ │ ├── MapProxy.php │ │ ├── OSMProviders.php │ │ ├── Plugin.php │ │ ├── Singleton.php │ │ └── Templates.php │ ├── Field │ │ └── OpenStreetMap.php │ ├── Helper │ │ ├── ArrayHelper.php │ │ └── MapHelper.php │ ├── Settings │ │ ├── Settings.php │ │ ├── SettingsOpenStreetMap.php │ │ └── Traits │ │ │ ├── GeocoderSettings.php │ │ │ ├── ProviderSettings.php │ │ │ └── UIElements.php │ └── WPCLI │ │ ├── Commands │ │ └── MapProxy.php │ │ └── WPCLI.php ├── api.php ├── autoload.php ├── proxy.php └── version.php ├── index.php ├── languages └── acf-openstreetmap-field.pot ├── readme.txt └── templates ├── admin.php ├── leaflet.php └── osm.php /LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 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 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /assets/css/acf-field-group-osm.css: -------------------------------------------------------------------------------- 1 | .acf-field-setting-center_lat .acf-input-prepend{height:auto}/*# sourceMappingURL=acf-field-group-osm.css.map */ 2 | -------------------------------------------------------------------------------- /assets/css/acf-field-group-osm.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["../../src/scss/acf-field-group-osm.scss"],"names":[],"mappings":"AACC,iDACC","file":"acf-field-group-osm.css"} -------------------------------------------------------------------------------- /assets/css/acf-input-osm.css: -------------------------------------------------------------------------------- 1 | .leaflet-above,.leaflet-below{display:flex}.leaflet-control-locate a{cursor:pointer}.leaflet-control-locate a .leaflet-control-locate-location-arrow{display:inline-block;width:16px;height:16px;margin:7px;background-image:url('data:image/svg+xml;charset=UTF-8,')}.leaflet-control-locate a .leaflet-control-locate-spinner{display:inline-block;width:16px;height:16px;margin:7px;background-image:url('data:image/svg+xml;charset=UTF-8,');animation:leaflet-control-locate-spin 2s linear infinite}.leaflet-control-locate.active a .leaflet-control-locate-location-arrow{background-image:url('data:image/svg+xml;charset=UTF-8,')}.leaflet-control-locate.following a .leaflet-control-locate-location-arrow{background-image:url('data:image/svg+xml;charset=UTF-8,')}.leaflet-touch .leaflet-bar .leaflet-locate-text-active{width:100%;max-width:200px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;padding:0 10px}.leaflet-touch .leaflet-bar .leaflet-locate-text-active .leaflet-locate-icon{padding:0 5px 0 0}.leaflet-control-locate-location circle{animation:leaflet-control-locate-throb 4s ease infinite}@keyframes leaflet-control-locate-throb{0%{stroke-width:1}50%{stroke-width:3;transform:scale(0.8, 0.8)}100%{stroke-width:1}}@keyframes leaflet-control-locate-spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.leaflet-control-geocoder{border-radius:4px;background:#fff;min-width:26px;min-height:26px}.leaflet-touch .leaflet-control-geocoder{min-width:30px;min-height:30px}.leaflet-control-geocoder a,.leaflet-control-geocoder .leaflet-control-geocoder-icon{border-bottom:none;display:inline-block}.leaflet-control-geocoder .leaflet-control-geocoder-alternatives a{width:inherit;height:inherit;line-height:inherit}.leaflet-control-geocoder a:hover,.leaflet-control-geocoder .leaflet-control-geocoder-icon:hover{border-bottom:none;display:inline-block}.leaflet-control-geocoder-form{display:none;vertical-align:middle}.leaflet-control-geocoder-expanded .leaflet-control-geocoder-form{display:inline-block}.leaflet-control-geocoder-form input{font-size:120%;border:0;background-color:transparent;width:246px}.leaflet-control-geocoder-icon{border-radius:4px;width:26px;height:26px;border:none;background-color:#fff;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12.2 13l3.4 6.6c.6 1.1 2.5-.4 2-1.2l-4-6.2z'/%3E%3Ccircle cx='10.8' cy='8.9' r='3.9' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:center;cursor:pointer}.leaflet-touch .leaflet-control-geocoder-icon{width:30px;height:30px}.leaflet-control-geocoder-throbber .leaflet-control-geocoder-icon{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' stroke='%23000' stroke-linecap='round' stroke-width='1.6' viewBox='0 0 24 24'%3E%3Cdefs/%3E%3Cg%3E%3Cpath stroke-opacity='.1' d='M14 8.4l3-5'/%3E%3Cpath stroke-opacity='.2' d='M15.6 10l5-3'/%3E%3Cpath stroke-opacity='.3' d='M16.2 12H22'/%3E%3Cpath stroke-opacity='.4' d='M15.6 14l5 3m-6.5-1.4l2.9 5'/%3E%3Cpath stroke-opacity='.5' d='M12 16.2V22m-2-6.4l-3 5'/%3E%3Cpath stroke-opacity='.6' d='M8.4 14l-5 3'/%3E%3Cpath stroke-opacity='.7' d='M7.8 12H2'/%3E%3Cpath stroke-opacity='.8' d='M8.4 10l-5-3'/%3E%3Cpath stroke-opacity='.9' d='M10 8.4l-3-5'/%3E%3Cpath d='M12 7.8V2'/%3E%3CanimateTransform attributeName='transform' calcMode='discrete' dur='1s' repeatCount='indefinite' type='rotate' values='0 12 12;30 12 12;60 12 12;90 12 12;120 12 12;150 12 12;180 12 12;210 12 12;240 12 12;270 12 12;300 12 12;330 12 12'/%3E%3C/g%3E%3C/svg%3E")}.leaflet-control-geocoder-form-no-error{display:none}.leaflet-control-geocoder-form input:focus{outline:none}.leaflet-control-geocoder-form button{display:none}.leaflet-control-geocoder-error{margin-top:8px;margin-left:8px;display:block;color:#444}.leaflet-control-geocoder-alternatives{display:block;width:272px;list-style:none;padding:0;margin:0}.leaflet-control-geocoder-alternatives-minimized{display:none;height:0}.leaflet-control-geocoder-alternatives li{white-space:nowrap;display:block;overflow:hidden;padding:5px 8px;text-overflow:ellipsis;border-bottom:1px solid #ccc;cursor:pointer}.leaflet-control-geocoder-alternatives li a,.leaflet-control-geocoder-alternatives li a:hover{width:inherit;height:inherit;line-height:inherit;background:inherit;border-radius:inherit;text-align:left}.leaflet-control-geocoder-alternatives li:last-child{border-bottom:none}.leaflet-control-geocoder-alternatives li:hover,.leaflet-control-geocoder-selected{background-color:#f5f5f5}.leaflet-control-geocoder-address-context{color:#666}[data-map=leaflet]{width:100%}.leaflet-map{user-select:none}.block-editor__container .leaflet-map{width:100%}.block-editor__container .leaflet-map .leaflet-top,.block-editor__container .leaflet-map .leaflet-bottom{z-index:80}.leaflet-map[data-can-add-marker=false]~.markers-instruction .can-add-marker{display:none}.leaflet-map[data-has-markers=false]~.markers-instruction .has-markers{display:none}.leaflet-map.add-marker-on-taphold~.markers-instruction .marker-on-dblclick{display:none}.leaflet-map.add-marker-on-dblclick~.markers-instruction .marker-on-taphold{display:none}.acf-block-preview iframe[src*="openstreetmap.org"]{pointer-events:none}.acf-field-open-street-map .acf-osm-map{width:100%;height:400px}.acf-field-open-street-map input[type=search][data-prop=address]{font-size:20px;font-weight:300;letter-spacing:.03em;color:#32373c}.osm-markers .osm-marker{position:relative;display:flex;align-items:center;padding:.25em 0;border-bottom:1px solid #f1f1f1}.osm-markers .osm-marker:nth-of-type(2n){background-color:#fafafa}.osm-markers .osm-marker.focus{background-color:rgba(255,185,0,.5)}.osm-markers .osm-marker>.locate.dashicons,.osm-markers .osm-marker>.locate.dashicons::before{font-size:32px;cursor:pointer}.osm-markers .osm-marker>.tools,.osm-markers .osm-marker>.locate{flex:0;min-width:32px;text-align:center}.osm-markers .osm-marker>.input{flex:1}.osm-markers .osm-marker input[type=text]{width:100%;font-size:20px;font-weight:300}.osm-markers .osm-marker a.acf-icon.light{border:1px solid #ccc}.osm-markers [data-id=__osm_marker_template__]{display:none}@keyframes pling{0%{left:0;top:0;width:12px;height:12px;opacity:0}5%{opacity:1}80%{opacity:1}100%{left:-25px;top:-25px;width:62px;height:62px;opacity:0}}.osm-marker-icon{border-radius:50%}.osm-marker-icon:before{content:"";border-style:solid;border-color:#0085ba rgba(0,0,0,0) rgba(0,0,0,0) rgba(0,0,0,0);border-width:20px 12px 0 12px;position:absolute;left:-6px;top:-14px;z-index:1}.osm-marker-icon:after{content:"";clip:rect(0, 0, 100%, 100%);width:26px;height:26px;border-radius:13px;background-color:#fff;border:8px solid #0085ba;box-sizing:border-box;position:absolute;bottom:18px;left:-7px}.osm-marker-icon.focus:after,.osm-marker-icon:focus:after{box-shadow:0 0 6px 12px rgba(255,185,0,.75)}.osm-marker-icon:hover:before{border-top-color:#dc3232}.osm-marker-icon:hover:after{content:"";font-family:"dashicons";color:#fff;font-size:26px;line-height:27px;border-color:#dc3232;background-color:#dc3232;border-width:0;z-index:2}.osm-marker-icon .pling{position:absolute;opacity:0;border:4px solid #0085ba;border-radius:50%;animation-name:pling;animation-duration:.75s;animation-iteration-count:1;animation-timing-function:ease-in}@media screen and (min-width: 768px){.osm-marker-icon .pling{border-width:2px}}.acf-osm-above{position:relative;z-index:2}.acf-osm-above+.leaflet-map{z-index:1}.acf-osm-above .leaflet-control-geocoder{display:flex;width:100%;box-shadow:none;padding:5px 0;box-sizing:border-box;background-color:rgba(0,0,0,0)}.acf-osm-above .leaflet-control-geocoder>.leaflet-control-geocoder-icon,.acf-osm-above .leaflet-control-geocoder>.leaflet-control-geocoder-form{border-radius:none}.acf-osm-above .leaflet-control-geocoder>.leaflet-control-geocoder-icon{flex:0;min-width:42px;height:38px;order:2;background-color:#0085ba;background-image:none;border-radius:0 4px 4px 0}.acf-osm-above .leaflet-control-geocoder>.leaflet-control-geocoder-icon:before{content:"";font-family:"dashicons";color:#fff;font-size:20px}.acf-osm-above .leaflet-control-geocoder>.leaflet-control-geocoder-form{flex:1;order:1}.acf-osm-above .leaflet-control-geocoder>.leaflet-control-geocoder-form input{padding:.25em 1em;font-size:20px;line-height:1.3;font-weight:300;border:1px solid #8c8f94;border-top-right-radius:0;border-bottom-right-radius:0;width:100%}.acf-osm-above .leaflet-control-geocoder>.leaflet-control-geocoder-error,.acf-osm-above .leaflet-control-geocoder>.leaflet-control-geocoder-alternatives{margin:0;position:absolute;left:.5em;top:calc(100% + .5em);background:#fff;max-height:calc(var(--map-height, 400)*1px - 1em);overflow:auto}.acf-osm-above .leaflet-control-geocoder>.leaflet-control-geocoder-error{padding:.5em 1em}.wp-block .leaflet-pane{z-index:40}.wp-block .leaflet-tile-pane{z-index:20}.wp-block .leaflet-shadow-pane{z-index:50}.wp-block .leaflet-overlay-pane{z-index:40}.wp-block .leaflet-marker-pane{z-index:60}.wp-block .leaflet-tooltip-pane{z-index:65}.wp-block .leaflet-popup-pane{z-index:70}.acf-osm-settings-wrap .leaflet-pane,.postbox .leaflet-pane,.components-panel .leaflet-pane,.wp-block .leaflet-pane{z-index:30}.leaflet-control-container a{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.wp-block .leaflet-control-layers{text-align:left}.leaflet-control-layers-scrollbar{overscroll-behavior:contain}@keyframes following{from{color:#0085ba}to{color:rgb(114.5,202.5,230)}}.leaflet-control a .dashicons{line-height:30px}.leaflet-control-locate+.leaflet-control-add-location-marker{display:none;border-top-left-radius:0;border-top-right-radius:0;border-top-width:0 !important;margin-top:-10px !important}[data-can-add-marker=true] .leaflet-control-locate.active{border-bottom-left-radius:0;border-bottom-right-radius:0}[data-can-add-marker=true] .leaflet-control-locate.active .dashicons-location-alt{position:relative}[data-can-add-marker=true] .leaflet-control-locate.active .dashicons-location-alt::before{content:""}[data-can-add-marker=true] .leaflet-control-locate.active+.leaflet-control-add-location-marker{display:block}.leaflet-control-locate:not(.active):not(.following) .dashicons:not(.dashicons-warning){border-radius:50%;outline:1px solid currentcolor;outline-offset:-3px;border-image:conic-gradient(currentcolor 6deg, transparent 6deg 90deg, currentcolor 90deg 96deg, transparent 96deg 180deg, currentcolor 180deg 186deg, transparent 186deg 270deg, currentcolor 270deg 276deg, transparent 276deg);border-width:.5em;border-style:solid;box-sizing:border-box;border-image-repeat:stretch;border-image-slice:50%;transform:rotate(-3deg);margin-top:5px}.leaflet-control-locate:not(.active):not(.following) .dashicons:not(.dashicons-warning)::before{color:rgba(0,0,0,0)}.leaflet-control-locate.following .dashicons{color:#e5f5fa;animation-name:following;animation-duration:2s;animation-iteration-count:infinite;animation-direction:alternate}.leaflet-control-locate a .dashicons-warning{color:#dc3232}.leaflet-control-locate a .spinner{float:none;margin:-3px 0 0 0}.leaflet-control-add-location-marker .dashicons::before{line-height:30px;font-size:18px}.leaflet-control-add-location-marker .dashicons::after{content:"";font-size:13px;position:absolute;top:-6px;right:0}/*# sourceMappingURL=acf-input-osm.css.map */ 2 | -------------------------------------------------------------------------------- /assets/css/acf-input-osm.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["../../src/scss/lib/leaflet/_corners.scss","../../node_modules/leaflet.locatecontrol/src/L.Control.Locate.scss","../../node_modules/leaflet-control-geocoder/dist/Control.Geocoder.css","../../src/scss/acf-input-osm.scss","../../src/scss/variables/_colors.scss","../../src/scss/variables/_dashicons.scss"],"names":[],"mappings":"CAAA,8BAEC,aCOC,0BACE,eAEA,iEACE,qBACA,WACA,YACA,WACA,0OAGF,0DACE,qBACA,WACA,YACA,WACA,6bACA,yDAIJ,wEACE,sPAGF,2EACE,sPAIJ,wDACE,WACA,gBACA,uBACA,mBACA,gBACA,eAEA,6EACE,kBAIJ,wCACE,wDAGF,wCACE,GACE,eAGF,IACE,eACA,0BAGF,KACE,gBAIJ,uCACE,GACE,uBAGF,KACE,0BC7EJ,uvGCYA,mBACC,WAGD,aACC,iBACA,sCACC,WACA,yGAGC,WAID,6EACC,aAID,uEACC,aAGF,4EACC,aAED,4EACC,aAID,oDACC,oBAKD,wCACC,WACA,aAED,iEACC,eACA,gBACA,qBACA,MC3Ce,QDgDhB,yBACC,kBACA,aACA,mBACA,gBACA,gCACA,yCACC,iBCnDgB,QDqDjB,+BACC,oCAIC,8FAEC,eACA,eAIH,iEAEC,OACA,eACA,kBAED,gCACC,OAED,0CACC,WACA,eACA,gBAED,0CACC,sBAGF,+CACC,aAIF,iBACC,iDACA,aACA,cACA,4DAGD,iBAEC,kBAGA,wBACC,WACA,mBACA,+DACA,8BACA,kBACA,UACA,UACA,UAID,uBACC,WACA,4BACA,MALK,KAML,OANK,KAOL,mBACA,sBACA,yBACA,sBACA,kBACA,YACA,UAOA,0DAGC,4CAID,8BACC,iBCrJM,QDuJP,6BACC,YACA,wBACA,WACA,UAlCI,KAmCJ,iBACA,aC7JM,QD8JN,iBC9JM,QD+JN,eACA,UAGF,wBAGC,kBACA,UACA,yBAIA,kBAEA,qBACA,wBACA,4BACA,kCARA,qCAND,wBAOE,kBAWH,eACC,kBACA,UACA,4BACC,UAED,yCAEC,aACA,WACA,gBACA,cACA,sBACA,+BACA,gJAEC,mBAGD,wEACC,OACA,eACA,YACA,QACA,iBCpNO,QDqNP,sBACA,0BACA,+EACC,QEnBc,IFoBd,wBACA,WACA,eAGF,wEACC,OACA,QACA,8EACC,kBACA,eACA,gBACA,gBACA,yBACA,0BACA,6BACA,WAGF,yJAEC,SACA,kBACA,UACA,sBACA,gBACA,kDACA,cAED,yEACC,iBAwBD,wBACC,WADD,6BACC,WADD,+BACC,WADD,gCACC,WADD,+BACC,WADD,gCACC,WADD,8BACC,WAOF,oHAIC,WAKD,6BACC,2BACC,yBACC,wBACD,sBACC,qBACC,iBAKJ,kCACC,gBAIF,kCACC,4BAGD,qBACC,WCrTS,QDsTT,+BAKC,8BACC,iBAMF,6DACC,aACA,yBACA,0BACA,8BACA,4BAGA,0DAOC,4BACA,6BAPA,kFACC,kBACA,0FACC,QErJe,IF0JjB,+FACC,cAKF,wFACC,kBACA,+BACA,oBACA,kOACA,kBACA,mBACA,sBACA,4BACA,uBACA,wBACA,eAEA,gGAEC,oBAKF,6CACC,MC5We,QD6Wf,yBACA,sBACA,mCACA,8BAID,6CACC,MChXM,QDkXP,mCACC,WACA,kBAMD,wDACC,iBACA,eAED,uDACC,QErOa,IFsOb,eACA,kBACA,SACA","file":"acf-input-osm.css"} -------------------------------------------------------------------------------- /assets/css/acf-osm-leaflet.css: -------------------------------------------------------------------------------- 1 | .leaflet-pane,.leaflet-tile,.leaflet-marker-icon,.leaflet-marker-shadow,.leaflet-tile-container,.leaflet-pane>svg,.leaflet-pane>canvas,.leaflet-zoom-box,.leaflet-image-layer,.leaflet-layer{position:absolute;left:0;top:0}.leaflet-container{overflow:hidden}.leaflet-tile,.leaflet-marker-icon,.leaflet-marker-shadow{-webkit-user-select:none;-moz-user-select:none;user-select:none;-webkit-user-drag:none}.leaflet-tile::selection{background:transparent}.leaflet-safari .leaflet-tile{image-rendering:-webkit-optimize-contrast}.leaflet-safari .leaflet-tile-container{width:1600px;height:1600px;-webkit-transform-origin:0 0}.leaflet-marker-icon,.leaflet-marker-shadow{display:block}.leaflet-container .leaflet-overlay-pane svg{max-width:none !important;max-height:none !important}.leaflet-container .leaflet-marker-pane img,.leaflet-container .leaflet-shadow-pane img,.leaflet-container .leaflet-tile-pane img,.leaflet-container img.leaflet-image-layer,.leaflet-container .leaflet-tile{max-width:none !important;max-height:none !important;width:auto;padding:0}.leaflet-container img.leaflet-tile{mix-blend-mode:plus-lighter}.leaflet-container.leaflet-touch-zoom{-ms-touch-action:pan-x pan-y;touch-action:pan-x pan-y}.leaflet-container.leaflet-touch-drag{-ms-touch-action:pinch-zoom;touch-action:none;touch-action:pinch-zoom}.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom{-ms-touch-action:none;touch-action:none}.leaflet-container{-webkit-tap-highlight-color:transparent}.leaflet-container a{-webkit-tap-highlight-color:rgba(51, 181, 229, 0.4)}.leaflet-tile{filter:inherit;visibility:hidden}.leaflet-tile-loaded{visibility:inherit}.leaflet-zoom-box{width:0;height:0;-moz-box-sizing:border-box;box-sizing:border-box;z-index:800}.leaflet-overlay-pane svg{-moz-user-select:none}.leaflet-pane{z-index:400}.leaflet-tile-pane{z-index:200}.leaflet-overlay-pane{z-index:400}.leaflet-shadow-pane{z-index:500}.leaflet-marker-pane{z-index:600}.leaflet-tooltip-pane{z-index:650}.leaflet-popup-pane{z-index:700}.leaflet-map-pane canvas{z-index:100}.leaflet-map-pane svg{z-index:200}.leaflet-vml-shape{width:1px;height:1px}.lvml{behavior:url(#default#VML);display:inline-block;position:absolute}.leaflet-control{position:relative;z-index:800;pointer-events:visiblePainted;pointer-events:auto}.leaflet-top,.leaflet-bottom{position:absolute;z-index:1000;pointer-events:none}.leaflet-top{top:0}.leaflet-right{right:0}.leaflet-bottom{bottom:0}.leaflet-left{left:0}.leaflet-control{float:left;clear:both}.leaflet-right .leaflet-control{float:right}.leaflet-top .leaflet-control{margin-top:10px}.leaflet-bottom .leaflet-control{margin-bottom:10px}.leaflet-left .leaflet-control{margin-left:10px}.leaflet-right .leaflet-control{margin-right:10px}.leaflet-fade-anim .leaflet-popup{opacity:0;-webkit-transition:opacity .2s linear;-moz-transition:opacity .2s linear;transition:opacity .2s linear}.leaflet-fade-anim .leaflet-map-pane .leaflet-popup{opacity:1}.leaflet-zoom-animated{-webkit-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0}svg.leaflet-zoom-animated{will-change:transform}.leaflet-zoom-anim .leaflet-zoom-animated{-webkit-transition:-webkit-transform .25s cubic-bezier(0, 0, 0.25, 1);-moz-transition:-moz-transform .25s cubic-bezier(0, 0, 0.25, 1);transition:transform .25s cubic-bezier(0, 0, 0.25, 1)}.leaflet-zoom-anim .leaflet-tile,.leaflet-pan-anim .leaflet-tile{-webkit-transition:none;-moz-transition:none;transition:none}.leaflet-zoom-anim .leaflet-zoom-hide{visibility:hidden}.leaflet-interactive{cursor:pointer}.leaflet-grab{cursor:-webkit-grab;cursor:-moz-grab;cursor:grab}.leaflet-crosshair,.leaflet-crosshair .leaflet-interactive{cursor:crosshair}.leaflet-popup-pane,.leaflet-control{cursor:auto}.leaflet-dragging .leaflet-grab,.leaflet-dragging .leaflet-grab .leaflet-interactive,.leaflet-dragging .leaflet-marker-draggable{cursor:move;cursor:-webkit-grabbing;cursor:-moz-grabbing;cursor:grabbing}.leaflet-marker-icon,.leaflet-marker-shadow,.leaflet-image-layer,.leaflet-pane>svg path,.leaflet-tile-container{pointer-events:none}.leaflet-marker-icon.leaflet-interactive,.leaflet-image-layer.leaflet-interactive,.leaflet-pane>svg path.leaflet-interactive,svg.leaflet-image-layer.leaflet-interactive path{pointer-events:visiblePainted;pointer-events:auto}.leaflet-container{background:#ddd;outline-offset:1px}.leaflet-container a{color:#0078a8}.leaflet-zoom-box{border:2px dotted #38f;background:rgba(255, 255, 255, 0.5)}.leaflet-container{font-family:"Helvetica Neue",Arial,Helvetica,sans-serif;font-size:12px;font-size:.75rem;line-height:1.5}.leaflet-bar{box-shadow:0 1px 5px rgba(0, 0, 0, 0.65);border-radius:4px}.leaflet-bar a{background-color:#fff;border-bottom:1px solid #ccc;width:26px;height:26px;line-height:26px;display:block;text-align:center;text-decoration:none;color:black}.leaflet-bar a,.leaflet-control-layers-toggle{background-position:50% 50%;background-repeat:no-repeat;display:block}.leaflet-bar a:hover,.leaflet-bar a:focus{background-color:#f4f4f4}.leaflet-bar a:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.leaflet-bar a:last-child{border-bottom-left-radius:4px;border-bottom-right-radius:4px;border-bottom:none}.leaflet-bar a.leaflet-disabled{cursor:default;background-color:#f4f4f4;color:#bbb}.leaflet-touch .leaflet-bar a{width:30px;height:30px;line-height:30px}.leaflet-touch .leaflet-bar a:first-child{border-top-left-radius:2px;border-top-right-radius:2px}.leaflet-touch .leaflet-bar a:last-child{border-bottom-left-radius:2px;border-bottom-right-radius:2px}.leaflet-control-zoom-in,.leaflet-control-zoom-out{font:bold 18px "Lucida Console",Monaco,monospace;text-indent:1px}.leaflet-touch .leaflet-control-zoom-in,.leaflet-touch .leaflet-control-zoom-out{font-size:22px}.leaflet-control-layers{box-shadow:0 1px 5px rgba(0, 0, 0, 0.4);background:#fff;border-radius:5px}.leaflet-control-layers-toggle{background-image:url(images/layers.png);width:36px;height:36px}.leaflet-retina .leaflet-control-layers-toggle{background-image:url(images/layers-2x.png);background-size:26px 26px}.leaflet-touch .leaflet-control-layers-toggle{width:44px;height:44px}.leaflet-control-layers .leaflet-control-layers-list,.leaflet-control-layers-expanded .leaflet-control-layers-toggle{display:none}.leaflet-control-layers-expanded .leaflet-control-layers-list{display:block;position:relative}.leaflet-control-layers-expanded{padding:6px 10px 6px 6px;color:#333;background:#fff}.leaflet-control-layers-scrollbar{overflow-y:scroll;overflow-x:hidden;padding-right:5px}.leaflet-control-layers-selector{margin-top:2px;position:relative;top:1px}.leaflet-control-layers label{display:block;font-size:13px;font-size:1.08333em}.leaflet-control-layers-separator{height:0;border-top:1px solid #ddd;margin:5px -10px 5px -6px}.leaflet-default-icon-path{background-image:url(images/marker-icon.png)}.leaflet-container .leaflet-control-attribution{background:#fff;background:rgba(255, 255, 255, 0.8);margin:0}.leaflet-control-attribution,.leaflet-control-scale-line{padding:0 5px;color:#333;line-height:1.4}.leaflet-control-attribution a{text-decoration:none}.leaflet-control-attribution a:hover,.leaflet-control-attribution a:focus{text-decoration:underline}.leaflet-attribution-flag{display:inline !important;vertical-align:baseline !important;width:1em;height:.6669em}.leaflet-left .leaflet-control-scale{margin-left:5px}.leaflet-bottom .leaflet-control-scale{margin-bottom:5px}.leaflet-control-scale-line{border:2px solid #777;border-top:none;line-height:1.1;padding:2px 5px 1px;white-space:nowrap;-moz-box-sizing:border-box;box-sizing:border-box;background:rgba(255, 255, 255, 0.8);text-shadow:1px 1px #fff}.leaflet-control-scale-line:not(:first-child){border-top:2px solid #777;border-bottom:none;margin-top:-2px}.leaflet-control-scale-line:not(:first-child):not(:last-child){border-bottom:2px solid #777}.leaflet-touch .leaflet-control-attribution,.leaflet-touch .leaflet-control-layers,.leaflet-touch .leaflet-bar{box-shadow:none}.leaflet-touch .leaflet-control-layers,.leaflet-touch .leaflet-bar{border:2px solid rgba(0, 0, 0, 0.2);background-clip:padding-box}.leaflet-popup{position:absolute;text-align:center;margin-bottom:20px}.leaflet-popup-content-wrapper{padding:1px;text-align:left;border-radius:12px}.leaflet-popup-content{margin:13px 24px 13px 20px;line-height:1.3;font-size:13px;font-size:1.08333em;min-height:1px}.leaflet-popup-content p{margin:17px 0;margin:1.3em 0}.leaflet-popup-tip-container{width:40px;height:20px;position:absolute;left:50%;margin-top:-1px;margin-left:-20px;overflow:hidden;pointer-events:none}.leaflet-popup-tip{width:17px;height:17px;padding:1px;margin:-10px auto 0;pointer-events:auto;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.leaflet-popup-content-wrapper,.leaflet-popup-tip{background:white;color:#333;box-shadow:0 3px 14px rgba(0, 0, 0, 0.4)}.leaflet-container a.leaflet-popup-close-button{position:absolute;top:0;right:0;border:none;text-align:center;width:24px;height:24px;font:16px/24px Tahoma,Verdana,sans-serif;color:#757575;text-decoration:none;background:transparent}.leaflet-container a.leaflet-popup-close-button:hover,.leaflet-container a.leaflet-popup-close-button:focus{color:#585858}.leaflet-popup-scrolled{overflow:auto}.leaflet-oldie .leaflet-popup-content-wrapper{-ms-zoom:1}.leaflet-oldie .leaflet-popup-tip{width:24px;margin:0 auto;-ms-filter:"progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";filter:progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)}.leaflet-oldie .leaflet-control-zoom,.leaflet-oldie .leaflet-control-layers,.leaflet-oldie .leaflet-popup-content-wrapper,.leaflet-oldie .leaflet-popup-tip{border:1px solid #999}.leaflet-div-icon{background:#fff;border:1px solid #666}.leaflet-tooltip{position:absolute;padding:6px;background-color:#fff;border:1px solid #fff;border-radius:3px;color:#222;white-space:nowrap;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;pointer-events:none;box-shadow:0 1px 3px rgba(0, 0, 0, 0.4)}.leaflet-tooltip.leaflet-interactive{cursor:pointer;pointer-events:auto}.leaflet-tooltip-top:before,.leaflet-tooltip-bottom:before,.leaflet-tooltip-left:before,.leaflet-tooltip-right:before{position:absolute;pointer-events:none;border:6px solid transparent;background:transparent;content:""}.leaflet-tooltip-bottom{margin-top:6px}.leaflet-tooltip-top{margin-top:-6px}.leaflet-tooltip-bottom:before,.leaflet-tooltip-top:before{left:50%;margin-left:-6px}.leaflet-tooltip-top:before{bottom:0;margin-bottom:-12px;border-top-color:#fff}.leaflet-tooltip-bottom:before{top:0;margin-top:-12px;margin-left:-6px;border-bottom-color:#fff}.leaflet-tooltip-left{margin-left:-6px}.leaflet-tooltip-right{margin-left:6px}.leaflet-tooltip-left:before,.leaflet-tooltip-right:before{top:50%;margin-top:-6px}.leaflet-tooltip-left:before{right:0;margin-right:-12px;border-left-color:#fff}.leaflet-tooltip-right:before{left:0;margin-left:-12px;border-right-color:#fff}@media print{.leaflet-control{-webkit-print-color-adjust:exact;print-color-adjust:exact}}/*# sourceMappingURL=acf-osm-leaflet.css.map */ 2 | -------------------------------------------------------------------------------- /assets/css/acf-osm-leaflet.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["../../node_modules/leaflet/dist/leaflet.css"],"names":[],"mappings":"AAEA,6LAUC,kBACA,OACA,MAED,mBACC,gBAED,0DAGC,yBACG,sBACK,iBACN,uBAGH,yBACC,uBAGD,8BACC,0CAGD,wCACC,aACA,cACA,6BAED,4CAEC,cAID,6CACC,0BACA,2BAED,8MAKC,0BACA,2BACA,WACA,UAGD,oCAEC,4BAGD,sCACC,6BACA,yBAED,sCACC,4BAEA,kBACA,wBAED,yDACC,sBACA,kBAED,mBACC,wCAED,qBACC,oDAED,cACC,eACA,kBAED,qBACC,mBAED,kBACC,QACA,SACA,2BACK,sBACL,YAGD,0BACC,sBAGD,0BAEA,+BACA,kCACA,iCACA,iCACA,kCACA,gCAEA,qCACA,kCAEA,mBACC,UACA,WAED,MACC,2BACA,qBACA,kBAMD,iBACC,kBACA,YACA,8BACA,oBAED,6BAEC,kBACA,aACA,oBAED,aACC,MAED,eACC,QAED,gBACC,SAED,cACC,OAED,iBACC,WACA,WAED,gCACC,YAED,8BACC,gBAED,iCACC,mBAED,+BACC,iBAED,gCACC,kBAMD,kCACC,UACA,sCACG,mCACK,8BAET,oDACC,UAED,uBACC,6BACI,yBACI,qBAET,0BACC,sBAGD,0CACC,sEACG,gEACK,sDAET,iEAEC,wBACG,qBACK,gBAGT,sCACC,kBAMD,qBACC,eAED,cACC,oBACA,iBACA,YAED,2DAEC,iBAED,qCAEC,YAED,iIAGC,YACA,wBACA,qBACA,gBAID,gHAKC,oBAGD,8KAIC,8BACA,oBAKD,mBACC,gBACA,mBAED,qBACC,cAED,kBACC,uBACA,oCAKD,mBACC,wDACA,eACA,iBACA,gBAMD,aACC,yCACA,kBAED,eACC,sBACA,6BACA,WACA,YACA,iBACA,cACA,kBACA,qBACA,YAED,8CAEC,4BACA,4BACA,cAED,0CAEC,yBAED,2BACC,2BACA,4BAED,0BACC,8BACA,+BACA,mBAED,gCACC,eACA,yBACA,WAGD,8BACC,WACA,YACA,iBAED,0CACC,2BACA,4BAED,yCACC,8BACA,+BAKD,mDAEC,iDACA,gBAGD,iFACC,eAMD,wBACC,wCACA,gBACA,kBAED,+BACC,wCACA,WACA,YAED,+CACC,2CACA,0BAED,8CACC,WACA,YAED,qHAEC,aAED,8DACC,cACA,kBAED,iCACC,yBACA,WACA,gBAED,kCACC,kBACA,kBACA,kBAED,iCACC,eACA,kBACA,QAED,8BACC,cACA,eACA,oBAED,kCACC,SACA,0BACA,0BAID,2BACC,6CAMD,gDACC,gBACA,oCACA,SAED,yDAEC,cACA,WACA,gBAED,+BACC,qBAED,0EAEC,0BAED,0BACC,0BACA,mCACA,UACA,eAED,qCACC,gBAED,uCACC,kBAED,4BACC,sBACA,gBACA,gBACA,oBACA,mBACA,2BACK,sBACL,oCACA,yBAED,8CACC,0BACA,mBACA,gBAED,+DACC,6BAGD,+GAGC,gBAED,mEAEC,oCACA,4BAMD,eACC,kBACA,kBACA,mBAED,+BACC,YACA,gBACA,mBAED,uBACC,2BACA,gBACA,eACA,oBACA,eAED,yBACC,cACA,eAED,6BACC,WACA,YACA,kBACA,SACA,gBACA,kBACA,gBACA,oBAED,mBACC,WACA,YACA,YAEA,oBACA,oBAEA,gCACG,6BACC,4BACI,wBAET,kDAEC,iBACA,WACA,yCAED,gDACC,kBACA,MACA,QACA,YACA,kBACA,WACA,YACA,yCACA,cACA,qBACA,uBAED,4GAEC,cAED,wBACC,cAGD,8CACC,WAED,kCACC,WACA,cAEA,uHACA,iHAGD,4JAIC,sBAMD,kBACC,gBACA,sBAMD,iBACC,kBACA,YACA,sBACA,sBACA,kBACA,WACA,mBACA,yBACA,sBACA,qBACA,iBACA,oBACA,wCAED,qCACC,eACA,oBAED,sHAIC,kBACA,oBACA,6BACA,uBACA,WAKD,wBACC,eAED,qBACC,gBAED,2DAEC,SACA,iBAED,4BACC,SACA,oBACA,sBAED,+BACC,MACA,iBACA,iBACA,yBAED,sBACC,iBAED,uBACC,gBAED,2DAEC,QACA,gBAED,6BACC,QACA,mBACA,uBAED,8BACC,OACA,kBACA,wBAKD,aAEC,iBACC,iCACA","file":"acf-osm-leaflet.css"} -------------------------------------------------------------------------------- /assets/css/acf-osm-settings.css: -------------------------------------------------------------------------------- 1 | .leaflet-bar-part .dashicons{margin-top:4px}.acf-osm-settings-wrap .tab-content{display:none}.acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-1]~.acf-osm-tab-1,.acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-2]~.acf-osm-tab-2,.acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-3]~.acf-osm-tab-3{display:block}.acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-1]~.nav-tab-wrapper [for=acf-osm-tab-1],.acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-2]~.nav-tab-wrapper [for=acf-osm-tab-2],.acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-3]~.nav-tab-wrapper [for=acf-osm-tab-3]{margin-bottom:-1px;box-shadow:none}.acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-1]~.nav-tab-wrapper [for=acf-osm-tab-1],.acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-1]~.nav-tab-wrapper [for=acf-osm-tab-1]:hover,.acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-1]~.nav-tab-wrapper [for=acf-osm-tab-1]:focus .acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-1]~.nav-tab-wrapper [for=acf-osm-tab-1]:focus:active,.acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-2]~.nav-tab-wrapper [for=acf-osm-tab-2],.acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-2]~.nav-tab-wrapper [for=acf-osm-tab-2]:hover,.acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-1]~.nav-tab-wrapper [for=acf-osm-tab-1]:focus .acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-2]~.nav-tab-wrapper [for=acf-osm-tab-2]:focus:active,.acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-3]~.nav-tab-wrapper [for=acf-osm-tab-3],.acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-3]~.nav-tab-wrapper [for=acf-osm-tab-3]:hover,.acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-1]~.nav-tab-wrapper [for=acf-osm-tab-1]:focus .acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-3]~.nav-tab-wrapper [for=acf-osm-tab-3]:focus:active,.acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-2]~.nav-tab-wrapper [for=acf-osm-tab-2]:focus .acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-1]~.nav-tab-wrapper [for=acf-osm-tab-1]:focus:active,.acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-2]~.nav-tab-wrapper [for=acf-osm-tab-2]:focus .acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-2]~.nav-tab-wrapper [for=acf-osm-tab-2]:focus:active,.acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-2]~.nav-tab-wrapper [for=acf-osm-tab-2]:focus .acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-3]~.nav-tab-wrapper [for=acf-osm-tab-3]:focus:active,.acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-3]~.nav-tab-wrapper [for=acf-osm-tab-3]:focus .acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-1]~.nav-tab-wrapper [for=acf-osm-tab-1]:focus:active,.acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-3]~.nav-tab-wrapper [for=acf-osm-tab-3]:focus .acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-2]~.nav-tab-wrapper [for=acf-osm-tab-2]:focus:active,.acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-3]~.nav-tab-wrapper [for=acf-osm-tab-3]:focus .acf-osm-settings-wrap [type=radio]:checked[id=acf-osm-tab-3]~.nav-tab-wrapper [for=acf-osm-tab-3]:focus:active{border-bottom:1px solid #f0f0f1;background:#f0f0f1;color:#000}.acf-osm-settings{display:flex}.acf-osm-settings .acf-osm-layer-variants{display:flex;flex-wrap:wrap;align-items:flex-start}.acf-osm-settings .acf-osm-layer-variants .layer-variant{flex:0 1 250px;padding:.5em .5em .5em 0}.acf-osm-settings .acf-osm-layer-variants .action-test{margin-left:auto;font-weight:normal}.acf-osm-settings .acf-osm-tag{display:inline-block;padding:.25em .5em;font-size:.8em;color:#fff;border-radius:1em;line-height:1em;margin-left:1em;font-weight:normal;white-space:nowrap;background-color:#32373c}.acf-osm-settings .acf-osm-tag.warn{background-color:#dc3232}.acf-osm-settings .acf-osm-test-map-container{position:relative;margin-left:5px;background-color:#fff;max-width:300px;min-width:300px}.acf-osm-settings .acf-osm-test-map{background:#0085ba;position:sticky;top:32px}.acf-osm-settings .leaflet-container{min-height:400px;height:calc(100vh - 32px)}.acf-osm-setting{transition:filter .3s}.acf-osm-setting.disabled{filter:grayscale(1) contrast(0.5) brightness(1.75)}.acf-osm-setting.disabled .disabled{filter:none}.acf-osm-setting-provider{background:#fff;padding:10px 20px;margin-bottom:5px}.acf-osm-setting-provider h4{margin-bottom:.33em}.acf-osm-geocoder-settings{display:grid;grid-template-columns:2fr 1fr;overflow:hidden;align-items:start;gap:2em}.acf-osm-geocoder-settings .leaflet-container{aspect-ratio:3/2}.acf-osm-geocoder-settings .acf-osm-test-map-container{overflow:hidden}.acf-osm-geocoder-settings .acf-osm-geocode-response{overflow:auto;max-width:100%}.acf-osm-geocoder-settings .acf-osm-geocode-response:empty{display:none}.acf-osm-geocoder-settings h3:has(+.acf-osm-geocode-response:empty){display:none}.acf-osm-geocoder-settings .card{max-width:none}.acf-osm-setting-access-key label [data-action=change-token]{margin-left:.5em}.acf-osm-setting-access-key label:has([data-action=cancel-token]) :first-child,.acf-osm-setting-access-key label:has([data-action=cancel-token]) [data-action=change-token]{display:none}/*# sourceMappingURL=acf-osm-settings.css.map */ 2 | -------------------------------------------------------------------------------- /assets/css/acf-osm-settings.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["../../src/scss/acf-osm-settings.scss","../../src/scss/variables/_colors.scss"],"names":[],"mappings":"AASC,6BACC,eAKD,oCACC,aAGA,uOAGC,cAED,ySAGC,mBACA,gBACA,qgFAIC,gCACA,mBACA,WAMJ,kBACC,aACA,0CACC,aACA,eACA,uBACA,yDACC,eACA,yBAGD,uDACC,iBACA,mBAGF,+BACC,qBACA,mBACA,eACA,WACA,kBACA,gBACA,gBACA,mBACA,mBACA,iBCpDe,QDqDf,oCACC,iBC7DM,QDgER,8CACC,kBACA,gBACA,sBACA,gBACA,gBAED,oCACC,WC/EQ,QDgFR,gBACA,SAED,qCACC,iBACA,0BAIF,iBACC,sBACA,0BACC,mDACA,oCACC,YAKH,0BACC,gBACA,kBACA,kBACA,6BACC,oBAGF,2BACC,aAEA,8BACA,gBACA,kBACA,QACA,8CACC,iBAED,uDACC,gBAED,qDACC,cACA,eACA,2DACC,aAGF,oEACC,aAED,iCACC,eAMA,6DACC,iBAGA,4KAEC","file":"acf-osm-settings.css"} -------------------------------------------------------------------------------- /assets/css/images/geocoder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcguffin/acf-openstreetmap-field/32bdab585c574dd60b7c7b65c6c3bb2a0683fe85/assets/css/images/geocoder.png -------------------------------------------------------------------------------- /assets/css/images/layers-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcguffin/acf-openstreetmap-field/32bdab585c574dd60b7c7b65c6c3bb2a0683fe85/assets/css/images/layers-2x.png -------------------------------------------------------------------------------- /assets/css/images/layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcguffin/acf-openstreetmap-field/32bdab585c574dd60b7c7b65c6c3bb2a0683fe85/assets/css/images/layers.png -------------------------------------------------------------------------------- /assets/css/images/marker-icon-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcguffin/acf-openstreetmap-field/32bdab585c574dd60b7c7b65c6c3bb2a0683fe85/assets/css/images/marker-icon-2x.png -------------------------------------------------------------------------------- /assets/css/images/marker-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcguffin/acf-openstreetmap-field/32bdab585c574dd60b7c7b65c6c3bb2a0683fe85/assets/css/images/marker-icon.png -------------------------------------------------------------------------------- /assets/css/images/marker-shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcguffin/acf-openstreetmap-field/32bdab585c574dd60b7c7b65c6c3bb2a0683fe85/assets/css/images/marker-shadow.png -------------------------------------------------------------------------------- /assets/css/images/throbber.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcguffin/acf-openstreetmap-field/32bdab585c574dd60b7c7b65c6c3bb2a0683fe85/assets/css/images/throbber.gif -------------------------------------------------------------------------------- /assets/js/acf-field-group-osm.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /* @preserve 2 | * Leaflet 1.9.4, a JS library for interactive maps. https://leafletjs.com 3 | * (c) 2010-2023 Vladimir Agafonkin, (c) 2010-2011 CloudMade 4 | */ 5 | 6 | /* @preserve 7 | * Leaflet Control Geocoder 8 | * https://github.com/perliedman/leaflet-control-geocoder 9 | * 10 | * Copyright (c) 2012 sa3m (https://github.com/sa3m) 11 | * Copyright (c) 2018 Per Liedman 12 | * All rights reserved. 13 | */ 14 | 15 | /*! 16 | Copyright (c) 2016 Dominik Moritz 17 | 18 | This file is part of the leaflet locate control. It is licensed under the MIT license. 19 | You can find the project at: https://github.com/domoritz/leaflet-locatecontrol 20 | */ 21 | -------------------------------------------------------------------------------- /assets/js/acf-input-osm.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /* @preserve 2 | * Leaflet 1.9.4, a JS library for interactive maps. https://leafletjs.com 3 | * (c) 2010-2023 Vladimir Agafonkin, (c) 2010-2011 CloudMade 4 | */ 5 | 6 | /* @preserve 7 | * Leaflet Control Geocoder 8 | * https://github.com/perliedman/leaflet-control-geocoder 9 | * 10 | * Copyright (c) 2012 sa3m (https://github.com/sa3m) 11 | * Copyright (c) 2018 Per Liedman 12 | * All rights reserved. 13 | */ 14 | 15 | /*! 16 | Copyright (c) 2016 Dominik Moritz 17 | 18 | This file is part of the leaflet locate control. It is licensed under the MIT license. 19 | You can find the project at: https://github.com/domoritz/leaflet-locatecontrol 20 | */ 21 | -------------------------------------------------------------------------------- /assets/js/acf-osm-frontend.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /* @preserve 2 | * Leaflet 1.9.4, a JS library for interactive maps. https://leafletjs.com 3 | * (c) 2010-2023 Vladimir Agafonkin, (c) 2010-2011 CloudMade 4 | */ 5 | 6 | /* @preserve 7 | * Leaflet Control Geocoder 8 | * https://github.com/perliedman/leaflet-control-geocoder 9 | * 10 | * Copyright (c) 2012 sa3m (https://github.com/sa3m) 11 | * Copyright (c) 2018 Per Liedman 12 | * All rights reserved. 13 | */ 14 | 15 | /*! 16 | Copyright (c) 2016 Dominik Moritz 17 | 18 | This file is part of the leaflet locate control. It is licensed under the MIT license. 19 | You can find the project at: https://github.com/domoritz/leaflet-locatecontrol 20 | */ 21 | -------------------------------------------------------------------------------- /assets/js/acf-osm-settings.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /* @preserve 2 | * Leaflet 1.9.4, a JS library for interactive maps. https://leafletjs.com 3 | * (c) 2010-2023 Vladimir Agafonkin, (c) 2010-2011 CloudMade 4 | */ 5 | 6 | /* @preserve 7 | * Leaflet Control Geocoder 8 | * https://github.com/perliedman/leaflet-control-geocoder 9 | * 10 | * Copyright (c) 2012 sa3m (https://github.com/sa3m) 11 | * Copyright (c) 2018 Per Liedman 12 | * All rights reserved. 13 | */ 14 | 15 | /*! 16 | Copyright (c) 2016 Dominik Moritz 17 | 18 | This file is part of the leaflet locate control. It is licensed under the MIT license. 19 | You can find the project at: https://github.com/domoritz/leaflet-locatecontrol 20 | */ 21 | -------------------------------------------------------------------------------- /assets/location-arrow-solid.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/spinner-solid.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /etc/leaflet-control-geocoders.json: -------------------------------------------------------------------------------- 1 | { 2 | "nominatim": { 3 | "label": "Nominatim", 4 | "options": { 5 | } 6 | }, 7 | "photon": { 8 | "label": "Photon", 9 | "options": { 10 | "apiKey": null 11 | }, 12 | "settings": { 13 | "apiKey": { 14 | "label": "Photon API Key", 15 | "type": "text", 16 | "required": false 17 | } 18 | } 19 | }, 20 | "opencage": { 21 | "label": "OpenCage", 22 | "options": { 23 | "apiKey": null 24 | }, 25 | "settings": { 26 | "apiKey": { 27 | "label": "OpenCage API Key", 28 | "type": "text", 29 | "required": true 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /include/ACFFieldOpenstreetmap/Compat/ACF.php: -------------------------------------------------------------------------------- 1 | $field['return_format'], 44 | 'value' => $field['value'], 45 | 'height' => 400, 46 | 'attr' => $field['attr'], 47 | ]; 48 | 49 | if ( isset( $field['attr'] ) ) { 50 | $inp_field['attr'] = $field['attr']; 51 | } 52 | 53 | $map_field = acf_get_field_type('open_street_map'); 54 | 55 | // format_value() returns sanitized HTML 56 | echo $map_field->format_value( $field['value'], null, $inp_field ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 57 | } 58 | 59 | /** 60 | * @action acf/include_field_types 61 | * 62 | * This function will include the field type class 63 | * 64 | * @type function 65 | * @date 17/02/2016 66 | * @since 1.0.0 67 | * 68 | * @param $version (int) major ACF version. Defaults to false 69 | * @return n/a 70 | */ 71 | public function include_field_types( $version = false ) { 72 | 73 | if ( version_compare( acf_get_setting('version'), '5.7', '>=' ) ) { 74 | acf_register_field_type( new Field\OpenStreetMap() ); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /include/ACFFieldOpenstreetmap/Core/Core.php: -------------------------------------------------------------------------------- 1 | base !== 'settings_page_acf_osm' ) { 50 | $provider_filters[] = 'enabled'; 51 | } 52 | 53 | $language = substr( get_locale(), 0, 2 ); 54 | 55 | /* frontend */ 56 | /** 57 | * Marker Icon HTML. Return false to use image icon (either leaflet default or return value of filter `acf_osm_marker_icon`) 58 | * 59 | * @param $marker_icon_html string Additional Icon HTML. 60 | */ 61 | $marker_html = apply_filters( 'acf_osm_marker_html', false ); 62 | 63 | if ( $marker_html !== false ) { 64 | $marker_html = wp_kses_post( $marker_html ); 65 | } 66 | 67 | $osm_l10n = [ 68 | 'options' => [ 69 | 'marker' => [ 70 | 71 | 'html' => $marker_html, 72 | 73 | /** 74 | * HTML Marker Icon css class 75 | * 76 | * @param $classname string Class name for HTML icon. Default 'acf-osm-marker-icon' 77 | */ 78 | 'className' => sanitize_html_class( apply_filters('acf_osm_marker_classname', 'acf-osm-marker-icon' ) ), 79 | 80 | /** 81 | * Return leaflet icon options. 82 | * 83 | * @see https://leafletjs.com/reference-1.3.2.html#icon 84 | * 85 | * @param $icon_options false (leaflet default icon or HTML icon) or array( 86 | * 'iconUrl' => image URL 87 | * 'iconRetinaUrl' => image URL 88 | * 'iconSize' => array( int, int ) 89 | * 'iconAnchor' => array( int, int ) 90 | * 'popupAnchor' => array( int, int ) 91 | * 'tooltipAnchor' => array( int, int ) 92 | * 'shadowUrl' => image URL 93 | * 'shadowRetinaUrl' => image URL 94 | * 'shadowSize' => array( int, int ) 95 | * 'shadowAnchor' => array( int, int ) 96 | * 'className' => string 97 | * ) 98 | */ 99 | 'icon' => apply_filters('acf_osm_marker_icon', false ), 100 | ], 101 | 102 | ], 103 | 'providers' => $leaflet_providers->get_providers( $provider_filters ), 104 | ]; 105 | $geocoders = $leaflet_geocoders->get_geocoders(); 106 | $osm_settings = [ 107 | 'options' => [ 108 | 'layer_config' => $leaflet_providers->get_layer_config(), // settings only 109 | ], 110 | 'geocoders' => array_combine( 111 | array_keys( $geocoders ), 112 | array_map( 113 | function( $geocoder ) use ( $leaflet_geocoders ) { 114 | return $leaflet_geocoders->get_options( $geocoder ); 115 | }, 116 | array_keys( $geocoders ) 117 | ), 118 | ), 119 | ]; 120 | 121 | /** 122 | * Get Geocoder options from the Admin UI. 123 | */ 124 | $geocoder_settings = get_option('acf_osm_geocoder'); 125 | 126 | $geocoder_name = $geocoder_settings['engine']; 127 | 128 | $osm_admin = [ 129 | 'options' => [ 130 | 'osm_layers' => $osm_providers->get_layers(), // flat list 131 | 'leaflet_layers' => $leaflet_providers->get_layers(), // flat list 132 | 'accuracy' => 7, // used to round lat and lng float number @see models/gs-model/fixedFloatSetter() 133 | /** 134 | * Filter Leaflet control geocoder options. 135 | * 136 | * @see https://www.liedman.net/leaflet-control-geocoder/docs/interfaces/geocodercontroloptions.html 137 | * 138 | * @param $geocoder_options array( 139 | * 'collapsed' => boolean 140 | * 'defaultMarkGeocode' => boolean 141 | * 'errorMessage' => string 142 | * 'position' => string 143 | * 'expand' => string ("touch" | "click" | "hover") 144 | * 'iconLabel' => string 145 | * 'placeholder' => string 146 | * 'queryMinLength' => number 147 | * 'showResultIcons' => boolean 148 | * 'suggestMinLength' => number 149 | * 'suggestTimeout' => number 150 | * ) 151 | */ 152 | 'geocoder_name' => $geocoder_name, 153 | 'geocoder_options' => apply_filters( 'acf_osm_geocoder_options', $leaflet_geocoders->get_options($geocoder_name) ), 154 | ], 155 | 'i18n' => [ 156 | 'search' => __( 'Search...', 'acf-openstreetmap-field' ), 157 | 'nothing_found' => __( 'Nothing found...', 'acf-openstreetmap-field' ), 158 | 'my_location' => __( 'My location', 'acf-openstreetmap-field' ), 159 | 'add_marker_at_location' 160 | => __( 'Add Marker at location', 'acf-openstreetmap-field' ), 161 | 'fit_markers_in_view' 162 | => __( 'Fit markers into view', 'acf-openstreetmap-field' ), 163 | 'address_format' => [ 164 | /* translators: address format for marker labels (street level). Available placeholders {building} {road} {house_number} {postcode} {city} {town} {village} {hamlet} {state} {country} */ 165 | 'street' => __( '{building} {road} {house_number}', 'acf-openstreetmap-field' ), 166 | /* translators: address format for marker labels (city level). Available placeholders {building} {road} {house_number} {postcode} {city} {town} {village} {hamlet} {state} {country} */ 167 | 'city' => __( '{postcode} {city} {town} {village} {hamlet}', 'acf-openstreetmap-field' ), 168 | /* translators: address format for marker labels (country level). Available placeholders {building} {road} {house_number} {postcode} {city} {town} {village} {hamlet} {state} {country} */ 169 | 'country' => __( '{state} {country}', 'acf-openstreetmap-field' ), 170 | ] 171 | ], 172 | ]; 173 | 174 | /* frontend */ 175 | wp_register_script( 'acf-osm-frontend', $this->get_asset_url( 'assets/js/acf-osm-frontend.js' ), [ ], $this->get_version(), [ 176 | 'strategy' => 'defer', 177 | 'in_footer' => true, 178 | ] ); 179 | wp_localize_script( 'acf-osm-frontend', 'acf_osm', $osm_l10n ); 180 | 181 | wp_register_style( 'leaflet', $this->get_asset_url( 'assets/css/acf-osm-leaflet.css' ), [], $this->get_version() ); 182 | 183 | /* backend */ 184 | 185 | // field js 186 | wp_register_script( 'acf-input-osm', $this->get_asset_url('assets/js/acf-input-osm.js'), ['acf-input','wp-backbone' ], $this->get_version(), [ 187 | // 'strategy' => 'defer', 188 | 'in_footer' => true, 189 | ] ); 190 | wp_localize_script( 'acf-input-osm', 'acf_osm', $osm_l10n ); 191 | wp_localize_script( 'acf-input-osm', 'acf_osm_admin', $osm_admin ); 192 | // field css 193 | wp_register_style( 'acf-input-osm', $this->get_asset_url( 'assets/css/acf-input-osm.css' ), [ 'leaflet', 'acf-input', 'dashicons' ], $this->get_version() ); 194 | 195 | 196 | // field group admin js 197 | wp_register_script( 'acf-field-group-osm', $this->get_asset_url('assets/js/acf-field-group-osm.js'), [ 'acf-field-group' ], $this->get_version(), [ 198 | // 'strategy' => 'defer', 199 | 'in_footer' => true, 200 | ] ); 201 | 202 | // field group admin css 203 | wp_register_style( 'acf-field-group-osm', $this->get_asset_url( 'assets/css/acf-field-group-osm.css' ), [], $this->get_version() ); 204 | wp_localize_script( 'acf-field-group-osm', 'acf_osm', $osm_l10n ); 205 | wp_localize_script( 'acf-field-group-osm', 'acf_osm_admin', $osm_admin ); 206 | 207 | 208 | // settings js 209 | wp_register_script( 'acf-osm-settings', $this->get_asset_url( 'assets/js/acf-osm-settings.js' ), ['wp-backbone'], $this->get_version() ); 210 | wp_localize_script( 'acf-osm-settings', 'acf_osm', $osm_l10n ); 211 | wp_localize_script( 'acf-osm-settings', 'acf_osm_settings', $osm_settings ); 212 | wp_localize_script( 'acf-osm-settings', 'acf_osm_admin', $osm_admin ); 213 | 214 | // settings css 215 | wp_register_style( 'acf-osm-settings', $this->get_asset_url( 'assets/css/acf-osm-settings.css' ), ['leaflet', 'acf-input-osm'], $this->get_version() ); 216 | } 217 | 218 | /** 219 | * Get asset url for this plugin 220 | * 221 | * @param string $asset URL part relative to plugin class 222 | * @return wp_enqueue_editor 223 | */ 224 | public function get_asset_url( $asset ) { 225 | return plugins_url( $asset, $this->get_plugin_file() ); 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /include/ACFFieldOpenstreetmap/Core/LeafletGeocoders.php: -------------------------------------------------------------------------------- 1 | => [ 'options' => [ ... ] ], => ... ] 19 | */ 20 | public function get_geocoders() { 21 | if ($this->geocoders !== null ) { 22 | return $this->geocoders; 23 | } 24 | 25 | $core = Core::instance(); 26 | $this->geocoders = json_decode($core->read_file('etc/leaflet-control-geocoders.json'), true); 27 | 28 | return $this->geocoders; 29 | } 30 | 31 | /** 32 | * Is an API key mandatory? 33 | * 34 | * @param string $geocoder_name 35 | * @return bool 36 | */ 37 | public function is_apikey_mandatory($geocoder_name) { 38 | $geocoders = $this->get_geocoders(); 39 | // Retrive default options 40 | $options = $geocoders[$geocoder_name]['options']; 41 | if( isset($options['apiKeyMandatory']) ) { 42 | return boolval($options['apiKeyMandatory']); 43 | } 44 | return false ; 45 | } 46 | 47 | /** 48 | * Is an API key mandatory? 49 | * 50 | * @param string $geocoder_name 51 | * @return array 52 | */ 53 | public function get_options($geocoder_name) { 54 | 55 | $geocoders = $this->get_geocoders(); 56 | 57 | if ( ! isset( $geocoders[$geocoder_name] ) ) { 58 | $geocoder_name = self::GEOCODER_DEFAULT; 59 | } 60 | 61 | // Retrive default options 62 | $options = $geocoders[$geocoder_name]['options']; 63 | 64 | // Enriches the options specifically for each geocoder 65 | switch ($geocoder_name) { 66 | 67 | case self::GEOCODER_NOMINATIM: 68 | /** 69 | * Nominatim options. 70 | * 71 | * - Address search @see https://nominatim.org/release-docs/develop/api/Search/ 72 | * - Reverse geocoding @see https://nominatim.org/release-docs/develop/api/Reverse/ 73 | * - Leaflet control @see https://github.com/perliedman/leaflet-control-geocoder/blob/master/src/geocoders/nominatim.ts 74 | */ 75 | 76 | $language = substr(get_locale(), 0, 2); 77 | $this->addGeocodingQueryParams($options, 'accept-language', $language); 78 | $this->addReverseQueryParams($options, 'accept-language', $language); 79 | 80 | break; 81 | 82 | case self::GEOCODER_PHOTON: 83 | /** 84 | * Photon options. 85 | * 86 | * Allowed parameters are: [q, location_bias_scale, debug, bbox, limit, osm_tag, lon, zoom, lang, lat, layer]" 87 | * - Search API @see https://photon.komoot.io @see https://github.com/komoot/photon?tab=readme-ov-file#search-api 88 | * - leaflet-control-geocoder PhotonOptions @see https://www.liedman.net/leaflet-control-geocoder/docs/interfaces/geocoders.PhotonOptions.html 89 | */ 90 | 91 | /* 92 | Photon will use 'accept-language' HTTP header which browsers set by default. 93 | $language = substr(get_locale(), 0, 2); 94 | $this->addGeocodingQueryParams($options, 'lang', $language); 95 | $this->addReverseQueryParams($options, 'lang', $language); 96 | */ 97 | break; 98 | 99 | case self::GEOCODER_OPENCAGE: 100 | /** 101 | * OpenCage options. 102 | * 103 | * - OpenCage API @see https://opencagedata.com/api 104 | * - leaflet-control-geocoder OpenCageOptions https://www.liedman.net/leaflet-control-geocoder/docs/interfaces/geocoders.OpenCageOptions.html 105 | */ 106 | $language = get_locale(); 107 | $this->addGeocodingQueryParams($options, 'language', $language); 108 | $this->addReverseQueryParams($options, 'language', $language); 109 | break; 110 | } 111 | 112 | // merge with settings 113 | $geocoder_settings = (array) get_option('acf_osm_geocoder'); 114 | $options['scale'] = $geocoder_settings['scale']; 115 | if ( isset( $geocoder_settings[$geocoder_name] ) && is_array( $geocoder_settings[$geocoder_name] ) ) { 116 | $options = wp_parse_args( $geocoder_settings[$geocoder_name], $options ); 117 | } 118 | 119 | // Parse credentials placeholder 120 | $options = array_map( function( $option_value ) { 121 | // TODO: use centralized function like in LeafletProviders 122 | if ( is_string($option_value) && preg_match( '/^<([^>]*)>$/imsU', $option_value ) ) { 123 | return ''; 124 | } 125 | return $option_value; 126 | }, $options ); 127 | 128 | return apply_filters( "acf_osm_{$geocoder_name}_options", $options); 129 | } 130 | 131 | /** 132 | * GeocoderOptions @see https://github.com/perliedman/leaflet-control-geocoder/blob/master/src/geocoders/api.ts 133 | */ 134 | protected function addGeocodingQueryParams(&$options, $key, $value) { 135 | if (! isset($options['geocodingQueryParams'])) { 136 | $options['geocodingQueryParams'] = []; 137 | } 138 | $options['geocodingQueryParams'][$key] = $value; 139 | } 140 | 141 | /** 142 | * GeocoderOptions @see https://github.com/perliedman/leaflet-control-geocoder/blob/master/src/geocoders/api.ts 143 | */ 144 | protected function addReverseQueryParams(&$options, $key, $value) { 145 | if (! isset($options['reverseQueryParams'])) { 146 | $options['reverseQueryParams'] = []; 147 | } 148 | $options['reverseQueryParams'][$key] = $value; 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /include/ACFFieldOpenstreetmap/Core/LeafletProviders.php: -------------------------------------------------------------------------------- 1 | get_proxies(); 27 | 28 | if ( is_null( $this->leaflet_providers ) ) { 29 | $core = Core::instance(); 30 | $this->leaflet_providers = json_decode( $core->read_file( 'etc/leaflet-providers.json' ), true ); 31 | } 32 | 33 | $providers = $this->leaflet_providers; 34 | 35 | foreach ( (array) $filters as $filter ) { 36 | if ( 'credentials' === $filter ) { 37 | 38 | // get configured token 39 | $tokens = get_option( 'acf_osm_provider_tokens', [] ); 40 | 41 | // merge tokens 42 | $providers = array_replace_recursive( $providers, $tokens ); 43 | 44 | // remove providers without access tokens 45 | $providers = array_filter( $providers, function( $provider, $provider_key ) { 46 | return ! $this->needs_access_token( $provider_key, $provider ) 47 | || $this->has_access_token( $provider_key, $provider ); 48 | }, ARRAY_FILTER_USE_BOTH ); 49 | 50 | if ( ! $unfiltered ) { 51 | $providers = apply_filters( 'acf_osm_leaflet_providers_'.$filter, $providers ); 52 | } 53 | } 54 | 55 | if ( 'enabled' === $filter ) { 56 | 57 | // remove disabled providers 58 | $disabled_providers = get_option( 'acf_osm_providers', [] ); 59 | 60 | $providers = array_replace_recursive( $providers, $disabled_providers ); 61 | 62 | $providers = array_filter( $providers, function( $el ) { 63 | return is_array( $el ); 64 | } ); 65 | 66 | foreach ( $providers as &$provider ) { 67 | if ( isset( $provider['variants'] ) ) { 68 | // remove disabled variants 69 | $provider['variants'] = array_filter( $provider['variants'], function( $el ) { 70 | return ! in_array( $el, [ '0', false ], true ); 71 | } ); 72 | // remove empty variants 73 | if ( ! count( $provider['variants'] ) ) { 74 | unset( $provider['variants'] ); 75 | } 76 | } 77 | } 78 | } 79 | } 80 | 81 | if ( ! $unfiltered ) { 82 | $providers = apply_filters( 'acf_osm_leaflet_providers', $providers ); 83 | } 84 | 85 | return $providers; 86 | } 87 | 88 | /** 89 | * Get token configuration options 90 | * 91 | * @return array 92 | */ 93 | public function get_token_options() { 94 | 95 | $token_options = []; 96 | 97 | foreach ( $this->get_providers() as $provider => $data ) { 98 | foreach( $data['options'] as $option => $value ) { 99 | if ( is_string($value) && ( 1 === preg_match( '/^<([^>]*)>$/imsU', $value, $matches ) ) ) { // '' 100 | 101 | if ( ! isset($token_options[ $provider ]['options'] ) ) { 102 | $token_options[ $provider ] = [ 'options' => [] ]; 103 | } 104 | $token_options[ $provider ]['options'][ $option ] = ''; 105 | } 106 | } 107 | } 108 | 109 | return $token_options; 110 | } 111 | 112 | /** 113 | * Get a flat leaflet provider list 114 | * 115 | * @return array [ 116 | * 'provider_key' => 'provider', 117 | * 'provider_key.variant' => 'provider.variant', 118 | * ... 119 | * ] 120 | */ 121 | public function get_layers() { 122 | 123 | $providers = []; 124 | 125 | foreach ( $this->get_providers([ 'credentials', 'enabled' ]) as $provider_key => $provider_data ) { 126 | // 127 | if ( isset( $provider_data[ 'variants' ] ) ) { 128 | foreach ( $provider_data[ 'variants' ] as $variant => $variant_data ) { 129 | // bounded variants disabled through settings! 130 | // if ( ! is_string( $variant_data ) && isset( $variant_data['options']['bounds'] ) ) { 131 | // // no variants with bounds! 132 | // continue; 133 | // } 134 | $providers[ $provider_key . '.' . $variant ] = $provider_key . '.' . $variant; 135 | 136 | if ( is_string( $variant_data ) || isset( $variant_data['options'] ) ) { 137 | 138 | $providers[ $provider_key . '.' . $variant ] = $provider_key . '.' . $variant; 139 | 140 | } else { 141 | 142 | // $providers[ $provider_key ] = $provider_key; 143 | 144 | } 145 | } 146 | } else { 147 | $providers[ $provider_key ] = $provider_key; 148 | } 149 | } 150 | 151 | return $providers; 152 | } 153 | 154 | public function get_layer_config() { 155 | return $this->filter_recursive( get_option( 'acf_osm_provider_tokens', [] ) ); 156 | } 157 | 158 | /** 159 | * Convert string variant definitions to object 160 | */ 161 | public function unify_provider_variants( $provider ) { 162 | if ( isset( $provider['variants'] ) ) { 163 | $provider['variants'] = array_map( function( $variant ) { 164 | if ( is_string( $variant ) ) { 165 | $variant = [ 166 | 'options' => [ 167 | 'variant' => $variant, 168 | ] 169 | ]; 170 | } 171 | if ( ! isset( $variant['options'] ) ) { 172 | $variant['options'] = []; 173 | } 174 | return $variant; 175 | }, $provider['variants'] ); 176 | } 177 | return $provider; 178 | } 179 | 180 | 181 | /** 182 | * @param array $arr 183 | * @return array 184 | */ 185 | private function filter_recursive( $arr ) { 186 | foreach ( $arr as &$value ) { 187 | if ( is_array( $value ) ) { 188 | $value = $this->filter_recursive( $value ); 189 | } 190 | } 191 | $arr = array_filter( $arr ); 192 | return $arr; 193 | } 194 | 195 | 196 | /** 197 | * Whether an access key needs to be entered to make this provider work. 198 | * 199 | * @param string $provider_key 200 | * @param Array $provider_data 201 | * @return boolean Whether this map provider requires an access key and the access key is not configured yet 202 | */ 203 | public function needs_access_token( $provider_key, $provider_data ) { 204 | foreach ( $provider_data['options'] as $option => $value ) { 205 | if ( is_string($value) && ( 1 === preg_match( '/^<([^>]*)>$/imsU', $value ) ) ) { 206 | return true; 207 | } 208 | } 209 | return false; 210 | } 211 | 212 | /** 213 | * Whether an access key needs to be entered to make this provider work. 214 | * 215 | * @param string $provider_key 216 | * @param Array $provider_data 217 | * @return boolean Whether this map provider requires an access key and the access key is not configured yet 218 | */ 219 | public function has_access_token( $provider_key, $provider_data ) { 220 | $token_option = get_option( 'acf_osm_provider_tokens' ); 221 | foreach ( $provider_data['options'] as $option => $value ) { 222 | if ( is_string($value) && ( 1 === preg_match( '/^<([^>]*)>$/imsU', $value ) ) ) { 223 | return isset( $token_option[ $provider_key ][ 'options' ][ $option ] ) 224 | && ! empty( $token_option[ $provider_key ][ 'options' ][ $option ] ); 225 | } 226 | } 227 | return false; 228 | } 229 | 230 | } 231 | -------------------------------------------------------------------------------- /include/ACFFieldOpenstreetmap/Core/MapProxy.php: -------------------------------------------------------------------------------- 1 | proxies ) ) { 29 | $this->proxies = array_keys( array_filter( (array) get_option( 'acf_osm_proxy' ) ) ); 30 | } 31 | return $this->proxies; 32 | } 33 | 34 | /** 35 | * Apply proxy config to all providers 36 | * @filter acf_osm_leaflet_providers 37 | */ 38 | public function proxify_providers( $providers ) { 39 | 40 | $proxies = $this->get_proxies(); 41 | $force = apply_filters( 'acf_osm_force_proxy', false ); 42 | 43 | foreach ( $providers as $provider_key => &$provider ) { 44 | if ( $force || in_array( $provider_key, $proxies ) ) { 45 | $provider = $this->proxify_provider( $provider_key, $provider ); 46 | } 47 | } 48 | 49 | return $providers; 50 | } 51 | 52 | /** 53 | * Apply proxy config to provider 54 | * 55 | * @param string $provider_key 56 | * @param array $provider 57 | * @return array 58 | */ 59 | private function proxify_provider( $provider_key, $provider ) { 60 | 61 | // make sure variant config is an array 62 | $provider = LeafletProviders::instance()->unify_provider_variants( $provider ); 63 | 64 | $provider = $this->proxify_tileset( $provider, $provider_key ); 65 | 66 | if ( isset( $provider['variants'] ) ) { 67 | foreach ( $provider['variants'] as $variant_key => $variant ) { 68 | if ( ! isset( $variant['url'] ) ) { 69 | $variant['url'] = $provider['url']; 70 | } 71 | $provider['variants'][$variant_key] = $this->proxify_tileset( $variant, $provider_key, $variant_key ); 72 | } 73 | } 74 | return $provider; 75 | } 76 | 77 | /** 78 | * Apply proxy config to provider or variant 79 | * 80 | * @param string $provider_key 81 | * @param array $provider 82 | * @return array 83 | */ 84 | private function proxify_tileset( $tileset, $provider_key, $variant_key = '' ) { 85 | 86 | // resolution capability? 87 | if ( strpos( $tileset['url'], '{r}') !== false ) { 88 | $url_params_part = '{z}/{x}/{y}{r}'; 89 | } else { 90 | $url_params_part = '{z}/{x}/{y}'; 91 | } 92 | 93 | // remove unneeded props from provider (and hide access tokens on the way) 94 | foreach ( array_keys( $tileset['options'] ) as $option ) { 95 | if ( strpos( $tileset['url'], "{{$option}}") !== false ) { 96 | unset( $tileset['options'][$option] ); 97 | } 98 | } 99 | 100 | // reconfigure url 101 | $tileset['url'] = content_url( $this->get_proxy_path( $provider_key, $variant_key ) . $url_params_part ); 102 | 103 | return $tileset; 104 | } 105 | 106 | /** 107 | * Setup proxy directory in wp-content/ and save proxy config in uploads. 108 | * 109 | * @action update_option_acf_osm_provider_tokens 110 | * @action update_option_acf_osm_providers 111 | * @action update_option_acf_osm_proxy 112 | */ 113 | public function setup_proxies() { 114 | 115 | $upload_dir = wp_upload_dir( null, false ); 116 | $this->setup_proxy_dir(); 117 | return $this->save_proxy_config( $upload_dir['basedir'] ); 118 | 119 | } 120 | 121 | /** 122 | * Save proxy config 123 | * 124 | * @param string $destination_path 125 | */ 126 | public function save_proxy_config( $destination_path ) { 127 | 128 | if ( ! WP_Filesystem() ) { 129 | return new \WP_Error( 'acf-osm', __( 'No Filesystem', 'acf-openstreetmap-field' ) ); 130 | } 131 | 132 | global $wp_filesystem; 133 | 134 | if ( ! $wp_filesystem->is_writable( $destination_path ) ) { 135 | return new \WP_Error( 'acf-osm', __( 'Filesystem not writable', 'acf-openstreetmap-field' ) ); 136 | } 137 | 138 | $proxied_providers = LeafletProviders::instance()->get_providers( ['credentials'], true ); 139 | $proxy_config = []; 140 | foreach ( $proxied_providers as $provider_key => $provider ) { 141 | 142 | $provider = LeafletProviders::instance()->unify_provider_variants( $provider ); 143 | 144 | if ( isset( $provider['options']['subdomains'] ) ) { 145 | $subdomains = $provider['options']['subdomains']; 146 | } else { 147 | $subdomains = 'abc'; 148 | } 149 | 150 | $proxy_config[$provider_key] = [ 151 | 'base_url' => $this->generate_url( $provider['url'], $provider['options'] ), 152 | 'subdomains' => $subdomains, 153 | ]; 154 | 155 | if ( isset( $provider['variants'] ) ) { 156 | foreach ( $provider['variants'] as $variant_key => $variant ) { 157 | if ( isset( $variant['url'] ) ) { 158 | $variant_url = $variant['url']; 159 | } else { 160 | $variant_url = $provider['url']; 161 | } 162 | 163 | $variant_url = $this->generate_url( $variant_url, $variant['options'] ); 164 | $variant_url = $this->generate_url( $variant_url, $provider['options'] ); 165 | 166 | if ( isset( $variant['options']['subdomains'] ) ) { 167 | $variant_subdomains = $variant['options']['subdomains']; 168 | } else { 169 | $variant_subdomains = $subdomains; 170 | } 171 | 172 | $proxy_config["{$provider_key}.{$variant_key}"] = [ 173 | 'base_url' => $variant_url, 174 | 'subdomains' => $variant_subdomains, 175 | ]; 176 | } 177 | } 178 | } 179 | 180 | $content = 'put_contents( 188 | untrailingslashit( $destination_path ) . '/acf-osm-proxy-config.php', 189 | $content 190 | ); 191 | } 192 | 193 | /** 194 | * @param string $base_url 195 | * @param array $options 196 | */ 197 | private function generate_url( $base_url, $options ) { 198 | $url = $base_url; 199 | foreach ( $options as $option => $value ) { 200 | if ( is_scalar( $value ) ) { 201 | $url = str_replace( "{{$option}}", str_replace(' ', '%20', $value), $url ); 202 | } 203 | } 204 | return $url; 205 | } 206 | 207 | /** 208 | * Setup proxy directory in wp-content/maps/ 209 | */ 210 | public function setup_proxy_dir( $force = false ) { 211 | global $wp_filesystem; 212 | 213 | if ( ! WP_Filesystem() ) { 214 | return new \WP_Error( 'acf-osm', __( 'No Filesystem', 'acf-openstreetmap-field' ) ); 215 | } 216 | 217 | $proxy_path = trailingslashit( trailingslashit( WP_CONTENT_DIR ) . $this->get_proxy_path() ) ; 218 | 219 | wp_mkdir_p( $proxy_path ); 220 | 221 | if ( ! $wp_filesystem->is_writable( $proxy_path ) ) { 222 | return new \WP_Error( 'acf-osm', __( 'Filesystem not writable', 'acf-openstreetmap-field' ) ); 223 | } 224 | 225 | if ( $force || ! $wp_filesystem->exists( $proxy_path . '.htaccess' ) ) { 226 | $content = '# Generously generated by ACF OpenStreetMap Field Plugin' . "\n"; 227 | $content .= 'RewriteEngine On' . "\n"; 228 | $content .= 'RewriteBase /wp-content/maps' . "\n"; 229 | $content .= 'RewriteRule . index.php [L]' . "\n"; 230 | 231 | $wp_filesystem->put_contents( $proxy_path . '.htaccess', $content ); 232 | } 233 | 234 | if ( $force || ! $wp_filesystem->exists( $proxy_path . 'index.php' ) ) { 235 | $upload_dir = wp_upload_dir( null, false ); 236 | 237 | $content = 'get_plugin_dir() ) 247 | ); 248 | 249 | $wp_filesystem->put_contents( $proxy_path . 'index.php', $content ); 250 | } 251 | 252 | // save a global config 253 | if ( is_multisite() && ( $force || ! $wp_filesystem->exists( $proxy_path . 'acf-osm-proxy-config.php' ) ) ) { 254 | 255 | switch_to_blog( get_main_site_id() ); 256 | 257 | $this->save_proxy_config( $proxy_path ); 258 | 259 | restore_current_blog(); 260 | } 261 | } 262 | 263 | /** 264 | * Remove Proxy Directory 265 | */ 266 | public function reset_proxy_dir() { 267 | 268 | if ( ! WP_Filesystem() ) { 269 | return new \WP_Error( 'acf-osm', __( 'No Filesystem', 'acf-openstreetmap-field' ) ); 270 | } 271 | 272 | global $wp_filesystem; 273 | 274 | $proxy_path = trailingslashit( trailingslashit( WP_CONTENT_DIR ) . $this->get_proxy_path() ) ; 275 | 276 | if ( ! $wp_filesystem->is_writable( $proxy_path ) ) { 277 | return new \WP_Error( 'acf-osm', __( 'Filesystem not writable', 'acf-openstreetmap-field' ) ); 278 | } 279 | 280 | return $wp_filesystem->rmdir( $proxy_path, true ); 281 | } 282 | 283 | /** 284 | * @param string $provider_key 285 | * @param string $variant_key 286 | * @return string 287 | */ 288 | private function get_proxy_path( $provider_key = '', $variant_key = '' ) { 289 | $path = 'maps'; 290 | if ( $provider_key ) { 291 | if ( is_multisite() && ! is_main_site() ) { 292 | $path .= sprintf('/sites/%d', get_current_blog_id() ); 293 | } 294 | $path .= '/' . $provider_key; 295 | if ( $variant_key ) { 296 | $path .= '.' . $variant_key; 297 | } 298 | } 299 | return trailingslashit( $path ); 300 | } 301 | 302 | } 303 | -------------------------------------------------------------------------------- /include/ACFFieldOpenstreetmap/Core/OSMProviders.php: -------------------------------------------------------------------------------- 1 | 'OpenStreetMap.HOT', 11 | 'T' => 'Thunderforest.Transport', 12 | 'C' => 'Thunderforest.OpenCycleMap', 13 | ]; 14 | 15 | /** @var array mapping of OSM iframe layers to leaflet layers */ 16 | private $iframe_layers = [ 17 | 'mapnik' => 'OpenStreetMap.Mapnik', 18 | 'cyclemap' => 'Thunderforest.OpenCycleMap', 19 | 'transportmap' => 'Thunderforest.Transport', 20 | 'hot' => 'OpenStreetMap.HOT', 21 | ]; 22 | 23 | /** 24 | * Returns raw leaflet providers 25 | * @param array $filters credentials|enabled 26 | * @return array 27 | */ 28 | public function get_providers( $filters = [] ) {} 29 | 30 | 31 | public function get_token_options() {} 32 | 33 | /** 34 | * get default OpenStreetMap Layers 35 | * 36 | * @return array( 37 | * 'layer_id' => 'Layer Label', 38 | * ... 39 | * ) 40 | */ 41 | public function get_layers( $context = 'iframe' ) { 42 | /* 43 | mapnik 44 | cyclemap C Cycle 45 | transportmap T Transport 46 | hot H Humantarian 47 | */ 48 | if ( 'iframe' === $context ) { 49 | return $this->iframe_layers; 50 | } else if ( 'link' === $context ) { 51 | return $this->link_layers; 52 | } 53 | } 54 | 55 | /** 56 | * @param config array [ 57 | * 'lat' : (float), 58 | * 'lng' : (float), 59 | * 'markers' : optional. 60 | * [ 61 | * 'lat' : (float), 62 | * 'lng' : (float), 63 | * ], 64 | * 'layers' : optional. any of 65 | * [ 66 | * 'OpenStreetMap', 67 | * 'Thunderforest.OpenCycleMap', 68 | * 'Thunderforest.Transport', 69 | * 'OpenStreetMap.HOT', 70 | * ], 71 | * ] 72 | * @return string URL 73 | */ 74 | public function get_iframe_url( $config ) { 75 | 76 | $config = wp_parse_args( $config, [ 77 | 'lat' => 0, 78 | 'lng' => 0, 79 | 'zoom' => 0, 80 | 'markers' => [], 81 | 'layers' => [], 82 | ]); 83 | 84 | $bbox = Helper\MapHelper::getBbox( $config['lat'], $config['lng'], $config['zoom'] ); 85 | $args = [ 86 | 'bbox' => implode( ',', $bbox ), 87 | ]; 88 | 89 | foreach ( $config['layers'] as $layer ) { 90 | $i_layer = array_search( $layer, $this->iframe_layers ); 91 | if ( false !== $i_layer ) { 92 | $args['layer'] = $i_layer; 93 | break; 94 | } 95 | } 96 | foreach ( $config['markers'] as $marker ) { 97 | $args['marker'] = implode(',', [ $marker['lat'], $marker['lng'] ] ); 98 | break; 99 | } 100 | 101 | return add_query_arg( $args, 'https://www.openstreetmap.org/export/embed.html' ); 102 | } 103 | 104 | /** 105 | * @param config array [ 106 | * 'lat' : (float), 107 | * 'lng' : (float), 108 | * 'markers' : optional. 109 | * [ 110 | * 'lat' : (float), 111 | * 'lng' : (float), 112 | * ], 113 | * 'layers' : optional. any of 114 | * [ 115 | * 'OpenStreetMap', 116 | * 'Thunderforest.OpenCycleMap', 117 | * 'Thunderforest.Transport', 118 | * 'OpenStreetMap.HOT', 119 | * ], 120 | * ] 121 | * @return string URL 122 | */ 123 | public function get_link_url( $config ) { 124 | 125 | $config = wp_parse_args( $config, [ 126 | 'lat' => 0, 127 | 'lng' => 0, 128 | 'zoom' => 0, 129 | 'markers' => [], 130 | 'layers' => [], 131 | ]); 132 | 133 | $args = []; 134 | 135 | foreach ( $config['markers'] as $marker ) { 136 | $args['mlat'] = $marker['lat']; 137 | $args['mlon'] = $marker['lng']; 138 | } 139 | 140 | $map_link = add_query_arg( $args, 'https://www.openstreetmap.org/' ); 141 | $map_link .= '#map=' . implode( '/', [ 142 | intval( $config['zoom'] ), 143 | floatval( $config['lat'] ), 144 | floatval( $config['lng'] ) 145 | ] ); 146 | 147 | 148 | foreach ( $config['layers'] as $layer ) { 149 | $l_layer = array_search( $layer, $this->link_layers ); 150 | if ( false !== $l_layer ) { 151 | $map_link .= '&layers='.$l_layer; 152 | break; 153 | } 154 | } 155 | 156 | return $map_link; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /include/ACFFieldOpenstreetmap/Core/Plugin.php: -------------------------------------------------------------------------------- 1 | plugin_file = $file; 25 | 26 | add_action( 'admin_init', [ $this, 'maybe_upgrade' ] ); 27 | add_filter( 'extra_plugin_headers', [ $this, 'add_plugin_header' ] ); 28 | 29 | add_action( 'plugins_loaded', [ $this , 'load_textdomain' ] ); 30 | 31 | parent::__construct(); 32 | } 33 | 34 | /** 35 | * @filter extra_plugin_headers 36 | */ 37 | public function add_plugin_header( $headers ) { 38 | $headers['GithubRepo'] = 'Github Repository'; 39 | return $headers; 40 | } 41 | 42 | /** 43 | * @return string full plugin file path 44 | */ 45 | public function get_plugin_file() { 46 | return $this->plugin_file; 47 | } 48 | 49 | /** 50 | * @param string $file Path within plugin directory 51 | * @return boolean|string file contents, false on failure 52 | */ 53 | public function read_file( $file ) { 54 | 55 | 56 | $core = Core::instance(); 57 | 58 | $path = wp_normalize_path( $core->get_plugin_dir() . '/' . $file ); 59 | 60 | if ( file_exists( $path ) ) { 61 | return file_get_contents( $path ); 62 | } 63 | 64 | return false; 65 | } 66 | 67 | /** 68 | * @return string full plugin file path 69 | */ 70 | public function get_plugin_dir() { 71 | return plugin_dir_path( $this->get_plugin_file() ); 72 | } 73 | 74 | /** 75 | * @return string plugin slug 76 | */ 77 | public function get_slug() { 78 | return basename( $this->get_plugin_dir() ); 79 | } 80 | 81 | /** 82 | * @return string Path to the main plugin file from plugins directory 83 | */ 84 | public function get_wp_plugin() { 85 | return plugin_basename( $this->get_plugin_file() ); 86 | } 87 | 88 | /** 89 | * @return string current plugin version 90 | */ 91 | public function get_version() { 92 | if ( is_null( $this->_version ) ) { 93 | $this->_version = include_once $this->get_plugin_dir() . '/include/version.php'; 94 | } 95 | return $this->_version; 96 | } 97 | 98 | /** 99 | * @param string $which Which plugin meta to get. NUll 100 | * @return string|array plugin meta 101 | */ 102 | public function get_plugin_meta( $which = null ) { 103 | if ( ! isset( $this->plugin_meta ) ) { 104 | if ( ! function_exists('get_plugin_data') ) { 105 | require_once ABSPATH . 'wp-admin/includes/plugin.php'; 106 | } 107 | $this->plugin_meta = get_plugin_data( $this->get_plugin_file() ); 108 | } 109 | if ( isset( $this->plugin_meta[ $which ] ) ) { 110 | return $this->plugin_meta[ $which ]; 111 | } 112 | return $this->plugin_meta; 113 | } 114 | 115 | /** 116 | * @action plugins_loaded 117 | */ 118 | public function maybe_upgrade() { 119 | // trigger upgrade 120 | $new_version = $this->get_version(); 121 | $old_version = get_site_option( 'acf-openstreetmap-field_version' ); 122 | 123 | // call upgrade 124 | if ( version_compare( $new_version, $old_version, '>' ) ) { 125 | 126 | // Do update stuff here 127 | MapProxy::instance()->setup_proxy_dir( true ); 128 | 129 | update_site_option( 'acf-openstreetmap-field_version', $new_version ); // TODO: store blog-wide 130 | } 131 | } 132 | 133 | /** 134 | * Load text domain 135 | * 136 | * @action plugins_loaded 137 | */ 138 | public function load_textdomain() { 139 | $path = pathinfo( $this->get_wp_plugin(), PATHINFO_DIRNAME ); 140 | load_plugin_textdomain( 'acf-openstreetmap-field', false, $path . '/languages' ); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /include/ACFFieldOpenstreetmap/Core/Singleton.php: -------------------------------------------------------------------------------- 1 | =' ); 16 | } 17 | 18 | /** 19 | * @inheritdoc 20 | */ 21 | protected function __construct() { 22 | if ( self::is_supported() ) { 23 | add_action( 'get_template_part', [ $this, 'get_template_part' ], 10, 4 ); 24 | } 25 | } 26 | 27 | /** 28 | * @action get_template_part 29 | */ 30 | public function get_template_part( $slug, $name = null, $templates = [], $args = [] ) { 31 | 32 | if ( false === strpos( $slug, $this->template_dirname ) ) { 33 | return; 34 | } 35 | 36 | $template = str_replace( $this->template_dirname . '/', '', $slug ); 37 | $name = (string) $name; 38 | 39 | $locate = [ "{$slug}.php" ]; 40 | if ( '' !== $name ) { 41 | $locate[] = "{$slug}-{$name}.php"; 42 | } 43 | 44 | // the theme can handle it! 45 | if ( locate_template( $locate, false ) ) { 46 | return; 47 | } 48 | 49 | // we'll have to handle it 50 | $core = Core::instance(); 51 | $file = $core->get_plugin_dir() . 'templates/' . str_replace( $this->template_dirname . '/','',$slug) . '.php'; 52 | 53 | if ( file_exists( $file ) ) { 54 | load_template( $file, false, $args ); 55 | } 56 | } 57 | 58 | /** 59 | * @return Array template slug 60 | */ 61 | public function get_templates() { 62 | if ( is_null( $this->templates ) ) { 63 | $this->templates = []; 64 | // scan ./templates/*.php 65 | // scan /osm-maps/*.php 66 | // return [ 'osm-maps/template-name' => 'Template Name', ] // or Header Map Template Name: ... 67 | $core = Core::instance(); 68 | $paths = [ 69 | $core->get_plugin_dir() . '/templates/', 70 | get_template_directory() . '/osm-maps/', 71 | get_stylesheet_directory() . '/osm-maps/', 72 | ]; 73 | foreach ( array_unique( $paths ) as $path ) { 74 | $len = strlen( $path ); 75 | foreach( glob( $path . '*.php' ) as $file ) { 76 | $template = substr( $file, $len, -4 ); 77 | $file_data = get_file_data( $file, [ 'name' => 'Map Template Name', 'private' => 'Private' ] ); 78 | $name = empty( $file_data['name'] ) ? ucwords($template) : $file_data['name']; 79 | $this->templates[$template] = [ 80 | 'file' => $file, 81 | 'name' => $file_data['name'], 82 | 'private' => boolval( $file_data['private'] ), 83 | ]; 84 | } 85 | } 86 | } 87 | return array_filter( $this->templates, function( $template ) { 88 | return ! $template['private']; 89 | }); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php: -------------------------------------------------------------------------------- 1 | name = 'open_street_map'; 28 | /* 29 | * label (string) Multiple words, can include spaces, visible when selecting a field type 30 | */ 31 | $this->label = __("OpenStreetMap",'acf-openstreetmap-field'); 32 | 33 | 34 | $this->show_in_rest = true; 35 | /* 36 | * category (string) basic | content | choice | relational | jquery | layout | CUSTOM GROUP NAME 37 | */ 38 | $this->category = 'jquery'; 39 | 40 | $this->default_values = [ 41 | // hamburg 42 | 'lat' => 53.55064, 43 | 'lng' => 10.00065, 44 | 'zoom' => 12, 45 | 'layers' => [ 'OpenStreetMap.Mapnik' ], 46 | 'markers' => [], 47 | // gm compatibility 48 | 'address' => '', 49 | 'version' => '', 50 | ]; 51 | /* 52 | * defaults (array) Array of default settings which are merged into the field object. These are used later in settings 53 | */ 54 | $this->defaults = [ 55 | 'center_lat' => $this->default_values['lat'], 56 | 'center_lng' => $this->default_values['lng'], 57 | 'zoom' => $this->default_values['zoom'], 58 | 59 | 'height' => 400, 60 | 'return_format' => 'leaflet', 61 | 'allow_map_layers' => 1, 62 | 'max_markers' => '', 63 | 'layers' => $this->default_values['layers'], 64 | ]; 65 | 66 | /* 67 | * l10n (array) Array of strings that are used in JavaScript. This allows JS strings to be translated in PHP and loaded via: 68 | * var message = acf._e('FIELD_NAME', 'error'); 69 | */ 70 | $this->l10n = []; 71 | 72 | add_action( 'print_media_templates', [ $this, 'print_media_templates' ] ); 73 | } 74 | 75 | /* 76 | * render_field_settings() 77 | * 78 | * Create extra settings for your field. These are visible when editing a field 79 | * 80 | * @type action 81 | * @since 3.6 82 | * @date 23/01/13 83 | * 84 | * @param $field (array) the $field being edited 85 | * @return n/a 86 | */ 87 | 88 | function render_field_settings( $field ) { 89 | 90 | $templates = Core\Templates::instance(); 91 | 92 | $field = $this->sanitize_field( $field ); 93 | 94 | $return_choices = $templates->get_templates(); 95 | $return_choices = array_map( function( $template ) { 96 | return $template['name']; 97 | }, $return_choices ); 98 | 99 | $is_legacy = version_compare( acf()->version, '6.0.0', '<' ); 100 | 101 | 102 | // return_format 103 | acf_render_field_setting( $field, [ 104 | 'label' => __('Return Format','acf'), 105 | 'instructions' => '', 106 | 'type' => 'radio', 107 | 'name' => 'return_format', 108 | 'choices' => [ 109 | 'raw' => __("Raw Data",'acf-openstreetmap-field'), 110 | ] + $return_choices, 111 | 'layout' => 'horizontal', 112 | ]); 113 | 114 | if ( $is_legacy ) { 115 | $this->render_field_presentation_settings( $field ); 116 | $this->render_field_validation_settings( $field ); 117 | } 118 | } 119 | 120 | /** 121 | * Renders the field settings used in the "Validation" tab. 122 | * 123 | * @since 6.0 124 | * 125 | * @param array $field The field settings array. 126 | * @return void 127 | */ 128 | function render_field_validation_settings( $field ) { 129 | 130 | // allow_layer selection 131 | acf_render_field_setting( $field, [ 132 | 'label' => __( 'Max. number of Markers', 'acf-openstreetmap-field' ), 133 | 'instructions' => __( 'Leave empty for infinite markers', 'acf-openstreetmap-field' ), 134 | 'name' => 'max_markers', 135 | 'type' => 'number', 136 | 'ui' => 1, 137 | 'min' => 0, 138 | 'step' => 1, 139 | ]); 140 | } 141 | 142 | /** 143 | * Renders the field settings used in the "Presentation" tab. 144 | * 145 | * @since 6.0 146 | * 147 | * @param array $field The field settings array. 148 | * @return void 149 | */ 150 | function render_field_presentation_settings( $field ) { 151 | 152 | $leafletProviders = Core\LeafletProviders::instance(); 153 | $osmProviders = Core\OSMProviders::instance(); 154 | 155 | acf_render_field_setting( $field, [ 156 | 'label' => __( 'Map Appearance', 'acf-openstreetmap-field' ), 157 | 'instructions' => __( 'Set zoom, center and select layers being displayed.', 'acf-openstreetmap-field' ), 158 | 'type' => 'open_street_map', 159 | 'name' => 'leaflet_map', 160 | 161 | 'return_format' => 'admin', 162 | 'attr' => [ 163 | 'data-editor-config' => [ 164 | 'allow_providers' => true, 165 | 'restrict_providers' => false, 166 | 'max_markers' => 0, // no markers 167 | 'name_prefix' => $field['prefix'], 168 | ], 169 | 'data-map-layers' => $field['layers'], 170 | ], 171 | 'value' => [ 172 | 'lat' => $field['center_lat'], 173 | 'lng' => $field['center_lng'], 174 | 'zoom' => $field['zoom'], 175 | 'layers' => $field['layers'], 176 | 'markers' => [], 177 | ], 178 | 'wrapper' => [ 179 | 'data-name' => 'wrapper', 180 | 'class' => 'acf-field-setting-wrapper', 181 | ], 182 | ] ); 183 | 184 | // lat 185 | acf_render_field_setting( $field, [ 186 | 'label' => __('Map Position','acf-openstreetmap-field'), 187 | 'instructions' => __('Center the initial map','acf-openstreetmap-field'), 188 | 'type' => 'number', 189 | 'name' => 'center_lat', 190 | 'prepend' => __('lat','acf-openstreetmap-field'), 191 | 'placeholder' => $this->default_values['lat'], 192 | // 'step' => 0.1, 193 | ]); 194 | 195 | // lng 196 | acf_render_field_setting( $field, [ 197 | 'label' => __( 'Center', 'acf-openstreetmap-field' ), 198 | 'instructions' => __( 'Center the initial map', 'acf-openstreetmap-field' ), 199 | 'type' => 'number', 200 | 'name' => 'center_lng', 201 | 'prepend' => __('lng','acf-openstreetmap-field'), 202 | 'placeholder' => $this->default_values['lng'], 203 | '_append' => 'center_lat', 204 | // 'step' => 0.1, 205 | ]); 206 | 207 | // zoom 208 | acf_render_field_setting( $field, [ 209 | 'label' => __( 'Zoom', 'acf-openstreetmap-field' ), 210 | 'instructions' => __( 'Set the initial zoom level', 'acf-openstreetmap-field' ), 211 | 'type' => 'number', 212 | 'name' => 'zoom', 213 | 'min' => 1, 214 | 'max' => 22, 215 | 'prepend' => __('zoom','acf-openstreetmap-field'), 216 | 'placeholder' => $this->default_values['zoom'], 217 | '_append' => 'center_lat', 218 | ]); 219 | 220 | // allow_layer selection 221 | acf_render_field_setting( $field, [ 222 | 'label' => __( 'Allow layer selection', 'acf-openstreetmap-field' ), 223 | 'instructions' => '', 224 | 'name' => 'allow_map_layers', 225 | 'type' => 'true_false', 226 | 'ui' => 1, 227 | ]); 228 | 229 | // Leaflet layers 230 | acf_render_field_setting( $field, [ 231 | 'label' => __( 'Leaflet Layers', 'acf-openstreetmap-field' ), 232 | 'instructions' => '', 233 | 'name' => 'layers', 234 | 'type' => 'select', 235 | 'multiple' => 1, 236 | 'choices' => $leafletProviders->get_layers(), 237 | 'wrapper' => [ 238 | 'class' => 'acf-hidden', 239 | ], 240 | ]); 241 | 242 | // map height 243 | acf_render_field_setting( $field, [ 244 | 'label' => __('Height','acf'), 245 | 'instructions' => __('Customize the map height','acf-openstreetmap-field'), 246 | 'type' => 'text', 247 | 'name' => 'height', 248 | 'append' => 'px', 249 | ]); 250 | } 251 | 252 | 253 | /* 254 | * render_field() 255 | * 256 | * Create the HTML interface for your field 257 | * 258 | * @param $field (array) the $field being rendered 259 | * 260 | * @type action 261 | * @since 3.6 262 | * @date 23/01/13 263 | * 264 | * @param $field (array) the $field being edited 265 | * @return n/a 266 | */ 267 | function render_field( $field ) { 268 | 269 | $core = Core\Core::instance(); 270 | 271 | if ( is_null( $field['value'] ) ) { 272 | $field['value'] = $this->sanitize_value( [], $field, 'display' ); 273 | } 274 | 275 | // json_encoded value 276 | acf_hidden_input([ 277 | 'id' => $field['id'], 278 | 'name' => $field['name'], 279 | 'value' => json_encode( $field['value'] ), 280 | 'class' => 'osm-json', 281 | ]); 282 | 283 | $restrict_providers = isset($field['return_format']) && $field['return_format'] === 'osm' 284 | ? array_values( Core\OSMProviders::instance()->get_layers() ) 285 | : false; 286 | 287 | $max_markers = $field['max_markers'] === '' ? false : intval( $field['max_markers'] ); 288 | 289 | if ( 'osm' === $field['return_format'] ) { 290 | if ( $max_markers === false ) { // no restriction > max one marker 291 | $max_markers = 1; 292 | } 293 | // only one marker max 294 | $max_markers = min( $max_markers, 1 ); 295 | } 296 | $map_args = [ 297 | 'field' => $field + [ 298 | 'attr' => [ 299 | 'data-editor-config' => [ 300 | 'allow_providers' => $field['allow_map_layers'], 301 | 'restrict_providers' => $restrict_providers, 302 | 'max_markers' => $max_markers, 303 | 'name_prefix' => $field['name'], 304 | ], 305 | ], 306 | ], 307 | 'map' => $field['value'], 308 | ]; 309 | if ( Core\Templates::is_supported() ) { 310 | get_template_part( 'osm-maps/admin', null, $map_args ); 311 | } else { 312 | // legacy 313 | $attr = [ 314 | 'data-editor-config' => json_encode([ 315 | 'allow_providers' => $field['allow_map_layers'], 316 | 'restrict_providers' => array_values( $providers ), 317 | 'max_markers' => $max_markers, 318 | 'name_prefix' => $field['name'], 319 | ]), 320 | 'class' => 'leaflet-map', 321 | 'data-height' => $field['height'], 322 | 'data-map' => 'leaflet', 323 | 'data-map-lng' => $field['value']['lng'], 324 | 'data-map-lat' => $field['value']['lat'], 325 | 'data-map-zoom' => $field['value']['zoom'], 326 | 'data-map-layers' => $field['value']['layers'], 327 | 'data-map-markers' => $field['value']['markers'], 328 | ]; 329 | 330 | ?> 331 |
>
332 | 344 |
345 |

346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 |

356 |
357 | 361 |
362 |
363 | sanitize_value( $value, $field, 'display' ); 442 | 443 | return $value; 444 | } 445 | 446 | /** 447 | * Sanitize lat, lng, convert legacy properties 448 | */ 449 | private function sanitize_geodata( $value, $default_latlng = null ) { 450 | 451 | // convert settings from <= 1.0.1 > display only? 452 | if ( isset( $value['center_lat'] ) ) { 453 | if ( ( ! isset( $value['lat'] ) || empty( $value['lat'] ) ) && ! empty( $value['center_lat'] ) ) { 454 | $value['lat'] = $value['center_lat']; 455 | } 456 | unset( $value['center_lat'] ); 457 | } 458 | 459 | if ( isset( $value['center_lng'] ) ) { 460 | if ( ( ! isset( $value['lng'] ) || empty( $value['lng'] ) ) && ! empty( $value['center_lng'] ) ) { 461 | $value['lng'] = $value['center_lng']; 462 | } 463 | unset( $value['center_lng'] ); 464 | } 465 | 466 | // apply defaults 467 | if ( ! is_null( $default_latlng ) ) { 468 | $value = wp_parse_args( $value, $default_latlng ); 469 | } 470 | 471 | // typecast values 472 | $value['lat'] = floatval( $value['lat'] ); 473 | $value['lng'] = floatval( $value['lng'] ); 474 | 475 | // maybe sanitize zoom 476 | if ( isset( $value['zoom'] )) { 477 | // boundaries 478 | $value['zoom'] = min( 22, max( 0, intval( $value['zoom'] ) ) ); 479 | } 480 | 481 | return $value; 482 | } 483 | 484 | /** 485 | * @param array $value array( 'lat' => float, 'lng => float, 'zoom' => int, 'address' => string, 'markers' => array, 'layers' => array ) 486 | * @param array $field 487 | * @param string $context edit|dispaly|update 488 | * @return array Sanitized $value 489 | */ 490 | private function sanitize_value( $value, $field, $context = '' ) { 491 | 492 | if ( is_string( $value ) ) { 493 | // try to json-decode 494 | $value = json_decode( $value ); 495 | if ( is_null( $value ) ) { 496 | $value = []; 497 | } 498 | } 499 | 500 | $value = (array) $value; 501 | 502 | // sanitize field 503 | $field = $this->sanitize_field( $field ); 504 | 505 | // 506 | // Markers 507 | // 508 | if ( ! isset( $value['markers']) || ! is_array( $value['markers'] ) ) { 509 | $value['markers'] = []; 510 | } 511 | 512 | // make sure its an indexed array 513 | $value['markers'] = array_values( $value['markers'] ); 514 | 515 | // Maybe get marker from ACF GoogleMaps data 516 | if ( 'display' === $context ) { // display + edit 517 | 518 | $value = $this->sanitize_geodata( $value, [ 519 | 'lat' => $field['center_lat'], 520 | 'lng' => $field['center_lng'], 521 | 'zoom' => $field['zoom'], 522 | ] ); 523 | 524 | if ( ! empty( $value[ 'address' ] ) ) { 525 | 526 | // create marker from GM field address 527 | if ( $field['max_markers'] !== 0 && ! count( $value[ 'markers' ] ) ) { 528 | 529 | $value['markers'][] = [ 530 | 'label' => wp_kses_post( $value['address'] ), 531 | 'default_label' => '', 532 | 'lat' => $value['lat'], 533 | 'lng' => $value['lng'], 534 | ]; 535 | } 536 | } else { 537 | if ( count( $value['markers'] ) ) { 538 | // update address from first marker 539 | $value['address'] = $value['markers'][0]['label']; 540 | } else { 541 | $value['address'] = ''; 542 | } 543 | } 544 | } 545 | 546 | // typecast 547 | foreach ( $value['markers'] as &$marker ) { 548 | 549 | // typecast values 550 | $marker['lat'] = floatval( $marker['lat'] ); 551 | $marker['lng'] = floatval( $marker['lng'] ); 552 | 553 | $marker['label'] = wp_kses_post( $marker[ 'label' ], [], $allowed_protocols = '' ); 554 | $marker['default_label'] = wp_kses_post( $marker[ 'default_label' ], [], $allowed_protocols = '' ); 555 | } 556 | 557 | // store data to be used by ACF GM Field 558 | if ( 'update' === $context ) { 559 | $value[ 'version' ] = Core\Core::instance()->get_version(); 560 | 561 | if ( count( $value['markers'] ) ) { 562 | // update address from first marker 563 | $value['address'] = $value['markers'][0]['label']; 564 | } else { 565 | $value['address'] = ''; 566 | } 567 | } 568 | 569 | // Sanitize HTML from address 570 | $value[ 'address' ] = wp_kses_post( $value[ 'address' ] ); 571 | 572 | // 573 | // Layers 574 | // 575 | if ( ! isset( $value['layers'] ) || ! is_array( $value['layers'] ) || ! count( $value['layers'] ) || ! $field['allow_map_layers'] ) { 576 | $value['layers'] = $field['layers']; 577 | } else { 578 | // normalize layers 579 | $value['layers'] = $this->sanitize_layers( $value['layers'] ); 580 | } 581 | 582 | return array_intersect_key( $value, $this->default_values ); 583 | 584 | } 585 | 586 | /** 587 | * Sanitize layers 588 | */ 589 | private function sanitize_layers( $layers ) { 590 | $layers = (array) $layers; 591 | 592 | $layers = array_map( function( $layer ) { 593 | if ( 'OpenStreetMap' === $layer ) { 594 | $layer = 'OpenStreetMap.Mapnik'; 595 | } 596 | return $layer; 597 | }, $layers ); 598 | $layers = array_filter( $layers ); 599 | $layers = array_unique( $layers ); 600 | $layers = array_values( $layers ); 601 | return $layers; 602 | } 603 | 604 | /* 605 | * update_value() 606 | * 607 | * This filter is applied to the $value before it is saved in the db 608 | * 609 | * @type filter 610 | * @since 3.6 611 | * @date 23/01/13 612 | * 613 | * @param $value (mixed) the value found in the database 614 | * @param $post_id (mixed) the $post_id from which the value was loaded 615 | * @param $field (array) the field array holding all the field options 616 | * @return $value 617 | */ 618 | function update_value( $value, $post_id, $field ) { 619 | 620 | // sanitize data from UI! 621 | 622 | // normalize markers 623 | 624 | 625 | if ( is_string( $value ) ) { 626 | $value = json_decode( stripslashes($value), true ); 627 | } 628 | 629 | if ( ! is_array( $value ) ) { 630 | $value = $this->defaults; 631 | } 632 | 633 | $value = $this->sanitize_value( $value, $field, 'update' ); 634 | 635 | 636 | 637 | return $value; 638 | } 639 | 640 | 641 | /* 642 | * format_value() 643 | * 644 | * This filter is appied to the $value after it is loaded from the db and before it is returned to the template 645 | * 646 | * @type filter 647 | * @since 3.6 648 | * @date 23/01/13 649 | * 650 | * @param $value (mixed) the value which was loaded from the database 651 | * @param $post_id (mixed) the $post_id from which the value was loaded 652 | * @param $field (array) the field array holding all the field options 653 | * 654 | * @return $value (mixed) the modified value 655 | */ 656 | function format_value( $value, $post_id, $field ) { 657 | 658 | // bail early if no value 659 | if ( empty( $value ) ) { 660 | return $value; 661 | } 662 | 663 | $value = $this->sanitize_value( $value, $field, 'display' ); 664 | 665 | if ( 'raw' === $field['return_format'] ) { 666 | 667 | // ensure backwards compatibility <= 1.0.1 668 | $value['center_lat'] = $value['lat']; 669 | $value['center_lng'] = $value['lng']; 670 | 671 | } else if ( Core\Templates::is_supported() ) { 672 | 673 | if ( 'osm' === $field['return_format'] && has_filter( 'osm_map_iframe_template' ) ) { 674 | _deprecated_hook( 'osm_map_iframe_template', '1.3.0', 'theme overrides', 'The filter is no longer in effect.' ); 675 | } 676 | 677 | ob_start(); 678 | 679 | get_template_part( 'osm-maps/' . $field['return_format'], null, [ 680 | 'field' => $field, 681 | 'map' => $value, 682 | ] ); 683 | 684 | $value = ob_get_clean(); 685 | 686 | } else if ( $field['return_format'] === 'admin' ) { // wp < 5.5 687 | 688 | $attr = $field['attr'] + [ 689 | 'class' => 'leaflet-map', 690 | 'data-height' => $field['height'], 691 | 'data-map' => 'leaflet', 692 | 'data-map-lng' => $value['lng'], 693 | 'data-map-lat' => $value['lat'], 694 | 'data-map-zoom' => $value['zoom'], 695 | 'data-map-layers' => $value['layers'], 696 | 'data-map-markers' => $value['markers'], 697 | ]; 698 | $value = sprintf( 699 | '
', 700 | acf_esc_attr( $attr ) 701 | ); 702 | 703 | } else if ( $field['return_format'] === 'osm' ) { // wp < 5.5 704 | 705 | // features: one marker max. four maps to choose from 706 | $osm_providers = Core\OSMProviders::instance(); 707 | 708 | $iframe_atts = [ 709 | 'height' => $field['height'], 710 | 'width' => '425', 711 | 'frameborder' => 0, 712 | 'scrolling' => 'no', 713 | 'marginheight' => 0, 714 | 'marginwidth' => 0, 715 | ]; 716 | 717 | $html = '
%4$s'; 718 | 719 | /** 720 | * Filter iframe HTML. 721 | * 722 | * @param string $html Template String. Placeholders: %1$s: iFrame Source, %2$s: iframe attributes, %3$s: URL to bigger map, %4$s: Link-Text. 723 | */ 724 | $html = apply_filters( 'osm_map_iframe_template', $html ); 725 | 726 | $value = sprintf( 727 | $html, 728 | $osm_providers->get_iframe_url( $value ), 729 | acf_esc_attr( $iframe_atts ), 730 | esc_url( $osm_providers->get_link_url( $value ) ), 731 | esc_html__( 'View Larger Map','acf-openstreetmap-field' ) 732 | ); 733 | 734 | } else if ( $field['return_format'] === 'leaflet' ) { 735 | 736 | // features: multiple markers. lots of maps to choose from 737 | $map_attr = [ 738 | 'class' => 'leaflet-map', 739 | 'data-height' => $field['height'], 740 | 'data-map' => 'leaflet', 741 | 'data-map-lng' => $value['lng'], 742 | 'data-map-lat' => $value['lat'], 743 | 'data-map-zoom' => $value['zoom'], 744 | 'data-map-layers' => $value['layers'], 745 | 'data-map-markers' => $value['markers'], 746 | ]; 747 | 748 | if ( isset( $field['attr'] ) ) { 749 | $map_attr = $field['attr'] + $map_attr; 750 | } 751 | 752 | 753 | $html = sprintf('
', acf_esc_attr( $map_attr ) ); 754 | $value = $html; 755 | 756 | wp_enqueue_style( 'leaflet' ); 757 | 758 | } 759 | 760 | // return 761 | return $value; 762 | } 763 | 764 | /** 765 | * Apply basic formatting to prepare the value for default REST output. 766 | * 767 | * @param mixed $value 768 | * @param int|string $post_id 769 | * @param array $field 770 | * @return array|mixed 771 | */ 772 | public function format_value_for_rest( $value, $post_id, array $field ) { 773 | 774 | if ( ! $value ) { 775 | return null; 776 | } 777 | 778 | return acf_format_numerics( $value ); 779 | } 780 | 781 | 782 | //*/ 783 | 784 | 785 | /* 786 | * validate_value() 787 | * 788 | * This filter is used to perform validation on the value prior to saving. 789 | * All values are validated regardless of the field's required setting. This allows you to validate and return 790 | * messages to the user if the value is not correct 791 | * 792 | * @type filter 793 | * @date 11/02/2014 794 | * @since 5.0.0 795 | * 796 | * @param $valid (boolean) validation status based on the value and the field's required setting 797 | * @param $value (mixed) the $_POST value 798 | * @param $field (array) the field array holding all the field options 799 | * @param $input (string) the corresponding input name for $_POST value 800 | * @return $valid 801 | */ 802 | function validate_value( $valid, $value, $field, $input ){ 803 | 804 | // bail early if not required 805 | if( ! $field['required'] || $field['max_markers'] === 0 ) { 806 | 807 | return $valid; 808 | 809 | } 810 | 811 | $value = json_decode( stripslashes( $value ), true ); 812 | 813 | if ( ! count( $value['markers'] ) ) { 814 | 815 | return __('Please set a marker on the map.','acf-openstreetmap-field'); 816 | 817 | } 818 | 819 | // return 820 | return $valid; 821 | } 822 | 823 | 824 | 825 | /* 826 | * load_field() 827 | * 828 | * This filter is applied to the $field after it is loaded from the database 829 | * 830 | * @type filter 831 | * @date 23/01/2013 832 | * @since 3.6.0 833 | * 834 | * @param $field (array) the field array holding all the field options 835 | * @return $field 836 | */ 837 | function load_field( $field ) { 838 | 839 | return $this->sanitize_field( $field, 'display' ); 840 | } 841 | 842 | /* 843 | * update_field() 844 | * 845 | * This filter is applied to the $field before it is saved to the database 846 | * 847 | * @type filter 848 | * @date 23/01/2013 849 | * @since 3.6.0 850 | * 851 | * @param $field (array) the field array holding all the field options 852 | * @return $field 853 | */ 854 | function update_field( $field ) { 855 | 856 | return $this->sanitize_field( $field, 'update' ); 857 | } 858 | 859 | 860 | /** 861 | * @param array $field 862 | * @param string $context 863 | * @return array Sanitized $field 864 | */ 865 | private function sanitize_field( $field, $context = '' ) { 866 | 867 | $field = wp_parse_args( $field, $this->defaults ); 868 | 869 | // typecast and restrict values 870 | $field['center_lat'] = floatval( $field['center_lat'] ); 871 | $field['center_lng'] = floatval( $field['center_lng'] ); 872 | $field['zoom'] = min( 22, max( 1, intval( $field['zoom'] ) ) ); 873 | 874 | // layers 875 | $field['layers'] = $this->sanitize_layers( $field['layers'] ); 876 | 877 | return $field; 878 | } 879 | 880 | /** 881 | * @action wp_footer 882 | */ 883 | public function maybe_print_media_templates() { 884 | if ( ! did_action( 'print_media_templates' ) ) { 885 | $this->print_media_templates(); 886 | } 887 | } 888 | 889 | /** 890 | * @action print_media_templates 891 | */ 892 | public function print_media_templates() { 893 | ?> 894 | 909 | $lat, 1 => $lon ]; 22 | 23 | $radOff = $what === 0 24 | ? $offset / self::EARTH_RADIUS 25 | : $offset / ( self::EARTH_RADIUS * cos( M_PI * $coord[0] / 180 ) ); 26 | 27 | return $coord[$what] + $radOff * 180 / M_PI; 28 | } 29 | 30 | /** 31 | * Convert lat/lng/zoom coordinates to bounding box 32 | * 33 | * @param Float $lat 34 | * @param Float $lon 35 | * @param Float $zoom 36 | * 37 | * @return Array [ 38 | * 0 => (Float) MinLng, 39 | * 1 => (Float) MinLat, 40 | * 2 => (Float) MaxLng, 41 | * 3 => (Float) MaxLat, 42 | * ] 43 | */ 44 | public static function getBBox($lat, $lon, $zoom ) { 45 | 46 | $offset = self::zoomToOffset( $zoom ); 47 | 48 | return [ 49 | 0 => self::getCoordOffset(1, $lat, $lon, -$offset), 50 | 1 => self::getCoordOffset(0, $lat, $lon, -$offset), 51 | 2 => self::getCoordOffset(1, $lat, $lon, $offset), 52 | 3 => self::getCoordOffset(0, $lat, $lon, $offset), 53 | ]; // 0 = minlon, 1 = minlat, 2 = maxlon, 3 = maxlat, 4,5 = original val (marker) 54 | } 55 | 56 | /** 57 | * Get fraction of Earth's Perimeter that should be visible at zoom level 58 | * 59 | * @param Int $zoom 60 | * 61 | * @return Float 62 | */ 63 | public static function zoomToOffset( $zoom ) { 64 | 65 | return ( self::EARTH_RADIUS * M_PI * 2 ) / pow( 2, $zoom ); 66 | 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /include/ACFFieldOpenstreetmap/Settings/Settings.php: -------------------------------------------------------------------------------- 1 | true, 26 | // 'geo_json_feed' => false, 27 | // 'geo_post_types' => [ 28 | // 'post' => true, // one post = one geojson object 29 | // 'page' => false, 30 | // ], 31 | // ], '', true ); 32 | 33 | add_option( 'acf_osm_geocoder', $this->geocoder_defaults, '', true ); 34 | 35 | add_option( 'acf_osm_provider_tokens', [], '', false ); 36 | add_option( 'acf_osm_providers', $this->get_default_option_providers(), '', false ); 37 | add_option( 'acf_osm_proxy', [], '', false ); 38 | 39 | add_action( 'admin_menu', [ $this, 'admin_menu' ] ); 40 | add_action( "load-settings_page_acf_osm", [ $this, 'enqueue_assets' ] ); 41 | 42 | add_filter( 'plugin_action_links_'.$core->get_wp_plugin(), [ $this, 'plugin_actions_links' ], 20, 4 ); 43 | 44 | parent::__construct(); 45 | 46 | } 47 | 48 | /** 49 | * @filter plugin_action_links_{$plugin_file} 50 | */ 51 | public function plugin_actions_links( $actions, $plugin_file, $plugin_data, $context ) { 52 | if ( isset( $plugin_data['Name'] ) && current_user_can( 'manage_options' ) ) { 53 | $actions['settings'] = sprintf( 54 | '%s', 55 | esc_url( 56 | add_query_arg( 57 | [ 'page' => $this->optionset ], 58 | admin_url( 'options-general.php' ) 59 | ) 60 | ), 61 | /* translators: %s: Plugin name. */ 62 | esc_attr( sprintf( _x( '%s Settings', 'plugin', 'acf-openstreetmap-field' ), $plugin_data['Name'] ) ), 63 | __( 'Settings', 'acf-openstreetmap-field' ) 64 | ); 65 | } 66 | return $actions; 67 | } 68 | 69 | /** 70 | * Add Settings page 71 | * 72 | * @action admin_menu 73 | */ 74 | public function admin_menu() { 75 | $page_hook = add_options_page( __('OpenStreetMap Settings' , 'acf-openstreetmap-field' ),__('OpenStreetMap' , 'acf-openstreetmap-field'),'manage_options', $this->optionset, [ $this, 'settings_page' ] ); 76 | } 77 | 78 | /** 79 | * Render Settings page 80 | */ 81 | public function settings_page() { 82 | 83 | if ( ! current_user_can( 'manage_options' ) ) { 84 | wp_die( esc_html__( 'You do not have sufficient permissions to access this page.' ) ); 85 | } 86 | 87 | $core = Core\Core::instance(); 88 | $providers = Core\LeafletProviders::instance(); 89 | 90 | ?> 91 |
92 |

93 | 94 |
95 | optionset ); ?> 96 | 98 | */ ?> 99 | 100 | 101 | 114 | 117 |

118 |
119 | 124 |
125 |
126 | */ ?> 127 |
128 |

129 | providers_description(); ?> 130 |
131 |
132 | get_providers( [], true ); 135 | 136 | foreach ( $provider_settings as $provider_key => $provider_data ) { 137 | 138 | $this->print_provider_setting( $provider_key, $provider_data ); 139 | 140 | } 141 | 142 | ?> 143 |
144 |
145 |
146 |
154 |
155 |
156 |
157 |
158 | 159 |
160 |
161 | print_geocoder_settings(); ?> 162 |
163 | 164 | 167 | 168 | 169 | register_assets(); 180 | 181 | // registering in Core\Core does not work ... why? 182 | wp_enqueue_script( 'acf-osm-settings' ); 183 | wp_enqueue_style( 'acf-osm-settings' ); 184 | } 185 | 186 | /** 187 | * Setup options. 188 | * 189 | * @action admin_init 190 | */ 191 | public function register_settings() { 192 | 193 | $this->register_settings_providers(); 194 | $this->register_settings_geocoder(); 195 | 196 | } 197 | 198 | /** 199 | * @return array Disable tile providers with bounds 200 | */ 201 | private function get_default_option_providers() { 202 | 203 | $providers = Core\LeafletProviders::instance(); 204 | $is_https = strpos( get_option('home'), 'https:' ) === 0; 205 | $provider_settings = $providers->get_providers(['credentials']); 206 | $default_option = []; 207 | 208 | foreach ( $provider_settings as $provider_key => $provider_data ) { 209 | if ( $this->has_bounds( $provider_data ) || ( $is_https && $this->is_insecure( $provider_data ) ) ) { 210 | $default_option[ $provider_key ] = '0'; 211 | continue; 212 | } 213 | if ( isset( $provider_data['variants'] ) ) { 214 | foreach ( $provider_data['variants'] as $variant_key => $variant_data ) { 215 | if ( $this->has_bounds( $variant_data ) || ( $is_https && $this->is_insecure( $variant_data ) )) { 216 | $default_option[ $provider_key ]['variants'][$variant_key] = '0'; 217 | } 218 | } 219 | } 220 | } 221 | return $default_option; 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php: -------------------------------------------------------------------------------- 1 | Core\LeafletGeocoders::GEOCODER_DEFAULT, 14 | 'scale' => '18', // (int) 0-18 | 'auto' 15 | 'opencage' => [ 16 | 'apiKey' => null, 17 | ], 18 | ]; 19 | 20 | /** @var array */ 21 | private $geocoder_scale_options; 22 | 23 | /** 24 | * Output geocoder settings 25 | */ 26 | private function print_geocoder_settings() { 27 | $geocoders = Core\LeafletGeocoders::instance(); 28 | ?> 29 |

30 |
31 |
32 | 33 | optionset, 'geocoder' ); 35 | ?> 36 | 37 | get_geocoders() as $slug => $geocoder ) { 40 | if ( ! isset( $geocoder['settings'] ) ) { 41 | continue; 42 | } 43 | ?> 44 |
45 |

46 | 47 |

48 | 49 | optionset, "geocoder-{$slug}" ); 51 | ?> 52 | 53 |
54 | 58 |
59 |
60 |
61 |
70 |
71 |
72 |

73 |
74 | 75 |

76 |

77 |

 78 | 			
79 |
80 | optionset, 'acf_osm_geocoder', [ $this , 'sanitize_geocoder' ] ); 92 | 93 | add_settings_section( 94 | $settings_section, 95 | __( 'Geocoder Settings', 'acf-openstreetmap-field' ), 96 | [ $this, 'tokens_description' ], 97 | $this->optionset 98 | ); 99 | 100 | add_settings_field( 101 | "{$settings_section}-engine", 102 | __('Geocoder','acf-openstreetmap-field'), 103 | function() use ( $geocoder_option, $geocoders ) { 104 | echo $this->select_ui( array_map( function($geocoder) { // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 105 | return $geocoder['label']; 106 | }, $geocoders->get_geocoders() ), $geocoder_option['engine'], 'acf_osm_geocoder[engine]' ); 107 | }, 108 | $this->optionset, 109 | 'geocoder' 110 | ); 111 | 112 | add_settings_field( 113 | "{$settings_section}-scale", 114 | __( 'Reverse Geocoder Detail Level', 'acf-openstreetmap-field' ), 115 | function() use ( $geocoder_option ) { 116 | echo $this->select_ui( $this->get_scale_options(), $geocoder_option['scale'], 'acf_osm_geocoder[scale]' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 117 | }, 118 | $this->optionset, 119 | 'geocoder' 120 | ); 121 | 122 | foreach ( $geocoders->get_geocoders() as $slug => $geocoder ) { 123 | if ( isset( $geocoder['settings'] ) ) { 124 | foreach ( $geocoder['settings'] as $prop => $setting ) { 125 | // TODO: generate service settings from $geocoders->get_geocoders() 126 | $label = _x( $setting['label'], 'geocoder', 'acf-openstreetmap-field'); // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText 127 | if ( $setting['required'] ) { 128 | $label .= ' ' . __('(Required)', 'acf-openstreetmap-field'); 129 | } 130 | add_settings_field( 131 | "{$settings_section}-{$slug}-{$prop}", 132 | $label, 133 | function() use ( $setting, $geocoder_option, $slug, $prop ) { 134 | $value = isset( $geocoder_option[$slug][$prop] ) 135 | ? $geocoder_option[$slug][$prop] 136 | : ''; 137 | // TODO: choose UI by $setting['type'] 138 | printf( 139 | '', 140 | 'acf_osm_geocoder[opencage][apiKey]', 141 | esc_attr( $value ) 142 | ); 143 | }, 144 | $this->optionset, 145 | "geocoder-{$slug}" 146 | ); 147 | 148 | } 149 | } 150 | } 151 | } 152 | 153 | /** 154 | * @return array 155 | */ 156 | private function get_scale_options() { 157 | if ( ! isset( $this->geocoder_scale_options ) ) { 158 | /* 159 | | NOMINATIM | ACF OpenStreetMap Field | 160 | |-----------------------------------------------|--------------------------| 161 | | zoom | Detail level (DE) | Detail level (US) | zoom | Detail level | 162 | |-------|-------------------|-------------------|---------|----------------| 163 | | 0 | country | country | 0 | country | 164 | | 1 | country | country | 1 | country | 165 | | 2 | country | country | 2 | country | 166 | | 3 | country | country | 3 | country | 167 | | 4 | country | country | 4 | country | 168 | | 5 | state | state | 5 | state | 169 | | 6 | state | state | 6 | state | 170 | | 7 | state | state | 8 | county | 171 | | 8 | county | city | 8 | county | 172 | | 9 | county | city | 9 | county | 173 | | 10 | village | city | 10 | village/suburb | 174 | | 11 | village | city | 11 | village/suburb | 175 | | 12 | village | city | 12 | village/suburb | 176 | | 13 | village | suburb | 13 | village/suburb | 177 | | 14 | postcode | neighbourhood | 16 | village/suburb | 178 | | 15 | postcode | neighbourhood | 16 | village/suburb | 179 | | 16 | road (major) | road (major) | 18 | building | 180 | | 17 | road (+minor) | road (+minor) | 18 | building | 181 | | 18 | building | building | 18 | building | 182 | */ 183 | $this->geocoder_scale_options = [ 184 | 'auto' => __('Derived from zoom', 'acf-openstreetmap-field'), 185 | '0' => __('0 (Country)', 'acf-openstreetmap-field'), 186 | '1' => __('1', 'acf-openstreetmap-field'), 187 | '2' => __('2', 'acf-openstreetmap-field'), 188 | '3' => __('3', 'acf-openstreetmap-field'), 189 | '4' => __('4', 'acf-openstreetmap-field'), 190 | '5' => __('5', 'acf-openstreetmap-field'), 191 | '6' => __('6', 'acf-openstreetmap-field'), 192 | '7' => __('7', 'acf-openstreetmap-field'), 193 | '8' => __('8', 'acf-openstreetmap-field'), 194 | '9' => __('9', 'acf-openstreetmap-field'), 195 | '10' => __('10', 'acf-openstreetmap-field'), 196 | '11' => __('11', 'acf-openstreetmap-field'), 197 | '12' => __('12', 'acf-openstreetmap-field'), 198 | '13' => __('13', 'acf-openstreetmap-field'), 199 | '14' => __('14', 'acf-openstreetmap-field'), 200 | '15' => __('15', 'acf-openstreetmap-field'), 201 | '16' => __('16', 'acf-openstreetmap-field'), 202 | '17' => __('17', 'acf-openstreetmap-field'), 203 | '18' => __('18 (Building)', 'acf-openstreetmap-field'), 204 | ]; 205 | } 206 | return $this->geocoder_scale_options; 207 | } 208 | 209 | /** 210 | * @param array $new_value 211 | * @return array $new_value 212 | */ 213 | public function sanitize_geocoder( $new_values ) { 214 | 215 | // make sure defaults are present 216 | $values = array_replace_recursive( $this->geocoder_defaults, $new_values ); 217 | 218 | // make sure geocoder exists 219 | if ( ! in_array( $new_values['engine'], Core\LeafletGeocoders::GEOCODERS ) ) { 220 | $values['engine'] = Core\LeafletGeocoders::GEOCODER_DEFAULT; 221 | } 222 | 223 | if ( ! array_key_exists( $values['scale'], $this->get_scale_options() ) ) { 224 | $values['scale'] = $this->geocoder_defaults['scale']; 225 | } 226 | 227 | $values['opencage']['apiKey'] = sanitize_text_field( $values['opencage']['apiKey'] ); 228 | 229 | return $values; 230 | 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /include/ACFFieldOpenstreetmap/Settings/Traits/ProviderSettings.php: -------------------------------------------------------------------------------- 1 | optionset 24 | ); 25 | 26 | // register_setting( $this->optionset, 'acf_osm_features', [ $this , 'sanitize_features' ] ); 27 | register_setting( $this->optionset, 'acf_osm_provider_tokens', [ $this , 'sanitize_provider_tokens' ] ); 28 | register_setting( $this->optionset, 'acf_osm_providers', [ $this , 'sanitize_providers' ] ); 29 | register_setting( $this->optionset, 'acf_osm_proxy', [ $this , 'sanitize_proxy' ] ); 30 | } 31 | 32 | /** 33 | * @param string $provider_key 34 | * @param array $provider_data 35 | */ 36 | public function print_provider_setting( $provider_key, $provider_data ) { 37 | 38 | $providers = Core\LeafletProviders::instance(); 39 | 40 | // @list( $provider_key, $provider_data ) = array_values( $args ); 41 | $provider_option = get_option( 'acf_osm_providers' ); 42 | $proxy_option = get_option( 'acf_osm_proxy' ); 43 | 44 | $is_parent_disabled = isset( $provider_option[$provider_key] ) && $provider_option[$provider_key] === false; 45 | $needs_access_key = $providers->needs_access_token( $provider_key, $provider_data ); 46 | $has_access_key = $providers->has_access_token( $provider_key, $provider_data ); 47 | 48 | ?> 49 |
50 | 51 |

print_tags( $provider_data ); 57 | $this->print_test_link( $provider_key ); 58 | 59 | } 60 | ?>

61 | 66 |
67 | 80 | 81 | 94 | 95 |
96 | 102 |
103 |

104 |
105 | $variant ) { 107 | 108 | $is_disabled = isset( $provider_option[ $provider_key ]['variants'][ $variant_key ] ) 109 | && in_array( $provider_option[$provider_key]['variants'][$variant_key], [ '0', false ], true ); 110 | 111 | ?> 112 |
113 | 129 |
130 | print_tags( $variant ); 133 | 134 | ?> 135 |
136 |
137 |
140 |
141 | print_access_token_inputs( $provider_key, $provider_data ); 146 | 147 | ?> 148 |
149 | '] 163 | foreach ( $provider_data['options'] as $option => $value ) { 164 | 165 | if ( is_string($value) && ( 1 === preg_match( '/^<([^>]*)>$/imsU', $value, $matches ) ) ) { 166 | $current_value = ''; 167 | $has_value = isset( $token_option[ $provider_key ][ 'options' ][ $option ]) && ! empty( $token_option[ $provider_key ][ 'options' ][ $option ] ); 168 | ?> 169 |
170 |
171 |

172 | 194 |
195 | ]*)>$/imsU', $value, $matches ) ) { 209 | $value = ''; 210 | } 211 | 212 | printf('', 213 | esc_attr( $field_id ), 214 | esc_attr( $field_name ), 215 | esc_attr( $value ) 216 | ); 217 | 218 | } 219 | 220 | /** 221 | * Sanitize value of setting_1 222 | * 223 | * @return string sanitized value 224 | */ 225 | public function sanitize_provider_tokens( $new_values ) { 226 | $core = Core\Core::instance(); 227 | $providers = Core\LeafletProviders::instance(); 228 | 229 | $token_options = $providers->get_token_options(); 230 | 231 | $prev_values = get_option('acf_osm_provider_tokens'); 232 | 233 | // merge new values 234 | $values = array_replace_recursive( $prev_values, $new_values ); 235 | // remove empty values 236 | $values = Helper\ArrayHelper::filter_recursive( $values ); 237 | 238 | return $values; 239 | } 240 | 241 | /** 242 | * Print layer tags 243 | */ 244 | private function print_tags( $options ) { 245 | 246 | $tag = '%s'; 247 | 248 | if ( $this->is_insecure( $options ) ) { 249 | $is_https = strpos( get_option('home'), 'https:' ) === 0; 250 | printf( 251 | $tag, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 252 | esc_html__( 'The map tiles are loaded through an insecure http connection.', 'acf-openstreetmap-field' ), 253 | 'acf-osm-tag' . ( $is_https ? ' warn' : '' ), 254 | esc_html__( 'Insecure', 'acf-openstreetmap-field' ) 255 | ); 256 | } 257 | if ( $this->is_overlay( $options ) ) { 258 | printf( 259 | $tag, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 260 | esc_html__( 'This is an overlay to be displayed over a base map.', 'acf-openstreetmap-field' ), 261 | 'acf-osm-tag', 262 | esc_html__( 'Overlay', 'acf-openstreetmap-field' ) 263 | ); 264 | } 265 | if ( $this->has_bounds( $options ) ) { 266 | printf( 267 | $tag, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 268 | esc_html__( 'Only available for a specific region.', 'acf-openstreetmap-field' ), 269 | 'acf-osm-tag', 270 | esc_html__( 'Bounds', 'acf-openstreetmap-field' ) 271 | ); 272 | } 273 | if ( isset( $options['options']['minZoom'] ) && isset( $options['options']['maxZoom'] ) ) { 274 | printf( 275 | $tag, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 276 | esc_html__( 'Zoom is restricted.', 'acf-openstreetmap-field' ), 277 | 'acf-osm-tag', 278 | esc_html( sprintf( 279 | /* translators: 1: min zoom value, 2: max zoom value */ 280 | __( 'Zoom: %1$d–%2$d', 'acf-openstreetmap-field' ), 281 | $options['options']['minZoom'], $options['options']['maxZoom'] 282 | )) 283 | ); 284 | } else if ( isset( $options['options']['minZoom'] ) ) { 285 | printf( 286 | $tag, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 287 | esc_html__( 'Zoom levels are restricted.', 'acf-openstreetmap-field' ), 288 | 'acf-osm-tag', 289 | esc_html( sprintf( 290 | /* translators: min zoom value */ 291 | __( 'Min Zoom: %d', 'acf-openstreetmap-field' ), 292 | $options['options']['minZoom'] 293 | )) 294 | ); 295 | 296 | } else if ( isset( $options['options']['maxZoom'] ) ) { 297 | printf( 298 | $tag, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 299 | esc_html__( 'Zoom levels are restricted.', 'acf-openstreetmap-field' ), 300 | 'acf-osm-tag', 301 | esc_html(sprintf( 302 | /* translators: max zoom value */ 303 | __( 'Max Zoom: %d', 'acf-openstreetmap-field' ), 304 | $options['options']['maxZoom'] // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 305 | )) 306 | ); 307 | } 308 | } 309 | 310 | /** 311 | * 312 | */ 313 | public function sanitize_providers( $values ) { 314 | try { 315 | $values = array_map( [ $this, 'boolval_recursive' ], (array) $values ); 316 | } catch ( \Exception $err ) { 317 | $values = []; 318 | } 319 | return $values; 320 | } 321 | 322 | /** 323 | * 324 | */ 325 | public function sanitize_proxy( $values ) { 326 | try { 327 | $values = array_filter( (array) $values ); 328 | $values = array_map( 'boolval', $values ); 329 | } catch ( \Exception $err ) { 330 | $values = []; 331 | } 332 | return $values; 333 | } 334 | 335 | /** 336 | * @param string $key 337 | * @return string 338 | */ 339 | private function sanitize_key_case( $key ) { 340 | return preg_replace( '/[^A-Za-z0-9_\-]/', '', $key ); 341 | } 342 | 343 | private function boolval_recursive( $val ) { 344 | if ( $val === '0' ) { 345 | return false; 346 | } else if ( is_array( $val ) ) { 347 | return array_map( [ $this, 'boolval_recursive' ], $val ); 348 | } 349 | throw new \Exception('invalid value'); 350 | } 351 | 352 | /** 353 | * Whether a map tile provider is insecure. 354 | * 355 | * @param array $options Map provider options 356 | * @return boolean 357 | */ 358 | private function is_insecure( $options ) { 359 | return is_array($options) && isset( $options['url'] ) && strpos( $options['url'], 'http:' ) === 0; 360 | } 361 | 362 | /** 363 | * Whether a map tile provider has bounds 364 | * 365 | * @param array $options Map provider options 366 | * @return boolean 367 | */ 368 | private function has_bounds( $options ) { 369 | return is_array($options) && isset( $options['options']['bounds'] ); 370 | } 371 | 372 | /** 373 | * Whether a map tile is overlay. 374 | * 375 | * @param array $options Map provider options 376 | * @return boolean 377 | */ 378 | private function is_overlay( $options ) { 379 | return is_array($options) && isset( $options['isOverlay'] ) && $options['isOverlay'];; 380 | } 381 | 382 | /** 383 | * @param string $key Provider key 384 | */ 385 | private function print_test_link( $key ) { 386 | ?> 387 | 388 | 389 | 390 | 399 |
400 |

401 |

402 |
403 | %2$s', 9 | esc_attr( $name ), 10 | implode( 11 | "\n", 12 | array_map( 13 | function( $value, $label ) use ( $current ) { 14 | return sprintf( 15 | '', 16 | esc_attr( $value ), 17 | selected( $value, $current, false ), 18 | esc_html( $label ) 19 | ); 20 | }, 21 | array_keys( $options ), 22 | array_values( $options ) 23 | ) 24 | ) 25 | ); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /include/ACFFieldOpenstreetmap/WPCLI/Commands/MapProxy.php: -------------------------------------------------------------------------------- 1 | false, 30 | ]); 31 | $proxy = Core\MapProxy::instance(); 32 | $result = $proxy->setup_proxy_dir( $assoc_args['force'] ); 33 | if ( is_wp_error( $result ) ) { 34 | \WP_CLI::error( $result->get_error_message() ); 35 | } else { 36 | \WP_CLI::success( "Create proxy directory in wp-content/maps/" ); 37 | } 38 | } 39 | 40 | /** 41 | * remove proxy dir in wp-content/maps/ 42 | * 43 | * ## EXAMPLES 44 | * 45 | * wp map-proxy uninstall 46 | * 47 | */ 48 | public function uninstall( $args, $assoc_args ) { 49 | $proxy = Core\MapProxy::instance(); 50 | $result = $proxy->reset_proxy_dir(); 51 | if ( is_wp_error( $result ) ) { 52 | \WP_CLI::error( $result->get_error_message() ); 53 | } else { 54 | \WP_CLI::success( "Removed proxy directory" ); 55 | } 56 | } 57 | 58 | /** 59 | * Generate local proxy configuration 60 | * 61 | * ## EXAMPLES 62 | * 63 | * wp map-proxy configure 64 | * 65 | */ 66 | public function configure( $args, $assoc_args ) { 67 | 68 | $proxy = Core\MapProxy::instance(); 69 | $result = $upload_dir = wp_upload_dir( null, false ); 70 | $proxy->save_proxy_config( $upload_dir['basedir'] ); 71 | 72 | if ( is_wp_error( $result ) ) { 73 | \WP_CLI::error( $result->get_error_message() ); 74 | } else { 75 | \WP_CLI::success( "Create proxy config in ". $upload_dir['basedir'] ); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /include/ACFFieldOpenstreetmap/WPCLI/WPCLI.php: -------------------------------------------------------------------------------- 1 | 'Install map proxy directory', 20 | 'is_deferred' => false, 21 | ] ); 22 | \WP_CLI::add_command( 'map-proxy uninstall', [ new Commands\MapProxy(), 'uninstall' ], [ 23 | 'shortdesc' => 'remove map proxy directory', 24 | 'is_deferred' => false, 25 | ] ); 26 | \WP_CLI::add_command( 'map-proxy configure', [ new Commands\MapProxy(), 'configure' ], [ 27 | 'shortdesc' => 'Save local map proxy configuration', 28 | 'is_deferred' => false, 29 | ] ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /include/api.php: -------------------------------------------------------------------------------- 1 | get_iframe_url( $map ); 11 | } 12 | 13 | /** 14 | * Get link to openstreetmap.org 15 | * 16 | * @param Array $map Map Data from ACF field 17 | * @return String 18 | */ 19 | function acf_osm_get_link_url( $map ) { 20 | return \ACFFieldOpenstreetmap\Core\OSMProviders::instance()->get_link_url( $map ); 21 | } 22 | -------------------------------------------------------------------------------- /include/autoload.php: -------------------------------------------------------------------------------- 1 | /// 25 | if ( ! preg_match( '/\/([a-z0-9\.]+)\/(\d+)\/(\d+)\/(\d+)(@2x)?$/i', $request_uri, $map_matches ) ) { 26 | http_response_code( 400 ); 27 | exit(); 28 | } 29 | 30 | $proxy_dir = pathinfo( $script_filename, PATHINFO_DIRNAME ); 31 | // request didn't come from proxy dir. 32 | if ( ! preg_match( '/wp-content\/maps$/', $proxy_dir ) ) { 33 | http_response_code( 400 ); 34 | exit(); 35 | } 36 | 37 | // get local config in uploads dir 38 | $config_path = pathinfo( $proxy_dir, PATHINFO_DIRNAME ) . '/uploads'; 39 | 40 | // multisite 41 | if ( preg_match( '/\/sites\/(\d+)\//i', $request_uri, $matches ) ) { 42 | @list( $garbage, $blog_id ) = $matches; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited 43 | $config_path .= '/sites/' . $blog_id; 44 | } 45 | // $proxy_config is a global config. Merge with local config from up-content/maps/uploads/acf-osm-proxy-config.php 46 | if ( file_exists( $config_path . '/acf-osm-proxy-config.php' ) ) { 47 | if ( $local_proxy_config = include( $config_path . '/acf-osm-proxy-config.php' ) ) { 48 | if ( is_array( $local_proxy_config ) ) { 49 | $proxy_config = array_replace( $proxy_config, $local_proxy_config ); 50 | } 51 | } 52 | } 53 | 54 | @list( $garbage, $provider, $z, $x, $y, $r ) = $map_matches; 55 | 56 | 57 | 58 | if ( ! isset( $proxy_config[$provider] ) ) { 59 | http_response_code(404); 60 | exit(); 61 | } 62 | 63 | // read from config 64 | $base_url = $proxy_config[ $provider ][ 'base_url' ]; 65 | $subdomains = $proxy_config[ $provider ][ 'subdomains' ]; 66 | 67 | $s = $subdomains[ rand( 0, strlen( $subdomains ) - 1 ) ]; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited 68 | 69 | // fill vars 70 | $url = str_replace( 71 | [ '{z}', '{x}', '{y}', '{s}', '{r}' ], 72 | [ $z, $x, $y, $s, $r ], 73 | $base_url 74 | ); 75 | 76 | // response headers being forwarded 77 | $send_response_headers = [ 78 | 'Expires', 79 | 'Cache-Control', 80 | 'ETag', 81 | 'Date', 82 | 'Content-Type', 83 | ]; 84 | $request_headers = []; 85 | 86 | // get http headers from user 87 | foreach ( [ 88 | 'User-Agent', 89 | 'Accept', 90 | 'Accept-Language', 91 | 'Accept-Encoding', 92 | 'Referer', 93 | 'Sec-GPC', 94 | 'Sec-Fetch-Dest', 95 | 'Sec-Fetch-Mode', 96 | 'Sec-Fetch-Site', 97 | 'Priority', 98 | 'Pragma', 99 | 'Cache-Control', 100 | ] as $header ) { 101 | $hdr = 'HTTP_'.str_replace( '-', '_', strtoupper( $header ) ); 102 | if ( isset( $_SERVER[ $hdr ] ) ) { 103 | $request_headers[] = "{$header}: ".stripslashes($_SERVER[ $hdr ]); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput 104 | } 105 | } 106 | 107 | /** @var int $http_status assume success */ 108 | $http_status = 200; 109 | 110 | /** @var int $request_status 1: host resolved, 2: remote connected, 3: got filesize, 4: got mime type */ 111 | $request_status = 0; 112 | 113 | $ctx = stream_context_create(['http' => [ 114 | 'method' => 'GET', 115 | 'header' => implode("\r\n", $request_headers ), 116 | ]], 117 | [ 118 | 'notification' => function( $notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max ) use ( &$http_status, &$request_status ) { 119 | // debugging 120 | // $notification_codes = [ 121 | // STREAM_NOTIFY_RESOLVE => 'STREAM_NOTIFY_RESOLVE', 122 | // STREAM_NOTIFY_CONNECT => 'STREAM_NOTIFY_CONNECT', 123 | // STREAM_NOTIFY_AUTH_REQUIRED => 'STREAM_NOTIFY_AUTH_REQUIRED', 124 | // STREAM_NOTIFY_MIME_TYPE_IS => 'STREAM_NOTIFY_MIME_TYPE_IS', 125 | // STREAM_NOTIFY_FILE_SIZE_IS => 'STREAM_NOTIFY_FILE_SIZE_IS', 126 | // STREAM_NOTIFY_REDIRECTED => 'STREAM_NOTIFY_REDIRECTED', 127 | // STREAM_NOTIFY_PROGRESS => 'STREAM_NOTIFY_PROGRESS', 128 | // STREAM_NOTIFY_COMPLETED => 'STREAM_NOTIFY_COMPLETED', 129 | // STREAM_NOTIFY_FAILURE => 'STREAM_NOTIFY_FAILURE', 130 | // STREAM_NOTIFY_FAILURE => 'STREAM_NOTIFY_FAILURE', 131 | // ]; 132 | 133 | switch ( $notification_code ) { 134 | case STREAM_NOTIFY_RESOLVE: 135 | $request_status = 1; 136 | break; 137 | case STREAM_NOTIFY_CONNECT: 138 | $request_status = 2; 139 | break; 140 | case STREAM_NOTIFY_FILE_SIZE_IS: 141 | $request_status = 3; 142 | break; 143 | case STREAM_NOTIFY_MIME_TYPE_IS: 144 | $request_status = 4; 145 | break; 146 | case STREAM_NOTIFY_PROGRESS: 147 | $request_status = 5; 148 | break; 149 | case STREAM_NOTIFY_FAILURE: // 404 150 | $http_status = $message_code; 151 | break; 152 | } 153 | }, 154 | ]); 155 | 156 | $response_reg = '/^(' . implode( '|', $send_response_headers ) . '):/i'; 157 | 158 | $contents = file_get_contents( $url, false, $ctx ); 159 | 160 | if ( ! $request_status ) { 161 | $http_status = 502; 162 | } 163 | 164 | http_response_code( $http_status ); 165 | 166 | if ( isset( $http_response_header ) ) { 167 | foreach ( $http_response_header as $response_header ) { 168 | if ( preg_match( $response_reg, $response_header ) ) { 169 | header( $response_header ); 170 | } 171 | } 172 | if ( 200 === $http_status ) { 173 | echo $contents; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /include/version.php: -------------------------------------------------------------------------------- 1 | \n" 8 | "Language-Team: LANGUAGE \n" 9 | "MIME-Version: 1.0\n" 10 | "Content-Type: text/plain; charset=UTF-8\n" 11 | "Content-Transfer-Encoding: 8bit\n" 12 | "POT-Creation-Date: 2024-12-30T15:25:57+00:00\n" 13 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 14 | "X-Generator: WP-CLI 2.11.0\n" 15 | "X-Domain: acf-openstreetmap-field\n" 16 | 17 | #. Plugin Name of the plugin 18 | #: index.php 19 | msgid "ACF OpenStreetMap Field" 20 | msgstr "" 21 | 22 | #. Plugin URI of the plugin 23 | #: index.php 24 | msgid "https://wordpress.org/plugins/acf-openstreetmap-field" 25 | msgstr "" 26 | 27 | #. Description of the plugin 28 | #: index.php 29 | msgid "A configurable OpenStreetMap Field for ACF." 30 | msgstr "" 31 | 32 | #. Author of the plugin 33 | #: index.php 34 | msgid "Jörn Lund" 35 | msgstr "" 36 | 37 | #. Author URI of the plugin 38 | #: index.php 39 | msgid "https://github.com/mcguffin" 40 | msgstr "" 41 | 42 | #: include/ACFFieldOpenstreetmap/Blocks~/Leaflet.php:48 43 | msgid "A Leaflet map" 44 | msgstr "" 45 | 46 | #: include/ACFFieldOpenstreetmap/Core/Core.php:156 47 | msgid "Search..." 48 | msgstr "" 49 | 50 | #: include/ACFFieldOpenstreetmap/Core/Core.php:157 51 | msgid "Nothing found..." 52 | msgstr "" 53 | 54 | #: include/ACFFieldOpenstreetmap/Core/Core.php:158 55 | msgid "My location" 56 | msgstr "" 57 | 58 | #: include/ACFFieldOpenstreetmap/Core/Core.php:160 59 | msgid "Add Marker at location" 60 | msgstr "" 61 | 62 | #: include/ACFFieldOpenstreetmap/Core/Core.php:162 63 | msgid "Fit markers into view" 64 | msgstr "" 65 | 66 | #. translators: address format for marker labels (street level). Available placeholders {building} {road} {house_number} {postcode} {city} {town} {village} {hamlet} {state} {country} 67 | #: include/ACFFieldOpenstreetmap/Core/Core.php:165 68 | msgid "{building} {road} {house_number}" 69 | msgstr "" 70 | 71 | #. translators: address format for marker labels (city level). Available placeholders {building} {road} {house_number} {postcode} {city} {town} {village} {hamlet} {state} {country} 72 | #: include/ACFFieldOpenstreetmap/Core/Core.php:167 73 | msgid "{postcode} {city} {town} {village} {hamlet}" 74 | msgstr "" 75 | 76 | #. translators: address format for marker labels (country level). Available placeholders {building} {road} {house_number} {postcode} {city} {town} {village} {hamlet} {state} {country} 77 | #: include/ACFFieldOpenstreetmap/Core/Core.php:169 78 | msgid "{state} {country}" 79 | msgstr "" 80 | 81 | #: include/ACFFieldOpenstreetmap/Core/MapProxy.php:129 82 | #: include/ACFFieldOpenstreetmap/Core/MapProxy.php:214 83 | #: include/ACFFieldOpenstreetmap/Core/MapProxy.php:269 84 | msgid "No Filesystem" 85 | msgstr "" 86 | 87 | #: include/ACFFieldOpenstreetmap/Core/MapProxy.php:135 88 | #: include/ACFFieldOpenstreetmap/Core/MapProxy.php:222 89 | #: include/ACFFieldOpenstreetmap/Core/MapProxy.php:277 90 | msgid "Filesystem not writable" 91 | msgstr "" 92 | 93 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:31 94 | #: include/ACFFieldOpenstreetmap/Settings/SettingsOpenStreetMap.php:75 95 | msgid "OpenStreetMap" 96 | msgstr "" 97 | 98 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:109 99 | msgid "Raw Data" 100 | msgstr "" 101 | 102 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:132 103 | msgid "Max. number of Markers" 104 | msgstr "" 105 | 106 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:133 107 | msgid "Leave empty for infinite markers" 108 | msgstr "" 109 | 110 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:156 111 | msgid "Map Appearance" 112 | msgstr "" 113 | 114 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:157 115 | msgid "Set zoom, center and select layers being displayed." 116 | msgstr "" 117 | 118 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:186 119 | msgid "Map Position" 120 | msgstr "" 121 | 122 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:187 123 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:198 124 | msgid "Center the initial map" 125 | msgstr "" 126 | 127 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:190 128 | msgid "lat" 129 | msgstr "" 130 | 131 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:197 132 | msgid "Center" 133 | msgstr "" 134 | 135 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:201 136 | msgid "lng" 137 | msgstr "" 138 | 139 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:209 140 | msgid "Zoom" 141 | msgstr "" 142 | 143 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:210 144 | msgid "Set the initial zoom level" 145 | msgstr "" 146 | 147 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:215 148 | msgid "zoom" 149 | msgstr "" 150 | 151 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:222 152 | msgid "Allow layer selection" 153 | msgstr "" 154 | 155 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:231 156 | msgid "Leaflet Layers" 157 | msgstr "" 158 | 159 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:245 160 | msgid "Customize the map height" 161 | msgstr "" 162 | 163 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:347 164 | msgid "Double click to add Marker." 165 | msgstr "" 166 | 167 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:350 168 | msgid "Tap and hold to add Marker." 169 | msgstr "" 170 | 171 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:353 172 | msgid "Drag Marker to move." 173 | msgstr "" 174 | 175 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:731 176 | #: templates/osm.php:25 177 | msgid "View Larger Map" 178 | msgstr "" 179 | 180 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:815 181 | msgid "Please set a marker on the map." 182 | msgstr "" 183 | 184 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:898 185 | msgid "Locate Marker" 186 | msgstr "" 187 | 188 | #: include/ACFFieldOpenstreetmap/Field/OpenStreetMap.php:906 189 | msgid "Remove Marker" 190 | msgstr "" 191 | 192 | #. translators: %s: Plugin name. 193 | #: include/ACFFieldOpenstreetmap/Settings/SettingsOpenStreetMap.php:62 194 | msgctxt "plugin" 195 | msgid "%s Settings" 196 | msgstr "" 197 | 198 | #: include/ACFFieldOpenstreetmap/Settings/SettingsOpenStreetMap.php:63 199 | msgid "Settings" 200 | msgstr "" 201 | 202 | #: include/ACFFieldOpenstreetmap/Settings/SettingsOpenStreetMap.php:75 203 | msgid "OpenStreetMap Settings" 204 | msgstr "" 205 | 206 | #: include/ACFFieldOpenstreetmap/Settings/SettingsOpenStreetMap.php:92 207 | msgid "ACF OpenStreetMap" 208 | msgstr "" 209 | 210 | #: include/ACFFieldOpenstreetmap/Settings/SettingsOpenStreetMap.php:108 211 | msgid "Providers" 212 | msgstr "" 213 | 214 | #: include/ACFFieldOpenstreetmap/Settings/SettingsOpenStreetMap.php:111 215 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:102 216 | msgid "Geocoder" 217 | msgstr "" 218 | 219 | #: include/ACFFieldOpenstreetmap/Settings/SettingsOpenStreetMap.php:128 220 | msgid "Map Tile Provider Settings" 221 | msgstr "" 222 | 223 | #: include/ACFFieldOpenstreetmap/Settings/SettingsOpenStreetMap.php:165 224 | msgid "Save Settings" 225 | msgstr "" 226 | 227 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:29 228 | msgid "Geocoder Options" 229 | msgstr "" 230 | 231 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:73 232 | msgid "Use search to geocode." 233 | msgstr "" 234 | 235 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:74 236 | msgid "Click on the map for reverse geocode." 237 | msgstr "" 238 | 239 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:76 240 | msgid "Geocoder response" 241 | msgstr "" 242 | 243 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:95 244 | msgid "Geocoder Settings" 245 | msgstr "" 246 | 247 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:114 248 | msgid "Reverse Geocoder Detail Level" 249 | msgstr "" 250 | 251 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:128 252 | msgid "(Required)" 253 | msgstr "" 254 | 255 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:184 256 | msgid "Derived from zoom" 257 | msgstr "" 258 | 259 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:185 260 | msgid "0 (Country)" 261 | msgstr "" 262 | 263 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:186 264 | msgid "1" 265 | msgstr "" 266 | 267 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:187 268 | msgid "2" 269 | msgstr "" 270 | 271 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:188 272 | msgid "3" 273 | msgstr "" 274 | 275 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:189 276 | msgid "4" 277 | msgstr "" 278 | 279 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:190 280 | msgid "5" 281 | msgstr "" 282 | 283 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:191 284 | msgid "6" 285 | msgstr "" 286 | 287 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:192 288 | msgid "7" 289 | msgstr "" 290 | 291 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:193 292 | msgid "8" 293 | msgstr "" 294 | 295 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:194 296 | msgid "9" 297 | msgstr "" 298 | 299 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:195 300 | msgid "10" 301 | msgstr "" 302 | 303 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:196 304 | msgid "11" 305 | msgstr "" 306 | 307 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:197 308 | msgid "12" 309 | msgstr "" 310 | 311 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:198 312 | msgid "13" 313 | msgstr "" 314 | 315 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:199 316 | msgid "14" 317 | msgstr "" 318 | 319 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:200 320 | msgid "15" 321 | msgstr "" 322 | 323 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:201 324 | msgid "16" 325 | msgstr "" 326 | 327 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:202 328 | msgid "17" 329 | msgstr "" 330 | 331 | #: include/ACFFieldOpenstreetmap/Settings/Traits/GeocoderSettings.php:203 332 | msgid "18 (Building)" 333 | msgstr "" 334 | 335 | #: include/ACFFieldOpenstreetmap/Settings/Traits/ProviderSettings.php:21 336 | msgid "Map Layer Settings" 337 | msgstr "" 338 | 339 | #: include/ACFFieldOpenstreetmap/Settings/Traits/ProviderSettings.php:103 340 | msgid "Disable Layer variants" 341 | msgstr "" 342 | 343 | #: include/ACFFieldOpenstreetmap/Settings/Traits/ProviderSettings.php:175 344 | msgid "configured." 345 | msgstr "" 346 | 347 | #: include/ACFFieldOpenstreetmap/Settings/Traits/ProviderSettings.php:176 348 | msgid "Reset" 349 | msgstr "" 350 | 351 | #: include/ACFFieldOpenstreetmap/Settings/Traits/ProviderSettings.php:190 352 | msgid "Cancel" 353 | msgstr "" 354 | 355 | #: include/ACFFieldOpenstreetmap/Settings/Traits/ProviderSettings.php:252 356 | msgid "The map tiles are loaded through an insecure http connection." 357 | msgstr "" 358 | 359 | #: include/ACFFieldOpenstreetmap/Settings/Traits/ProviderSettings.php:254 360 | msgid "Insecure" 361 | msgstr "" 362 | 363 | #: include/ACFFieldOpenstreetmap/Settings/Traits/ProviderSettings.php:260 364 | msgid "This is an overlay to be displayed over a base map." 365 | msgstr "" 366 | 367 | #: include/ACFFieldOpenstreetmap/Settings/Traits/ProviderSettings.php:262 368 | msgid "Overlay" 369 | msgstr "" 370 | 371 | #: include/ACFFieldOpenstreetmap/Settings/Traits/ProviderSettings.php:268 372 | msgid "Only available for a specific region." 373 | msgstr "" 374 | 375 | #: include/ACFFieldOpenstreetmap/Settings/Traits/ProviderSettings.php:270 376 | msgid "Bounds" 377 | msgstr "" 378 | 379 | #: include/ACFFieldOpenstreetmap/Settings/Traits/ProviderSettings.php:276 380 | msgid "Zoom is restricted." 381 | msgstr "" 382 | 383 | #. translators: 1: min zoom value, 2: max zoom value 384 | #: include/ACFFieldOpenstreetmap/Settings/Traits/ProviderSettings.php:280 385 | msgid "Zoom: %1$d–%2$d" 386 | msgstr "" 387 | 388 | #: include/ACFFieldOpenstreetmap/Settings/Traits/ProviderSettings.php:287 389 | #: include/ACFFieldOpenstreetmap/Settings/Traits/ProviderSettings.php:299 390 | msgid "Zoom levels are restricted." 391 | msgstr "" 392 | 393 | #. translators: min zoom value 394 | #: include/ACFFieldOpenstreetmap/Settings/Traits/ProviderSettings.php:291 395 | msgid "Min Zoom: %d" 396 | msgstr "" 397 | 398 | #. translators: max zoom value 399 | #: include/ACFFieldOpenstreetmap/Settings/Traits/ProviderSettings.php:303 400 | msgid "Max Zoom: %d" 401 | msgstr "" 402 | 403 | #: include/ACFFieldOpenstreetmap/Settings/Traits/ProviderSettings.php:388 404 | msgid "Test" 405 | msgstr "" 406 | 407 | #: include/ACFFieldOpenstreetmap/Settings/Traits/ProviderSettings.php:400 408 | msgid "Select which map tile providers should be selectable in the ACF Field." 409 | msgstr "" 410 | 411 | #: include/ACFFieldOpenstreetmap/Settings/Traits/ProviderSettings.php:401 412 | msgid "Configure Access Tokens for various Map Tile providers." 413 | msgstr "" 414 | 415 | #: src/php/json-strings.php:4 416 | msgctxt "geocoder" 417 | msgid "Nominatim" 418 | msgstr "" 419 | 420 | #: src/php/json-strings.php:5 421 | msgctxt "geocoder" 422 | msgid "Photon" 423 | msgstr "" 424 | 425 | #: src/php/json-strings.php:6 426 | msgctxt "geocoder" 427 | msgid "Photon API Key" 428 | msgstr "" 429 | 430 | #: src/php/json-strings.php:7 431 | msgctxt "geocoder" 432 | msgid "OpenCage" 433 | msgstr "" 434 | 435 | #: src/php/json-strings.php:8 436 | msgctxt "geocoder" 437 | msgid "OpenCage API Key" 438 | msgstr "" 439 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | === ACF OpenStreetMap Field === 2 | Contributors: podpirate 3 | Donate link: https://donate.openstreetmap.org/ 4 | Tags: map acf openstreetmap leaflet 5 | Requires at least: 4.8 6 | Requires PHP: 7.4 7 | Tested up to: 6.7 8 | Stable tag: 1.6.1 9 | License: GPLv3 or later 10 | License URI: http://www.gnu.org/licenses/gpl-3.0.html 11 | 12 | A configurable OpenStreetMap Field for ACF. 13 | 14 | == Description == 15 | 16 | Hazzle free OpenStreetMap with [ACF](https://www.advancedcustomfields.com/). 17 | 18 | ## Usage 19 | 20 | #### In the Fieldgroup editor: 21 | 22 | **Return Format:** 23 | 24 | - *Raw data* will return an array holding the field configuration. 25 | 26 | - *Leaflet JS* will return a fully functional leaflet map. Just include `` in your Theme. 27 | You can choose from a long list of map styles and it supports multiple markers. 28 | 29 | - *iFrame (OpenStreetMap.org)* Will return an iFrame HTML. Only four map styles are supported 30 | – the ones you find on [OpenStreetMap](https://www.openstreetmap.org/) – and not more than one marker. 31 | 32 | **Map Appearance:** Pan and zoom on the map and select from the Map layers to set the initial map position and style in the editor. 33 | 34 | **Map Position:** If you're more like a numbers person here you can enter numeric values for the map position. 35 | 36 | **Allow layer selection:** Allow the editors to select which map layers to show up in the frontend. 37 | 38 | **Height:** Map height in the frontend and editor. 39 | 40 | **Max. number of Markers** 41 | - *No value:* infinite markers 42 | - *0:* No markers 43 | - *Any other value:* Maximum number of markers. If the return format is *iFrame* there can ony be one marker. 44 | 45 | ## Map Proxy 46 | The plugin comes with a proxy mechanism for map tiles. If enabled the Browser will load the tiles from your server rather than directly from the tile provider. 47 | 48 | Use the proxy to hide sensitive credentials in the tile URL or for compliance with local privacy regulations like the European GDPR. 49 | 50 | Find more Details in the [GitHub wiki](https://github.com/mcguffin/acf-openstreetmap-field/wiki/The-Map-Proxy). 51 | 52 | ## Development 53 | 54 | Please head over to the source code [on Github](https://github.com/mcguffin/acf-openstreetmap-field). 55 | 56 | ## Credits 57 | - [ACF](https://www.advancedcustomfields.com/) for sure! 58 | - The [OpenStreetMap](https://www.openstreetmap.org/) project 59 | - [The Leaflet Project](https://leafletjs.com/) 60 | - The maintainers and [contributors](https://github.com/leaflet-extras/leaflet-providers/graphs/contributors) of [Leaflet providers](https://github.com/leaflet-extras/leaflet-providers) 61 | - The [very same](https://github.com/perliedman/leaflet-control-geocoder/graphs/contributors) for [Leaflet Control Geocode](https://github.com/perliedman/leaflet-control-geocoder) 62 | - [Dominik Moritz](https://www.domoritz.de/) who delighted us with [Leaflet locate control](https://github.com/domoritz/leaflet-locatecontrol) 63 | - Numerous individuals and organizations who provide wonderful Map related services free of charge. (You are credited in the map, I hope) 64 | - The proxy feature was inspired by an article by Klaus Meffert, Dr. DSGVO Blog, [Link (German)](https://dr-dsgvo.de/datenschutzfreundliches-karten-plugin-fur-webseiten-statt-google-maps-neue-moglichkeiten) 65 | 66 | == Installation == 67 | 68 | Follow the standard [WordPress plugin installation procedere](http://codex.wordpress.org/Managing_Plugins). 69 | 70 | 71 | == Frequently asked questions == 72 | 73 | = I found a bug. Where should I post it? = 74 | 75 | Please use the issues section in the [GitHub-Repository](https://github.com/mcguffin/acf-openstreetmap-field/issues). 76 | 77 | I will most likely not maintain the forum support forum on wordpress.org. Anyway, other users might have an answer for you, so it's worth a shot. 78 | 79 | = I'd like to suggest a feature. Where should I post it? = 80 | 81 | Please post an issue in the [GitHub-Repository](https://github.com/mcguffin/acf-openstreetmap-field/issues) 82 | 83 | = I am a map tile provider. Please don't include our service in your plugin. = 84 | 85 | The provisers list is taken from [Leaflet providers](https://github.com/leaflet-extras/leaflet-providers), so requests for an unlisting should go there first. 86 | 87 | If you want your service to remain in Leaflet Providers, you can Post an issue in the plugin's [GitHub-Repository](https://github.com/mcguffin/acf-openstreetmap-field/issues). 88 | Please provide me some way for me to verify, that you are acting on behalf of the Tile service provider your want to exclude. 89 | (E.g. the providers website has a link to your github account.) 90 | 91 | = Im getting these "Insecure Content" Warnings = 92 | 93 | Some providers do not support https. If these warnings bother you, choose a different one or use the proxy feature. 94 | 95 | = Why isn't the map loading? = 96 | 97 | There is very likely an issue with the map tiles provider you've choosen. Some of them might have gone offline or have suspended their service. Choose another one. 98 | 99 | = I need to do some fancy JS magic with my map. = 100 | 101 | Check out the [GitHub wiki](https://github.com/mcguffin/acf-openstreetmap-field/wiki). Some of the js events might come in handy for you. 102 | For Documentation of the map object, please refer to [LeafletJS](https://leafletjs.com). 103 | 104 | = Will you anwser support requests via email? = 105 | 106 | No. 107 | 108 | 109 | == Screenshots == 110 | 111 | 1. ACF Field Group Editor 112 | 2. Editing the Field Value 113 | 3. Display in the Frontend 114 | 4. Settings page. Configure API access keys and disable specific tile layers. 115 | 116 | == Upgrade Notice == 117 | 118 | **Attention:** Version 1.5.0 may involve some breaking changes. 119 | 120 | The global Leaflet object is no longer available. 121 | 122 | 123 | == Changelog == 124 | 125 | = 1.6.2 = 126 | - Support proxy on multisite 127 | - Introduce proxy WP-CLI commands 128 | - Fix: Content-Type HTTP-Header for some providers 129 | 130 | = 1.6.1 = 131 | - Fix PHP fatal during upgrade 132 | 133 | = 1.6.0 = 134 | - Introduce Map Proxy 135 | - Slightly improve settings page 136 | - Update map providers 137 | - Fix: _load_textdomain_just_in_time notice 138 | - Fix: Add marker pointer events 139 | - Fix: Maps in WP Admin not inited 140 | 141 | = 1.5.7. = 142 | - Fix: Backend Map broken 143 | - Fix: Geocoded result not stored in raw data 144 | 145 | = 1.5.6. = 146 | Fix: PHP notice version_compare 147 | 148 | = 1.5.5 = 149 | - JS: use IntersectionObserver to detect whether a map has become visible 150 | - Fix: ACF field not inited in Flexible Content and repeaters 151 | - Fix: JS recursion 152 | - Fix: fit bounds not working 153 | - Fix: marker drag not triggered 154 | - Fix: marker unique-IDs not always created 155 | - Fix: Block editor issues 156 | 157 | = 1.5.4 = 158 | - Fix: JS ReferenceError on move marker with max markers = 1 159 | 160 | = 1.5.3 = 161 | - Fix: Disable provider settings not displaying 162 | 163 | = 1.5.2 = 164 | - Fix: JS Error if some providers are disabled 165 | 166 | = 1.5.1 = 167 | - Backend UI: Attribution below map 168 | - ACF Field: Introduce conditional logic 169 | - Fix: Some map controls not visible in Blockeditor sidebar 170 | - Fix: Marker instructions display 171 | - Providers: [Migrate Stamen to Stadia Maps](https://maps.stamen.com/stadia-partnership/) 172 | - Providers: Update Esri Ocean base map, OpenAIP, Opensnowmap, OpenWeathermap, OpenFireMap, NLS, OpenRailwayMap, Jawg, MapTiler, MtbMap, nlmaps 173 | - Providers: Remove HERE (Legacy), Hydda (service down) 174 | - JS: Rewritten ACF integration 175 | 176 | = 1.5.0 = 177 | - Use Leaflet noConflict 178 | - Refactor JS 179 | - Geocoder: Address detail level is now controlled by map zoom 180 | - Geocoder: Provide filters for configuration overides 181 | - Fix: Make JS event `acf-osm-map-marker-created` bubbling 182 | - Fix: JS Crashes in ACF Blocks 183 | - Fix: Weird coordinates (worldCopyJump) 184 | 185 | = 1.4.3 = 186 | - Fix: JS – acf hook `acf-osm/create-marker` undefined argument + not firing on geocode 187 | 188 | = 1.4.2 = 189 | - Fix: JS Error on append repeater 190 | 191 | = 1.4.1 = 192 | - JS: remove console.log 193 | - Fix: admin js broken after jquery removal 194 | 195 | = 1.4.0 = 196 | - UI: Adapt to ACF 6 field group admin 197 | - JS API: do acf actions on marker events 198 | - JS Frontend: remove jQuery dependency 199 | - Data: add geocode results to raw data 200 | - Fix: search submit button did not submit 201 | - Fix: print template script only if input element is present 202 | - Fix: value sanitation. Shold now work with Frontend Admin for ACF 203 | 204 | = 1.3.5 = 205 | - Fix: Admin Marker styling broken 206 | - Fix: PHP Fatal with suki theme 207 | - Fix: include leaflet control geocode assets 208 | 209 | = 1.3.4 = 210 | - Fix: locate control API 211 | 212 | = 1.3.3 = 213 | - Upgrade leafletjs, leaflet-control-geocoder, leaflet-providers, leaflet, leaflet.locatecontrol to latest releases 214 | - Remove HikeBike map provider 215 | - Support ACF Rest API integration (since ACF 5.11) 216 | - Fix: PHP 8 compatibility 217 | - Fix: iframes in block preview not editable 218 | - Fix: quote missing on html attribute in osm template 219 | - Test with WP 6.0 220 | 221 | = 1.3.2 = 222 | - Fix: No such variant of OpenStreetMap (Mapnik) 223 | - Fix: Popups not opening in Safari 224 | - Quick and dirty Fix: invalid (localized) lat/lng object. 225 | 226 | = 1.3.1 = 227 | - Fix: JS Event acf-osm-map-marker-create not applying marker options 228 | 229 | = 1.3.0 = 230 | - Theme Overrides: Override map output in your theme 231 | - Breaking Change: Use native JS Events 232 | - Breaking Change: `osm_map_iframe_template` filter gone in WP 5.5 233 | - Fix: jQuery 3.x (WP 5.6) compatibility 234 | - Fix: Map not showing on login form 235 | - Fix: Providers not loaded if webroot owner is not www-user 236 | - Upgrade: Leaflet 1.7.1 237 | - Upgrade: Leaflet Providers 1.11.0 238 | - Upgrade: Leaflet Control Geocoder 2.1.0 239 | 240 | = 1.2.2 = 241 | - Fix: Duplicated Row (ACF 5.9+) 242 | 243 | = 1.2.1 = 244 | - Upgrade FreeMapSK, CyclOSM 245 | 246 | = 1.2.0 = 247 | - Feature: Settings page allowing you to disable specific map tile providersw 248 | - Feature: Fit markers in view (backend) 249 | - Upgrade: leaflet-providers, leaflet-control-geocoder, leaflet.locatecontrol 250 | 251 | = 1.1.9 = 252 | - UI: Add Settings link on plugins list table 253 | - Fix: hide map provider with unconfigured api key from layer selection 254 | - Upgrade: leaflet-control-geocoder, leaflet.locatecontrol, leaflet-providers 255 | - Security hardening 256 | 257 | = 1.1.8 = 258 | - Feature: make marker address formats localizable. 259 | - JS: pass map init object along with acf-os-map-create event 260 | - UI: hide add marker at my location button if markers cant be added 261 | 262 | = 1.1.7 = 263 | - Feature: Add locate me button to backend 264 | - Fix: Geocoder search result still visible after marker added to map. 265 | - Fix: Required field and max_markers = 0 never saved 266 | - Fix: HERE app code not included in api requests 267 | 268 | = 1.1.6 = 269 | - Feature: Observe DOM for newly added maps 270 | - Feature: allow manipulation of layer config in JS 271 | - Fix: JS event 'acf-osm-map-marker-create' not triggered 272 | 273 | = 1.1.5 = 274 | - JS: added event Listener for ajax-loaded maps. Use $(my_map_div).trigger('acf-osm-map-added'); on each newly added map. 275 | - Upgrade LeafletJS to 1.6.0 276 | 277 | = 1.1.4 = 278 | - Upgrade Leaflet Providers to 1.9.0 279 | - Upgrade Leaflet Control Geocode to 1.10.0 280 | - Fix: Redraw maps when they become visible 281 | 282 | = 1.1.3 = 283 | - UI: Better formatting for automatic marker labels 284 | - Fix: Map controls zindex in Block-Editor 285 | - Fix: Adding markers not working on mobile devices 286 | 287 | = 1.1.2 = 288 | - Fix: PHP Strict Standards message 289 | 290 | = 1.1.1 = 291 | - Fix: Required Field behaviour – "required" means now "must hava a marker" 292 | 293 | = 1.1.0 = 294 | - UI: Usability Improvements 295 | - Tested: Verfied Compatibility with Widgets, Block-Editor, Frontend Form 296 | - Stored data pretty much like google map field 297 | - Code: Refactored JS 298 | 299 | = 1.0.1 = 300 | Convert Values from ACF Googlemaps-Field 301 | 302 | = 1.0.0 = 303 | Initial Release 304 | -------------------------------------------------------------------------------- /templates/admin.php: -------------------------------------------------------------------------------- 1 | 'leaflet-map', 11 | 'data-height' => $field['height'], 12 | 'data-map' => 'leaflet', 13 | 'data-map-lng' => $osm_map['lng'], 14 | 'data-map-lat' => $osm_map['lat'], 15 | 'data-map-zoom' => $osm_map['zoom'], 16 | 'data-map-layers' => $osm_map['layers'], 17 | 'data-map-markers' => $osm_map['markers'], 18 | ]; 19 | 20 | ?> 21 |
>
22 | 'leaflet-map', 12 | 'data-height' => $field['height'], 13 | 'data-map' => 'leaflet', 14 | 'data-map-lng' => $osm_map['lng'], 15 | 'data-map-lat' => $osm_map['lat'], 16 | 'data-map-zoom' => $osm_map['zoom'], 17 | 'data-map-layers' => $osm_map['layers'], 18 | 'data-map-markers' => $osm_map['markers'], 19 | ]; 20 | 21 | 22 | ?> 23 |
>
24 | $field['height'], 14 | 'width' => '425', 15 | 'frameborder' => 0, 16 | 'scrolling' => 'no', 17 | 'marginheight' => 0, 18 | 'marginwidth' => 0, 19 | ]; 20 | 21 | ?> 22 |
23 | 24 | 25 | 26 | 27 | 28 | --------------------------------------------------------------------------------