Initial commit

This commit is contained in:
2020-04-07 13:03:04 +00:00
committed by Gitium
commit 00f842d9bf
1673 changed files with 471161 additions and 0 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
<svg viewBox="0 0 37 28" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414"><path d="M12.29 26.462c.328.375.75.562 1.266.562s.937-.187 1.266-.562L35.563 5.79c.329-.328.493-.75.493-1.265 0-.516-.164-.938-.493-1.266L32.962.728a1.567 1.567 0 0 0-1.23-.563c-.493 0-.926.188-1.301.563L13.556 17.603 5.681 9.728c-.375-.375-.808-.563-1.301-.563-.492 0-.902.188-1.23.563L.548 12.259c-.328.328-.492.75-.492 1.265 0 .516.164.938.492 1.266L12.29 26.462z" fill="#6ab255" fill-rule="nonzero"/></svg>

After

Width:  |  Height:  |  Size: 560 B

View File

@ -0,0 +1 @@
<svg viewBox="0 0 33 33" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414"><path d="M27.592 32.359a1.928 1.928 0 0 1-1.417.583 1.928 1.928 0 0 1-1.416-.583l-8.084-8.084-8.083 8.084a1.928 1.928 0 0 1-1.417.583 1.93 1.93 0 0 1-1.417-.583l-4.5-4.5a1.932 1.932 0 0 1-.583-1.417c0-.555.195-1.028.583-1.417l8.084-8.083-8.084-8.084a1.931 1.931 0 0 1-.583-1.416c0-.556.195-1.028.583-1.417l4.5-4.5A1.93 1.93 0 0 1 7.175.942c.556 0 1.028.194 1.417.583l8.083 8.083 8.084-8.083a1.928 1.928 0 0 1 1.416-.583c.556 0 1.028.194 1.417.583l4.5 4.5c.389.389.583.861.583 1.417 0 .555-.194 1.027-.583 1.416l-8.083 8.084 8.083 8.083c.389.389.583.862.583 1.417 0 .556-.194 1.028-.583 1.417l-4.5 4.5z" fill="#d83638" fill-rule="nonzero"/></svg>

After

Width:  |  Height:  |  Size: 795 B

View File

@ -0,0 +1 @@
<svg viewBox="0 0 53 53" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-miterlimit="10"><path d="M37.592 42.359a1.928 1.928 0 0 1-1.417.583 1.928 1.928 0 0 1-1.416-.583l-8.084-8.084-8.083 8.084a1.928 1.928 0 0 1-1.417.583 1.93 1.93 0 0 1-1.417-.583l-4.5-4.5a1.932 1.932 0 0 1-.583-1.417c0-.556.195-1.028.583-1.417l8.084-8.083-8.084-8.084a1.93 1.93 0 0 1-.583-1.416c0-.556.195-1.028.583-1.417l4.5-4.5a1.93 1.93 0 0 1 1.417-.584 1.93 1.93 0 0 1 1.417.584l8.083 8.083 8.084-8.083a1.928 1.928 0 0 1 1.416-.584 1.93 1.93 0 0 1 1.417.584l4.5 4.5c.389.389.583.861.583 1.417 0 .555-.194 1.028-.583 1.416l-8.083 8.084 8.083 8.083c.389.389.583.861.583 1.417s-.194 1.028-.583 1.417l-4.5 4.5z" fill="none" stroke="#d83638" stroke-width="2" stroke-dasharray="4,2"/></svg>

After

Width:  |  Height:  |  Size: 793 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 871 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#9ea3a8" width="64" height="64" viewBox="0 0 43 34"><path d="M.007 3.585v16.836q0 3.586 3.751 3.585L20 24v-5h10v-4.986l.991-1L34 13V3.585Q34 0 30.249 0H3.758Q.007 0 .007 3.585zm3.517 2.572a1.49 1.49 0 0 1-.508-.935 1.581 1.581 0 0 1 .274-1.208 1.449 1.449 0 0 1 1.094-.663 1.756 1.756 0 0 1 1.25.312l11.409 7.716 11.331-7.716a1.96 1.96 0 0 1 1.289-.312 1.546 1.546 0 0 1 1.094.663 1.4 1.4 0 0 1 .273 1.208 1.67 1.67 0 0 1-.547.935l-13.44 11.068z"/><path d="M22 28h10l-.009 4.624a1.126 1.126 0 0 0 1.922.8l8.25-8.236a1.126 1.126 0 0 0 0-1.594l-8.25-8.241a1.126 1.126 0 0 0-1.922.8v4.866L22 21v7z"/></svg>

After

Width:  |  Height:  |  Size: 649 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 180"><path d="M84.4 65.4c0 3.7.4 6.7 1.1 8.9.8 2.2 1.8 4.6 3.2 7.2.5.8.7 1.6.7 2.3 0 1-.6 2-1.9 3L81.2 91c-.9.6-1.8.9-2.6.9-1 0-2-.5-3-1.4-1.4-1.5-2.6-3.1-3.6-4.7-1-1.7-2-3.6-3.1-5.9-7.8 9.2-17.6 13.8-29.4 13.8-8.4 0-15.1-2.4-20-7.2-4.9-4.8-7.4-11.2-7.4-19.2 0-8.5 3-15.4 9.1-20.6s14.2-7.8 24.5-7.8c3.4 0 6.9.3 10.6.8s7.5 1.3 11.5 2.2v-7.3c0-7.6-1.6-12.9-4.7-16-3.2-3.1-8.6-4.6-16.3-4.6-3.5 0-7.1.4-10.8 1.3-3.7.9-7.3 2-10.8 3.4-1.6.7-2.8 1.1-3.5 1.3-.7.2-1.2.3-1.6.3-1.4 0-2.1-1-2.1-3.1v-4.9c0-1.6.2-2.8.7-3.5s1.4-1.4 2.8-2.1c3.5-1.8 7.7-3.3 12.6-4.5C39 .9 44.2.3 49.7.3 61.6.3 70.3 3 75.9 8.4c5.5 5.4 8.3 13.6 8.3 24.6v32.4h.2zM43.8 80.6c3.3 0 6.7-.6 10.3-1.8 3.6-1.2 6.8-3.4 9.5-6.4 1.6-1.9 2.8-4 3.4-6.4.6-2.4 1-5.3 1-8.7v-4.2c-2.9-.7-6-1.3-9.2-1.7-3.2-.4-6.3-.6-9.4-.6-6.7 0-11.6 1.3-14.9 4-3.3 2.7-4.9 6.5-4.9 11.5 0 4.7 1.2 8.2 3.7 10.6 2.4 2.5 5.9 3.7 10.5 3.7zm80.3 10.8c-1.8 0-3-.3-3.8-1-.8-.6-1.5-2-2.1-3.9L94.7 9.2c-.6-2-.9-3.3-.9-4 0-1.6.8-2.5 2.4-2.5h9.8c1.9 0 3.2.3 3.9 1 .8.6 1.4 2 2 3.9l16.8 66.2 15.6-66.2c.5-2 1.1-3.3 1.9-3.9.8-.6 2.2-1 4-1h8c1.9 0 3.2.3 4 1 .8.6 1.5 2 1.9 3.9l15.8 67 17.3-67c.6-2 1.3-3.3 2-3.9.8-.6 2.1-1 3.9-1h9.3c1.6 0 2.5.8 2.5 2.5 0 .5-.1 1-.2 1.6-.1.6-.3 1.4-.7 2.5l-24.1 77.3c-.6 2-1.3 3.3-2.1 3.9s-2.1 1-3.8 1h-8.6c-1.9 0-3.2-.3-4-1-.8-.7-1.5-2-1.9-4L154 22l-15.4 64.4c-.5 2-1.1 3.3-1.9 4-.8.7-2.2 1-4 1h-8.6zm128.5 2.7c-5.2 0-10.4-.6-15.4-1.8-5-1.2-8.9-2.5-11.5-4-1.6-.9-2.7-1.9-3.1-2.8-.4-.9-.6-1.9-.6-2.8v-5.1c0-2.1.8-3.1 2.3-3.1.6 0 1.2.1 1.8.3.6.2 1.5.6 2.5 1 3.4 1.5 7.1 2.7 11 3.5 4 .8 7.9 1.2 11.9 1.2 6.3 0 11.2-1.1 14.6-3.3 3.4-2.2 5.2-5.4 5.2-9.5 0-2.8-.9-5.1-2.7-7-1.8-1.9-5.2-3.6-10.1-5.2L244 51c-7.3-2.3-12.7-5.7-16-10.2-3.3-4.4-5-9.3-5-14.5 0-4.2.9-7.9 2.7-11.1 1.8-3.2 4.2-6 7.2-8.2 3-2.3 6.4-4 10.4-5.2S251.5.1 255.9.1c2.2 0 4.5.1 6.7.4 2.3.3 4.4.7 6.5 1.1 2 .5 3.9 1 5.7 1.6 1.8.6 3.2 1.2 4.2 1.8 1.4.8 2.4 1.6 3 2.5.6.8.9 1.9.9 3.3v4.7c0 2.1-.8 3.2-2.3 3.2-.8 0-2.1-.4-3.8-1.2-5.7-2.6-12.1-3.9-19.2-3.9-5.7 0-10.2.9-13.3 2.8-3.1 1.9-4.7 4.8-4.7 8.9 0 2.8 1 5.2 3 7.1 2 1.9 5.7 3.8 11 5.5l14.2 4.5c7.2 2.3 12.4 5.5 15.5 9.6s4.6 8.8 4.6 14c0 4.3-.9 8.2-2.6 11.6-1.8 3.4-4.2 6.4-7.3 8.8-3.1 2.5-6.8 4.3-11.1 5.6-4.5 1.4-9.2 2.1-14.3 2.1z" fill="#262f3e"/><path d="M271.5 142.7c-32.9 24.3-80.7 37.2-121.8 37.2-57.6 0-109.5-21.3-148.7-56.7-3.1-2.8-.3-6.6 3.4-4.4 42.4 24.6 94.7 39.5 148.8 39.5 36.5 0 76.6-7.6 113.5-23.2 5.5-2.5 10.2 3.6 4.8 7.6zm13.7-15.6c-4.2-5.4-27.8-2.6-38.5-1.3-3.2.4-3.7-2.4-.8-4.5 18.8-13.2 49.7-9.4 53.3-5 3.6 4.5-1 35.4-18.6 50.2-2.7 2.3-5.3 1.1-4.1-1.9 4-9.9 12.9-32.2 8.7-37.5z" fill="#f59931"/></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1 @@
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 254.79 80.25" xml:space="preserve"><style>.st0{fill:#4285f4}.st1{fill:#ea4335}</style><g id="XMLID_11_"><path id="XMLID_10_" class="st0" d="M31.87 28.59v8.59H52.4C51.77 42 50.17 45.52 47.72 48c-3 3-7.68 6.28-15.85 6.28-12.64 0-22.52-10.19-22.52-22.83S19.23 8.62 31.87 8.62c6.81 0 11.8 2.69 15.46 6.14l6.04-6.04C48.28 3.77 41.43 0 31.87 0 14.56 0 0 14.1 0 31.42s14.56 31.42 31.87 31.42c9.36 0 16.41-3.07 21.92-8.8 5.65-5.65 7.44-13.65 7.44-20.07 0-1.99-.14-3.84-.45-5.38H31.87z"/><path id="XMLID_24_" class="st1" d="M86.88 21.61c-11.21 0-20.35 8.52-20.35 20.28 0 11.66 9.15 20.28 20.35 20.28s20.35-8.59 20.35-20.28c0-11.77-9.14-20.28-20.35-20.28zm0 32.57c-6.14 0-11.45-5.06-11.45-12.29 0-7.3 5.31-12.29 11.45-12.29s11.45 4.99 11.45 12.29c0 7.22-5.3 12.29-11.45 12.29z"/><path id="XMLID_21_" class="st0" d="M186.65 26.15h-.31c-1.99-2.37-5.83-4.54-10.68-4.54-10.12 0-18.95 8.83-18.95 20.28 0 11.38 8.83 20.28 18.95 20.28 4.85 0 8.69-2.16 10.68-4.61h.31v2.83c0 7.75-4.15 11.9-10.82 11.9-5.45 0-8.83-3.91-10.23-7.23l-7.75 3.21c2.23 5.38 8.13 11.97 17.98 11.97 10.44 0 19.27-6.14 19.27-21.12V22.65h-8.45v3.5zm-10.23 28.03c-6.14 0-10.82-5.24-10.82-12.29 0-7.16 4.68-12.29 10.82-12.29 6.07 0 10.82 5.24 10.82 12.36.04 7.08-4.75 12.22-10.82 12.22z"/><path id="XMLID_18_" d="M132.26 21.61c-11.21 0-20.35 8.52-20.35 20.28 0 11.66 9.15 20.28 20.35 20.28s20.35-8.59 20.35-20.28c0-11.77-9.14-20.28-20.35-20.28zm0 32.57c-6.14 0-11.45-5.06-11.45-12.29 0-7.3 5.31-12.29 11.45-12.29s11.45 4.99 11.45 12.29c0 7.22-5.3 12.29-11.45 12.29z" fill="#fbbc05"/><path id="XMLID_3_" d="M202.08.84h8.76v61.33h-8.76V.84z" fill="#34a853"/><path id="XMLID_14_" class="st1" d="M237.89 54.18c-4.54 0-7.75-2.06-9.84-6.14l27.12-11.21-.91-2.3c-1.68-4.54-6.84-12.92-17.35-12.92-10.44 0-19.13 8.2-19.13 20.28 0 11.38 8.59 20.28 20.11 20.28 9.29 0 14.66-5.69 16.9-8.97l-6.91-4.61c-2.31 3.35-5.45 5.59-9.99 5.59zm-.63-24.96c3.6 0 6.67 1.85 7.68 4.47l-18.33 7.57c.01-8.52 6.05-12.04 10.65-12.04z"/></g></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 604 129"><path d="M213.2 74.3l-3.6 10.2h-.3c-.6-2.3-1.7-5.8-3.5-10L186.5 26h-18.9v77.3h12.5V55.6c0-3 0-6.4-.1-10.6-.1-2.1-.3-3.7-.4-4.9h.3c.6 3 1.3 5.2 1.8 6.6l23.2 56.4h8.8l23-56.9c.5-1.3 1-3.9 1.5-6.1h.3c-.3 5.7-.5 10.8-.6 13.9v49h13.3V25.8H233l-19.8 48.5zm50.6-26.7h13V103h-13zm6.6-23.4c-2.2 0-4 .8-5.5 2.2-1.5 1.4-2.3 3.2-2.3 5.4 0 2.1.8 3.9 2.3 5.3 1.5 1.4 3.3 2.1 5.5 2.1s4.1-.8 5.5-2.1c1.5-1.4 2.3-3.2 2.3-5.3s-.8-3.9-2.3-5.4c-1.3-1.4-3.2-2.2-5.5-2.2m52.5 22.9c-2.4-.5-4.9-.8-7.3-.8-5.9 0-11.3 1.3-15.8 3.9-4.5 2.6-8.1 6.2-10.4 10.7-2.4 4.6-3.6 9.9-3.6 16 0 5.3 1.2 10 3.5 14.3 2.3 4.2 5.5 7.6 9.8 9.9 4.1 2.3 8.9 3.5 14.3 3.5 6.2 0 11.5-1.3 15.7-3.7l.1-.1v-12l-.5.4c-1.9 1.4-4.1 2.6-6.3 3.3-2.3.8-4.4 1.2-6.2 1.2-5.2 0-9.3-1.5-12.2-4.8-3-3.2-4.5-7.6-4.5-13.1 0-5.7 1.5-10.2 4.6-13.5 3.1-3.3 7.2-5 12.2-5 4.2 0 8.5 1.4 12.4 4.2l.5.4V49.2l-.1-.1c-1.7-.7-3.6-1.5-6.2-2m42.9-.4c-3.2 0-6.2 1-8.8 3.1-2.2 1.8-3.7 4.4-5 7.5h-.1v-9.7h-13V103h13V74.7c0-4.8 1-8.8 3.2-11.7 2.2-3 5-4.5 8.4-4.5 1.2 0 2.4.3 3.9.5 1.4.4 2.4.8 3.1 1.3l.5.4v-13l-.3-.1c-.9-.6-2.7-.9-4.9-.9m35.4-.3c-9.1 0-16.4 2.7-21.5 8-5.2 5.3-7.7 12.6-7.7 21.8 0 8.6 2.6 15.6 7.6 20.7 5 5 11.8 7.6 20.3 7.6 8.9 0 16-2.7 21.1-8.1 5.2-5.4 7.7-12.6 7.7-21.5 0-8.8-2.4-15.8-7.3-20.9-4.7-5.1-11.6-7.6-20.2-7.6M411.6 89c-2.4 3.1-6.2 4.6-10.9 4.6s-8.5-1.5-11.2-4.8c-2.7-3.1-4-7.6-4-13.3 0-5.9 1.4-10.4 4-13.6 2.7-3.2 6.4-4.8 11.1-4.8 4.6 0 8.2 1.5 10.8 4.6 2.6 3.1 4 7.6 4 13.5-.2 6-1.3 10.7-3.8 13.8m46.1-18.4c-4.1-1.7-6.7-3-7.9-4.1-1-1-1.5-2.4-1.5-4.2 0-1.5.6-3 2.1-4s3.2-1.5 5.7-1.5c2.2 0 4.5.4 6.7 1s4.2 1.5 5.8 2.7l.5.4V48.7l-.3-.1c-1.5-.6-3.5-1.2-5.9-1.7-2.4-.4-4.6-.6-6.4-.6-6.2 0-11.3 1.5-15.3 4.8-4 3.1-5.9 7.3-5.9 12.2 0 2.6.4 4.9 1.3 6.8.9 1.9 2.2 3.7 4 5.2 1.8 1.4 4.4 3 8 4.5 3 1.3 5.3 2.3 6.7 3.1 1.4.8 2.3 1.7 3 2.4.5.8.8 1.8.8 3.1 0 3.7-2.8 5.5-8.5 5.5-2.2 0-4.5-.4-7.2-1.3s-5.2-2.2-7.3-3.7l-.5-.4v12.7l.3.1c1.9.9 4.2 1.5 7 2.2 2.8.5 5.3.9 7.5.9 6.7 0 12.2-1.5 16.1-4.8 4-3.2 6.1-7.3 6.1-12.6 0-3.7-1-7-3.2-9.5-2.9-2.4-6.5-4.9-11.7-6.9m49.2-24.2c-9.1 0-16.4 2.7-21.5 8s-7.7 12.6-7.7 21.8c0 8.6 2.6 15.6 7.6 20.7 5 5 11.8 7.6 20.3 7.6 8.9 0 16-2.7 21.1-8.1 5.2-5.4 7.7-12.6 7.7-21.5 0-8.8-2.4-15.8-7.3-20.9-4.7-5.1-11.6-7.6-20.2-7.6M517.2 89c-2.4 3.1-6.2 4.6-10.9 4.6-4.8 0-8.5-1.5-11.2-4.8-2.7-3.1-4-7.6-4-13.3 0-5.9 1.4-10.4 4-13.6 2.7-3.2 6.4-4.8 11.1-4.8 4.5 0 8.2 1.5 10.8 4.6 2.6 3.1 4 7.6 4 13.5 0 6-1.3 10.7-3.8 13.8m86.7-30.7V47.6h-13.1V31.2l-.4.1L578 35l-.3.1v12.5h-19.6v-7c0-3.2.8-5.7 2.2-7.3s3.5-2.4 6.1-2.4c1.8 0 3.7.4 5.8 1.3l.5.3V21.2l-.3-.1c-1.8-.6-4.2-1-7.3-1-3.9 0-7.3.9-10.4 2.4-3.1 1.7-5.4 4-7.1 7.1-1.7 3-2.6 6.4-2.6 10.3v7.7h-9.1v10.6h9.1V103h13.1V58.3h19.6v28.5c0 11.7 5.5 17.6 16.5 17.6 1.8 0 3.7-.3 5.5-.6 1.9-.4 3.3-.9 4.1-1.3l.1-.1V91.7l-.5.4c-.8.5-1.5.9-2.7 1.2-1 .3-1.9.4-2.6.4-2.6 0-4.4-.6-5.7-2.1-1.2-1.4-1.8-3.7-1.8-7.1V58.3h13.3z" fill="#737373"/><path fill="#F25022" d="M0 0h61.3v61.3H0z"/><path fill="#7FBA00" d="M67.7 0H129v61.3H67.7z"/><path fill="#00A4EF" d="M0 67.7h61.3V129H0z"/><path fill="#FFB900" d="M67.7 67.7H129V129H67.7z"/></svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="152" height="80"><path d="M77.5 0C118.645 0 152 17.909 152 40s-33.355 40-74.5 40S0 62.091 0 40 36.355 0 77.5 0z" fill-rule="evenodd" fill="#777bb3"/><path d="M32.331 21.353h15.952q7.023.059 10.178 4.044t2.083 10.884a20.864 20.864 0 0 1-1.844 6.186 18.385 18.385 0 0 1-3.809 5.472 13.3 13.3 0 0 1-6.369 3.925 29.343 29.343 0 0 1-7.022.836h-7.145L32.093 64H23.82l8.511-42.643m6.964 6.78l-3.571 17.839a4.38 4.38 0 0 0 .714.059h.833a31.319 31.319 0 0 0 9.523-1.13q3.809-1.249 5.119-8.683 1.071-6.245-2.143-7.2a26.728 26.728 0 0 0-7.916-.892q-.714.059-1.369.059h-1.25l.06-.059M69.968 9.994h8.214l-2.321 11.36h7.38q6.071.12 9.047 2.5 3.036 2.378 1.786 9.04L90.086 52.7h-8.333l3.809-18.913q.595-2.974-.357-4.223T81.1 28.312l-6.607-.059L69.611 52.7H61.4L69.971 10M102.9 21.353h15.951q7.023.059 10.178 4.044t2.083 10.884a20.861 20.861 0 0 1-1.845 6.185 18.389 18.389 0 0 1-3.809 5.472 13.3 13.3 0 0 1-6.369 3.925 29.341 29.341 0 0 1-7.023.833h-7.143L102.656 64h-8.273l8.517-42.647m6.963 6.78l-3.571 17.842a4.376 4.376 0 0 0 .714.059h.834a31.317 31.317 0 0 0 9.523-1.13q3.809-1.249 5.119-8.683 1.071-6.245-2.143-7.2a26.724 26.724 0 0 0-7.916-.892q-.714.059-1.369.059H109.8l.059-.059" fill="#fff" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1 @@
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 733.7 160" xml:space="preserve"><style>.st0{fill:#243846}.st2{fill:#3f7cbc}</style><path class="st0" d="M151.1 140.8l18.5-14.5c5.2 9 13.5 14.2 23 14.2 10.3 0 15.8-6.7 15.8-14 0-8.7-10.6-11.5-21.9-15-14.2-4.4-30.1-9.9-30.1-30.2 0-17 14.8-30.5 35.3-30.5 17.3 0 27.2 6.5 35.8 15.4l-16.7 12.6c-4.4-6.5-10.6-10-18.9-10-9.4 0-14.5 5.1-14.5 11.8 0 8.1 10.2 10.9 21.5 14.7 14.4 4.7 30.7 11 30.7 31.4 0 16.9-13.4 33.1-36.8 33.1-19.3.1-32.1-8.1-41.7-19zm162.6-55.1h19.8v8.1c4.7-6 11.8-9.6 20.1-9.6 17.1 0 27.5 11 27.5 29.8v44.3h-20.3v-41.7c0-9.7-4.5-15.4-13.4-15.4-7.6 0-13.8 5.2-13.8 17.4v39.7h-19.9V85.7zm72 36.4c0-25.7 18.9-37.8 35.3-37.8 9.4 0 16.9 3.5 21.7 8.6V52.3h19.9v106.1h-19.9v-8.1c-4.8 5.7-12.5 9.6-21.9 9.6-15.5 0-35.1-12.3-35.1-37.8zm57.5-.2c0-10.8-7.8-19.5-18.6-19.5-11 0-19.5 8.3-19.5 19.5s8.4 19.6 19.5 19.6c10.8 0 18.6-8.8 18.6-19.6zm24-16.5c0-30.2 22.8-54.5 54.2-54.5 15.7 0 28.9 5.7 38.5 14.7 3.9 3.7 7.2 7.9 9.8 12.5L552 88.9c-6.5-12.1-16.6-18.3-30.4-18.3-19.3 0-34.3 15.8-34.3 34.9 0 19.5 14.7 34.9 35 34.9 15.4 0 26.3-8.7 30.1-22.2h-33.3V98.9h55.1v8.1c0 28.5-20.3 53-51.9 53-33.2-.1-55.1-25.3-55.1-54.6zm112-19.7H599v11.9c3.6-7.6 10.2-11.9 20.1-11.9h8l-7.2 19.3h-5.4c-10.6 0-15.3 5.5-15.3 19v34.3h-19.9V85.7h-.1zm53 0h19.9v72.7h-19.9v-53.3H625l7.2-19.4zm10-11c6.6 0 11.9-5.3 11.9-11.9s-5.3-11.9-11.9-11.9c-6.6 0-11.9 5.3-11.9 11.9 0 6.5 5.3 11.9 11.9 11.9zm14.6 47.4c0-25.7 18.9-37.8 35.3-37.8 9.4 0 16.9 3.5 21.7 8.6V52.3h19.9v106.1h-19.9v-8.1c-4.8 5.7-12.5 9.6-21.9 9.6-15.5 0-35.1-12.3-35.1-37.8zm57.6-.2c0-10.8-7.8-19.5-18.6-19.5-11 0-19.5 8.3-19.5 19.5s8.4 19.6 19.5 19.6c10.7 0 18.6-8.8 18.6-19.6zm-405.4 0c0-20.9-15.3-37.6-37.5-37.6-20.9 0-37.8 16.9-37.8 37.8s15.7 37.8 38.4 37.8c15.7 0 27-7.6 33.3-18.4l-15.8-9.4c-3.3 6.4-9.8 10.4-17.4 10.4-10.5 0-17-5.2-19.3-13.2H309v-7.4zm-55.2-8.7c3.1-6.8 9.4-11.5 17.9-11.5 8.4 0 14.7 3.9 17.3 11.5h-35.2z"/><path d="M42.4 116h42.4v42.4H42.4zm0-42.5H0V116h42.4z" fill="#9edbee"/><path class="st2" d="M0 116h42.4v42.4H0z"/><path d="M127.3 73.5H84.9V116h42.4zM42.4 31.1h42.4v42.4H42.4z" fill="#07b2e2"/><path fill="#0f9cd5" d="M42.4 73.5V116h42.5V73.5z"/><path class="st2" d="M84.9 31.1h42.4v42.4H84.9z"/><path class="st0" d="M171.2 5.5v24.7h-5.7V5.5h-8.8v-5h23.4v4.9h-8.9v.1zm50.5 24.7h-5.4l-6.6-21.6-6.6 21.6h-5.4L189.4.4l6 .1 5.5 21 6.2-21h5.7l6.2 21 5.4-21h5.7l-8.4 29.7zm19.8 0V.5h5.7v29.7h-5.7zm19 0V.5h5.7v24.7h9.9l.1 5h-15.7zm27.5 0V.5h5.7v29.7H288zm31.8.6c-8.4 0-13.9-6.2-13.9-15.4S311.4 0 319.9 0s13.9 6.2 13.9 15.4c-.1 9.1-5.5 15.4-14 15.4zm0-26.1c-5.1 0-8.1 4.2-8.1 10.7s3.1 10.7 8.1 10.7c5.1 0 8.2-4.2 8.2-10.7s-3.1-10.7-8.2-10.7z"/></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 713 103"><path d="M150.3 32.9c-7.2 0-11.9 2.4-11.9 6.6s4.9 6.1 12.1 6.9c10.3.9 23.7 2.6 23.7 16.6 0 9.9-9.4 17-23.8 17-9.1 0-17.8-2-25.5-9.9l6.1-7.9c5.1 5.1 12 8 19.2 7.9 6.2 0 12.3-1.9 12.3-6.9s-4.8-6.7-13-7.4c-10.4-.9-22.8-4-22.8-15.9s12.8-16.4 23.2-16.4c7.8-.2 15.3 2.3 21.5 7.1l-6.1 7.1c-4.2-3.3-9.5-5-15-4.8zm62.5 36.6c5.9 0 12.7-2 16.2-5.8l7.6 7.1c-5.8 6.2-15.4 9.2-24 9.2-18.3 0-30.1-11-30.1-28.2 0-16.4 12.2-28.2 29.9-28.2 16.4 0 27.7 9.3 27.7 27.8 0 1.5-.1 3.2-.2 4.8h-45.2c.9 8.3 7.8 13.3 18.1 13.3zm-.4-36c-8.5 0-15.8 4.5-17.6 13.2h33.9c-.8-8.6-6.6-13.2-16.3-13.2zm81.7 15c0-9.3-5.4-14.6-15.1-14.6-4.2 0-8.3 1.7-11.3 4.8-3 3.1-4.5 7.3-4.4 11.6v28.5h-11.7v-54h10.7l.7 7.5c4.7-5.6 11.5-8.9 18.8-8.8 13.5 0 24 8.1 24 24.9v30.3H294l.1-30.2zM377 78.7h-11l-.7-8.5c-4.4 6.4-11.7 10.1-19.3 9.8-16.2 0-28.5-10.4-28.5-28.2 0-18.3 12.1-28.2 28.3-28.2 6.8 0 16 3.2 19.6 9.6V2.5h11.7l-.1 76.2zm-47.9-27c0 10.9 7.7 17.8 17.6 17.8 9.6 0 17.5-7.9 17.5-17.7s-7.8-17.7-17.5-17.7c-9.9 0-17.6 6.7-17.6 17.6zM398.7 1c1.9-.2 3.7.5 5.1 1.8S406 6 406 7.9c-.3 3.9-3.4 6.8-7.2 6.8s-7-3-7.2-6.8c0-1.9.7-3.8 2.1-5.1s3.2-1.9 5-1.8zm5.8 77.7h-11.7V24.8h11.7v53.9zm58.2-30.2c0-9.3-5.4-14.6-15.1-14.6-4.2 0-8.3 1.7-11.3 4.8-3 3.1-4.5 7.3-4.4 11.6v28.5h-11.7v-54h10.6l.7 7.5c4.7-5.6 11.6-8.9 18.8-8.8 13.5 0 24 8.1 24 24.9v30.3h-11.7l.1-30.2zm38.4-14.9c3.6-6.4 12.8-10.1 19.6-10.1 16.1 0 28.3 9.9 28.3 28.2 0 17.9-13.1 28.2-28.4 28.2-7 0-15.1-2.9-19.5-9.8l-.7 8.5h-11V2.5h11.7v31.1zm.7 18.1c-.1 4.8 1.8 9.4 5.2 12.8 3.4 3.4 8 5.2 12.7 5 10.2 0 17.6-6.9 17.6-17.8S529.8 34 519.7 34c-4.7-.2-9.3 1.6-12.7 5-3.4 3.4-5.3 8-5.2 12.7zm71.7 27h-11.7V2.5h11.7v76.2zm27.1-24.6c0 9.2 5.3 15.5 15.2 15.5 4.2 0 8.3-1.7 11.2-4.7 2.9-3.1 4.5-7.2 4.3-11.5V24.8H643v53.9h-10.5l-.7-7.4c-4.8 5.8-11.9 9-19.2 8.7-13.7 0-23.5-9.5-23.5-25.7V24.8h11.7l-.2 29.3zm85.1 15.4c5.9 0 12.7-2 16.2-5.8l7.6 7.1c-5.8 6.2-15.4 9.2-24 9.2-18.3 0-30.1-11-30.1-28.2 0-16.4 12.2-28.2 29.9-28.2 16.4 0 27.7 9.3 27.7 27.8 0 1.5-.1 3.2-.2 4.8h-45.3c1 8.3 7.9 13.3 18.2 13.3zm-.4-36c-8.5 0-15.9 4.5-17.6 13.2h33.8c-.7-8.6-6.6-13.2-16.2-13.2z" fill="#091e3f"/><path d="M90.8 26.3c-3.6-6.4-9.6-11-16.7-12.9-1.5-.4-3-.6-4.5-.8C64.6 5.3 56.2.9 47.2.9S29.9 5.3 24.9 12.7C16 13.5 8 18.6 3.6 26.3c-4.4 7.8-4.8 17.2-1.1 25.4C-1.2 59.8-.8 69.2 3.6 77c3.6 6.4 9.6 11 16.7 12.9 1.5.4 3 .7 4.6.8 5 7.4 13.4 11.8 22.4 11.8S64.6 98 69.7 90.6c8.9-.8 16.8-5.9 21.2-13.6 4.5-7.8 4.9-17.2 1.1-25.4 3.7-8.1 3.2-17.5-1.2-25.3zm-6.8 4c2.2 3.8 3 8.1 2.3 12.4-1.5-1.3-3.1-2.5-4.8-3.5-6.3-3.7-13.9-4.7-21-2.8-4.3 1.1-8.3 3.3-11.6 6.3-1.2-7.7 2.4-15.3 9.2-19.3 4.3-2.5 9.4-3.2 14.2-2 5.1 1.3 9.3 4.5 11.7 8.9zM47.2 9.9c4.2 0 8.3 1.5 11.5 4.2-1.9.6-3.7 1.4-5.4 2.4-10.1 6-15.3 17.8-12.7 29.3-7.1-2.9-11.7-9.7-11.7-17.3C28.8 18.3 37 10 47.2 9.9zM10.6 30.8c2.1-3.6 5.5-6.4 9.5-8-.4 1.9-.7 3.9-.7 5.8 0 11.7 7.8 22.2 19.4 25.8-2.1 1.7-4.5 2.9-7.1 3.6-4.8 1.2-9.9.6-14.2-1.9-9.1-5.1-12.2-16.4-7-25.3h.1zM10.5 73c-2.2-3.8-3-8.1-2.3-12.4 1.5 1.3 3.1 2.5 4.8 3.5 4.2 2.4 9 3.7 13.9 3.7 2.4 0 4.8-.3 7.1-.9 4.3-1.1 8.3-3.3 11.6-6.3 1.2 7.7-2.4 15.3-9.2 19.3-4.3 2.5-9.4 3.2-14.2 2-5-1.3-9.2-4.5-11.7-8.9zm36.9 20.4c-4.2 0-8.3-1.5-11.5-4.2 1.9-.6 3.7-1.4 5.4-2.4 10.1-6 15.3-17.8 12.8-29.2 8.2 3.3 13 11.9 11.4 20.6-1.7 8.7-9.3 15.1-18.1 15.2zm34.7-20.8c-2.1 3.6-5.3 6.4-9.2 8 .4-1.9.7-3.9.7-5.9 0-11.8-7.6-22.2-18.8-25.8 2-1.7 4.4-2.9 6.9-3.6 4.7-1.2 9.6-.5 13.8 2 8.7 5.2 11.7 16.4 6.6 25.3z" fill="#0092ff"/></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="181" height="60"><defs><style>.cls-1{fill:#ccc;fill-rule:evenodd}</style></defs><path id="Rounded_Rectangle_1" data-name="Rounded Rectangle 1" class="cls-1" d="M47.124 46.084h34.292a4.277 4.277 0 1 1 0 8.555H47.124a4.277 4.277 0 1 1 0-8.555z"/><path id="Rounded_Rectangle_1-2" data-name="Rounded Rectangle 1" class="cls-1" d="M25.707 26.777h55.7a4.284 4.284 0 0 1 4.284 4.284v.016a4.284 4.284 0 0 1-4.284 4.284h-55.7a4.284 4.284 0 0 1-4.284-4.284v-.016a4.284 4.284 0 0 1 4.284-4.284z"/><path id="Rounded_Rectangle_1-3" data-name="Rounded Rectangle 1" class="cls-1" d="M4.284 6.416H81.41a4.284 4.284 0 0 1 4.284 4.284v.016A4.284 4.284 0 0 1 81.41 15H4.284A4.284 4.284 0 0 1 0 10.716V10.7a4.284 4.284 0 0 1 4.284-4.284z"/><path id="_" data-name="" d="M178.878 57.783a6.911 6.911 0 0 1-5.186 2.2h-68.954a6.9 6.9 0 0 1-5.186-2.2 7.317 7.317 0 0 1-2.113-5.261V8.516a7.327 7.327 0 0 1 2.113-5.261 6.914 6.914 0 0 1 5.186-2.2h68.954a6.922 6.922 0 0 1 5.186 2.2 7.338 7.338 0 0 1 2.113 5.261v44.005a7.328 7.328 0 0 1-2.113 5.262zm-8.835-49.458l-30.732 24.681L108.58 8.325q-2.693-2.3-4.8-.383a2.672 2.672 0 0 0-.768 2.2 3.334 3.334 0 0 0 .96 1.818l19.976 18.367-19.208 19.9a1.743 1.743 0 0 0-.192 2.487 1.392 1.392 0 0 0 1.249.574 2.532 2.532 0 0 0 1.44-.383l21.512-18.176 10.562 9.371 10.372-9.375L171.2 52.9a2.536 2.536 0 0 0 1.441.383 1.958 1.958 0 0 0 1.44-.574q.96-1.148-.384-2.487l-19.207-19.9 19.971-18.362a4.023 4.023 0 0 0 1.056-1.818 2.274 2.274 0 0 0-.864-2.2q-1.923-1.91-4.61.383z" fill="#819eaf" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1 @@
<svg id="recommended_-_orange_overlay" data-name="recommended - orange overlay" xmlns="http://www.w3.org/2000/svg" width="159" height="22"><defs><style>.cls-2{fill:#fff;fill-rule:evenodd}</style></defs><path id="reocmmended_bg" data-name="reocmmended bg" d="M0 0h155a4 4 0 0 1 4 4v18H4a4 4 0 0 1-4-4V0z" fill="#fb963c"/><path id="recommended" class="cls-2" d="M1524.28 1519.89a3.713 3.713 0 0 1 2.55.8 2.721 2.721 0 0 1 .92 2.19 3.405 3.405 0 0 1-.47 1.82 2.434 2.434 0 0 1-1.51 1.08v.03a1.994 1.994 0 0 1 .81.32 1.891 1.891 0 0 1 .49.53 2.042 2.042 0 0 1 .27.7 6.668 6.668 0 0 1 .14.8c.02.28.04.56.05.85a7.893 7.893 0 0 0 .08.85 5.045 5.045 0 0 0 .18.79 1.922 1.922 0 0 0 .36.66h-1.69a.973.973 0 0 1-.22-.48 4.45 4.45 0 0 1-.07-.68q-.015-.375-.03-.81a5.839 5.839 0 0 0-.1-.84c-.04-.28-.1-.55-.16-.8a1.693 1.693 0 0 0-.3-.65 1.437 1.437 0 0 0-.55-.45 2.013 2.013 0 0 0-.89-.17h-3.72v4.88h-1.52v-11.42h5.38zm.32 5.18a2.22 2.22 0 0 0 .84-.31 1.732 1.732 0 0 0 .58-.62 2.176 2.176 0 0 0 .21-1.02 2.043 2.043 0 0 0-.48-1.41 1.968 1.968 0 0 0-1.55-.54h-3.78v3.98h3.17a5.512 5.512 0 0 0 1.01-.08zm13.55-5.18v1.28h-6.37v3.63h5.94v1.28h-5.94v3.95h6.42v1.28h-7.94v-11.42h7.89zm9.19 1.61a3.555 3.555 0 0 0-2.07-.6 3.676 3.676 0 0 0-1.75.38 3.618 3.618 0 0 0-1.2 1.03 4.6 4.6 0 0 0-.7 1.48 7.07 7.07 0 0 0-.22 1.73 7.879 7.879 0 0 0 .22 1.85 4.521 4.521 0 0 0 .7 1.52 3.557 3.557 0 0 0 1.21 1.03 3.717 3.717 0 0 0 1.76.38 3.431 3.431 0 0 0 1.33-.24 3.08 3.08 0 0 0 1.68-1.74 4.308 4.308 0 0 0 .28-1.31h1.52a5.151 5.151 0 0 1-1.48 3.36 4.839 4.839 0 0 1-3.46 1.2 5.428 5.428 0 0 1-2.32-.46 4.576 4.576 0 0 1-1.65-1.25 5.658 5.658 0 0 1-.98-1.89 8.07 8.07 0 0 1-.33-2.34 7.745 7.745 0 0 1 .35-2.34 5.756 5.756 0 0 1 1.03-1.91 4.743 4.743 0 0 1 1.7-1.29 5.389 5.389 0 0 1 2.33-.47 5.8 5.8 0 0 1 1.69.24 4.54 4.54 0 0 1 1.43.7 4.145 4.145 0 0 1 1.04 1.16 4.09 4.09 0 0 1 .54 1.61h-1.52a2.819 2.819 0 0 0-1.13-1.83zm6.16 5.8a4.694 4.694 0 0 0 .7 1.52 3.781 3.781 0 0 0 1.23 1.08 4.228 4.228 0 0 0 3.59 0 3.781 3.781 0 0 0 1.23-1.08 4.694 4.694 0 0 0 .7-1.52 6.4 6.4 0 0 0 0-3.4 4.694 4.694 0 0 0-.7-1.52 3.781 3.781 0 0 0-1.23-1.08 4.228 4.228 0 0 0-3.59 0 3.781 3.781 0 0 0-1.23 1.08 4.694 4.694 0 0 0-.7 1.52 6.4 6.4 0 0 0 0 3.4zm-1.4-3.95a5.6 5.6 0 0 1 1.03-1.91 5.124 5.124 0 0 1 1.71-1.33 6.049 6.049 0 0 1 4.77 0 5.124 5.124 0 0 1 1.71 1.33 5.6 5.6 0 0 1 1.03 1.91 7.407 7.407 0 0 1 0 4.5 5.6 5.6 0 0 1-1.03 1.91 5.1 5.1 0 0 1-1.71 1.32 6.049 6.049 0 0 1-4.77 0 5.1 5.1 0 0 1-1.71-1.32 5.6 5.6 0 0 1-1.03-1.91 7.407 7.407 0 0 1 0-4.5zm14.96-3.46l3.6 9.6 3.62-9.6h2.08v11.42h-1.44v-9.5h-.03l-3.57 9.5h-1.3l-3.56-9.5h-.04v9.5h-1.44v-11.42h2.08zm14.34 0l3.6 9.6 3.62-9.6h2.08v11.42h-1.44v-9.5h-.04l-3.56 9.5h-1.3l-3.57-9.5h-.03v9.5h-1.44v-11.42h2.08zm20.11 0v1.28h-6.37v3.63h5.94v1.28h-5.94v3.95h6.42v1.28h-7.94v-11.42h7.89zm3.89 0l6.02 9.26h.03v-9.26h1.44v11.42h-1.67l-5.96-9.17h-.04v9.17h-1.44v-11.42h1.62zm14.4 10.14a5.574 5.574 0 0 0 .64-.04 3.326 3.326 0 0 0 .82-.19 3.832 3.832 0 0 0 .85-.44 2.832 2.832 0 0 0 .76-.78 4.181 4.181 0 0 0 .55-1.24 6.328 6.328 0 0 0 .22-1.8 7.855 7.855 0 0 0-.2-1.84 3.432 3.432 0 0 0-.66-1.37 2.86 2.86 0 0 0-1.17-.87 4.839 4.839 0 0 0-1.78-.29h-2.56v8.86h2.53zm-.13-10.14a5.738 5.738 0 0 1 4.07 1.34 5.385 5.385 0 0 1 1.42 4.1 9.354 9.354 0 0 1-.32 2.55 4.655 4.655 0 0 1-.99 1.87 4.228 4.228 0 0 1-1.71 1.16 6.842 6.842 0 0 1-2.47.4h-3.92v-11.42h3.92zm15.63 0v1.28h-6.36v3.63h5.93v1.28h-5.93v3.95h6.41v1.28h-7.93v-11.42h7.88zm6.34 10.14a5.574 5.574 0 0 0 .64-.04 3.326 3.326 0 0 0 .82-.19 3.832 3.832 0 0 0 .85-.44 2.832 2.832 0 0 0 .76-.78 4.181 4.181 0 0 0 .55-1.24 6.328 6.328 0 0 0 .22-1.8 7.855 7.855 0 0 0-.2-1.84 3.432 3.432 0 0 0-.66-1.37 2.86 2.86 0 0 0-1.17-.87 4.839 4.839 0 0 0-1.78-.29h-2.56v8.86h2.53zm-.13-10.14a5.738 5.738 0 0 1 4.07 1.34 5.385 5.385 0 0 1 1.42 4.1 9.354 9.354 0 0 1-.32 2.55 4.655 4.655 0 0 1-.99 1.87 4.228 4.228 0 0 1-1.71 1.16 6.842 6.842 0 0 1-2.47.4h-3.92v-11.42h3.92z" transform="translate(-1493 -1514)"/><path id="star" class="cls-2" d="M1504.56 1518.67l-1.78 3.62-4 .58a.872.872 0 0 0-.48 1.49l2.89 2.82-.69 3.98a.875.875 0 0 0 1.27.92l3.58-1.88 3.57 1.88a.877.877 0 0 0 1.27-.92l-.69-3.98 2.89-2.82a.872.872 0 0 0-.48-1.49l-3.99-.58-1.79-3.62a.876.876 0 0 0-1.57 0z" transform="translate(-1493 -1514)"/></svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,388 @@
/**
* jquery-match-height 0.7.2 by @liabru
* http://brm.io/jquery-match-height/
* License: MIT
*/
;(function(factory) { // eslint-disable-line no-extra-semi
'use strict';
if (typeof define === 'function' && define.amd) {
// AMD
define(['jquery'], factory);
} else if (typeof module !== 'undefined' && module.exports) {
// CommonJS
module.exports = factory(require('jquery'));
} else {
// Global
factory(jQuery);
}
})(function($) {
/*
* internal
*/
var _previousResizeWidth = -1,
_updateTimeout = -1;
/*
* _parse
* value parse utility function
*/
var _parse = function(value) {
// parse value and convert NaN to 0
return parseFloat(value) || 0;
};
/*
* _rows
* utility function returns array of jQuery selections representing each row
* (as displayed after float wrapping applied by browser)
*/
var _rows = function(elements) {
var tolerance = 1,
$elements = $(elements),
lastTop = null,
rows = [];
// group elements by their top position
$elements.each(function(){
var $that = $(this),
top = $that.offset().top - _parse($that.css('margin-top')),
lastRow = rows.length > 0 ? rows[rows.length - 1] : null;
if (lastRow === null) {
// first item on the row, so just push it
rows.push($that);
} else {
// if the row top is the same, add to the row group
if (Math.floor(Math.abs(lastTop - top)) <= tolerance) {
rows[rows.length - 1] = lastRow.add($that);
} else {
// otherwise start a new row group
rows.push($that);
}
}
// keep track of the last row top
lastTop = top;
});
return rows;
};
/*
* _parseOptions
* handle plugin options
*/
var _parseOptions = function(options) {
var opts = {
byRow: true,
property: 'height',
target: null,
remove: false
};
if (typeof options === 'object') {
return $.extend(opts, options);
}
if (typeof options === 'boolean') {
opts.byRow = options;
} else if (options === 'remove') {
opts.remove = true;
}
return opts;
};
/*
* matchHeight
* plugin definition
*/
var matchHeight = $.fn.matchHeight = function(options) {
var opts = _parseOptions(options);
// handle remove
if (opts.remove) {
var that = this;
// remove fixed height from all selected elements
this.css(opts.property, '');
// remove selected elements from all groups
$.each(matchHeight._groups, function(key, group) {
group.elements = group.elements.not(that);
});
// TODO: cleanup empty groups
return this;
}
if (this.length <= 1 && !opts.target) {
return this;
}
// keep track of this group so we can re-apply later on load and resize events
matchHeight._groups.push({
elements: this,
options: opts
});
// match each element's height to the tallest element in the selection
matchHeight._apply(this, opts);
return this;
};
/*
* plugin global options
*/
matchHeight.version = '0.7.2';
matchHeight._groups = [];
matchHeight._throttle = 80;
matchHeight._maintainScroll = false;
matchHeight._beforeUpdate = null;
matchHeight._afterUpdate = null;
matchHeight._rows = _rows;
matchHeight._parse = _parse;
matchHeight._parseOptions = _parseOptions;
/*
* matchHeight._apply
* apply matchHeight to given elements
*/
matchHeight._apply = function(elements, options) {
var opts = _parseOptions(options),
$elements = $(elements),
rows = [$elements];
// take note of scroll position
var scrollTop = $(window).scrollTop(),
htmlHeight = $('html').outerHeight(true);
// get hidden parents
var $hiddenParents = $elements.parents().filter(':hidden');
// cache the original inline style
$hiddenParents.each(function() {
var $that = $(this);
$that.data('style-cache', $that.attr('style'));
});
// temporarily must force hidden parents visible
$hiddenParents.css('display', 'block');
// get rows if using byRow, otherwise assume one row
if (opts.byRow && !opts.target) {
// must first force an arbitrary equal height so floating elements break evenly
$elements.each(function() {
var $that = $(this),
display = $that.css('display');
// temporarily force a usable display value
if (display !== 'inline-block' && display !== 'flex' && display !== 'inline-flex') {
display = 'block';
}
// cache the original inline style
$that.data('style-cache', $that.attr('style'));
$that.css({
'display': display,
'padding-top': '0',
'padding-bottom': '0',
'margin-top': '0',
'margin-bottom': '0',
'border-top-width': '0',
'border-bottom-width': '0',
'height': '100px',
'overflow': 'hidden'
});
});
// get the array of rows (based on element top position)
rows = _rows($elements);
// revert original inline styles
$elements.each(function() {
var $that = $(this);
$that.attr('style', $that.data('style-cache') || '');
});
}
$.each(rows, function(key, row) {
var $row = $(row),
targetHeight = 0;
if (!opts.target) {
// skip apply to rows with only one item
if (opts.byRow && $row.length <= 1) {
$row.css(opts.property, '');
return;
}
// iterate the row and find the max height
$row.each(function(){
var $that = $(this),
style = $that.attr('style'),
display = $that.css('display');
// temporarily force a usable display value
if (display !== 'inline-block' && display !== 'flex' && display !== 'inline-flex') {
display = 'block';
}
// ensure we get the correct actual height (and not a previously set height value)
var css = { 'display': display };
css[opts.property] = '';
$that.css(css);
// find the max height (including padding, but not margin)
if ($that.outerHeight(false) > targetHeight) {
targetHeight = $that.outerHeight(false);
}
// revert styles
if (style) {
$that.attr('style', style);
} else {
$that.css('display', '');
}
});
} else {
// if target set, use the height of the target element
targetHeight = opts.target.outerHeight(false);
}
// iterate the row and apply the height to all elements
$row.each(function(){
var $that = $(this),
verticalPadding = 0;
// don't apply to a target
if (opts.target && $that.is(opts.target)) {
return;
}
// handle padding and border correctly (required when not using border-box)
if ($that.css('box-sizing') !== 'border-box') {
verticalPadding += _parse($that.css('border-top-width')) + _parse($that.css('border-bottom-width'));
verticalPadding += _parse($that.css('padding-top')) + _parse($that.css('padding-bottom'));
}
// set the height (accounting for padding and border)
$that.css(opts.property, (targetHeight - verticalPadding) + 'px');
});
});
// revert hidden parents
$hiddenParents.each(function() {
var $that = $(this);
$that.attr('style', $that.data('style-cache') || null);
});
// restore scroll position if enabled
if (matchHeight._maintainScroll) {
$(window).scrollTop((scrollTop / htmlHeight) * $('html').outerHeight(true));
}
return this;
};
/*
* matchHeight._applyDataApi
* applies matchHeight to all elements with a data-match-height attribute
*/
matchHeight._applyDataApi = function() {
var groups = {};
// generate groups by their groupId set by elements using data-match-height
$('[data-match-height], [data-mh]').each(function() {
var $this = $(this),
groupId = $this.attr('data-mh') || $this.attr('data-match-height');
if (groupId in groups) {
groups[groupId] = groups[groupId].add($this);
} else {
groups[groupId] = $this;
}
});
// apply matchHeight to each group
$.each(groups, function() {
this.matchHeight(true);
});
};
/*
* matchHeight._update
* updates matchHeight on all current groups with their correct options
*/
var _update = function(event) {
if (matchHeight._beforeUpdate) {
matchHeight._beforeUpdate(event, matchHeight._groups);
}
$.each(matchHeight._groups, function() {
matchHeight._apply(this.elements, this.options);
});
if (matchHeight._afterUpdate) {
matchHeight._afterUpdate(event, matchHeight._groups);
}
};
matchHeight._update = function(throttle, event) {
// prevent update if fired from a resize event
// where the viewport width hasn't actually changed
// fixes an event looping bug in IE8
if (event && event.type === 'resize') {
var windowWidth = $(window).width();
if (windowWidth === _previousResizeWidth) {
return;
}
_previousResizeWidth = windowWidth;
}
// throttle updates
if (!throttle) {
_update(event);
} else if (_updateTimeout === -1) {
_updateTimeout = setTimeout(function() {
_update(event);
_updateTimeout = -1;
}, matchHeight._throttle);
}
};
/*
* bind events
*/
// apply on DOM ready event
$(matchHeight._applyDataApi);
// use on or bind where supported
var on = $.fn.on ? 'on' : 'bind';
// update heights on load and resize events
$(window)[on]('load', function(event) {
matchHeight._update(false, event);
});
// throttled update heights on resize events
$(window)[on]('resize orientationchange', function(event) {
matchHeight._update(true, event);
});
});

View File

@ -0,0 +1 @@
!function(t){"use strict";"function"==typeof define&&define.amd?define(["jquery"],t):"undefined"!=typeof module&&module.exports?module.exports=t(require("jquery")):t(jQuery)}(function(l){function h(t){return parseFloat(t)||0}function c(t){var e=l(t),n=null,a=[];return e.each(function(){var t=l(this),e=t.offset().top-h(t.css("margin-top")),o=0<a.length?a[a.length-1]:null;null===o?a.push(t):Math.floor(Math.abs(n-e))<=1?a[a.length-1]=o.add(t):a.push(t),n=e}),a}function p(t){var e={byRow:!0,property:"height",target:null,remove:!1};return"object"==typeof t?l.extend(e,t):("boolean"==typeof t?e.byRow=t:"remove"===t&&(e.remove=!0),e)}var n=-1,a=-1,u=l.fn.matchHeight=function(t){var e=p(t);if(e.remove){var o=this;return this.css(e.property,""),l.each(u._groups,function(t,e){e.elements=e.elements.not(o)}),this}return this.length<=1&&!e.target||(u._groups.push({elements:this,options:e}),u._apply(this,e)),this};u.version="0.7.2",u._groups=[],u._throttle=80,u._maintainScroll=!1,u._beforeUpdate=null,u._afterUpdate=null,u._rows=c,u._parse=h,u._parseOptions=p,u._apply=function(t,e){var i=p(e),o=l(t),n=[o],a=l(window).scrollTop(),r=l("html").outerHeight(!0),s=o.parents().filter(":hidden");return s.each(function(){var t=l(this);t.data("style-cache",t.attr("style"))}),s.css("display","block"),i.byRow&&!i.target&&(o.each(function(){var t=l(this),e=t.css("display");"inline-block"!==e&&"flex"!==e&&"inline-flex"!==e&&(e="block"),t.data("style-cache",t.attr("style")),t.css({display:e,"padding-top":"0","padding-bottom":"0","margin-top":"0","margin-bottom":"0","border-top-width":"0","border-bottom-width":"0",height:"100px",overflow:"hidden"})}),n=c(o),o.each(function(){var t=l(this);t.attr("style",t.data("style-cache")||"")})),l.each(n,function(t,e){var o=l(e),a=0;if(i.target)a=i.target.outerHeight(!1);else{if(i.byRow&&o.length<=1)return void o.css(i.property,"");o.each(function(){var t=l(this),e=t.attr("style"),o=t.css("display");"inline-block"!==o&&"flex"!==o&&"inline-flex"!==o&&(o="block");var n={display:o};n[i.property]="",t.css(n),t.outerHeight(!1)>a&&(a=t.outerHeight(!1)),e?t.attr("style",e):t.css("display","")})}o.each(function(){var t=l(this),e=0;i.target&&t.is(i.target)||("border-box"!==t.css("box-sizing")&&(e+=h(t.css("border-top-width"))+h(t.css("border-bottom-width")),e+=h(t.css("padding-top"))+h(t.css("padding-bottom"))),t.css(i.property,a-e+"px"))})}),s.each(function(){var t=l(this);t.attr("style",t.data("style-cache")||null)}),u._maintainScroll&&l(window).scrollTop(a/r*l("html").outerHeight(!0)),this},u._applyDataApi=function(){var o={};l("[data-match-height], [data-mh]").each(function(){var t=l(this),e=t.attr("data-mh")||t.attr("data-match-height");o[e]=e in o?o[e].add(t):t}),l.each(o,function(){this.matchHeight(!0)})};function i(t){u._beforeUpdate&&u._beforeUpdate(t,u._groups),l.each(u._groups,function(){u._apply(this.elements,this.options)}),u._afterUpdate&&u._afterUpdate(t,u._groups)}u._update=function(t,e){if(e&&"resize"===e.type){var o=l(window).width();if(o===n)return;n=o}t?-1===a&&(a=setTimeout(function(){i(e),a=-1},u._throttle)):i(e)},l(u._applyDataApi);var t=l.fn.on?"on":"bind";l(window)[t]("load",function(t){u._update(!1,t)}),l(window)[t]("resize orientationchange",function(t){u._update(!0,t)})});

View File

@ -0,0 +1,190 @@
/* global WPMailSMTP, jQuery, wp_mail_smtp_about */
var WPMailSMTP = window.WPMailSMTP || {};
WPMailSMTP.Admin = WPMailSMTP.Admin || {};
/**
* WP Mail SMTP Admin area About module.
*
* @since 1.5.0
*/
WPMailSMTP.Admin.About = WPMailSMTP.Admin.About || (function ( document, window, $ ) {
'use strict';
/**
* Private functions and properties.
*
* @since 1.5.0
*
* @type {Object}
*/
var __private = {};
/**
* Public functions and properties.
*
* @since 1.5.0
*
* @type {Object}
*/
var app = {
/**
* Start the engine. DOM is not ready yet, use only to init something.
*
* @since 1.5.0
*/
init: function () {
// Do that when DOM is ready.
$( document ).ready( app.ready );
},
/**
* DOM is fully loaded.
*
* @since 1.5.0
*/
ready: function () {
app.pageHolder = $( '.wp-mail-smtp-page-about' );
app.bindActions();
$( '.wp-mail-smtp-page' ).trigger( 'WPMailSMTP.Admin.About.ready' );
},
/**
* Process all generic actions/events, mostly custom that were fired by our API.
*
* @since 1.5.0
*/
bindActions: function () {
/*
* Make plugins description the same height.
*/
jQuery('.wp-mail-smtp-admin-about-plugins .plugin-item .details').matchHeight();
/*
* Install/Active the plugins.
*/
$( document ).on( 'click', '.wp-mail-smtp-admin-about-plugins .plugin-item .action-button .button', function( e ) {
e.preventDefault();
var $btn = $( this );
if ( $btn.hasClass( 'disabled' ) || $btn.hasClass( 'loading' ) ) {
return false;
}
var $plugin = $btn.closest( '.plugin-item' ),
plugin = $btn.attr( 'data-plugin' ),
task,
cssClass,
statusText,
buttonText,
errorText,
successText;
$btn.addClass( 'loading disabled' );
$btn.text( wp_mail_smtp_about.plugin_processing );
if ( $btn.hasClass( 'status-inactive' ) ) {
// Activate.
task = 'about_plugin_activate';
cssClass = 'status-active button button-secondary disabled';
statusText = wp_mail_smtp_about.plugin_active;
buttonText = wp_mail_smtp_about.plugin_activated;
errorText = wp_mail_smtp_about.plugin_activate;
} else if ( $btn.hasClass( 'status-download' ) ) {
// Install & Activate.
task = 'about_plugin_install';
cssClass = 'status-active button disabled';
statusText = wp_mail_smtp_about.plugin_active;
buttonText = wp_mail_smtp_about.plugin_activated;
errorText = wp_mail_smtp_about.plugin_activate;
} else {
return;
}
// Setup ajax POST data.
var data = {
action: 'wp_mail_smtp_ajax',
task: task,
nonce : wp_mail_smtp_about.nonce,
plugin: plugin
};
$.post( wp_mail_smtp_about.ajax_url, data, function( res ) {
var is_install_successful;
if ( res.success ) {
is_install_successful = true;
if ( 'about_plugin_install' === task ) {
$btn.attr( 'data-plugin', res.data.basename );
successText = res.data.msg;
if ( ! res.data.is_activated ) {
cssClass = 'button';
statusText = wp_mail_smtp_about.plugin_inactive;
buttonText = wp_mail_smtp_about.plugin_activate;
}
} else {
successText = res.data;
}
$plugin.find( '.actions' ).append( '<div class="msg success">'+successText+'</div>' );
$plugin.find( 'span.status-label' )
.removeClass( 'status-active status-inactive status-download' )
.addClass( cssClass )
.removeClass( 'button button-primary button-secondary disabled' )
.text( statusText );
$btn
.removeClass( 'status-active status-inactive status-download' )
.removeClass( 'button button-primary button-secondary disabled' )
.addClass( cssClass ).html( buttonText );
} else {
is_install_successful = false;
if (
res.hasOwnProperty( 'data' ) &&
res.data.hasOwnProperty( 0 ) &&
res.data[ 0 ].hasOwnProperty( 'code' ) &&
res.data[ 0 ].code === 'download_failed'
) {
// Specific server-returned error.
$plugin.find( '.actions' ).append( '<div class="msg error">' + wp_mail_smtp_about.plugin_install_error + '</div>' );
}
else {
// Generic error.
$plugin.find( '.actions' ).append( '<div class="msg error">' + res.data + '</div>' );
}
$btn.html( wp_mail_smtp_about.plugin_download_btn );
}
if ( ! is_install_successful ) {
$btn.removeClass( 'disabled' );
}
$btn.removeClass( 'loading' );
// Automatically clear plugin messages after 3 seconds.
setTimeout( function () {
$( '.plugin-item .msg' ).remove();
}, 3000 );
}).fail( function( xhr ) {
console.log( xhr.responseText );
});
});
}
};
// Provide access to public functions/properties.
return app;
})( document, window, jQuery );
// Initialize.
WPMailSMTP.Admin.About.init();

View File

@ -0,0 +1 @@
var WPMailSMTP=window.WPMailSMTP||{};WPMailSMTP.Admin=WPMailSMTP.Admin||{},WPMailSMTP.Admin.About=WPMailSMTP.Admin.About||function(a,t,p){"use strict";var i={init:function(){p(a).ready(i.ready)},ready:function(){i.pageHolder=p(".wp-mail-smtp-page-about"),i.bindActions(),p(".wp-mail-smtp-page").trigger("WPMailSMTP.Admin.About.ready")},bindActions:function(){jQuery(".wp-mail-smtp-admin-about-plugins .plugin-item .details").matchHeight(),p(a).on("click",".wp-mail-smtp-admin-about-plugins .plugin-item .action-button .button",function(a){a.preventDefault();var i=p(this);if(i.hasClass("disabled")||i.hasClass("loading"))return!1;var s,n,l,e,o,u=i.closest(".plugin-item"),t=i.attr("data-plugin");if(i.addClass("loading disabled"),i.text(wp_mail_smtp_about.plugin_processing),i.hasClass("status-inactive"))s="about_plugin_activate",n="status-active button button-secondary disabled",l=wp_mail_smtp_about.plugin_active,e=wp_mail_smtp_about.plugin_activated,wp_mail_smtp_about.plugin_activate;else{if(!i.hasClass("status-download"))return;s="about_plugin_install",n="status-active button disabled",l=wp_mail_smtp_about.plugin_active,e=wp_mail_smtp_about.plugin_activated,wp_mail_smtp_about.plugin_activate}var d={action:"wp_mail_smtp_ajax",task:s,nonce:wp_mail_smtp_about.nonce,plugin:t};p.post(wp_mail_smtp_about.ajax_url,d,function(a){var t;a.success?(t=!0,"about_plugin_install"===s?(i.attr("data-plugin",a.data.basename),o=a.data.msg,a.data.is_activated||(n="button",l=wp_mail_smtp_about.plugin_inactive,e=wp_mail_smtp_about.plugin_activate)):o=a.data,u.find(".actions").append('<div class="msg success">'+o+"</div>"),u.find("span.status-label").removeClass("status-active status-inactive status-download").addClass(n).removeClass("button button-primary button-secondary disabled").text(l),i.removeClass("status-active status-inactive status-download").removeClass("button button-primary button-secondary disabled").addClass(n).html(e)):(t=!1,a.hasOwnProperty("data")&&a.data.hasOwnProperty(0)&&a.data[0].hasOwnProperty("code")&&"download_failed"===a.data[0].code?u.find(".actions").append('<div class="msg error">'+wp_mail_smtp_about.plugin_install_error+"</div>"):u.find(".actions").append('<div class="msg error">'+a.data+"</div>"),i.html(wp_mail_smtp_about.plugin_download_btn)),t||i.removeClass("disabled"),i.removeClass("loading"),setTimeout(function(){p(".plugin-item .msg").remove()},3e3)}).fail(function(a){console.log(a.responseText)})})}};return i}(document,window,jQuery),WPMailSMTP.Admin.About.init();

View File

@ -0,0 +1,282 @@
/* globals jQuery, wp_mail_smtp */
var WPMailSMTP = window.WPMailSMTP || {};
WPMailSMTP.Admin = WPMailSMTP.Admin || {};
/**
* WP Mail SMTP Admin area module.
*
* @since 1.6.0
*/
WPMailSMTP.Admin.Settings = WPMailSMTP.Admin.Settings || (function ( document, window, $ ) {
'use strict';
/**
* Private functions and properties.
*
* @since 1.6.0
*
* @type {Object}
*/
var __private = {};
/**
* Public functions and properties.
*
* @since 1.6.0
*
* @type {Object}
*/
var app = {
/**
* State attribute showing if one of the plugin settings
* changed and was not yet saved.
*
* @since {VERSION}
*
* @type {boolean}
*/
pluginSettingsChanged: false,
/**
* Start the engine. DOM is not ready yet, use only to init something.
*
* @since 1.6.0
*/
init: function () {
// Do that when DOM is ready.
$( document ).ready( app.ready );
},
/**
* DOM is fully loaded.
*
* @since 1.6.0
*/
ready: function () {
app.pageHolder = $( '.wp-mail-smtp-tab-settings' );
// If there are screen options we have to move them.
$( '#screen-meta-links, #screen-meta' ).prependTo( '#wp-mail-smtp-header-temp' ).show();
app.bindActions();
},
/**
* Process all generic actions/events, mostly custom that were fired by our API.
*
* @since 1.6.0
*/
bindActions: function () {
// Mailer selection.
$( '.wp-mail-smtp-mailer-image', app.pageHolder ).click( function () {
$( this ).parents( '.wp-mail-smtp-mailer' ).find( 'input' ).trigger( 'click' );
} );
$( '.wp-mail-smtp-mailer input', app.pageHolder ).click( function () {
var $input = $( this );
if ( $input.prop( 'disabled' ) ) {
// Educational Popup.
if ( $input.hasClass( 'educate' ) ) {
app.education.upgradeMailer( $input );
}
return false;
}
// Deselect the current mailer.
$( '.wp-mail-smtp-mailer', app.pageHolder ).removeClass( 'active' );
// Select the correct one.
$( this ).parents( '.wp-mail-smtp-mailer' ).addClass( 'active' );
// Hide all mailers options and display for a currently clicked one.
$( '.wp-mail-smtp-mailer-option', app.pageHolder ).addClass( 'hidden' ).removeClass( 'active' );
$( '.wp-mail-smtp-mailer-option-' + $( this ).val(), app.pageHolder ).addClass( 'active' ).removeClass( 'hidden' );
} );
app.mailers.smtp.bindActions();
// Dismiss Pro banner at the bottom of the page.
$( '#wp-mail-smtp-pro-banner-dismiss', app.pageHolder ).on( 'click', function () {
$.ajax( {
url: ajaxurl,
dataType: 'json',
type: 'POST',
data: {
action: 'wp_mail_smtp_ajax',
task: 'pro_banner_dismiss'
}
} )
.always( function () {
$( '#wp-mail-smtp-pro-banner', app.pageHolder ).fadeOut( 'fast' );
} );
} );
// Dismis educational notices for certain mailers.
$( '.js-wp-mail-smtp-mailer-notice-dismiss', app.pageHolder ).on( 'click', function ( e ) {
e.preventDefault();
var $btn = $( this ),
$notice = $btn.parents( '.inline-notice' );
if ( $btn.hasClass( 'disabled' ) ) {
return false;
}
$.ajax( {
url: ajaxurl,
dataType: 'json',
type: 'POST',
data: {
action: 'wp_mail_smtp_ajax',
task: 'notice_dismiss',
notice: $notice.data( 'notice' ),
mailer: $notice.data( 'mailer' )
},
beforeSend: function () {
$btn.addClass( 'disabled' );
}
} )
.always( function () {
$notice.fadeOut( 'fast', function () {
$btn.removeClass( 'disabled' );
} );
} );
} );
// Show/hide debug output.
$( '#wp-mail-smtp-debug .error-log-toggle' ).on( 'click', function ( e ) {
e.preventDefault();
$( '#wp-mail-smtp-debug .error-log-toggle' ).find( '.dashicons' ).toggleClass( 'dashicons-arrow-right-alt2 dashicons-arrow-down-alt2' );
$( '#wp-mail-smtp-debug .error-log' ).slideToggle();
$( '#wp-mail-smtp-debug .error-log-note' ).toggle();
} );
// Remove mailer connection.
$( '.js-wp-mail-smtp-provider-remove', app.pageHolder ).on( 'click', function () {
return confirm( wp_mail_smtp.text_provider_remove );
} );
// Copy input text to clipboard.
$( '.wp-mail-smtp-setting-copy', app.pageHolder ).click( function ( e ) {
e.preventDefault();
var target = $( '#' + $( this ).data( 'source_id' ) ).get( 0 );
target.select();
document.execCommand( 'Copy' );
} );
app.triggerExitNotice();
},
education: {
upgradeMailer: function ( $input ) {
$.alert( {
backgroundDismiss: true,
escapeKey: true,
animationBounce: 1,
theme: 'modern',
animateFromElement: false,
draggable: false,
closeIcon: true,
useBootstrap: false,
title: wp_mail_smtp.education.upgrade_title.replace( /%name%/g, $input.siblings( 'label' ).text().trim() ),
icon: '"></i>' + wp_mail_smtp.education.upgrade_icon_lock + '<i class="',
content: $( '.wp-mail-smtp-mailer-options .wp-mail-smtp-mailer-option-' + $input.val() + ' .wp-mail-smtp-setting-field' ).html(),
boxWidth: '550px',
onOpenBefore: function () {
this.$btnc.after( '<div class="discount-note">' + wp_mail_smtp.education.upgrade_bonus + wp_mail_smtp.education.upgrade_doc + '</div>' );
},
buttons: {
confirm: {
text: wp_mail_smtp.education.upgrade_button,
btnClass: 'btn-confirm',
keys: [ 'enter' ],
action: function () {
window.open( wp_mail_smtp.education.upgrade_url + '&utm_content=' + encodeURI( $input.val() ), '_blank' );
}
}
}
} );
}
},
/**
* Individual mailers specific js code.
*
* @since 1.6.0
*/
mailers: {
smtp: {
bindActions: function () {
// Hide SMTP-specific user/pass when Auth disabled.
$( '#wp-mail-smtp-setting-smtp-auth' ).change( function () {
$( '#wp-mail-smtp-setting-row-smtp-user, #wp-mail-smtp-setting-row-smtp-pass' ).toggleClass( 'inactive' );
} );
// Port default values based on encryption type.
$( '#wp-mail-smtp-setting-row-smtp-encryption input' ).change( function () {
var $input = $( this ),
$smtpPort = $( '#wp-mail-smtp-setting-smtp-port', app.pageHolder );
if ( 'tls' === $input.val() ) {
$smtpPort.val( '587' );
$( '#wp-mail-smtp-setting-row-smtp-autotls' ).addClass( 'inactive' );
}
else if ( 'ssl' === $input.val() ) {
$smtpPort.val( '465' );
$( '#wp-mail-smtp-setting-row-smtp-autotls' ).removeClass( 'inactive' );
}
else {
$smtpPort.val( '25' );
$( '#wp-mail-smtp-setting-row-smtp-autotls' ).removeClass( 'inactive' );
}
} );
}
}
},
/**
* Exit notice JS code when plugin settings are not saved.
*
* @since {VERSION}
*/
triggerExitNotice: function () {
var $settingPages = $( '.wp-mail-smtp-page-general:not( .wp-mail-smtp-tab-test )' );
// Display an exit notice, if settings are not saved.
$( window ).on( 'beforeunload', function () {
if ( app.pluginSettingsChanged ) {
return wp_mail_smtp.text_settings_not_saved;
}
} );
// Set settings changed attribute, if any input was changed.
$( ':input:not( #wp-mail-smtp-setting-license-key )', $settingPages ).on( 'change', function () {
app.pluginSettingsChanged = true;
} );
// Clear the settings changed attribute, if the settings are about to be saved.
$( 'form', $settingPages ).on( 'submit', function () {
app.pluginSettingsChanged = false;
} );
}
};
// Provide access to public functions/properties.
return app;
})( document, window, jQuery );
// Initialize.
WPMailSMTP.Admin.Settings.init();

View File

@ -0,0 +1 @@
var WPMailSMTP=window.WPMailSMTP||{};WPMailSMTP.Admin=WPMailSMTP.Admin||{},WPMailSMTP.Admin.Settings=WPMailSMTP.Admin.Settings||function(i,e,a){"use strict";var n={pluginSettingsChanged:!1,init:function(){a(i).ready(n.ready)},ready:function(){n.pageHolder=a(".wp-mail-smtp-tab-settings"),a("#screen-meta-links, #screen-meta").prependTo("#wp-mail-smtp-header-temp").show(),n.bindActions()},bindActions:function(){a(".wp-mail-smtp-mailer-image",n.pageHolder).click(function(){a(this).parents(".wp-mail-smtp-mailer").find("input").trigger("click")}),a(".wp-mail-smtp-mailer input",n.pageHolder).click(function(){var t=a(this);if(t.prop("disabled"))return t.hasClass("educate")&&n.education.upgradeMailer(t),!1;a(".wp-mail-smtp-mailer",n.pageHolder).removeClass("active"),a(this).parents(".wp-mail-smtp-mailer").addClass("active"),a(".wp-mail-smtp-mailer-option",n.pageHolder).addClass("hidden").removeClass("active"),a(".wp-mail-smtp-mailer-option-"+a(this).val(),n.pageHolder).addClass("active").removeClass("hidden")}),n.mailers.smtp.bindActions(),a("#wp-mail-smtp-pro-banner-dismiss",n.pageHolder).on("click",function(){a.ajax({url:ajaxurl,dataType:"json",type:"POST",data:{action:"wp_mail_smtp_ajax",task:"pro_banner_dismiss"}}).always(function(){a("#wp-mail-smtp-pro-banner",n.pageHolder).fadeOut("fast")})}),a(".js-wp-mail-smtp-mailer-notice-dismiss",n.pageHolder).on("click",function(t){t.preventDefault();var i=a(this),e=i.parents(".inline-notice");if(i.hasClass("disabled"))return!1;a.ajax({url:ajaxurl,dataType:"json",type:"POST",data:{action:"wp_mail_smtp_ajax",task:"notice_dismiss",notice:e.data("notice"),mailer:e.data("mailer")},beforeSend:function(){i.addClass("disabled")}}).always(function(){e.fadeOut("fast",function(){i.removeClass("disabled")})})}),a("#wp-mail-smtp-debug .error-log-toggle").on("click",function(t){t.preventDefault(),a("#wp-mail-smtp-debug .error-log-toggle").find(".dashicons").toggleClass("dashicons-arrow-right-alt2 dashicons-arrow-down-alt2"),a("#wp-mail-smtp-debug .error-log").slideToggle(),a("#wp-mail-smtp-debug .error-log-note").toggle()}),a(".js-wp-mail-smtp-provider-remove",n.pageHolder).on("click",function(){return confirm(wp_mail_smtp.text_provider_remove)}),a(".wp-mail-smtp-setting-copy",n.pageHolder).click(function(t){t.preventDefault(),a("#"+a(this).data("source_id")).get(0).select(),i.execCommand("Copy")}),n.triggerExitNotice()},education:{upgradeMailer:function(t){a.alert({backgroundDismiss:!0,escapeKey:!0,animationBounce:1,theme:"modern",animateFromElement:!1,draggable:!1,closeIcon:!0,useBootstrap:!1,title:wp_mail_smtp.education.upgrade_title.replace(/%name%/g,t.siblings("label").text().trim()),icon:'"></i>'+wp_mail_smtp.education.upgrade_icon_lock+'<i class="',content:a(".wp-mail-smtp-mailer-options .wp-mail-smtp-mailer-option-"+t.val()+" .wp-mail-smtp-setting-field").html(),boxWidth:"550px",onOpenBefore:function(){this.$btnc.after('<div class="discount-note">'+wp_mail_smtp.education.upgrade_bonus+wp_mail_smtp.education.upgrade_doc+"</div>")},buttons:{confirm:{text:wp_mail_smtp.education.upgrade_button,btnClass:"btn-confirm",keys:["enter"],action:function(){e.open(wp_mail_smtp.education.upgrade_url+"&utm_content="+encodeURI(t.val()),"_blank")}}}})}},mailers:{smtp:{bindActions:function(){a("#wp-mail-smtp-setting-smtp-auth").change(function(){a("#wp-mail-smtp-setting-row-smtp-user, #wp-mail-smtp-setting-row-smtp-pass").toggleClass("inactive")}),a("#wp-mail-smtp-setting-row-smtp-encryption input").change(function(){var t=a(this),i=a("#wp-mail-smtp-setting-smtp-port",n.pageHolder);"tls"===t.val()?(i.val("587"),a("#wp-mail-smtp-setting-row-smtp-autotls").addClass("inactive")):("ssl"===t.val()?i.val("465"):i.val("25"),a("#wp-mail-smtp-setting-row-smtp-autotls").removeClass("inactive"))})}}},triggerExitNotice:function(){var t=a(".wp-mail-smtp-page-general:not( .wp-mail-smtp-tab-test )");a(e).on("beforeunload",function(){if(n.pluginSettingsChanged)return wp_mail_smtp.text_settings_not_saved}),a(":input:not( #wp-mail-smtp-setting-license-key )",t).on("change",function(){n.pluginSettingsChanged=!0}),a("form",t).on("submit",function(){n.pluginSettingsChanged=!1})}};return n}(document,window,jQuery),WPMailSMTP.Admin.Settings.init();

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<bundle name="WP Mail SMTP">
<domain name="wp-mail-smtp">
<project name="WP Mail SMTP" slug="wp-mail-smtp">
<source>
<directory>.</directory>
</source>
<target>
<directory>assets/languages</directory>
</target>
<template>
<file>assets/languages/wp-mail-smtp.pot</file>
</template>
</project>
</domain>
<domain name="wp-mail-smtp-pro">
<project name="WP Mail SMTP Pro" slug="wp-mail-smtp-pro">
<source>
<directory>.</directory>
</source>
<target>
<directory>assets/pro/languages</directory>
</target>
<template>
<file>assets/pro/languages/wp-mail-smtp-pro.pot</file>
</template>
</project>
</domain>
</bundle>

View File

@ -0,0 +1,406 @@
=== WP Mail SMTP by WPForms ===
Contributors: wpforms, jaredatch, smub, slaFFik
Tags: smtp, wp mail smtp, wordpress smtp, gmail smtp, sendgrid smtp, mailgun smtp, mail, mailer, phpmailer, wp_mail, email, mailgun, sengrid, gmail, pepipost, sendinblue, wp smtp
Requires at least: 4.9
Tested up to: 5.3
Stable tag: 1.9.0
Requires PHP: 5.3
The most popular WordPress SMTP and PHP Mailer plugin. Trusted by over 1 million sites.
== Description ==
### WordPress Mail SMTP Plugin
Having problems with your WordPress site not sending emails? You're not alone. Over 1 million websites use WP Mail SMTP to send their emails reliably.
Our goal is to make email deliverability easy and reliable. We want to ensure your emails reach the inbox.
WP Mail SMTP fixes your email deliverability by reconfiguring WordPress to use a proper SMTP provider when sending emails.
= What is SMTP? =
SMTP (Simple Mail Transfer Protocol) is an industry standard for sending emails. Proper SMTP configuration helps increase email deliverability by using authentication.
Popular email clients like Gmail, Yahoo, and Office 365 are in a constant battle with email spammers. One of the things they look at is if an email is originating from the location it claims to be originating from.
If the proper authentication isn't there, then emails either go in the SPAM folder or worst, don't get delivered at all.
This is a problem for a lot of WordPress sites because by default, WordPress uses the PHP mail function to send emails generated by WordPress or any contact form plugin like <a href="https://wpforms.com/" rel="friend">WPForms</a>.
The issue is that most <a href"http://www.wpbeginner.com/wordpress-hosting/" rel="friend">WordPress hosting companies</a> don't have their servers properly configured for sending PHP emails.
The combination of two causes your WordPress emails to not get delivered.
= How does WP Mail SMTP work? =
WP Mail SMTP plugin easily resolves email delivery problems by improving and changing how your WordPress site sends email. We reconfigure the `wp_mail()` function to either use proper SMTP host credentials or leverage a built-in SMTP mail provider.
When using one of our built-in SMTP mail provider integrations (recommended), emails are sent using the provider's direct API. This means even if your web host is blocking SMTP ports, your emails still send successfully.
This helps you fix all WordPress not sending email issues.
WP Mail SMTP plugin includes many different SMTP setup options:
1. Pepipost SMTP <strong>(Recommended)</strong>
2. Sendinblue SMTP <strong>(Recommended)</strong>
3. Mailgun SMTP
4. SendGrid SMTP
5. Gmail SMTP
6. Microsoft SMTP (Outlook.com and Office 365) <a href="https://wpmailsmtp.com/?utm_source=wprepo&utm_medium=link&utm_campaign=liteversion&utm_content=readme" rel="friend">[Pro]</a>
7. Amazon SES SMTP <a href="https://wpmailsmtp.com/?utm_source=wprepo&utm_medium=link&utm_campaign=liteversion&utm_content=readme" rel="friend">[Pro]</a>
8. All Other SMTP
For all options, you can specify the "from name" and "email address" for outgoing emails.
Instead of having users use different SMTP plugins and workflows for different SMTP providers, we decided to bring it all in one. This is what makes WP Mail SMTP, the best SMTP solution for WordPress.
= Pepipost SMTP =
Pepipost is a recommended transactional email service.
Every month they delivers over 8 billion emails from 20,000+ customers.
Their mission is to reliably send emails in the most efficient way and at the most disruptive pricing ever.
Pepipost provides users 30,000 emails the first 30 days.
Read our <a href="https://wpmailsmtp.com/docs/how-to-set-up-the-pepipost-mailer-in-wp-mail-smtp/" rel="friend">Pepipost documentation</a> for more details.
= Sendinblue SMTP =
Sendinblue is a recommended transactional email service.
They serve 80,000+ growing companies around the world and send over 30 million emails each day.
Their email deliverability experts are constantly at work optimizing the reliability and speed of their SMTP infrastructure. Sendinblue provides users 300 free emails per day.
Read our <a href="https://wpmailsmtp.com/docs/how-to-set-up-the-sendinblue-mailer-in-wp-mail-smtp/" rel="friend">Sendinblue documentation</a> for more details.
= Mailgun SMTP =
Mailgun SMTP is a popular SMTP service provider that allows you to send large quantities of emails. They provide 5,000 free emails per month for 3 months.
WP Mail SMTP plugin offers a native integration with MailGun. All you have to do is connect your Mailgun account, and you will improve your email deliverability.
Read our <a href="https://wpmailsmtp.com/docs/how-to-set-up-the-mailgun-mailer-in-wp-mail-smtp/" rel="friend">Mailgun documentation</a> for more details.
= SendGrid SMTP =
SendGrid has a free SMTP plan that you can use to send up to 100 emails per day. With our native SendGrid SMTP integration, you can easily and securely set up SendGrid SMTP on your WordPress site.
Read our <a href="https://wpmailsmtp.com/docs/how-to-set-up-the-sendgrid-mailer-in-wp-mail-smtp/" rel="friend">SendGrid documentation</a> for more details.
= Gmail SMTP =
Often bloggers and small business owners don't want to use third-party SMTP services. Well you can use your Gmail or G Suite account for SMTP emails.
This allows you to use your <a href="http://www.wpbeginner.com/beginners-guide/how-to-setup-a-professional-email-address-with-gmail-and-google-apps/" rel="friend">professional email address</a> and improve email deliverability.
Unlike other Gmail SMTP plugins, our Gmail SMTP option uses OAuth to authenticate your Google account, keeping your login information 100% secure.
Read our <a href="https://wpmailsmtp.com/docs/how-to-set-up-the-gmail-mailer-in-wp-mail-smtp/" rel="friend">Gmail documentation</a> for more details.
= Microsoft SMTP (Outlook.com and Office 365) =
Many business use Outlook.com or Office 365 to their to power their email. For those users, the Microsoft mailer can be a great option. This integration allows you to use your existing Outlook.com or Office 365 account to send your emails reliably.
= Amazon SES SMTP =
Advanced or technical users can harness the power of Amazon AWS (Amazon Web Services) with the Amazon SES mailer. With this integration, you can send a high volume of emails at a very reasonable rate.
Read our <a href="https://wpmailsmtp.com/docs/how-to-set-up-the-amazon-ses-mailer-in-wp-mail-smtp/" rel="friend">Amazon SES documentation</a> for more details.
= Other SMTP =
WP Mail SMTP plugin also works with all major email services such as Gmail, Yahoo, Outlook, Microsoft Live, and any other email sending service that offers SMTP.
You can set the following options:
* Specify an SMTP host.
* Specify an SMTP port.
* Choose SSL / TLS encryption.
* Choose to use SMTP authentication or not.
* Specify an SMTP username and password.
To see recommended settings for the popular services as well as troubleshooting tips, check out our <a href="https://wpmailsmtp.com/docs/how-to-set-up-the-other-smtp-mailer-in-wp-mail-smtp/" rel="friend">SMTP documentation</a>.
We hope that you find WP Mail SMTP plugin helpful!
### WP Mail SMTP PRO
In addition to native Microsoft and Amazon SES integrations, WP Mail SMTP Pro provides access to many other powerful features and services.
<a href="https://wpmailsmtp.com/?utm_source=wprepo&utm_medium=link&utm_campaign=liteversion&utm_content=readme" rel="friend">Click here to purchase WP Mail SMTP Pro now!</a>
= Email Log =
Email Logging lets you log and view all emails sent from your site. Email logs are helpful for storing emails for your records, auditing outgoing emails, and debugging during site development.
= Manage WordPress Emails and Notifications =
The Manage Notification feature gives you full control over which email notifications WordPress sends. This means you can disable different WordPress notification emails. Don't want to receive emails when new users are created? No problem, turn it off.
= Expert Support =
We provide <a href="https://wordpress.org/support/topic/wp-mail-smtp-support-policy/">limited support</a> for the WP Mail SMTP plugin on the WordPress.org forums. Access to our world class one-on-one email support is available to <a href="https://wpmailsmtp.com/?utm_source=wprepo&utm_medium=link&utm_campaign=liteversion&utm_content=readme" rel="friend">WP Mail SMTP Pro</a> users.
= White Glove Setup =
Our White Glove Setup service is a great option that anyone can benefit from. Whether you don't have the time or maybe you feel a bit in over your head - we've got you covered.
You can sit back and relax while we set up everything for you. White glove setup includes WP Mail SMTP plugin installation and setup, configuration adjustments to your DNS for proper email domain name verification, Mailgun setup, and final testing to confirm everything is passing with flying colors.
### Security
The WP Mail SMTP team takes security very seriously. Not only does the plugin follow all security best practices, but we have several options available to ensure your site is safe and secure.
- Direct SMTP mailer integrations (recommended), such as Google and Mailgun, use the official provider APIs. This means you never enter your username or password in the plugin settings and these credentials are not stored in the database. Instead, we use tokens or API keys which are much more secure.
- When using Other SMTP mailer, we provide the option to insert your password in your `wp-config.php` file, so it's not visible in your WordPress settings or saved in the database.
### Credits
WP Mail SMTP plugin was originally created by Callum Macdonald. It is now owned and maintained by the team behind <a href="https://wpforms.com/" rel="friend">WPForms</a> - the best drag & drop form builder for WordPress.
You can try the <a href="https://wordpress.org/plugins/wpforms-lite/" rel="friend">free version of WPForms plugin</a> to see why it's the best in the market.
### What's Next
If you like this plugin, then consider checking out our other projects:
* <a href="https://optinmonster.com/" rel="friend" title="OptinMonster">OptinMonster</a> - Get More Email Subscribers with the most popular conversion optimization plugin for WordPress.
* <a href="https://www.monsterinsights.com/" rel="friend" title="MonsterInsights">MonsterInsights</a> - See the Stats that Matter and Grow Your Business with Confidence. Best Google Analytics Plugin for WordPress.
* <a href="https://www.seedprod.com/" rel="friend" title="SeedProd">SeedProd</a> - Jumpstart your website with the #1 Coming Soon & Maintenance Mode Plugin for WordPress.
Visit <a href="http://www.wpbeginner.com/" rel="friend" title="WPBeginner">WPBeginner</a> to learn from our <a href="http://www.wpbeginner.com/category/wp-tutorials/" rel="friend" title="WordPress Tutorials">WordPress Tutorials</a> and find out about other <a href="http://www.wpbeginner.com/category/plugins/" rel="friend" title="Best WordPress Plugins">best WordPress plugins</a>.
== Installation ==
1. Install WP Mail SMTP by WPForms either via the WordPress.org plugin repository or by uploading the files to your server. (See instructions on <a href="http://www.wpbeginner.com/beginners-guide/step-by-step-guide-to-install-a-wordpress-plugin-for-beginners/" rel="friend">how to install a WordPress plugin</a>)
2. Activate WP Mail SMTP by WPForms.
3. Navigate to the Settings area of WP Mail SMTP in the WordPress admin.
4. Choose your SMTP option (Mailgun SMTP, SendGrid SMTP, Gmail SMTP, or Other SMTP) and follow the instructions to set it up.
5. Need more help? Get support with <a href="https://wpmailsmtp.com/?utm_source=wprepo&utm_medium=link&utm_campaign=liteversion&utm_content=readme" rel="friend" title="WPForms">WP Mail SMTP PRO</a>.
== Frequently Asked Questions ==
= Can I use this plugin to send email via Gmail, G Suite, Outlook.com, Office 365, Hotmail, Yahoo, or AOL SMTP? =
Yes! We have extensive documentation that covers setting up SMTP most popular email services.
<a href="https://wpforms.com/docs/how-to-set-up-smtp-using-the-wp-mail-smtp-plugin/" rel="friend">Read our docs</a> to see the correct SMTP settings for each service.
= Help! I need support or have an issue. =
Please read <a href="https://wordpress.org/support/topic/wp-mail-smtp-support-policy/">our support policy</a> for more information.
Limited support is available for WP Mail SMTP users via WordPress.org support forums.
Email support and set up assistance is available to WP Mail SMTP Pro users.
= I found a bug, now what? =
If you've stumbled upon a bug, the best place to report it is in the <a href="https://github.com/awesomemotive/wp-mail-smtp">WP Mail SMTP GitHub repository</a>. GitHub is where the plugin is actively developed, and posting there will get your issue quickly seen by our developers (myself and Slava). Once posted, we'll review your bug report and triage the bug. When creating an issue, the more details you can add to your report, the faster the bug can be solved.
= Can you add feature x, y or z to the plugin? =
Short answer: maybe.
By all means please contact us to discuss features or options you'd like to see added to the plugin. We can't guarantee to add all of them, but we will consider all sensible requests. We can be contacted here:
<a href="https://wpmailsmtp.com/contact/" rel="friend">https://wpmailsmtp.com/contact/</a>
== Screenshots ==
1. WP Mail SMTP Settings page
2. Gmail / G Suite settings
3. Mailgun settings
4. SendGrid settings
5. SMTP settings
6. Send a Test Email
== Changelog ==
= 1.9.0 - 2020-03-23 =
* Added: Add various Status tests and Info section on Tools > Site Health page.
* Added: Notify admin if there are unsaved changes in plugin admin area options.
* Fixed: Test email now has a proper bottom margin for better look.
* Changed: Update "About us" plugin page with relevant information.
* Changed: Save default WordPress FROM Email address when incorrect FROM Email address is saved by a user.
= 1.8.1 - 2019-12-13 =
* Fixed: Revert Guzzle version to 6.4.1 because Sendinblue and Gmail mailers may experience issues under certain circumstances while sending emails (not all sites are affected).
* Fixed: Make compatible the WordPress PhpMailer class inline attachments management with the Sendgrid API.
= 1.8.0 - 2019-12-12 =
* Added: New recommended mailer: Pepipost.
* Added: "Suggest a Mailer" link in a list of mailers to send us your ideas about new ones.
* Fixed: Sendgrid: Content ID for attachments missing.
* Changed: Timeout to HTTP requests (pepipost, sendgrid, mailgun), same as max_execution_time, to prevent fails when sending emails with big attachments.
= 1.7.1 - 2019-11-11 =
* Fixed: Compatibility with WordPress 5.3.
* Fixed: `Processor::get_default_email()` always returns empty value when server incorrectly configured.
= 1.7.0 - 2019-10-24 =
* Added: Add a new constant `WPMS_DO_NOT_SEND` to block email sending.
* Fixed: Default email (wordpress@example.com) rewriting in CLI mode.
* Fixed: Incorrect conflicts detection with certain plugins.
* Fixed: various typos in plugin settings.
= 1.6.2 - 2019-09-02 =
* Fixed: Race condition when loading with certain plugins, that send emails very early. Makes email delivery more reliable.
= 1.6.0 - 2019-08-21 =
* Added: New transactional mailer: Sendinblue.
* Added: Educate users to use transactional mailers for better deliverability.
* Added: New option and filter to disable admin area delivery error notices.
* Changed: Hide private API key saved in the DB for API based mailers using `input[type=password]`.
* Changed: Update links to various docs, pointing now to https://wpmailsmtp.com.
= 1.5.2 - 2019-07-18 =
* Fixed: "Redirect URI mismatch" error for "Gmail" mailer when trying to re-authorize an account that was initially created with version < v1.5.0.
* Changed: Make "Authentication" setting in "Other SMTP" mailer ON by default for new users.
* Changed: Mailers docs links now point to wpmailsmtp.com own site.
= 1.5.1 - 2019-07-12 =
* Fixed: Duplicated emails sent to the first recipient in a loop (and others not receiving their emails).
= 1.5.0 - 2019-07-09 =
* Added: Loсo plugin support.
* Added: "About us" admin area page.
* Added: Display in debug output a possible conflicting plugin existence.
* Added: Lots of actions and filters to improve flexibility of the plugin.
* Changed: Plugin menu is now top level.
* Changed: Hide secrets/API keys in page DOM in plugin admin area.
* Changed: Do not save constant values into the database when plugin settings are saved.
* Changed: Lots of i18n improvements to support translation for both free and paid version of the plugin.
* Changed: Gmail mailer - allow to change From Name email header.
* Changed: Gmail mailer - display email used to create a connection.
* Changed: WordPress 4.9 is the minimum WordPress version we support.
* Fixed: X-Mailer header should be present in all emails.
* Fixed: PHP notices when migrating under certain circumstances from 0.x version of the plugin.
* Fixed: Options::get_group() now supports values set via constants.
= 1.4.2 - 2019-03-23 =
* Changed: Tested up to WordPress 5.1.x.
* Changed: Removed TGMPA library.
= 1.4.1 - 2018-12-03 =
* Fixed: correctly process backslashes in SMTP passwords defined via constants.
* Changed: allow to send a Test Email when Default (none) mailer is selected in plugin settings.
= 1.4.0 - 2018-11-29 =
* Added: New option: Do Not Send - block emails from being sent.
* Added: New option: Send HTML or plain text emails when doing an Email Test.
* Added: New option: Mailgun region selection - US and EU (US is default to preserve compatibility).
* Fixed: Compatibility with WordPress 3.6+.
* Fixed: Compatibility with WordPress 5.0.
* Fixed: Constants usage is much more reliable now, works correctly on Multisite. Constants are global accross the whole network.
* Fixed: Preserve multipart emails when using Sendgrid/Mailgun mailers (were converted to HTML-only).
* Fixed: Security hardening.
* Changed: Prefill Email Test page From field with currently logged in user email.
* Changed: Update libraries: google/apiclient-services, google/auth, phpseclib/phpseclib and their dependecies.
* Changed: Display in debug output cURL version if Gmail mailing failed.
* Changed: Display in debug output OpenSSL version if it exists if Gmail/SMTP mailing failed.
* Changed: Display plugin version in dashboard error notice when emailing failed.
* Changed: Do not allow to send Test Email if mailer not configured properly.
* Changed: Notify in plugin admin area that Gmail doesn't allow to redefine From Name/Email etc.
* Changed: List all constants with descriptions in plugin main file: wp_mail_smtp.php.
* Changed: TGMPA: change descriptions from "Required" to "Recommended" (labels were incorrect).
= 1.3.3 - 2018-07-05 =
* Fixed: Compatibility with other plugins, that are using Google Service or Google Client classes.
* Changed: Optimize code loading.
= 1.3.2 - 2018-06-29 =
* Make sure that other plugins/themes are not conflicting with our TGMPA library.
= 1.3.1 - 2018-06-29 =
* Fixed: Other SMTP: Clear new Debug messages about failed email delivery on next successful email sending.
* Fixed: Introduce conditional autoloader to workaround Gmail PHP 5.5 requirement and its library compatibility issues vs PHP 5.3+ minimum viable plugin version.
= 1.3.0 - 2018-06-28 =
* Added: New option: force From Email rewrite regardless of the current value.
* Added: New option: force From Name rewrite regardless of the current value.
* Added: New option: remove all plugin data on plugin uninstall (when user deletes it).
* Added: Notify site admins in wp-admin area with a notice about last failed email delivery. Cleans up on successful delivery.
* Added: Notify site admins in wp-admin area with a notice about possible compatibility issues with other SMTP and email delivery plugins.
* Added: Improve User Debug Experience when doing Email Test - display helpful description and steps to fix the issue.
* Added: New users: provide default SMTP Port value for new users based on Encryption selection.
* Added: New users: notify about not configured plugin settings.
* Added: New users: Recommend free WPForms Lite plugin for those who don't have it.
* Added: SendGrid/Mailgun: provide support for multipart/alternative types of emails.
* Added: Gmail: new button to remove connection and to connect a new Google account.
* Fixed: Support plugin installation into /mu-plugins/ directory.
* Fixed: SendGrid: required text/plain part of email being the first one - fixes plain text emails not having links.
* Fixed: SendGrid and Mailgun: improperly sending plain text emails in html format.
* Fixed: SMTP Debug output was empty in some cases.
* Fixed: Compatibility with lots of other plugins that use Google Analytics library of different versions.
* Fixed: "client_id is empty" is no more a problem, should be fixed.
* Changed: For SendGrid and Mailgun allow using custom defined attachments names if present. Fallback to file name.
* Changed: Gmail: switch to a wider scope to prevent possible issues in certain circumstances.
* Changed: Remove whitespaces start/end of keys, secrets etc.
* Changed: Improved helpful description tests of various options.
* Changed: Improved plugin autoloading functionality.
= 1.2.5 - 2017-02-05 =
* Fixed: `Return path` can't be turned off.
* Fixed: `Authentication` sometimes can't be turned off.
* Fixed: `Auto TLS` sometimes can't be turned off.
* Fixed: BCC support for Gmail was broken.
* Fixed: Debug output improved to handle SELinux and grsecurity.
* Fixed: Strip slashes from plugin settings (useful for `From Name` option).
* Fixed: Change the way sanitization is done to prevent accidental removal of useful data.
* Fixed: Plugin activation will not overwrite settings back to defaults.
* Fixed: Properly set `Auto TLS` option on plugin activation.
* Fixed: Providers autoloading improved for certain Windows-based installs.
* Fixed: Use the proper path to load translations from plugin's `/languages` directory.
* Changed: Do not autoload on each page request plugin settings from WordPress options table.
* Changed: Do not autoload Pepipost classes unless it's saved as active mailer in settings.
= 1.2.4 - 2017-01-28 =
* Fixed: Improved escaping in debug reporting.
= 1.2.3 - 2017-01-22 =
* Fixed: Gmail tokens were reset after clicking Save Settings.
* Fixed: Slight typo in Gmail success message.
= 1.2.2 - 2017-12-27 =
* Fixed: Correctly handle Mailgun debug message for an incorrect api key.
* Fixed: Fatal error for Gmail and SMTP mailers with Nginx web-server (without Apache at all).
* Changed: Update X-Mailer emails header to show the real sender with a mailer and plugin version.
= 1.2.1 - 2017-12-21 =
* Fixed: Failed SMTP connections generate fatal errors.
= 1.2.0 - 2017-12-21 =
* Fixed: Decrease the factual minimum WordPress version from 3.9 to 3.6.
* Changed: Improve debug output for all mail providers.
= 1.1.0 - 2017-12-18 =
* Added: New option "Auto TLS" for SMTP mailer. Default is enabled. Migration routine for all sites.
* Changed: Improve debug output - clear styles and context-aware content.
* Changed: Better exceptions handling for Google authentication process.
* Changed: Do not sanitize passwords, api keys etc - as they may contain special characters in certain order and sanitization will break those values.
* Changed: Improve wording of some helpful texts inside plugin admin area.
* Fixed: Do not include certain files in dependency libraries that are not used by Google mailer. This should stop flagging plugin by Wordfence and VaultPress.
* Fixed: Constants usage is working now, to define the SMTP password, for example.
* Fixed: Notice for default mailer.
= 1.0.2 - 2017-12-12 =
* Fixed: PHPMailer using incorrect SMTPSecure value.
= 1.0.1 - 2017-12-12 =
* Fixed: Global POST processing conflict.
= 1.0.0 - 2017-12-12 =
* Added: Automatic migration tool to move options from older storage format to a new one.
* Added: Added Gmail & G Suite email provider integration - without your email and password.
* Added: Added SendGrid email provider integration - using the API key only.
* Added: Added Mailgun email provider integration - using the API key and configured domain only.
* Added: New compatibility mode - for PHP 5.2 old plugin will be loaded, for PHP 5.3 and higher - new version of admin area and new functionality.
* Changed: The new look of the admin area.
* Changed: SMTP password field now has "password" type.
* Changed: SMTP password field does not display real password at all when using constants in `wp-config.php` to define it.
* Changed: Escape properly all translations.
* Changed: More helpful test email content (with a mailer name).

View File

@ -0,0 +1,891 @@
<?php
namespace WPMailSMTP\Admin;
use WPMailSMTP\WP;
use WPMailSMTP\Options;
/**
* Class Area registers and process all wp-admin display functionality.
*
* @since 1.0.0
*/
class Area {
/**
* @since 1.0.0
*
* @var string Slug of the admin area page.
*/
const SLUG = 'wp-mail-smtp';
/**
* @since 1.0.0
*
* @var string Admin page unique hook.
*/
public $hook;
/**
* @since 1.0.0
*
* @var PageAbstract[]
*/
private $pages;
/**
* @since 1.5.0
*
* @var array List of official registered pages.
*/
public static $pages_registered = array( 'general', 'logs', 'about' );
/**
* Area constructor.
*
* @since 1.0.0
*/
public function __construct() {
$this->hooks();
}
/**
* Assign all hooks to proper places.
*
* @since 1.0.0
*/
protected function hooks() {
// Add the Settings link to a plugin on Plugins page.
add_filter( 'plugin_action_links', array( $this, 'add_plugin_action_link' ), 10, 2 );
// Add the options page.
add_action( 'admin_menu', array( $this, 'add_admin_options_page' ) );
// Admin footer text.
add_filter( 'admin_footer_text', array( $this, 'get_admin_footer' ), 1, 2 );
// Enqueue admin area scripts and styles.
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );
// Process the admin page forms actions.
add_action( 'admin_init', array( $this, 'process_actions' ) );
// Display custom notices based on the error/success codes.
add_action( 'admin_init', array( $this, 'display_custom_auth_notices' ) );
// Display notice instructing the user to complete plugin setup.
add_action( 'admin_init', array( $this, 'display_setup_notice' ) );
// Outputs the plugin admin header.
add_action( 'in_admin_header', array( $this, 'display_admin_header' ), 100 );
// Hide all unrelated to the plugin notices on the plugin admin pages.
add_action( 'admin_print_scripts', array( $this, 'hide_unrelated_notices' ) );
// Process all AJAX requests.
add_action( 'wp_ajax_wp_mail_smtp_ajax', array( $this, 'process_ajax' ) );
}
/**
* Display custom notices based on the error/success codes.
*
* @since 1.0.0
*/
public function display_custom_auth_notices() {
$error = isset( $_GET['error'] ) ? sanitize_key( $_GET['error'] ) : ''; // phpcs:ignore
$success = isset( $_GET['success'] ) ? sanitize_key( $_GET['success'] ) : ''; // phpcs:ignore
if ( empty( $error ) && empty( $success ) ) {
return;
}
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
switch ( $error ) {
case 'google_access_denied':
WP::add_admin_notice(
/* translators: %s - error code, returned by Google API. */
sprintf( esc_html__( 'There was an error while processing the authentication request: %s. Please try again.', 'wp-mail-smtp' ), '<code>' . $error . '</code>' ),
WP::ADMIN_NOTICE_ERROR
);
break;
case 'google_no_code_scope':
case 'microsoft_no_code':
WP::add_admin_notice(
esc_html__( 'There was an error while processing the authentication request. Please try again.', 'wp-mail-smtp' ),
WP::ADMIN_NOTICE_ERROR
);
break;
case 'google_no_clients':
WP::add_admin_notice(
esc_html__( 'There was an error while processing the authentication request. Please make sure that you have Client ID and Client Secret both valid and saved.', 'wp-mail-smtp' ),
WP::ADMIN_NOTICE_ERROR
);
break;
}
switch ( $success ) {
case 'google_site_linked':
WP::add_admin_notice(
esc_html__( 'You have successfully linked the current site with your Google API project. Now you can start sending emails through Gmail.', 'wp-mail-smtp' ),
WP::ADMIN_NOTICE_SUCCESS
);
break;
case 'microsoft_site_linked':
WP::add_admin_notice(
esc_html__( 'You have successfully linked the current site with your Microsoft API project. Now you can start sending emails through Outlook.', 'wp-mail-smtp' ),
WP::ADMIN_NOTICE_SUCCESS
);
break;
}
}
/**
* Display notice instructing the user to complete plugin setup.
*
* @since 1.3.0
*/
public function display_setup_notice() {
// Bail if we're not on a plugin page.
if ( ! $this->is_admin_page( 'general' ) ) {
return;
}
$default_options = wp_json_encode( Options::get_defaults() );
$current_options = wp_json_encode( Options::init()->get_all() );
// Check if the current settings are the same as the default settings.
if ( $current_options !== $default_options ) {
return;
}
// Display notice informing user further action is needed.
WP::add_admin_notice(
sprintf(
wp_kses(
/* translators: %s - Mailer anchor link. */
__( 'Thanks for using WP Mail SMTP! To complete the plugin setup and start sending emails, <strong>please select and configure your <a href="%s">Mailer</a></strong>.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
),
'strong' => array(),
)
),
wp_mail_smtp()->get_admin()->get_admin_page_url( self::SLUG . '#wp-mail-smtp-setting-row-mailer' )
),
WP::ADMIN_NOTICE_INFO
);
}
/**
* Add admin area menu item.
*
* @since 1.0.0
* @since 1.5.0 Moved the menu to the top level. Added several more pages.
*/
public function add_admin_options_page() {
$this->hook = \add_menu_page(
\esc_html__( 'WP Mail SMTP', 'wp-mail-smtp' ),
\esc_html__( 'WP Mail SMTP', 'wp-mail-smtp' ),
'manage_options',
self::SLUG,
array( $this, 'display' ),
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9IiM5ZWEzYTgiIHdpZHRoPSI2NCIgaGVpZ2h0PSI2NCIgdmlld0JveD0iMCAwIDQzIDM0Ij48cGF0aCBkPSJNMC4wMDcsMy41ODVWMjAuNDIxcTAsMy41ODYsMy43NTEsMy41ODVMMjAsMjRWMTlIMzBWMTQuMDE0bDAuOTkxLTFMMzQsMTNWMy41ODVRMzQsMCwzMC4yNDksMEgzLjc1OFEwLjAwNywwLC4wMDcsMy41ODVoMFpNMy41MjQsNi4xNTdhMS40OSwxLjQ5LDAsMCwxLS41MDgtMC45MzUsMS41ODEsMS41ODEsMCwwLDEsLjI3NC0xLjIwOCwxLjQ0OSwxLjQ0OSwwLDAsMSwxLjA5NC0uNjYzLDEuNzU2LDEuNzU2LDAsMCwxLDEuMjUuMzEybDExLjQwOSw3LjcxNkwyOC4zNzQsMy42NjNhMS45NiwxLjk2LDAsMCwxLDEuMjg5LS4zMTIsMS41NDYsMS41NDYsMCwwLDEsMS4wOTQuNjYzLDEuNCwxLjQsMCwwLDEsLjI3MywxLjIwOCwxLjY3LDEuNjcsMCwwLDEtLjU0Ny45MzVMMTcuMDQzLDE3LjIyNVoiLz48cGF0aCBkPSJNMjIsMjhIMzJsLTAuMDA5LDQuNjI0YTEuMTI2LDEuMTI2LDAsMCwwLDEuOTIyLjhsOC4yNS04LjIzNmExLjEyNiwxLjEyNiwwLDAsMCwwLTEuNTk0bC04LjI1LTguMjQxYTEuMTI2LDEuMTI2LDAsMCwwLTEuOTIyLjh2NC44NjZMMjIsMjF2N1oiLz48L3N2Zz4=',
98
);
\add_submenu_page(
self::SLUG,
$this->get_current_tab_title() . ' &lsaquo; ' . \esc_html__( 'Settings', 'wp-mail-smtp' ),
\esc_html__( 'Settings', 'wp-mail-smtp' ),
'manage_options',
self::SLUG,
array( $this, 'display' )
);
\add_submenu_page(
self::SLUG,
\esc_html__( 'Email Log', 'wp-mail-smtp' ),
\esc_html__( 'Email Log', 'wp-mail-smtp' ),
'manage_options',
self::SLUG . '-logs',
array( $this, 'display' )
);
\add_submenu_page(
self::SLUG,
\esc_html__( 'About Us', 'wp-mail-smtp' ),
\esc_html__( 'About Us', 'wp-mail-smtp' ),
'manage_options',
self::SLUG . '-about',
array( $this, 'display' )
);
}
/**
* Enqueue admin area scripts and styles.
*
* @since 1.0.0
* @since 1.5.0 Added new assets for new pages.
* @since 1.7.0 Added jQuery Confirm library css/js files.
*
* @param string $hook
*/
public function enqueue_assets( $hook ) {
if ( strpos( $hook, self::SLUG ) === false ) {
return;
}
// General styles and js.
\wp_enqueue_style(
'wp-mail-smtp-admin',
\wp_mail_smtp()->assets_url . '/css/smtp-admin.min.css',
false,
WPMS_PLUGIN_VER
);
\wp_enqueue_script(
'wp-mail-smtp-admin',
\wp_mail_smtp()->assets_url . '/js/smtp-admin' . WP::asset_min() . '.js',
array( 'jquery' ),
WPMS_PLUGIN_VER,
false
);
\wp_localize_script(
'wp-mail-smtp-admin',
'wp_mail_smtp',
array(
'text_provider_remove' => esc_html__( 'Are you sure you want to reset the current provider connection? You will need to immediately create a new one to be able to send emails.', 'wp-mail-smtp' ),
'text_settings_not_saved' => esc_html__( 'Changes that you made to the settings are not saved!', 'wp-mail-smtp' ),
'education' => array(
'upgrade_icon_lock' => '<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="lock" class="svg-inline--fa fa-lock fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M400 224h-24v-72C376 68.2 307.8 0 224 0S72 68.2 72 152v72H48c-26.5 0-48 21.5-48 48v192c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V272c0-26.5-21.5-48-48-48zm-104 0H152v-72c0-39.7 32.3-72 72-72s72 32.3 72 72v72z"></path></svg>',
'upgrade_title' => esc_html__( '%name% is a PRO Feature', 'wp-mail-smtp' ),
'upgrade_button' => esc_html__( 'Upgrade to Pro', 'wp-mail-smtp' ),
'upgrade_url' => 'https://wpmailsmtp.com/lite-upgrade/?discount=SMTPLITEUPGRADE&utm_source=WordPress&utm_medium=plugin-settings&utm_campaign=liteplugin',
'upgrade_bonus' => '<p>' .
wp_kses(
__( '<strong>Bonus:</strong> WP Mail SMTP users get <span>20% off</span> regular price,<br>applied at checkout.', 'wp-mail-smtp' ),
array(
'strong' => true,
'span' => true,
'br' => true,
)
)
. '</p>',
'upgrade_doc' => '<a href="https://wpmailsmtp.com/docs/how-to-upgrade-wp-mail-smtp-to-pro-version/?utm_source=WordPress&amp;utm_medium=link&amp;utm_campaign=liteplugin" target="_blank" rel="noopener noreferrer" class="already-purchased">
' . esc_html__( 'Already purchased?', 'wp-mail-smtp' ) . '
</a>',
),
)
);
/*
* jQuery Confirm library v3.3.4.
*/
\wp_enqueue_style(
'wp-mail-smtp-admin-jconfirm',
\wp_mail_smtp()->assets_url . '/libs/jquery-confirm.min.css',
array( 'wp-mail-smtp-admin' ),
'3.3.4'
);
\wp_enqueue_script(
'wp-mail-smtp-admin-jconfirm',
\wp_mail_smtp()->assets_url . '/libs/jquery-confirm.min.js',
array( 'wp-mail-smtp-admin' ),
'3.3.4',
false
);
/*
* Logs page.
*/
if ( $this->is_admin_page( 'logs' ) ) {
\wp_enqueue_style(
'wp-mail-smtp-admin-logs',
apply_filters( 'wp_mail_smtp_admin_enqueue_assets_logs_css', '' ),
array( 'wp-mail-smtp-admin' ),
WPMS_PLUGIN_VER
);
\wp_enqueue_script(
'wp-mail-smtp-admin-logs',
apply_filters( 'wp_mail_smtp_admin_enqueue_assets_logs_js', '' ),
array( 'wp-mail-smtp-admin' ),
WPMS_PLUGIN_VER,
false
);
}
/*
* About page.
*/
if ( $this->is_admin_page( 'about' ) ) {
\wp_enqueue_style(
'wp-mail-smtp-admin-about',
\wp_mail_smtp()->assets_url . '/css/smtp-about.min.css',
array( 'wp-mail-smtp-admin' ),
WPMS_PLUGIN_VER
);
\wp_enqueue_script(
'wp-mail-smtp-admin-about',
\wp_mail_smtp()->assets_url . '/js/smtp-about' . WP::asset_min() . '.js',
array( 'wp-mail-smtp-admin' ),
'0.7.2',
false
);
$settings = array(
'ajax_url' => \admin_url( 'admin-ajax.php' ),
'nonce' => \wp_create_nonce( 'wp-mail-smtp-about' ),
// Strings.
'plugin_activate' => \esc_html__( 'Activate', 'wp-mail-smtp' ),
'plugin_activated' => \esc_html__( 'Activated', 'wp-mail-smtp' ),
'plugin_active' => \esc_html__( 'Active', 'wp-mail-smtp' ),
'plugin_inactive' => \esc_html__( 'Inactive', 'wp-mail-smtp' ),
'plugin_processing' => \esc_html__( 'Processing...', 'wp-mail-smtp' ),
'plugin_install_error' => \esc_html__( 'Could not install a plugin. Please download from WordPress.org and install manually.', 'wp-mail-smtp' ),
'plugin_install_activate_btn' => \esc_html__( 'Install and Activate', 'wp-mail-smtp' ),
'plugin_activate_btn' => \esc_html__( 'Activate', 'wp-mail-smtp' ),
'plugin_download_btn' => \esc_html__( 'Download', 'wp-mail-smtp' ),
);
\wp_localize_script(
'wp-mail-smtp-admin-about',
'wp_mail_smtp_about',
$settings
);
\wp_enqueue_script(
'wp-mail-smtp-admin-about-matchheight',
\wp_mail_smtp()->assets_url . '/js/jquery.matchHeight.min.js',
array( 'wp-mail-smtp-admin' ),
'0.7.2',
false
);
}
do_action( 'wp_mail_smtp_admin_area_enqueue_assets', $hook );
}
/**
* Outputs the plugin admin header.
*
* @since 1.0.0
*/
public function display_admin_header() {
// Bail if we're not on a plugin page.
if ( ! $this->is_admin_page() ) {
return;
}
?>
<div id="wp-mail-smtp-header-temp"></div>
<div id="wp-mail-smtp-header">
<!--suppress HtmlUnknownTarget -->
<img class="wp-mail-smtp-header-logo" src="<?php echo esc_url( wp_mail_smtp()->assets_url ); ?>/images/logo.svg" alt="WP Mail SMTP"/>
</div>
<?php
}
/**
* Display a text to ask users to review the plugin on WP.org.
*
* @since 1.0.0
*
* @param string $text
*
* @return string
*/
public function get_admin_footer( $text ) {
if ( $this->is_admin_page() ) {
$url = 'https://wordpress.org/support/plugin/wp-mail-smtp/reviews/?filter=5#new-post';
$text = sprintf(
wp_kses(
/* translators: %1$s - WP.org link; %2$s - same WP.org link. */
__( 'Please rate <strong>WP Mail SMTP</strong> <a href="%1$s" target="_blank" rel="noopener noreferrer">&#9733;&#9733;&#9733;&#9733;&#9733;</a> on <a href="%2$s" target="_blank" rel="noopener noreferrer">WordPress.org</a> to help us spread the word. Thank you from the WP Mail SMTP team!', 'wp-mail-smtp' ),
array(
'strong' => array(),
'a' => array(
'href' => array(),
'target' => array(),
'rel' => array(),
),
)
),
$url,
$url
);
}
return $text;
}
/**
* Display content of the admin area page.
*
* @since 1.0.0
* @since 1.5.0 Rewrite to distinguish between General tabs and separate pages.
*/
public function display() {
// Bail if we're not on a plugin page.
if ( ! $this->is_admin_page() ) {
return;
}
$page = ! empty( $_GET['page'] ) ? \sanitize_key( $_GET['page'] ) : ''; // phpcs:ignore
?>
<div class="wrap" id="wp-mail-smtp">
<?php
switch ( $page ) {
case self::SLUG:
?>
<div class="wp-mail-smtp-page wp-mail-smtp-page-general wp-mail-smtp-tab-<?php echo esc_attr( $this->get_current_tab() ); ?>">
<?php $this->display_tabs(); ?>
</div>
<?php
break;
case self::SLUG . '-logs':
$logs_class = apply_filters( 'wp_mail_smtp_admin_display_get_logs_fqcn', '\WPMailSMTP\Admin\Pages\Logs' );
/** @var \WPMailSMTP\Admin\PageAbstract $logs */
$logs = new $logs_class();
$is_archive = wp_mail_smtp()->is_pro() && wp_mail_smtp()->pro->get_logs()->is_archive();
?>
<div class="wp-mail-smtp-page wp-mail-smtp-page-logs <?php echo $is_archive ? 'wp-mail-smtp-page-logs-archive' : 'wp-mail-smtp-page-logs-single'; ?>">
<?php $logs->display(); ?>
</div>
<?php
break;
case self::SLUG . '-about':
$about = new Pages\About();
?>
<div class="wp-mail-smtp-page wp-mail-smtp-page-about wp-mail-smtp-tab-about-<?php echo \esc_attr( $about->get_current_tab() ); ?>">
<?php $about->display(); ?>
</div>
<?php
break;
}
?>
</div>
<?php
}
/**
* Display General page tabs.
*
* @since 1.5.0
*/
protected function display_tabs() {
?>
<div class="wp-mail-smtp-page-title">
<?php
foreach ( $this->get_pages() as $page_slug => $page ) :
$label = $page->get_label();
if ( empty( $label ) ) {
continue;
}
$class = $page_slug === $this->get_current_tab() ? 'active' : '';
?>
<a href="<?php echo esc_url( $page->get_link() ); ?>" class="tab <?php echo esc_attr( $class ); ?>">
<?php echo esc_html( $label ); ?>
</a>
<?php endforeach; ?>
</div>
<div class="wp-mail-smtp-page-content">
<h1 class="screen-reader-text">
<?php echo esc_html( $this->get_current_tab_title() ); ?>
</h1>
<?php $this->display_current_tab_content(); ?>
</div>
<?php
}
/**
* Get the current tab content.
*
* @since 1.0.0
*/
public function display_current_tab_content() {
$pages = $this->get_pages();
if ( ! array_key_exists( $this->get_current_tab(), $pages ) ) {
return;
}
$pages[ $this->get_current_tab() ]->display();
}
/**
* Get the current admin area tab.
*
* @since 1.0.0
*
* @return string
*/
protected function get_current_tab() {
$current = '';
if ( $this->is_admin_page( 'general' ) ) {
$current = ! empty( $_GET['tab'] ) ? sanitize_key( $_GET['tab'] ) : 'settings'; // phpcs:ignore
}
return $current;
}
/**
* Get the array of default registered tabs for General page admin area.
*
* @since 1.0.0
*
* @return \WPMailSMTP\Admin\PageAbstract[]
*/
public function get_pages() {
if ( empty( $this->pages ) ) {
$this->pages = array(
'settings' => new Pages\SettingsTab(),
'test' => new Pages\TestTab(),
'logs' => new Pages\LogsTab(),
'control' => new Pages\ControlTab(),
'misc' => new Pages\MiscTab(),
'auth' => new Pages\AuthTab(),
);
}
return apply_filters( 'wp_mail_smtp_admin_get_pages', $this->pages );
}
/**
* Get the current tab title.
*
* @since 1.0.0
*
* @return string
*/
public function get_current_tab_title() {
$pages = $this->get_pages();
if ( ! array_key_exists( $this->get_current_tab(), $pages ) ) {
return '';
}
return $pages[ $this->get_current_tab() ]->get_title();
}
/**
* Check whether we are on an admin page.
*
* @since 1.0.0
* @since 1.5.0 Added support for new pages.
*
* @param array|string $slug ID(s) of a plugin page. Possible values: 'general', 'logs', 'about' or array of them.
*
* @return bool
*/
public function is_admin_page( $slug = array() ) {
$cur_page = isset( $_GET['page'] ) ? sanitize_key( $_GET['page'] ) : ''; // phpcs:ignore
$check = self::SLUG;
$pages_equal = false;
if ( is_string( $slug ) ) {
$slug = sanitize_key( $slug );
if (
in_array( $slug, self::$pages_registered, true ) &&
$slug !== 'general'
) {
$check = self::SLUG . '-' . $slug;
}
$pages_equal = $cur_page === $check;
} elseif ( is_array( $slug ) ) {
if ( empty( $slug ) ) {
$slug = array_map( function ( $v ) {
if ( $v === 'general' ) {
return Area::SLUG;
}
return Area::SLUG . '-' . $v;
}, self::$pages_registered );
} else {
$slug = array_map( function ( $v ) {
if ( $v === 'general' ) {
return Area::SLUG;
}
return Area::SLUG . '-' . sanitize_key( $v );
}, $slug );
}
$pages_equal = in_array( $cur_page, $slug, true );
}
return is_admin() && $pages_equal;
}
/**
* Give ability to use either admin area option or a filter to hide error notices about failed email delivery.
* Filter has higher priority and overrides an option.
*
* @since 1.6.0
*
* @return bool
*/
public function is_error_delivery_notice_enabled() {
$is_hard_enabled = (bool) apply_filters( 'wp_mail_smtp_admin_is_error_delivery_notice_enabled', true );
// If someone changed the value to false using a filter - disable completely.
if ( ! $is_hard_enabled ) {
return false;
}
return ! (bool) Options::init()->get( 'general', 'email_delivery_errors_hidden' );
}
/**
* All possible plugin forms manipulation will be done here.
*
* @since 1.0.0
*/
public function process_actions() {
// Bail if we're not on a plugin General page.
if ( ! $this->is_admin_page( 'general' ) ) {
return;
}
$pages = $this->get_pages();
// Allow to process only own tabs.
if ( ! array_key_exists( $this->get_current_tab(), $pages ) ) {
return;
}
// Process POST only if it exists.
if ( ! empty( $_POST ) ) {
if ( ! empty( $_POST['wp-mail-smtp'] ) ) {
$post = $_POST['wp-mail-smtp'];
} else {
$post = array();
}
$pages[ $this->get_current_tab() ]->process_post( $post );
}
// This won't do anything for most pages.
// Works for plugin page only, when GET params are allowed.
$pages[ $this->get_current_tab() ]->process_auth();
}
/**
* Process all AJAX requests.
*
* @since 1.3.0
* @since 1.5.0 Added tasks to process plugins management.
*/
public function process_ajax() {
$data = array();
// Only admins can fire these ajax requests.
if ( ! current_user_can( 'manage_options' ) ) {
wp_send_json_error( $data );
}
if ( empty( $_POST['task'] ) ) { // phpcs:ignore
wp_send_json_error( $data );
}
$task = sanitize_key( $_POST['task'] ); // phpcs:ignore
switch ( $task ) {
case 'pro_banner_dismiss':
update_user_meta( get_current_user_id(), 'wp_mail_smtp_pro_banner_dismissed', true );
$data['message'] = esc_html__( 'WP Mail SMTP Pro related message was successfully dismissed.', 'wp-mail-smtp' );
break;
case 'about_plugin_install':
Pages\About::ajax_plugin_install();
break;
case 'about_plugin_activate':
Pages\About::ajax_plugin_activate();
break;
case 'notice_dismiss':
$notice = sanitize_key( $_POST['notice'] ); // phpcs:ignore
$mailer = sanitize_key( $_POST['mailer'] ); // phpcs:ignore
if ( empty( $notice ) || empty( $mailer ) ) {
break;
}
update_user_meta( get_current_user_id(), "wp_mail_smtp_notice_{$notice}_for_{$mailer}_dismissed", true );
$data['message'] = esc_html__( 'Educational notice for this mailer was successfully dismissed.', 'wp-mail-smtp' );
break;
default:
// Allow custom tasks data processing being added here.
$data = apply_filters( 'wp_mail_smtp_admin_process_ajax_' . $task . '_data', $data );
}
// Final ability to rewrite all the data, just in case.
$data = (array) apply_filters( 'wp_mail_smtp_admin_process_ajax_data', $data, $task );
if ( empty( $data ) ) {
wp_send_json_error( $data );
}
wp_send_json_success( $data );
}
/**
* Add a link to Settings page of a plugin on Plugins page.
*
* @since 1.0.0
* @since 1.5.0 Added a link to Email Log.
*
* @param array $links
* @param string $file
*
* @return mixed
*/
public function add_plugin_action_link( $links, $file ) {
// Will target both pro and lite version of a plugin.
if ( strpos( $file, 'wp-mail-smtp' ) === false ) {
return $links;
}
$settings_link = '<a href="' . esc_url( $this->get_admin_page_url() ) . '">' . esc_html__( 'Settings', 'wp-mail-smtp' ) . '</a>';
$logs_link = '<a href="' . esc_url( $this->get_admin_page_url( self::SLUG . '-logs' ) ) . '">' . esc_html__( 'Email Log', 'wp-mail-smtp' ) . '</a>';
array_unshift( $links, $settings_link, $logs_link );
return $links;
}
/**
* Get plugin admin area page URL.
*
* @since 1.0.0
* @since 1.5.0 URL is changed to support the top level position of the plugin admin area.
*
* @param string $page
*
* @return string
*/
public function get_admin_page_url( $page = '' ) {
if ( empty( $page ) ) {
$page = self::SLUG;
}
return add_query_arg(
'page',
$page,
admin_url( 'admin.php' )
);
}
/**
* Remove all non-WP Mail SMTP plugin notices from plugin pages.
*
* @since 1.0.0
*/
public function hide_unrelated_notices() {
// Bail if we're not on our screen or page.
if ( empty( $_REQUEST['page'] ) || strpos( $_REQUEST['page'], self::SLUG ) === false ) {
return;
}
global $wp_filter;
if ( ! empty( $wp_filter['user_admin_notices']->callbacks ) && is_array( $wp_filter['user_admin_notices']->callbacks ) ) {
foreach ( $wp_filter['user_admin_notices']->callbacks as $priority => $hooks ) {
foreach ( $hooks as $name => $arr ) {
if ( is_object( $arr['function'] ) && $arr['function'] instanceof \Closure ) {
unset( $wp_filter['user_admin_notices']->callbacks[ $priority ][ $name ] );
continue;
}
if ( ! empty( $arr['function'][0] ) && is_object( $arr['function'][0] ) && strpos( strtolower( get_class( $arr['function'][0] ) ), 'wpmailsmtp' ) !== false ) {
continue;
}
if ( ! empty( $name ) && strpos( strtolower( $name ), 'wpmailsmtp' ) === false ) {
unset( $wp_filter['user_admin_notices']->callbacks[ $priority ][ $name ] );
}
}
}
}
if ( ! empty( $wp_filter['admin_notices']->callbacks ) && is_array( $wp_filter['admin_notices']->callbacks ) ) {
foreach ( $wp_filter['admin_notices']->callbacks as $priority => $hooks ) {
foreach ( $hooks as $name => $arr ) {
if ( is_object( $arr['function'] ) && $arr['function'] instanceof \Closure ) {
unset( $wp_filter['admin_notices']->callbacks[ $priority ][ $name ] );
continue;
}
if ( ! empty( $arr['function'][0] ) && is_object( $arr['function'][0] ) && strpos( strtolower( get_class( $arr['function'][0] ) ), 'wpmailsmtp' ) !== false ) {
continue;
}
if ( ! empty( $name ) && strpos( strtolower( $name ), 'wpmailsmtp' ) === false ) {
unset( $wp_filter['admin_notices']->callbacks[ $priority ][ $name ] );
}
}
}
}
if ( ! empty( $wp_filter['all_admin_notices']->callbacks ) && is_array( $wp_filter['all_admin_notices']->callbacks ) ) {
foreach ( $wp_filter['all_admin_notices']->callbacks as $priority => $hooks ) {
foreach ( $hooks as $name => $arr ) {
if ( is_object( $arr['function'] ) && $arr['function'] instanceof \Closure ) {
unset( $wp_filter['all_admin_notices']->callbacks[ $priority ][ $name ] );
continue;
}
if ( ! empty( $arr['function'][0] ) && is_object( $arr['function'][0] ) && strpos( strtolower( get_class( $arr['function'][0] ) ), 'wpmailsmtp' ) !== false ) {
continue;
}
if ( ! empty( $name ) && strpos( strtolower( $name ), 'wpmailsmtp' ) === false ) {
unset( $wp_filter['all_admin_notices']->callbacks[ $priority ][ $name ] );
}
}
}
}
}
}

View File

@ -0,0 +1,87 @@
<?php
namespace WPMailSMTP\Admin;
/**
* Class PageAbstract.
*
* @since 1.0.0
*/
abstract class PageAbstract implements PageInterface {
/**
* @var string Slug of a tab.
*/
protected $slug;
/**
* @inheritdoc
*/
public function get_link() {
return esc_url(
add_query_arg(
'tab',
$this->slug,
admin_url( 'admin.php?page=' . Area::SLUG )
)
);
}
/**
* Process tab form submission ($_POST ).
*
* @since 1.0.0
*
* @param array $data $_POST data specific for the plugin.
*/
public function process_post( $data ) {
}
/**
* Process tab & mailer specific Auth actions.
*
* @since 1.0.0
*/
public function process_auth() {
}
/**
* Print the nonce field for a specific tab.
*
* @since 1.0.0
*/
public function wp_nonce_field() {
wp_nonce_field( Area::SLUG . '-' . $this->slug );
}
/**
* Make sure that a user was referred from plugin admin page.
* To avoid security problems.
*
* @since 1.0.0
*/
public function check_admin_referer() {
check_admin_referer( Area::SLUG . '-' . $this->slug );
}
/**
* Save button to be reused on other tabs.
*
* @since 1.5.0
*/
public function display_save_btn() {
?>
<p class="wp-mail-smtp-submit">
<button type="submit" class="wp-mail-smtp-btn wp-mail-smtp-btn-md wp-mail-smtp-btn-orange">
<?php esc_html_e( 'Save Settings', 'wp-mail-smtp' ); ?>
</button>
</p>
<?php
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace WPMailSMTP\Admin;
/**
* Class PageInterface defines what should be in each page class.
*
* @since 1.0.0
*/
interface PageInterface {
/**
* URL to a tab.
*
* @since 1.0.0
*
* @return string
*/
public function get_link();
/**
* Title of a tab.
*
* @since 1.0.0
*
* @return string
*/
public function get_title();
/**
* Link label of a tab.
*
* @since 1.0.0
*
* @return string
*/
public function get_label();
/**
* Tab content.
*
* @since 1.0.0
*/
public function display();
}

View File

@ -0,0 +1,717 @@
<?php
namespace WPMailSMTP\Admin\Pages;
use WPMailSMTP\Admin\Area;
use WPMailSMTP\Admin\PageAbstract;
use WPMailSMTP\Admin\PluginsInstallSkin;
use WPMailSMTP\Admin\PluginsInstallUpgrader;
/**
* Class About to display a page with About Us and Versus content.
*
* @since 1.5.0
*/
class About extends PageAbstract {
/**
* @since 1.5.0
*
* @var string Slug of a page.
*/
protected $slug = 'about';
/**
* @since 1.5.0
*
* @var array List of supported tabs.
*/
protected $tabs = array( 'about', 'versus' );
/**
* Get the page/tab link.
*
* @since 1.5.0
*
* @param string $tab Tab to generate a link to.
*
* @return string
*/
public function get_link( $tab = '' ) {
return add_query_arg(
'tab',
$this->get_defined_tab( $tab ),
admin_url( 'admin.php?page=' . Area::SLUG . '-' . $this->slug )
);
}
/**
* Get the current tab.
*
* @since 1.5.0
*
* @return string Current tab.
*/
public function get_current_tab() {
if ( empty( $_GET['tab'] ) ) { // phpcs:ignore
return $this->slug;
}
return $this->get_defined_tab( $_GET['tab'] ); // phpcs:ignore
}
/**
* Get the defined or default tab.
*
* @since 1.5.0
*
* @param string $tab Tab to check.
*
* @return string Defined tab. Fallback to default one if it doesn't exist.
*/
protected function get_defined_tab( $tab ) {
$tab = \sanitize_key( $tab );
return \in_array( $tab, $this->tabs, true ) ? $tab : $this->slug;
}
/**
* Get label for a tab.
* Process only those that exists.
* Defaults to "About Us".
*
* @since 1.5.0
*
* @param string $tab Tab to get label for.
*
* @return string
*/
public function get_label( $tab = '' ) {
switch ( $this->get_defined_tab( $tab ) ) {
case 'versus':
$label = \sprintf(
/* translators: %s - plugin current license type. */
\esc_html__( '%s vs Pro', 'wp-mail-smtp' ),
\ucfirst( \wp_mail_smtp()->get_license_type() )
);
break;
case 'about':
default:
$label = \esc_html__( 'About Us', 'wp-mail-smtp' );
break;
}
return $label;
}
/**
* @inheritdoc
*/
public function get_title() {
return $this->get_label( $this->get_current_tab() );
}
/**
* Display About page content based on the current tab.
*
* @since 1.5.0
*/
public function display() {
?>
<div class="wp-mail-smtp-page-title">
<a href="<?php echo \esc_url( $this->get_link() ); ?>" class="tab <?php echo $this->get_current_tab() === 'about' ? 'active' : ''; ?>">
<?php echo \esc_html( $this->get_label( 'about' ) ); ?>
</a>
<?php if ( \wp_mail_smtp()->get_license_type() === 'lite' ) : ?>
<a href="<?php echo \esc_url( $this->get_link( 'versus' ) ); ?>" class="tab <?php echo $this->get_current_tab() === 'versus' ? 'active' : ''; ?>">
<?php echo \esc_html( $this->get_label( 'versus' ) ); ?>
</a>
<?php endif; ?>
</div>
<div class="wp-mail-smtp-page-content">
<h1 class="screen-reader-text">
<?php echo \esc_html( $this->get_label( $this->get_current_tab() ) ); ?>
</h1>
<?php
$callback = 'display_' . $this->get_current_tab();
if ( \method_exists( $this, $callback ) ) {
$this->{$callback}();
} else {
$this->display_about();
}
?>
</div>
<?php
}
/**
* Display an "About Us" tab content.
*
* @since 1.5.0
*/
protected function display_about() {
?>
<div class="wp-mail-smtp-admin-about-section wp-mail-smtp-admin-columns">
<div class="wp-mail-smtp-admin-column-60">
<h3>
<?php esc_html_e( 'Hello and welcome to WP Mail SMTP, the easiest and most popular WordPress SMTP plugin. We build software that helps your site reliably deliver emails every time.', 'wp-mail-smtp' ); ?>
</h3>
<p>
<?php esc_html_e( 'Email deliverability has been a well-documented problem for all WordPress websites. However as WPForms grew, we became more aware of this painful issue that affects our users and the larger WordPress community. So we decided to solve this problem and make a solution that\'s beginner friendly.', 'wp-mail-smtp' ); ?>
</p>
<p>
<?php esc_html_e( 'Our goal is to make reliable email deliverability easy for WordPress.', 'wp-mail-smtp' ); ?>
</p>
<p>
<?php
printf(
wp_kses(
/* translators: %1$s - WPForms URL, %2$s - WPBeginner URL, %3$s - OptinMonster URL, %4$s - MonsterInsights URL, %5$s - RafflePress URL */
__( 'WP Mail SMTP is brought to you by the same team that\'s behind the most user friendly WordPress forms, <a href="%1$s" target="_blank" rel="noopener noreferrer">WPForms</a>, the largest WordPress resource site, <a href="%2$s" target="_blank" rel="noopener noreferrer">WPBeginner</a>, the most popular lead-generation software, <a href="%3$s" target="_blank" rel="noopener noreferrer">OptinMonster</a>, the best WordPress analytics plugin, <a href="%4$s" target="_blank" rel="noopener noreferrer">MonsterInsights</a>, and the most powerful WordPress contest plugin, <a href="%5$s" target="_blank" rel="noopener noreferrer">RafflePress</a>.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'rel' => array(),
'target' => array(),
),
)
),
'https://wpforms.com/?utm_source=wpmailsmtpplugin&utm_medium=pluginaboutpage&utm_campaign=aboutwpmailsmtp',
'https://www.wpbeginner.com/?utm_source=wpmailsmtpplugin&utm_medium=pluginaboutpage&utm_campaign=aboutwpmailsmtp',
'https://optinmonster.com/?utm_source=wpmailsmtpplugin&utm_medium=pluginaboutpage&utm_campaign=aboutwpmailsmtp',
'https://www.monsterinsights.com/?utm_source=wpmailsmtpplugin&utm_medium=pluginaboutpage&utm_campaign=aboutwpmailsmtp',
'https://rafflepress.com/?utm_source=wpmailsmtpplugin&utm_medium=pluginaboutpage&utm_campaign=aboutwpmailsmtp'
);
?>
</p>
<p>
<?php esc_html_e( 'Yup, we know a thing or two about building awesome products that customers love.', 'wp-mail-smtp' ); ?>
</p>
</div>
<div class="wp-mail-smtp-admin-column-40 wp-mail-smtp-admin-column-last">
<figure>
<img src="<?php echo esc_url( wp_mail_smtp()->assets_url . '/images/about/team.jpg' ); ?>" alt="<?php esc_attr_e( 'The WPForms Team photo', 'wp-mail-smtp' ); ?>">
<figcaption>
<?php esc_html_e( 'The WPForms Team', 'wp-mail-smtp' ); ?>
</figcaption>
</figure>
</div>
</div>
<div class="wp-mail-smtp-admin-about-plugins">
<div class="plugins-container">
<?php
foreach ( $this->get_am_plugins() as $key => $plugin ) :
$is_url_external = false;
$data = $this->get_about_plugins_data( $plugin );
if ( isset( $plugin['pro'] ) && \array_key_exists( $plugin['pro']['path'], \get_plugins() ) ) {
$is_url_external = true;
$plugin = $plugin['pro'];
$data = array_merge( $data, $this->get_about_plugins_data( $plugin, true ) );
}
?>
<div class="plugin-container">
<div class="plugin-item">
<div class="details wp-mail-smtp-clear">
<img src="<?php echo \esc_url( $plugin['icon'] ); ?>">
<h5 class="plugin-name">
<?php echo $plugin['name']; ?>
</h5>
<p class="plugin-desc">
<?php echo $plugin['desc']; ?>
</p>
</div>
<div class="actions wp-mail-smtp-clear">
<div class="status">
<strong>
<?php
\printf(
/* translators: %s - status HTML text. */
\esc_html__( 'Status: %s', 'wp-mail-smtp' ),
'<span class="status-label ' . $data['status_class'] . '">' . $data['status_text'] . '</span>'
);
?>
</strong>
</div>
<div class="action-button">
<?php
$go_to_class = '';
if ( $is_url_external && $data['status_class'] === 'status-download' ) {
$go_to_class = 'go_to';
}
?>
<a href="<?php echo \esc_url( $plugin['url'] ); ?>"
class="<?php echo \esc_attr( $data['action_class'] ); ?> <?php echo $go_to_class; ?>"
data-plugin="<?php echo $data['plugin_src']; ?>">
<?php echo $data['action_text']; ?>
</a>
</div>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<?php
}
/**
* Generate all the required CSS classed and labels to be used in rendering.
*
* @since 1.5.0
*
* @param array $plugin
* @param bool $is_pro
*
* @return mixed
*/
protected function get_about_plugins_data( $plugin, $is_pro = false ) {
$data = array();
if ( \array_key_exists( $plugin['path'], \get_plugins() ) ) {
if ( \is_plugin_active( $plugin['path'] ) ) {
// Status text/status.
$data['status_class'] = 'status-active';
$data['status_text'] = \esc_html__( 'Active', 'wp-mail-smtp' );
// Button text/status.
$data['action_class'] = $data['status_class'] . ' button button-secondary disabled';
$data['action_text'] = \esc_html__( 'Activated', 'wp-mail-smtp' );
$data['plugin_src'] = \esc_attr( $plugin['path'] );
} else {
// Status text/status.
$data['status_class'] = 'status-inactive';
$data['status_text'] = \esc_html__( 'Inactive', 'wp-mail-smtp' );
// Button text/status.
$data['action_class'] = $data['status_class'] . ' button button-secondary';
$data['action_text'] = \esc_html__( 'Activate', 'wp-mail-smtp' );
$data['plugin_src'] = \esc_attr( $plugin['path'] );
}
} else {
if ( ! $is_pro ) {
// Doesn't exist, install.
// Status text/status.
$data['status_class'] = 'status-download';
$data['status_text'] = \esc_html__( 'Not Installed', 'wp-mail-smtp' );
// Button text/status.
$data['action_class'] = $data['status_class'] . ' button button-primary';
$data['action_text'] = \esc_html__( 'Install Plugin', 'wp-mail-smtp' );
$data['plugin_src'] = \esc_url( $plugin['url'] );
}
}
return $data;
}
/**
* List of AM plugins that we propose to install.
*
* @since 1.5.0
*
* @return array
*/
private function get_am_plugins() {
$data = array(
'mi' => array(
'path' => 'google-analytics-for-wordpress/googleanalytics.php',
'icon' => \wp_mail_smtp()->assets_url . '/images/about/plugin-mi.png',
'name' => \esc_html__( 'MonsterInsights', 'wp-mail-smtp' ),
'desc' => \esc_html__( 'MonsterInsights makes it “effortless” to properly connect your WordPress site with Google Analytics, so you can start making data-driven decisions to grow your business.', 'wp-mail-smtp' ),
'url' => 'https://downloads.wordpress.org/plugin/google-analytics-for-wordpress.zip',
'pro' => array(
'path' => 'google-analytics-premium/googleanalytics-premium.php',
'icon' => \wp_mail_smtp()->assets_url . '/images/about/plugin-mi.png',
'name' => \esc_html__( 'MonsterInsights Pro', 'wp-mail-smtp' ),
'desc' => \esc_html__( 'MonsterInsights makes it “effortless” to properly connect your WordPress site with Google Analytics, so you can start making data-driven decisions to grow your business.', 'wp-mail-smtp' ),
'url' => 'https://www.monsterinsights.com/?utm_source=WordPress&utm_medium=about&utm_campaign=smtp',
),
),
'om' => array(
'path' => 'optinmonster/optin-monster-wp-api.php',
'icon' => \wp_mail_smtp()->assets_url . '/images/about/plugin-om.png',
'name' => \esc_html__( 'OptinMonster', 'wp-mail-smtp' ),
'desc' => \esc_html__( 'Our high-converting optin forms like Exit-Intent® popups, Fullscreen Welcome Mats, and Scroll boxes help you dramatically boost conversions and get more email subscribers.', 'wp-mail-smtp' ),
'url' => 'https://downloads.wordpress.org/plugin/optinmonster.zip',
),
'wpforms' => array(
'path' => 'wpforms-lite/wpforms.php',
'icon' => \wp_mail_smtp()->assets_url . '/images/about/plugin-wpf.png',
'name' => \esc_html__( 'Contact Forms by WPForms', 'wp-mail-smtp' ),
'desc' => \esc_html__( 'The best WordPress contact form plugin. Drag & Drop online form builder that helps you create beautiful contact forms with just a few clicks.', 'wp-mail-smtp' ),
'url' => 'https://downloads.wordpress.org/plugin/wpforms-lite.zip',
'pro' => array(
'path' => 'wpforms/wpforms.php',
'icon' => \wp_mail_smtp()->assets_url . '/images/about/plugin-wpf.png',
'name' => \esc_html__( 'WPForms Pro', 'wp-mail-smtp' ),
'desc' => \esc_html__( 'The best WordPress contact form plugin. Drag & Drop online form builder that helps you create beautiful contact forms with just a few clicks.', 'wp-mail-smtp' ),
'url' => 'https://wpforms.com/?utm_source=WordPress&utm_medium=about&utm_campaign=smtp',
),
),
'rafflepress' => array(
'path' => 'rafflepress/rafflepress.php',
'icon' => \wp_mail_smtp()->assets_url . '/images/about/plugin-rp.png',
'name' => \esc_html__( 'RafflePress', 'wp-mail-smtp' ),
'desc' => \esc_html__( 'Turn your visitors into brand ambassadors! Easily grow your email list, website traffic, and social media followers with powerful viral giveaways & contests.', 'wp-mail-smtp' ),
'url' => 'https://downloads.wordpress.org/plugin/rafflepress.zip',
'pro' => array(
'path' => 'rafflepress-pro/rafflepress-pro.php',
'icon' => \wp_mail_smtp()->assets_url . '/images/about/plugin-rp.png',
'name' => \esc_html__( 'RafflePress Pro', 'wp-mail-smtp' ),
'desc' => \esc_html__( 'Turn your visitors into brand ambassadors! Easily grow your email list, website traffic, and social media followers with powerful viral giveaways & contests.', 'wp-mail-smtp' ),
'url' => 'https://rafflepress.com/pricing/',
),
),
);
return $data;
}
/**
* Active the given plugin.
*
* @since 1.5.0
*/
public static function ajax_plugin_activate() {
// Run a security check.
\check_ajax_referer( 'wp-mail-smtp-about', 'nonce' );
$error = \esc_html__( 'Could not activate the plugin. Please activate it from the Plugins page.', 'wp-mail-smtp' );
// Check for permissions.
if ( ! \current_user_can( 'activate_plugins' ) ) {
\wp_send_json_error( $error );
}
if ( isset( $_POST['plugin'] ) ) {
$activate = \activate_plugins( $_POST['plugin'] ); // phpcs:ignore
if ( ! \is_wp_error( $activate ) ) {
\wp_send_json_success( esc_html__( 'Plugin activated.', 'wp-mail-smtp' ) );
}
}
\wp_send_json_error( $error );
}
/**
* Install & activate the given plugin.
*
* @since 1.5.0
*/
public static function ajax_plugin_install() {
// Run a security check.
\check_ajax_referer( 'wp-mail-smtp-about', 'nonce' );
$error = \esc_html__( 'Could not install the plugin.', 'wp-mail-smtp' );
// Check for permissions.
if ( ! \current_user_can( 'activate_plugins' ) ) {
\wp_send_json_error( $error );
}
if ( empty( $_POST['plugin'] ) ) {
\wp_send_json_error();
}
// Set the current screen to avoid undefined notices.
\set_current_screen( 'wp-mail-smtp_page_wp-mail-smtp-about' );
// Prepare variables.
$url = \esc_url_raw(
\add_query_arg(
array(
'page' => 'wp-mail-smtp-about',
),
\admin_url( 'admin.php' )
)
);
$creds = \request_filesystem_credentials( $url, '', false, false, null );
// Check for file system permissions.
if ( false === $creds ) {
\wp_send_json_error( $error );
}
if ( ! \WP_Filesystem( $creds ) ) {
\wp_send_json_error( $error );
}
// Do not allow WordPress to search/download translations, as this will break JS output.
\remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 );
// Create the plugin upgrader with our custom skin.
$installer = new PluginsInstallUpgrader( new PluginsInstallSkin() );
// Error check.
if ( ! \method_exists( $installer, 'install' ) || empty( $_POST['plugin'] ) ) {
\wp_send_json_error( $error );
}
$installer->install( $_POST['plugin'] ); // phpcs:ignore
// Flush the cache and return the newly installed plugin basename.
\wp_cache_flush();
if ( $installer->plugin_info() ) {
$plugin_basename = $installer->plugin_info();
// Activate the plugin silently.
$activated = \activate_plugin( $plugin_basename );
if ( ! \is_wp_error( $activated ) ) {
\wp_send_json_success(
array(
'msg' => \esc_html__( 'Plugin installed & activated.', 'wp-mail-smtp' ),
'is_activated' => true,
'basename' => $plugin_basename,
)
);
} else {
\wp_send_json_success(
array(
'msg' => esc_html__( 'Plugin installed.', 'wp-mail-smtp' ),
'is_activated' => false,
'basename' => $plugin_basename,
)
);
}
}
\wp_send_json_error( $error );
}
/**
* Display a "Lite vs Pro" tab content.
*
* @since 1.5.0
*/
protected function display_versus() {
$license = \wp_mail_smtp()->get_license_type();
?>
<div class="wp-mail-smtp-admin-about-section wp-mail-smtp-admin-about-section-squashed">
<h1 class="centered">
<strong>
<?php
\printf(
/* translators: %s - plugin current license type. */
\esc_html__( '%s vs Pro', 'wp-mail-smtp' ),
\esc_html( \ucfirst( $license ) )
);
?>
</strong>
</h1>
<p class="centered <?php echo ( $license === 'pro' ? 'hidden' : '' ); ?>">
<?php esc_html_e( 'Get the most out of WP Mail SMTP by upgrading to Pro and unlocking all of the powerful features.', 'wp-mail-smtp' ); ?>
</p>
</div>
<div class="wp-mail-smtp-admin-about-section wp-mail-smtp-admin-about-section-squashed wp-mail-smtp-admin-about-section-hero wp-mail-smtp-admin-about-section-table">
<div class="wp-mail-smtp-admin-about-section-hero-main wp-mail-smtp-admin-columns">
<div class="wp-mail-smtp-admin-column-33">
<h3 class="no-margin">
<?php esc_html_e( 'Feature', 'wp-mail-smtp' ); ?>
</h3>
</div>
<div class="wp-mail-smtp-admin-column-33">
<h3 class="no-margin">
<?php echo esc_html( ucfirst( $license ) ); ?>
</h3>
</div>
<div class="wp-mail-smtp-admin-column-33">
<h3 class="no-margin">
<?php esc_html_e( 'Pro', 'wp-mail-smtp' ); ?>
</h3>
</div>
</div>
<div class="wp-mail-smtp-admin-about-section-hero-extra no-padding wp-mail-smtp-admin-columns">
<table>
<?php
foreach ( $this->get_license_features() as $slug => $name ) {
$current = $this->get_license_data( $slug, $license );
$pro = $this->get_license_data( $slug, 'pro' );
?>
<tr class="wp-mail-smtp-admin-columns">
<td class="wp-mail-smtp-admin-column-33">
<p><?php echo $name; ?></p>
</td>
<td class="wp-mail-smtp-admin-column-33">
<p class="features-<?php echo esc_attr( $current['status'] ); ?>">
<?php echo \implode( '<br>', $current['text'] ); ?>
</p>
</td>
<td class="wp-mail-smtp-admin-column-33">
<p class="features-full">
<?php echo \implode( '<br>', $pro['text'] ); ?>
</p>
</td>
</tr>
<?php
}
?>
</table>
</div>
</div>
<?php if ( 'lite' === $license ) : ?>
<div class="wp-mail-smtp-admin-about-section wp-mail-smtp-admin-about-section-hero">
<div class="wp-mail-smtp-admin-about-section-hero-main no-border">
<h3 class="call-to-action centered">
<a href="<?php echo esc_url( wp_mail_smtp()->get_upgrade_link( 'lite-vs-pro' ) ); ?>" target="_blank" rel="noopener noreferrer">
<?php \esc_html_e( 'Get WP Mail SMTP Pro Today and Unlock all of these Powerful Features', 'wp-mail-smtp' ); ?>
</a>
</h3>
<p class="centered">
<?php
echo \wp_kses(
\__( 'Bonus: WP Mail SMTP Lite users get <span class="price-off">20% off regular price</span>, automatically applied at checkout.', 'wp-mail-smtp' ),
array(
'span' => array(
'class' => array(),
),
)
);
?>
</p>
</div>
</div>
<?php endif; ?>
<?php
}
/**
* Get the list of features for all licenses.
*
* @since 1.5.0
*
* @return array
*/
private function get_license_features() {
return array(
'log' => \esc_html__( 'Email Log', 'wp-mail-smtp' ),
'control' => \esc_html__( 'Email Controls', 'wp-mail-smtp' ),
'mailers' => \esc_html__( 'Additional Mailers', 'wp-mail-smtp' ),
'support' => \esc_html__( 'Customer Support', 'wp-mail-smtp' ),
);
}
/**
* Get the array of data that compared the license data.
*
* @since 1.5.0
*
* @param string $feature Feature name.
* @param string $license License type to get data for.
*
* @return array|false
*/
private function get_license_data( $feature, $license ) {
$data = array(
'log' => array(
'lite' => array(
'status' => 'none',
'text' => array(
'<strong>' . esc_html__( 'Emails are not logged', 'wp-mail-smtp' ) . '</strong>',
),
),
'pro' => array(
'status' => 'full',
'text' => array(
'<strong>' . esc_html__( 'Complete Email Log management inside WordPress', 'wp-mail-smtp' ) . '</strong>',
),
),
),
'control' => array(
'lite' => array(
'status' => 'none',
'text' => array(
'<strong>' . esc_html__( 'No controls over whether default WordPress emails are sent', 'wp-mail-smtp' ) . '</strong>',
),
),
'pro' => array(
'status' => 'full',
'text' => array(
'<strong>' . esc_html__( 'Complete Email Controls management for most default WordPress emails', 'wp-mail-smtp' ) . '</strong>',
),
),
),
'mailers' => array(
'lite' => array(
'status' => 'none',
'text' => array(
'<strong>' . esc_html__( 'Only default list of mailers', 'wp-mail-smtp' ) . '</strong>',
),
),
'pro' => array(
'status' => 'full',
'text' => array(
'<strong>' . esc_html__( 'Additional mailers: Microsoft Outlook (with Office365 support) and Amazon SES', 'wp-mail-smtp' ) . '</strong>',
),
),
),
'support' => array(
'lite' => array(
'status' => 'none',
'text' => array(
'<strong>' . esc_html__( 'Limited Support', 'wp-mail-smtp' ) . '</strong>',
),
),
'pro' => array(
'status' => 'full',
'text' => array(
'<strong>' . esc_html__( 'Priority Support', 'wp-mail-smtp' ) . '</strong>',
),
),
),
);
// Wrong feature?
if ( ! isset( $data[ $feature ] ) ) {
return false;
}
// Wrong license type?
if ( ! isset( $data[ $feature ][ $license ] ) ) {
return false;
}
return $data[ $feature ][ $license ];
}
}

View File

@ -0,0 +1,63 @@
<?php
namespace WPMailSMTP\Admin\Pages;
use WPMailSMTP\Options;
use WPMailSMTP\Providers\AuthAbstract;
/**
* Class AuthTab.
*
* @since 1.0.0
*/
class AuthTab {
/**
* @var string Slug of a tab.
*/
protected $slug = 'auth';
/**
* Launch mailer specific Auth logic.
*
* @since 1.0.0
*/
public function process_auth() {
$auth = wp_mail_smtp()->get_providers()->get_auth( Options::init()->get( 'mail', 'mailer' ) );
if (
$auth &&
$auth instanceof AuthAbstract &&
method_exists( $auth, 'process' )
) {
$auth->process();
}
}
/**
* Return nothing, as we don't need this functionality.
*
* @since 1.0.0
*/
public function get_label() {
return '';
}
/**
* Return nothing, as we don't need this functionality.
*
* @since 1.0.0
*/
public function get_title() {
return '';
}
/**
* Do nothing, as we don't need this functionality.
*
* @since 1.0.0
*/
public function display() {
}
}

View File

@ -0,0 +1,124 @@
<?php
namespace WPMailSMTP\Admin\Pages;
use WPMailSMTP\Admin\PageAbstract;
/**
* Class ControlTab is a placeholder for Pro Email Control tab settings.
* Displays an upsell.
*
* @since 1.6.0
*/
class ControlTab extends PageAbstract {
/**
* @since 1.6.0
*
* @var string Slug of a tab.
*/
protected $slug = 'control';
/**
* @inheritdoc
*/
public function get_label() {
return esc_html__( 'Email Controls', 'wp-mail-smtp' );
}
/**
* @inheritdoc
*/
public function get_title() {
return $this->get_label();
}
/**
* @inheritdoc
*/
public function display() {
$features = array(
array(
'image' => 'comments.png',
'title' => esc_html__( 'Comment Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Manage emails sent when comments are published or awaiting moderation.', 'wp-mail-smtp' ),
),
array(
'image' => 'admin.png',
'title' => esc_html__( 'Site Admin Email Change Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Manage emails sent when site admin\'s account has been changed.', 'wp-mail-smtp' ),
),
array(
'image' => 'users.png',
'title' => esc_html__( 'User Change Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Limit emails triggered by password changed/reset, email changed, and more.', 'wp-mail-smtp' ),
),
array(
'image' => 'personal.png',
'title' => esc_html__( 'Personal Data Requests Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Control emails for data requests and data removal actions.', 'wp-mail-smtp' ),
),
array(
'image' => 'update.png',
'title' => esc_html__( 'Automatic Update Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Manage emails sent by the core automatic update process.', 'wp-mail-smtp' ),
),
array(
'image' => 'user_new.png',
'title' => esc_html__( 'New User Notifications', 'wp-mail-smtp' ),
'desc' => esc_html__( 'Toggle emails sent to both user and site administrator about new user accounts.', 'wp-mail-smtp' ),
),
)
?>
<div class="wp-mail-smtp-page-upsell">
<h2><?php esc_html_e( 'Unlock Email Controls', 'wp-mail-smtp' ); ?></h2>
<h3>
<?php esc_html_e( 'Email Controls allows you to granularly manage emails sent by WordPress.', 'wp-mail-smtp' ); ?>
</h3>
<div class="wp-mail-smtp-page-upsell-content">
<div class="wp-mail-smtp-page-upsell-features">
<?php foreach ( $features as $feature ) : ?>
<div class="wp-mail-smtp-page-upsell-feature">
<div class="wp-mail-smtp-page-upsell-feature-image">
<img src="<?php echo esc_url( wp_mail_smtp()->assets_url . '/images/control/' . $feature['image'] ); ?>" alt="">
</div>
<div class="wp-mail-smtp-page-upsell-feature-content">
<h4><?php echo esc_html( $feature['title'] ); ?></h4>
<p><?php echo esc_html( $feature['desc'] ); ?></p>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<div class="wp-mail-smtp-page-upsell-button">
<a href="https://wpmailsmtp.com/lite-upgrade/?discount=LITEUPGRADE&amp;utm_source=WordPress&amp;utm_medium=logs&amp;utm_campaign=liteplugin"
class="wp-mail-smtp-btn wp-mail-smtp-btn-lg wp-mail-smtp-btn-orange" target="_blank" rel="noopener noreferrer">
<?php esc_html_e( 'Upgrade to WP Mail SMTP Pro', 'wp-mail-smtp' ); ?>
</a>
</div>
</div>
<?php
}
/**
* Not used as we display an upsell.
*
* @since 1.6.0
*
* @param array $data
*/
public function process_post( $data ) {
}
}

View File

@ -0,0 +1,85 @@
<?php
namespace WPMailSMTP\Admin\Pages;
use WPMailSMTP\Admin\Area;
use WPMailSMTP\Admin\PageAbstract;
/**
* Class Logs
*/
class Logs extends PageAbstract {
/**
* @since 1.5.0
*
* @var string Slug of a page.
*/
protected $slug = 'logs';
/**
* Get the page/tab link.
*
* @since 1.5.0
*
* @return string
*/
public function get_link() {
return add_query_arg(
'page',
Area::SLUG . '-' . $this->slug,
admin_url( 'admin.php' )
);
}
/**
* @inheritdoc
*/
public function get_label() {
return esc_html__( 'Email Log', 'wp-mail-smtp' );
}
/**
* @inheritdoc
*/
public function get_title() {
return $this->get_label();
}
/**
* @inheritdoc
*/
public function display() {
?>
<div class="wp-mail-smtp-page-title">
<h1 class="page-title">
<?php echo esc_html( $this->get_label() ); ?>
</h1>
</div>
<div class="wp-mail-smtp-page-upsell">
<h2><?php esc_html_e( 'Unlock Email Logging', 'wp-mail-smtp' ); ?></h2>
<h3>
<?php esc_html_e( 'Keep track of every email sent from your WordPress site with email logging.', 'wp-mail-smtp' ); ?><br>
<?php esc_html_e( 'Troubleshoot sending issues, recover lost emails, and more!', 'wp-mail-smtp' ); ?>
</h3>
<div class="wp-mail-smtp-page-upsell-images">
<img src="<?php echo esc_url( wp_mail_smtp()->assets_url . '/images/logs/archive.png' ); ?>" alt="<?php esc_attr_e( 'Logs Archive Page Screenshot', 'wp-mail-smtp' ); ?>">
<img src="<?php echo esc_url( wp_mail_smtp()->assets_url . '/images/logs/single.png' ); ?>" alt="<?php esc_attr_e( 'Logs Single Page Screenshot', 'wp-mail-smtp' ); ?>">
</div>
<div class="wp-mail-smtp-page-upsell-button">
<a href="https://wpmailsmtp.com/lite-upgrade/?discount=LITEUPGRADE&amp;utm_source=WordPress&amp;utm_medium=logs&amp;utm_campaign=liteplugin" class="wp-mail-smtp-btn wp-mail-smtp-btn-lg wp-mail-smtp-btn-orange wp-mail-smtp-upgrade-modal" target="_blank" rel="noopener noreferrer">
<?php esc_html_e( 'Upgrade to WP Mail SMTP Pro', 'wp-mail-smtp' ); ?>
</a>
</div>
</div>
<?php
}
}

View File

@ -0,0 +1,73 @@
<?php
namespace WPMailSMTP\Admin\Pages;
use WPMailSMTP\Admin\Area;
use WPMailSMTP\Admin\PageAbstract;
/**
* Class LogsTab is a placeholder for Lite users and redirects them to Email Log page.
*
* @since 1.6.0
*/
class LogsTab extends PageAbstract {
/**
* Part of the slug of a tab.
*
* @since 1.6.0
*
* @var string
*/
protected $slug = 'logs';
/**
* @inheritdoc
*
* @since 1.6.0
*/
public function get_label() {
return esc_html__( 'Email Log', 'wp-mail-smtp' );
}
/**
* @inheritdoc
*
* @since 1.6.0
*/
public function get_title() {
return $this->get_label();
}
/**
* Custom URL for this tab, redirects to Email Log page.
*
* @since 1.6.0
*
* @return string
*/
public function get_link() {
return wp_mail_smtp()->get_admin()->get_admin_page_url( Area::SLUG . '-' . $this->slug );
}
/**
* Not used as we are simply redirecting users.
*
* @since 1.6.0
*/
public function display() {
}
/**
* Not used as we are simply redirecting users.
*
* @since 1.6.0
*
* @param array $data
*/
public function process_post( $data ) {
}
}

View File

@ -0,0 +1,219 @@
<?php
namespace WPMailSMTP\Admin\Pages;
use WPMailSMTP\Admin\PageAbstract;
use WPMailSMTP\Options;
use WPMailSMTP\WP;
/**
* Class MiscTab is part of Area, displays different plugin-related settings of the plugin (not related to emails).
*
* @since 1.0.0
*/
class MiscTab extends PageAbstract {
/**
* @var string Slug of a tab.
*/
protected $slug = 'misc';
/**
* @inheritdoc
*/
public function get_label() {
return esc_html__( 'Misc', 'wp-mail-smtp' );
}
/**
* @inheritdoc
*/
public function get_title() {
return $this->get_label();
}
/**
* @inheritdoc
*/
public function display() {
$options = new Options();
?>
<form method="POST" action="">
<?php $this->wp_nonce_field(); ?>
<!-- Section Title -->
<div class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-content wp-mail-smtp-clear section-heading no-desc" id="wp-mail-smtp-setting-row-email-heading">
<div class="wp-mail-smtp-setting-field">
<h2><?php echo $this->get_title(); ?></h2>
</div>
</div>
<!-- Do not send -->
<div id="wp-mail-smtp-setting-row-do_not_send" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-checkbox wp-mail-smtp-clear">
<div class="wp-mail-smtp-setting-label">
<label for="wp-mail-smtp-setting-do_not_send">
<?php esc_html_e( 'Do Not Send', 'wp-mail-smtp' ); ?>
</label>
</div>
<div class="wp-mail-smtp-setting-field">
<input name="wp-mail-smtp[general][do_not_send]" type="checkbox" value="true" id="wp-mail-smtp-setting-do_not_send"
<?php echo $options->is_const_defined( 'general', 'do_not_send' ) ? 'disabled' : ''; ?>
<?php checked( true, $options->get( 'general', 'do_not_send' ) ); ?>
>
<label for="wp-mail-smtp-setting-do_not_send">
<?php esc_html_e( 'Check this if you would like to stop sending all emails.', 'wp-mail-smtp' ); ?>
</label>
<p class="desc">
<?php
printf(
wp_kses(
__( 'Some plugins, like BuddyPress and Events Manager, are using their own email delivery solutions. By default, this option does not block their emails, as those plugins do not use default <code>wp_mail()</code> function to send emails.', 'wp-mail-smtp' ),
array(
'code' => array(),
)
)
);
?>
<br>
<?php esc_html_e( 'You will need to consult with their documentation to switch them to use default WordPress email delivery.', 'wp-mail-smtp' ); ?>
<br>
<?php esc_html_e( 'Test emails are allowed to be sent, regardless of this option.', 'wp-mail-smtp' ); ?>
<br>
<?php
if ( $options->is_const_defined( 'general', 'do_not_send' ) ) {
printf( /* translators: %1$s - constant that was used; %2$s - file where it was used. */
esc_html__( 'The value of this field was set using a constant %1$s most likely inside %2$s of your WordPress installation.', 'wp-mail-smtp' ),
'<code>WPMS_DO_NOT_SEND</code>',
'<code>wp-config.php</code>'
);
} else {
printf( /* translators: %1$s - constant to use; %2$s - file to put that constant in. */
esc_html__( 'If you want to disable using a constant, put %1$s in your %2$s file.', 'wp-mail-smtp' ),
'<code>define( \'WPMS_DO_NOT_SEND\', true );</code>',
'<code>wp-config.php</code>'
);
}
?>
</p>
</div>
</div>
<!-- Hide Announcements -->
<div id="wp-mail-smtp-setting-row-am_notifications_hidden" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-checkbox wp-mail-smtp-clear">
<div class="wp-mail-smtp-setting-label">
<label for="wp-mail-smtp-setting-am_notifications_hidden">
<?php esc_html_e( 'Hide Announcements', 'wp-mail-smtp' ); ?>
</label>
</div>
<div class="wp-mail-smtp-setting-field">
<input name="wp-mail-smtp[general][am_notifications_hidden]" type="checkbox"
value="true" <?php checked( true, $options->get( 'general', 'am_notifications_hidden' ) ); ?>
id="wp-mail-smtp-setting-am_notifications_hidden"
>
<label for="wp-mail-smtp-setting-am_notifications_hidden">
<?php esc_html_e( 'Check this if you would like to hide plugin announcements and update details.', 'wp-mail-smtp' ); ?>
</label>
</div>
</div>
<!-- Hide Email Delivery Errors -->
<div id="wp-mail-smtp-setting-row-email_delivery_errors_hidden"
class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-checkbox wp-mail-smtp-clear">
<div class="wp-mail-smtp-setting-label">
<label for="wp-mail-smtp-setting-email_delivery_errors_hidden">
<?php esc_html_e( 'Hide Email Delivery Errors', 'wp-mail-smtp' ); ?>
</label>
</div>
<div class="wp-mail-smtp-setting-field">
<?php
$is_hard_disabled = has_filter( 'wp_mail_smtp_admin_is_error_delivery_notice_enabled' ) && ! wp_mail_smtp()->get_admin()->is_error_delivery_notice_enabled();
?>
<?php if ( $is_hard_disabled ) : ?>
<input type="checkbox" disabled checked id="wp-mail-smtp-setting-email_delivery_errors_hidden">
<?php else : ?>
<input name="wp-mail-smtp[general][email_delivery_errors_hidden]" type="checkbox" value="true"
<?php checked( true, $options->get( 'general', 'email_delivery_errors_hidden' ) ); ?>
id="wp-mail-smtp-setting-email_delivery_errors_hidden">
<?php endif; ?>
<label for="wp-mail-smtp-setting-email_delivery_errors_hidden">
<?php esc_html_e( 'Check this if you would like to hide warnings alerting of email delivery errors.', 'wp-mail-smtp' ); ?>
</label>
<?php if ( $is_hard_disabled ) : ?>
<p class="desc">
<?php
printf( /* translators: %s - filter that was used to disabled. */
esc_html__( 'Email Delivery Errors were disabled using a %s filter.', 'wp-mail-smtp' ),
'<code>wp_mail_smtp_admin_is_error_delivery_notice_enabled</code>'
);
?>
</p>
<?php else : ?>
<p class="desc">
<?php
echo wp_kses(
__( '<strong>This is not recommended</strong> and should only be done for staging or development sites.', 'wp-mail-smtp' ),
array(
'strong' => true,
)
);
?>
</p>
<?php endif; ?>
</div>
</div>
<!-- Uninstall -->
<div id="wp-mail-smtp-setting-row-uninstall" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-checkbox wp-mail-smtp-clear">
<div class="wp-mail-smtp-setting-label">
<label for="wp-mail-smtp-setting-uninstall">
<?php esc_html_e( 'Uninstall WP Mail SMTP', 'wp-mail-smtp' ); ?>
</label>
</div>
<div class="wp-mail-smtp-setting-field">
<input name="wp-mail-smtp[general][uninstall]" type="checkbox"
value="true" <?php checked( true, $options->get( 'general', 'uninstall' ) ); ?>
id="wp-mail-smtp-setting-uninstall">
<label for="wp-mail-smtp-setting-uninstall">
<?php esc_html_e( 'Check this if you would like to remove ALL WP Mail SMTP data upon plugin deletion. All settings will be unrecoverable.', 'wp-mail-smtp' ); ?>
</label>
</div>
</div>
<?php $this->display_save_btn(); ?>
</form>
<?php
}
/**
* @inheritdoc
*/
public function process_post( $data ) {
$this->check_admin_referer();
$options = new Options();
// Unchecked checkboxes doesn't exist in $_POST, so we need to ensure we actually have them in data to save.
if ( empty( $data['general']['am_notifications_hidden'] ) ) {
$data['general']['am_notifications_hidden'] = false;
}
if ( empty( $data['general']['uninstall'] ) ) {
$data['general']['uninstall'] = false;
}
$to_save = array_merge( $options->get_all(), $data );
// All the sanitization is done there.
$options->set( $to_save );
WP::add_admin_notice(
esc_html__( 'Settings were successfully saved.', 'wp-mail-smtp' ),
WP::ADMIN_NOTICE_SUCCESS
);
}
}

View File

@ -0,0 +1,546 @@
<?php
namespace WPMailSMTP\Admin\Pages;
use WPMailSMTP\Admin\PageAbstract;
use WPMailSMTP\Debug;
use WPMailSMTP\Options;
use WPMailSMTP\WP;
/**
* Class SettingsTab is part of Area, displays general settings of the plugin.
*
* @since 1.0.0
*/
class SettingsTab extends PageAbstract {
/**
* Settings constructor.
*
* @since 1.5.0
*/
public function __construct() {
add_action( 'wp_mail_smtp_admin_pages_settings_license_key', array( __CLASS__, 'display_license_key_field_content' ) );
}
/**
* @var string Slug of a tab.
*/
protected $slug = 'settings';
/**
* @inheritdoc
*/
public function get_label() {
return esc_html__( 'General', 'wp-mail-smtp' );
}
/**
* @inheritdoc
*/
public function get_title() {
return $this->get_label();
}
/**
* @inheritdoc
*/
public function display() {
$options = new Options();
$mailer = $options->get( 'mail', 'mailer' );
$disabled_email = 'gmail' === $mailer || 'outlook' === $mailer ? 'disabled' : '';
$disabled_name = 'outlook' === $mailer ? 'disabled' : '';
?>
<form method="POST" action="" autocomplete="off">
<?php $this->wp_nonce_field(); ?>
<!-- License Section Title -->
<div class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-content wp-mail-smtp-clear section-heading" id="wp-mail-smtp-setting-row-license-heading">
<div class="wp-mail-smtp-setting-field">
<h2><?php esc_html_e( 'License', 'wp-mail-smtp' ); ?></h2>
<p class="desc">
<?php esc_html_e( 'Your license key provides access to updates and support.', 'wp-mail-smtp' ); ?>
</p>
</div>
</div>
<!-- License Key -->
<div id="wp-mail-smtp-setting-row-license_key" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-license_key wp-mail-smtp-clear">
<div class="wp-mail-smtp-setting-label">
<label for="wp-mail-smtp-setting-license_key"><?php esc_html_e( 'License Key', 'wp-mail-smtp' ); ?></label>
</div>
<div class="wp-mail-smtp-setting-field">
<?php do_action( 'wp_mail_smtp_admin_pages_settings_license_key', $options ); ?>
</div>
</div>
<!-- Mail Section Title -->
<div class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-content wp-mail-smtp-clear section-heading no-desc" id="wp-mail-smtp-setting-row-email-heading">
<div class="wp-mail-smtp-setting-field">
<h2><?php esc_html_e( 'Mail', 'wp-mail-smtp' ); ?></h2>
</div>
</div>
<!-- From Email -->
<div id="wp-mail-smtp-setting-row-from_email" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-email wp-mail-smtp-clear">
<div class="wp-mail-smtp-setting-label">
<label for="wp-mail-smtp-setting-from_email"><?php esc_html_e( 'From Email', 'wp-mail-smtp' ); ?></label>
</div>
<div class="wp-mail-smtp-setting-field">
<input name="wp-mail-smtp[mail][from_email]" type="email"
value="<?php echo esc_attr( $options->get( 'mail', 'from_email' ) ); ?>"
<?php echo $options->is_const_defined( 'mail', 'from_email' ) || ! empty( $disabled_email ) ? 'disabled' : ''; ?>
id="wp-mail-smtp-setting-from_email" spellcheck="false"
placeholder="<?php echo esc_attr( wp_mail_smtp()->get_processor()->get_default_email() ); ?>">
<?php if ( empty( $disabled_email ) ) : ?>
<p class="desc">
<?php esc_html_e( 'The email address which emails are sent from.', 'wp-mail-smtp' ); ?><br/>
<?php esc_html_e( 'If you using an email provider (Gmail, Yahoo, Outlook.com, etc) this should be your email address for that account.', 'wp-mail-smtp' ); ?>
</p>
<p class="desc">
<?php esc_html_e( 'Please note that other plugins can change this, to prevent this use the setting below.', 'wp-mail-smtp' ); ?>
</p>
<?php endif; ?>
<hr class="wp-mail-smtp-setting-mid-row-sep">
<input name="wp-mail-smtp[mail][from_email_force]" type="checkbox"
value="true" <?php checked( true, (bool) $options->get( 'mail', 'from_email_force' ) ); ?>
<?php echo $options->is_const_defined( 'mail', 'from_email_force' ) || ! empty( $disabled_email ) ? 'disabled' : ''; ?>
id="wp-mail-smtp-setting-from_email_force">
<label for="wp-mail-smtp-setting-from_email_force">
<?php esc_html_e( 'Force From Email', 'wp-mail-smtp' ); ?>
</label>
<?php if ( ! empty( $disabled_email ) ) : ?>
<p class="desc">
<?php esc_html_e( 'Current provider will automatically force From Email to be the email address that you use to set up the connection below.', 'wp-mail-smtp' ); ?>
</p>
<?php else : ?>
<p class="desc">
<?php esc_html_e( 'If checked, the From Email setting above will be used for all emails, ignoring values set by other plugins.', 'wp-mail-smtp' ); ?>
</p>
<?php endif; ?>
</div>
</div>
<!-- From Name -->
<div id="wp-mail-smtp-setting-row-from_name" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
<div class="wp-mail-smtp-setting-label">
<label for="wp-mail-smtp-setting-from_name"><?php esc_html_e( 'From Name', 'wp-mail-smtp' ); ?></label>
</div>
<div class="wp-mail-smtp-setting-field">
<input name="wp-mail-smtp[mail][from_name]" type="text"
value="<?php echo esc_attr( $options->get( 'mail', 'from_name' ) ); ?>"
<?php echo $options->is_const_defined( 'mail', 'from_name' ) || ! empty( $disabled_name ) ? 'disabled' : ''; ?>
id="wp-mail-smtp-setting-from_name" spellcheck="false"
placeholder="<?php echo esc_attr( wp_mail_smtp()->get_processor()->get_default_name() ); ?>">
<?php if ( empty( $disabled_name ) ) : ?>
<p class="desc">
<?php esc_html_e( 'The name which emails are sent from.', 'wp-mail-smtp' ); ?>
</p>
<?php endif; ?>
<hr class="wp-mail-smtp-setting-mid-row-sep">
<input name="wp-mail-smtp[mail][from_name_force]" type="checkbox"
value="true" <?php checked( true, (bool) $options->get( 'mail', 'from_name_force' ) ); ?>
<?php echo $options->is_const_defined( 'mail', 'from_name_force' ) || ! empty( $disabled_name ) ? 'disabled' : ''; ?>
id="wp-mail-smtp-setting-from_name_force">
<label for="wp-mail-smtp-setting-from_name_force">
<?php esc_html_e( 'Force From Name', 'wp-mail-smtp' ); ?>
</label>
<?php if ( ! empty( $disabled_name ) ) : ?>
<p class="desc">
<?php esc_html_e( 'Current provider doesn\'t support setting and forcing From Name. Emails will be sent on behalf of the account name used to setup the connection below.', 'wp-mail-smtp' ); ?>
</p>
<?php else : ?>
<p class="desc">
<?php esc_html_e( 'If checked, the From Name setting above will be used for all emails, ignoring values set by other plugins.', 'wp-mail-smtp' ); ?>
</p>
<?php endif; ?>
</div>
</div>
<!-- Return Path -->
<div id="wp-mail-smtp-setting-row-return_path" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-checkbox wp-mail-smtp-clear">
<div class="wp-mail-smtp-setting-label">
<label for="wp-mail-smtp-setting-return_path"><?php esc_html_e( 'Return Path', 'wp-mail-smtp' ); ?></label>
</div>
<div class="wp-mail-smtp-setting-field">
<input name="wp-mail-smtp[mail][return_path]" type="checkbox"
value="true" <?php checked( true, (bool) $options->get( 'mail', 'return_path' ) ); ?>
<?php echo $options->is_const_defined( 'mail', 'return_path' ) ? 'disabled' : ''; ?>
id="wp-mail-smtp-setting-return_path">
<label for="wp-mail-smtp-setting-return_path">
<?php esc_html_e( 'Set the return-path to match the From Email', 'wp-mail-smtp' ); ?>
</label>
<p class="desc">
<?php esc_html_e( 'Return Path indicates where non-delivery receipts - or bounce messages - are to be sent.', 'wp-mail-smtp' ); ?><br/>
<?php esc_html_e( 'If unchecked, bounce messages may be lost. Some providers may ignore this option.', 'wp-mail-smtp' ); ?>
</p>
</div>
</div>
<!-- Mailer -->
<div id="wp-mail-smtp-setting-row-mailer" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-mailer wp-mail-smtp-clear">
<div class="wp-mail-smtp-setting-label">
<label for="wp-mail-smtp-setting-mailer"><?php esc_html_e( 'Mailer', 'wp-mail-smtp' ); ?></label>
</div>
<div class="wp-mail-smtp-setting-field">
<div class="wp-mail-smtp-mailers">
<?php foreach ( wp_mail_smtp()->get_providers()->get_options_all() as $provider ) : ?>
<div class="wp-mail-smtp-mailer wp-mail-smtp-mailer-<?php echo esc_attr( $provider->get_slug() ); ?> <?php echo $mailer === $provider->get_slug() ? 'active' : ''; ?>">
<div class="wp-mail-smtp-mailer-image <?php echo $provider->is_recommended() ? 'is-recommended' : ''; ?>">
<img src="<?php echo esc_url( $provider->get_logo_url() ); ?>"
alt="<?php echo esc_attr( $provider->get_title() ); ?>">
</div>
<div class="wp-mail-smtp-mailer-text">
<?php if ( $provider->is_disabled() ) : ?>
<input type="radio" name="wp-mail-smtp[mail][mailer]" disabled class="educate"
id="wp-mail-smtp-setting-mailer-<?php echo esc_attr( $provider->get_slug() ); ?>"
value="<?php echo esc_attr( $provider->get_slug() ); ?>"
/>
<?php else : ?>
<input id="wp-mail-smtp-setting-mailer-<?php echo esc_attr( $provider->get_slug() ); ?>"
type="radio" name="wp-mail-smtp[mail][mailer]"
value="<?php echo esc_attr( $provider->get_slug() ); ?>"
<?php checked( $provider->get_slug(), $mailer ); ?>
<?php echo $options->is_const_defined( 'mail', 'mailer' ) || $provider->is_disabled() ? 'disabled' : ''; ?>
<?php echo $provider->is_disabled() ? 'class="educate"' : ''; ?>
/>
<?php endif; ?>
<label for="wp-mail-smtp-setting-mailer-<?php echo esc_attr( $provider->get_slug() ); ?>">
<?php echo esc_html( $provider->get_title() ); ?>
</label>
</div>
</div>
<?php endforeach; ?>
<!-- Suggest a mailer -->
<div class="wp-mail-smtp-mailer suggest-new">
<a href="https://wpmailsmtp.com/suggest-a-mailer" class="wp-mail-smtp-mailer-image" target="_blank" rel="noopener noreferrer">
<?php esc_html_e( 'Suggest a Mailer', 'wp-mail-smtp' ); ?>
</a>
<div class="wp-mail-smtp-mailer-text">
<label><?php esc_html_e( 'Suggest a Mailer', 'wp-mail-smtp' ); ?></label>
</div>
</div>
</div>
</div>
</div>
<!-- Mailer Options -->
<div class="wp-mail-smtp-mailer-options">
<?php foreach ( wp_mail_smtp()->get_providers()->get_options_all() as $provider ) : ?>
<?php $provider_desc = $provider->get_description(); ?>
<div class="wp-mail-smtp-mailer-option wp-mail-smtp-mailer-option-<?php echo esc_attr( $provider->get_slug() ); ?> <?php echo $mailer === $provider->get_slug() ? 'active' : 'hidden'; ?>">
<!-- Mailer Title/Notice/Description -->
<div class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-content wp-mail-smtp-clear section-heading <?php echo empty( $provider_desc ) ? 'no-desc' : ''; ?>" id="wp-mail-smtp-setting-row-email-heading">
<div class="wp-mail-smtp-setting-field">
<?php if ( $provider->is_disabled() ) : ?>
<?php $provider->display_options(); ?>
<?php else : ?>
<h2><?php echo $provider->get_title(); ?></h2>
<?php
$provider_edu_notice = $provider->get_notice( 'educational' );
$is_dismissed = (bool) get_user_meta( get_current_user_id(), "wp_mail_smtp_notice_educational_for_{$provider->get_slug()}_dismissed", true );
if ( ! empty( $provider_edu_notice ) && ! $is_dismissed ) :
?>
<p class="inline-notice inline-edu-notice"
data-notice="educational"
data-mailer="<?php echo esc_attr( $provider->get_slug() ); ?>">
<a href="#" title="<?php esc_attr_e( 'Dismiss this notice', 'wp-mail-smtp' ); ?>"
class="wp-mail-smtp-mailer-notice-dismiss js-wp-mail-smtp-mailer-notice-dismiss">
<span class="dashicons dashicons-dismiss"></span>
</a>
<?php echo $provider_edu_notice; ?>
</p>
<?php endif; ?>
<?php if ( ! empty( $provider_desc ) ) : ?>
<p class="desc"><?php echo $provider_desc; ?></p>
<?php endif; ?>
<?php endif; ?>
</div>
</div>
<?php $provider->display_options(); ?>
</div>
<?php endforeach; ?>
</div>
<?php $this->display_save_btn(); ?>
</form>
<?php
$this->display_wpforms();
$this->display_pro_banner();
}
/**
* License key text for a Lite version of the plugin.
*
* @since 1.5.0
*
* @param Options $options
*/
public static function display_license_key_field_content( $options ) {
?>
<p><?php esc_html_e( 'You\'re using WP Mail SMTP Lite - no license needed. Enjoy!', 'wp-mail-smtp' ); ?> 🙂</p>
<p>
<?php
printf(
wp_kses( /* translators: %s - WPMailSMTP.com upgrade URL. */
__( 'To unlock more features consider <strong><a href="%s" target="_blank" rel="noopener noreferrer" class="wp-mail-smtp-upgrade-modal">upgrading to PRO</a></strong>.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'class' => array(),
'target' => array(),
'rel' => array(),
),
'strong' => array(),
)
),
esc_url( wp_mail_smtp()->get_upgrade_link( 'general-license-key' ) )
);
?>
</p>
<p class="desc">
<?php
echo wp_kses(
__( 'As a valued WP Mail SMTP Lite user you receive <strong>20% off</strong>, automatically applied at checkout!', 'wp-mail-smtp' ),
array(
'strong' => array(),
'br' => array(),
)
);
?>
</p>
<?php
}
/**
* Display a WPForms related message.
*
* @since 1.3.0
* @since 1.4.0 Display only to site admins.
* @since 1.5.0 Do nothing.
*/
protected function display_wpforms() {
/*
* Used to have this check:
*
* $is_dismissed = get_user_meta( get_current_user_id(), 'wp_mail_smtp_wpforms_dismissed', true );
*/
}
/**
* Display WP Mail SMTP Pro upgrade banner.
*
* @since 1.5.0
*/
protected function display_pro_banner() {
// Display only to site admins. Only site admins can install plugins.
if ( ! is_super_admin() ) {
return;
}
// Do not display if WP Mail SMTP Pro already installed.
if ( wp_mail_smtp()->is_pro() ) {
return;
}
$is_dismissed = get_user_meta( get_current_user_id(), 'wp_mail_smtp_pro_banner_dismissed', true );
// Do not display if user dismissed.
if ( (bool) $is_dismissed === true ) {
return;
}
?>
<div id="wp-mail-smtp-pro-banner">
<span class="wp-mail-smtp-pro-banner-dismiss">
<button id="wp-mail-smtp-pro-banner-dismiss">
<span class="dashicons dashicons-dismiss"></span>
</button>
</span>
<h2>
<?php esc_html_e( 'Get WP Mail SMTP Pro and Unlock all the Powerful Features', 'wp-mail-smtp' ); ?>
</h2>
<p>
<?php esc_html_e( 'Thanks for being a loyal WP Mail SMTP user. Upgrade to WP Mail SMTP Pro to unlock more awesome features and experience why WP Mail SMTP is the most popular SMTP plugin.', 'wp-mail-smtp' ); ?>
</p>
<p>
<?php esc_html_e( 'We know that you will truly love WP Mail SMTP. It\'s used by over 1,000,000 websites.', 'wp-mail-smtp' ); ?>
</p>
<p><strong><?php esc_html_e( 'Pro Features:', 'wp-mail-smtp' ); ?></strong></p>
<div class="benefits">
<ul>
<li><?php esc_html_e( 'Manage Notifications - control which emails your site sends', 'wp-mail-smtp' ); ?></li>
<li><?php esc_html_e( 'Email Logging - keep track of every email sent from your site', 'wp-mail-smtp' ); ?></li>
<li><?php esc_html_e( 'Office 365 - send emails using your Office 365 account', 'wp-mail-smtp' ); ?></li>
<li><?php esc_html_e( 'Amazon SES - harness the power of AWS', 'wp-mail-smtp' ); ?></li>
<li><?php esc_html_e( 'Outlook.com - send emails using your Outlook.com account', 'wp-mail-smtp' ); ?></li>
<li><?php esc_html_e( 'Access to our world class support team', 'wp-mail-smtp' ); ?></li>
</ul>
<ul>
<li><?php esc_html_e( 'White Glove Setup - sit back and relax while we handle everything for you', 'wp-mail-smtp' ); ?></li>
<li class="arrow-right"><?php esc_html_e( 'Install WP Mail SMTP Pro plugin', 'wp-mail-smtp' ); ?></li>
<li class="arrow-right"><?php esc_html_e( 'Set up domain name verification (DNS)', 'wp-mail-smtp' ); ?></li>
<li class="arrow-right"><?php esc_html_e( 'Configure Mailgun service', 'wp-mail-smtp' ); ?></li>
<li class="arrow-right"><?php esc_html_e( 'Set up WP Mail SMTP Pro plugin', 'wp-mail-smtp' ); ?></li>
<li class="arrow-right"><?php esc_html_e( 'Test and verify email delivery', 'wp-mail-smtp' ); ?></li>
</ul>
</div>
<p>
<?php
printf(
wp_kses( /* translators: %s - WPMailSMTP.com URL. */
__( '<a href="%s" target="_blank" rel="noopener noreferrer">Get WP Mail SMTP Pro Today and Unlock all the Powerful Features &raquo;</a>', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'target' => array(),
'rel' => array(),
),
'strong' => array(),
)
),
esc_url( wp_mail_smtp()->get_upgrade_link( 'general-cta' ) )
);
?>
</p>
<p>
<?php
echo wp_kses(
__( '<strong>Bonus:</strong> WP Mail SMTP users get <span class="price-off">20% off regular price</span>, automatically applied at checkout.', 'wp-mail-smtp' ),
array(
'strong' => array(),
'span' => array(
'class' => array(),
),
)
);
?>
</p>
</div>
<?php
}
/**
* @inheritdoc
*/
public function process_post( $data ) {
$this->check_admin_referer();
$options = new Options();
$old_opt = $options->get_all();
// When checkbox is unchecked - it's not submitted at all, so we need to define its default false value.
if ( ! isset( $data['mail']['from_email_force'] ) ) {
$data['mail']['from_email_force'] = false;
}
if ( ! isset( $data['mail']['from_name_force'] ) ) {
$data['mail']['from_name_force'] = false;
}
if ( ! isset( $data['mail']['return_path'] ) ) {
$data['mail']['return_path'] = false;
}
if ( ! isset( $data['smtp']['autotls'] ) ) {
$data['smtp']['autotls'] = false;
}
if ( ! isset( $data['smtp']['auth'] ) ) {
$data['smtp']['auth'] = false;
}
// Remove all debug messages when switching mailers.
if (
! empty( $old_opt['mail']['mailer'] ) &&
! empty( $data['mail']['mailer'] ) &&
$old_opt['mail']['mailer'] !== $data['mail']['mailer']
) {
Debug::clear();
}
$to_redirect = false;
// Old and new Gmail client id/secret values are different - we need to invalidate tokens and scroll to Auth button.
if (
$options->get( 'mail', 'mailer' ) === 'gmail' &&
! empty( $data['gmail']['client_id'] ) &&
! empty( $data['gmail']['client_secret'] ) &&
(
$options->get( 'gmail', 'client_id' ) !== $data['gmail']['client_id'] ||
$options->get( 'gmail', 'client_secret' ) !== $data['gmail']['client_secret']
)
) {
unset( $old_opt['gmail'] );
if (
! empty( $data['gmail']['client_id'] ) &&
! empty( $data['gmail']['client_secret'] )
) {
$to_redirect = true;
}
}
// New gmail clients data will be added from new $data.
$to_save = Options::array_merge_recursive( $old_opt, $data );
// All the sanitization is done in Options class.
$options->set( $to_save );
if ( $to_redirect ) {
wp_redirect( $_POST['_wp_http_referer'] . '#wp-mail-smtp-setting-row-gmail-authorize' );
exit;
}
WP::add_admin_notice(
esc_html__( 'Settings were successfully saved.', 'wp-mail-smtp' ),
WP::ADMIN_NOTICE_SUCCESS
);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,55 @@
<?php
namespace WPMailSMTP\Admin;
/**
* WordPress class extended for on-the-fly plugin installations.
*
* @since 1.5.0
* @since 1.7.1 Removed feedback() method override to be compatible with PHP5.3+ and WP5.3.
*/
class PluginsInstallSkin extends \WP_Upgrader_Skin {
/**
* Empty out the header of its HTML content and only check to see if it has
* been performed or not.
*
* @since 1.5.0
*/
public function header() {
}
/**
* Empty out the footer of its HTML contents.
*
* @since 1.5.0
*/
public function footer() {
}
/**
* Instead of outputting HTML for errors, json_encode the errors and send them
* back to the Ajax script for processing.
*
* @since 1.5.0
*
* @param array $errors Array of errors with the install process.
*/
public function error( $errors ) {
if ( ! empty( $errors ) ) {
wp_send_json_error( $errors );
}
}
/**
* Empty out JavaScript output that calls function to decrement the update counts.
*
* @since 1.5.0
*
* @param string $type Type of update count to decrement.
*/
public function decrement_update_count( $type ) {
}
}

View File

@ -0,0 +1,576 @@
<?php
namespace WPMailSMTP\Admin;
use WP_Error;
use WP_Upgrader;
use WP_Filesystem_Base;
/** \WP_Upgrader class */
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
/** \Plugin_Upgrader class */
require_once ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php';
/**
* In WP 5.3 a PHP 5.6 splat operator (...$args) was added to \WP_Upgrader_Skin::feedback().
* We need to remove all calls to *Skin::feedback() method, as we can't override it in own Skin
* without breaking support for PHP 5.3-5.5.
*
* @internal Please do not use this class outside of core WPForms development. May be removed at any time.
*
* @since 1.7.1
*/
class PluginsInstallUpgrader extends \Plugin_Upgrader {
/**
* Run an upgrade/installation.
*
* Attempts to download the package (if it is not a local file), unpack it, and
* install it in the destination folder.
*
* @since 2.8.0
*
* @param array $options {
* Array or string of arguments for upgrading/installing a package.
*
* @type string $package The full path or URI of the package to install.
* Default empty.
* @type string $destination The full path to the destination folder.
* Default empty.
* @type bool $clear_destination Whether to delete any files already in the
* destination folder. Default false.
* @type bool $clear_working Whether to delete the files form the working
* directory after copying to the destination.
* Default false.
* @type bool $abort_if_destination_exists Whether to abort the installation if the destination
* folder already exists. When true, `$clear_destination`
* should be false. Default true.
* @type bool $is_multi Whether this run is one of multiple upgrade/installation
* actions being performed in bulk. When true, the skin
* WP_Upgrader::header() and WP_Upgrader::footer()
* aren't called. Default false.
* @type array $hook_extra Extra arguments to pass to the filter hooks called by
* WP_Upgrader::run().
* }
* @return array|false|WP_error The result from self::install_package() on success, otherwise a WP_Error,
* or false if unable to connect to the filesystem.
*/
public function run( $options ) {
$defaults = array(
'package' => '', // Please always pass this.
'destination' => '', // And this
'clear_destination' => false,
'abort_if_destination_exists' => true, // Abort if the Destination directory exists, Pass clear_destination as false please
'clear_working' => true,
'is_multi' => false,
'hook_extra' => array(), // Pass any extra $hook_extra args here, this will be passed to any hooked filters.
);
$options = wp_parse_args( $options, $defaults );
/**
* Filters the package options before running an update.
*
* See also {@see 'upgrader_process_complete'}.
*
* @since 4.3.0
*
* @param array $options {
* Options used by the upgrader.
*
* @type string $package Package for update.
* @type string $destination Update location.
* @type bool $clear_destination Clear the destination resource.
* @type bool $clear_working Clear the working resource.
* @type bool $abort_if_destination_exists Abort if the Destination directory exists.
* @type bool $is_multi Whether the upgrader is running multiple times.
* @type array $hook_extra {
* Extra hook arguments.
*
* @type string $action Type of action. Default 'update'.
* @type string $type Type of update process. Accepts 'plugin', 'theme', or 'core'.
* @type bool $bulk Whether the update process is a bulk update. Default true.
* @type string $plugin Path to the plugin file relative to the plugins directory.
* @type string $theme The stylesheet or template name of the theme.
* @type string $language_update_type The language pack update type. Accepts 'plugin', 'theme',
* or 'core'.
* @type object $language_update The language pack update offer.
* }
* }
*/
$options = apply_filters( 'upgrader_package_options', $options );
if ( ! $options['is_multi'] ) { // call $this->header separately if running multiple times
$this->skin->header();
}
// Connect to the Filesystem first.
$res = $this->fs_connect( array( WP_CONTENT_DIR, $options['destination'] ) );
// Mainly for non-connected filesystem.
if ( ! $res ) {
if ( ! $options['is_multi'] ) {
$this->skin->footer();
}
return false;
}
$this->skin->before();
if ( is_wp_error( $res ) ) {
$this->skin->error( $res );
$this->skin->after();
if ( ! $options['is_multi'] ) {
$this->skin->footer();
}
return $res;
}
/*
* Download the package (Note, This just returns the filename
* of the file if the package is a local file)
*/
$download = $this->download_package( $options['package'], true );
// Allow for signature soft-fail.
// WARNING: This may be removed in the future.
if ( is_wp_error( $download ) && $download->get_error_data( 'softfail-filename' ) ) {
// Don't output the 'no signature could be found' failure message for now.
if ( 'signature_verification_no_signature' != $download->get_error_code() || WP_DEBUG ) {
// Outout the failure error as a normal feedback, and not as an error:
//$this->skin->feedback( $download->get_error_message() );
// Report this failure back to WordPress.org for debugging purposes.
wp_version_check(
array(
'signature_failure_code' => $download->get_error_code(),
'signature_failure_data' => $download->get_error_data(),
)
);
}
// Pretend this error didn't happen.
$download = $download->get_error_data( 'softfail-filename' );
}
if ( is_wp_error( $download ) ) {
$this->skin->error( $download );
$this->skin->after();
if ( ! $options['is_multi'] ) {
$this->skin->footer();
}
return $download;
}
$delete_package = ( $download != $options['package'] ); // Do not delete a "local" file
// Unzips the file into a temporary directory.
$working_dir = $this->unpack_package( $download, $delete_package );
if ( is_wp_error( $working_dir ) ) {
$this->skin->error( $working_dir );
$this->skin->after();
if ( ! $options['is_multi'] ) {
$this->skin->footer();
}
return $working_dir;
}
// With the given options, this installs it to the destination directory.
$result = $this->install_package(
array(
'source' => $working_dir,
'destination' => $options['destination'],
'clear_destination' => $options['clear_destination'],
'abort_if_destination_exists' => $options['abort_if_destination_exists'],
'clear_working' => $options['clear_working'],
'hook_extra' => $options['hook_extra'],
)
);
$this->skin->set_result( $result );
if ( is_wp_error( $result ) ) {
$this->skin->error( $result );
//$this->skin->feedback( 'process_failed' );
} else {
// Installation succeeded.
//$this->skin->feedback( 'process_success' );
}
$this->skin->after();
if ( ! $options['is_multi'] ) {
/**
* Fires when the upgrader process is complete.
*
* See also {@see 'upgrader_package_options'}.
*
* @since 3.6.0
* @since 3.7.0 Added to WP_Upgrader::run().
* @since 4.6.0 `$translations` was added as a possible argument to `$hook_extra`.
*
* @param WP_Upgrader $this WP_Upgrader instance. In other contexts, $this, might be a
* Theme_Upgrader, Plugin_Upgrader, Core_Upgrade, or Language_Pack_Upgrader instance.
* @param array $hook_extra {
* Array of bulk item update data.
*
* @type string $action Type of action. Default 'update'.
* @type string $type Type of update process. Accepts 'plugin', 'theme', 'translation', or 'core'.
* @type bool $bulk Whether the update process is a bulk update. Default true.
* @type array $plugins Array of the basename paths of the plugins' main files.
* @type array $themes The theme slugs.
* @type array $translations {
* Array of translations update data.
*
* @type string $language The locale the translation is for.
* @type string $type Type of translation. Accepts 'plugin', 'theme', or 'core'.
* @type string $slug Text domain the translation is for. The slug of a theme/plugin or
* 'default' for core translations.
* @type string $version The version of a theme, plugin, or core.
* }
* }
*/
do_action( 'upgrader_process_complete', $this, $options['hook_extra'] );
$this->skin->footer();
}
return $result;
}
/**
* Toggle maintenance mode for the site.
*
* Creates/deletes the maintenance file to enable/disable maintenance mode.
*
* @since 2.8.0
*
* @global WP_Filesystem_Base $wp_filesystem Subclass
*
* @param bool $enable True to enable maintenance mode, false to disable.
*/
public function maintenance_mode( $enable = false ) {
global $wp_filesystem;
$file = $wp_filesystem->abspath() . '.maintenance';
if ( $enable ) {
//$this->skin->feedback( 'maintenance_start' );
// Create maintenance file to signal that we are upgrading
$maintenance_string = '<?php $upgrading = ' . time() . '; ?>';
$wp_filesystem->delete( $file );
$wp_filesystem->put_contents( $file, $maintenance_string, FS_CHMOD_FILE );
} elseif ( ! $enable && $wp_filesystem->exists( $file ) ) {
//$this->skin->feedback( 'maintenance_end' );
$wp_filesystem->delete( $file );
}
}
/**
* Download a package.
*
* @since 2.8.0
*
* @param string $package The URI of the package. If this is the full path to an
* existing local file, it will be returned untouched.
* @param bool $check_signatures Whether to validate file signatures. Default false.
* @return string|WP_Error The full path to the downloaded package file, or a WP_Error object.
*/
public function download_package( $package, $check_signatures = false ) {
/**
* Filters whether to return the package.
*
* @since 3.7.0
*
* @param bool $reply Whether to bail without returning the package.
* Default false.
* @param string $package The package file name.
* @param WP_Upgrader $this The WP_Upgrader instance.
*/
$reply = apply_filters( 'upgrader_pre_download', false, $package, $this );
if ( false !== $reply ) {
return $reply;
}
if ( ! preg_match( '!^(http|https|ftp)://!i', $package ) && file_exists( $package ) ) { //Local file or remote?
return $package; //must be a local file..
}
if ( empty( $package ) ) {
return new WP_Error( 'no_package', $this->strings['no_package'] );
}
//$this->skin->feedback( 'downloading_package', $package );
$download_file = download_url( $package, 300, $check_signatures );
if ( is_wp_error( $download_file ) && ! $download_file->get_error_data( 'softfail-filename' ) ) {
return new WP_Error( 'download_failed', $this->strings['download_failed'], $download_file->get_error_message() );
}
return $download_file;
}
/**
* Unpack a compressed package file.
*
* @since 2.8.0
*
* @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
*
* @param string $package Full path to the package file.
* @param bool $delete_package Optional. Whether to delete the package file after attempting
* to unpack it. Default true.
* @return string|WP_Error The path to the unpacked contents, or a WP_Error on failure.
*/
public function unpack_package( $package, $delete_package = true ) {
global $wp_filesystem;
//$this->skin->feedback( 'unpack_package' );
$upgrade_folder = $wp_filesystem->wp_content_dir() . 'upgrade/';
//Clean up contents of upgrade directory beforehand.
$upgrade_files = $wp_filesystem->dirlist( $upgrade_folder );
if ( ! empty( $upgrade_files ) ) {
foreach ( $upgrade_files as $file ) {
$wp_filesystem->delete( $upgrade_folder . $file['name'], true );
}
}
// We need a working directory - Strip off any .tmp or .zip suffixes
$working_dir = $upgrade_folder . basename( basename( $package, '.tmp' ), '.zip' );
// Clean up working directory
if ( $wp_filesystem->is_dir( $working_dir ) ) {
$wp_filesystem->delete( $working_dir, true );
}
// Unzip package to working directory
$result = unzip_file( $package, $working_dir );
// Once extracted, delete the package if required.
if ( $delete_package ) {
unlink( $package );
}
if ( is_wp_error( $result ) ) {
$wp_filesystem->delete( $working_dir, true );
if ( 'incompatible_archive' == $result->get_error_code() ) {
return new WP_Error( 'incompatible_archive', $this->strings['incompatible_archive'], $result->get_error_data() );
}
return $result;
}
return $working_dir;
}
/**
* Install a package.
*
* Copies the contents of a package form a source directory, and installs them in
* a destination directory. Optionally removes the source. It can also optionally
* clear out the destination folder if it already exists.
*
* @since 2.8.0
*
* @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
* @global array $wp_theme_directories
*
* @param array|string $args {
* Optional. Array or string of arguments for installing a package. Default empty array.
*
* @type string $source Required path to the package source. Default empty.
* @type string $destination Required path to a folder to install the package in.
* Default empty.
* @type bool $clear_destination Whether to delete any files already in the destination
* folder. Default false.
* @type bool $clear_working Whether to delete the files form the working directory
* after copying to the destination. Default false.
* @type bool $abort_if_destination_exists Whether to abort the installation if
* the destination folder already exists. Default true.
* @type array $hook_extra Extra arguments to pass to the filter hooks called by
* WP_Upgrader::install_package(). Default empty array.
* }
*
* @return array|WP_Error The result (also stored in `WP_Upgrader::$result`), or a WP_Error on failure.
*/
public function install_package( $args = array() ) {
global $wp_filesystem, $wp_theme_directories;
$defaults = array(
'source' => '', // Please always pass this
'destination' => '', // and this
'clear_destination' => false,
'clear_working' => false,
'abort_if_destination_exists' => true,
'hook_extra' => array(),
);
$args = wp_parse_args( $args, $defaults );
// These were previously extract()'d.
$source = $args['source'];
$destination = $args['destination'];
$clear_destination = $args['clear_destination'];
set_time_limit( 300 );
if ( empty( $source ) || empty( $destination ) ) {
return new WP_Error( 'bad_request', $this->strings['bad_request'] );
}
//$this->skin->feedback( 'installing_package' );
/**
* Filters the install response before the installation has started.
*
* Returning a truthy value, or one that could be evaluated as a WP_Error
* will effectively short-circuit the installation, returning that value
* instead.
*
* @since 2.8.0
*
* @param bool|WP_Error $response Response.
* @param array $hook_extra Extra arguments passed to hooked filters.
*/
$res = apply_filters( 'upgrader_pre_install', true, $args['hook_extra'] );
if ( is_wp_error( $res ) ) {
return $res;
}
//Retain the Original source and destinations
$remote_source = $args['source'];
$local_destination = $destination;
$source_files = array_keys( $wp_filesystem->dirlist( $remote_source ) );
$remote_destination = $wp_filesystem->find_folder( $local_destination );
//Locate which directory to copy to the new folder, This is based on the actual folder holding the files.
if ( 1 == count( $source_files ) && $wp_filesystem->is_dir( trailingslashit( $args['source'] ) . $source_files[0] . '/' ) ) { //Only one folder? Then we want its contents.
$source = trailingslashit( $args['source'] ) . trailingslashit( $source_files[0] );
} elseif ( count( $source_files ) == 0 ) {
return new WP_Error( 'incompatible_archive_empty', $this->strings['incompatible_archive'], $this->strings['no_files'] ); // There are no files?
} else { // It's only a single file, the upgrader will use the folder name of this file as the destination folder. Folder name is based on zip filename.
$source = trailingslashit( $args['source'] );
}
/**
* Filters the source file location for the upgrade package.
*
* @since 2.8.0
* @since 4.4.0 The $hook_extra parameter became available.
*
* @param string $source File source location.
* @param string $remote_source Remote file source location.
* @param WP_Upgrader $this WP_Upgrader instance.
* @param array $hook_extra Extra arguments passed to hooked filters.
*/
$source = apply_filters( 'upgrader_source_selection', $source, $remote_source, $this, $args['hook_extra'] );
if ( is_wp_error( $source ) ) {
return $source;
}
// Has the source location changed? If so, we need a new source_files list.
if ( $source !== $remote_source ) {
$source_files = array_keys( $wp_filesystem->dirlist( $source ) );
}
/*
* Protection against deleting files in any important base directories.
* Theme_Upgrader & Plugin_Upgrader also trigger this, as they pass the
* destination directory (WP_PLUGIN_DIR / wp-content/themes) intending
* to copy the directory into the directory, whilst they pass the source
* as the actual files to copy.
*/
$protected_directories = array( ABSPATH, WP_CONTENT_DIR, WP_PLUGIN_DIR, WP_CONTENT_DIR . '/themes' );
if ( is_array( $wp_theme_directories ) ) {
$protected_directories = array_merge( $protected_directories, $wp_theme_directories );
}
if ( in_array( $destination, $protected_directories ) ) {
$remote_destination = trailingslashit( $remote_destination ) . trailingslashit( basename( $source ) );
$destination = trailingslashit( $destination ) . trailingslashit( basename( $source ) );
}
if ( $clear_destination ) {
// We're going to clear the destination if there's something there.
//$this->skin->feedback( 'remove_old' );
$removed = $this->clear_destination( $remote_destination );
/**
* Filters whether the upgrader cleared the destination.
*
* @since 2.8.0
*
* @param mixed $removed Whether the destination was cleared. true on success, WP_Error on failure
* @param string $local_destination The local package destination.
* @param string $remote_destination The remote package destination.
* @param array $hook_extra Extra arguments passed to hooked filters.
*/
$removed = apply_filters( 'upgrader_clear_destination', $removed, $local_destination, $remote_destination, $args['hook_extra'] );
if ( is_wp_error( $removed ) ) {
return $removed;
}
} elseif ( $args['abort_if_destination_exists'] && $wp_filesystem->exists( $remote_destination ) ) {
//If we're not clearing the destination folder and something exists there already, Bail.
//But first check to see if there are actually any files in the folder.
$_files = $wp_filesystem->dirlist( $remote_destination );
if ( ! empty( $_files ) ) {
$wp_filesystem->delete( $remote_source, true ); //Clear out the source files.
return new WP_Error( 'folder_exists', $this->strings['folder_exists'], $remote_destination );
}
}
//Create destination if needed
if ( ! $wp_filesystem->exists( $remote_destination ) ) {
if ( ! $wp_filesystem->mkdir( $remote_destination, FS_CHMOD_DIR ) ) {
return new WP_Error( 'mkdir_failed_destination', $this->strings['mkdir_failed'], $remote_destination );
}
}
// Copy new version of item into place.
$result = copy_dir( $source, $remote_destination );
if ( is_wp_error( $result ) ) {
if ( $args['clear_working'] ) {
$wp_filesystem->delete( $remote_source, true );
}
return $result;
}
//Clear the Working folder?
if ( $args['clear_working'] ) {
$wp_filesystem->delete( $remote_source, true );
}
$destination_name = basename( str_replace( $local_destination, '', $destination ) );
if ( '.' == $destination_name ) {
$destination_name = '';
}
$this->result = compact( 'source', 'source_files', 'destination', 'destination_name', 'local_destination', 'remote_destination', 'clear_destination' );
/**
* Filters the installation response after the installation has finished.
*
* @since 2.8.0
*
* @param bool $response Installation response.
* @param array $hook_extra Extra arguments passed to hooked filters.
* @param array $result Installation result data.
*/
$res = apply_filters( 'upgrader_post_install', true, $args['hook_extra'], $this->result );
if ( is_wp_error( $res ) ) {
$this->result = $res;
return $res;
}
//Bombard the calling function will all the info which we've just used.
return $this->result;
}
}

View File

@ -0,0 +1,184 @@
<?php
namespace WPMailSMTP;
/**
* Class Conflicts
*
* @since 1.5.0
*/
class Conflicts {
/**
* @since 1.5.0
*
* @var array List of plugins WP Mail SMTP may be conflicting with.
*/
public static $plugins = array(
'swpsmtp_init_smtp' => array(
'name' => 'Easy WP SMTP',
),
'postman_start' => array(
'name' => 'Postman SMTP',
),
'post_start' => array(
'name' => 'Post SMTP Mailer/Email Log',
),
'mail_bank' => array(
'name' => 'WP Mail Bank',
),
'SMTP_MAILER' => array(
'name' => 'SMTP Mailer',
'class' => true,
),
'GMAIL_SMTP' => array(
'name' => 'Gmail SMTP',
'class' => true,
),
'WP_Email_Smtp' => array(
'name' => 'WP Email SMTP',
'class' => true,
),
'smtpmail_include' => array(
'name' => 'SMTP Mail',
),
'bwssmtp_init' => array(
'name' => 'SMTP by BestWebSoft',
),
'WPSendGrid_SMTP' => array(
'name' => 'WP SendGrid SMTP',
'class' => true,
),
'sar_friendly_smtp' => array(
'name' => 'SAR Friendly SMTP',
),
'WPGmail_SMTP' => array(
'name' => 'WP Gmail SMTP',
'class' => true,
),
'st_smtp_check_config' => array(
'name' => 'Cimy Swift SMTP',
),
'WP_Easy_SMTP' => array(
'name' => 'WP Easy SMTP',
'class' => true,
),
'WPMailgun_SMTP' => array(
'name' => 'WP Mailgun SMTP',
'class' => true,
),
'my_smtp_wp' => array(
'name' => 'MY SMTP WP',
),
'mail_booster' => array(
'name' => 'WP Mail Booster',
),
'Sendgrid_Settings' => array(
'name' => 'SendGrid',
'class' => true,
),
'WPMS_php_mailer' => array(
'name' => 'WP Mail Smtp Mailer',
),
'WPAmazonSES_SMTP' => array(
'name' => 'WP Amazon SES SMTP',
'class' => true,
),
'Postmark_Mail' => array(
'name' => 'Postmark for WordPress',
'class' => true,
),
'Mailgun' => array(
'name' => 'Mailgun',
'class' => true,
),
'WPSparkPost\SparkPost' => array(
'name' => 'SparkPost',
'class' => true,
),
'WPYahoo_SMTP' => array(
'name' => 'WP Yahoo SMTP',
'class' => true,
),
'wpses_init' => array(
'name' => 'WP SES',
'class' => true,
),
'TSPHPMailer' => array(
'name' => 'turboSMTP',
),
'WP_SMTP' => array(
'name' => 'WP SMTP',
'class' => true,
),
);
/**
* @var array Conflict information.
*/
protected $conflict = array();
/**
* Whether we have a conflict with predefined list of plugins.
*
* @since 1.5.0
*
* @return bool
*/
public function is_detected() {
foreach ( self::$plugins as $callback => $plugin ) {
if ( ! empty( $plugin['class'] ) ) {
$detected = \class_exists( $callback, false );
} else {
$detected = \function_exists( $callback );
}
if ( $detected ) {
$this->conflict = $plugin;
break;
}
}
return ! empty( $this->conflict );
}
/**
* Add a warning admin message to a user about the conflicting plugin.
*
* @since 1.5.0
*/
public function notify() {
if ( empty( $this->conflict ) ) {
return;
}
WP::add_admin_notice(
\sprintf( /* translators: %1$s - Plugin name causing conflict; %2$s - Plugin name causing conflict. */
\esc_html__( 'Heads up! WP Mail SMTP has detected %1$s is activated. Please deactivate %2$s to prevent conflicts.', 'wp-mail-smtp' ),
$this->get_conflict_name(),
$this->get_conflict_name()
),
WP::ADMIN_NOTICE_WARNING
);
}
/**
* Get the conflicting plugin name is any.
*
* @since 1.5.0
*
* @return null|string
*/
public function get_conflict_name() {
$name = null;
if ( ! empty( $this->conflict['name'] ) ) {
$name = $this->conflict['name'];
}
return $name;
}
}

View File

@ -0,0 +1,738 @@
<?php
namespace WPMailSMTP;
/**
* Class Core to handle all plugin initialization.
*
* @since 1.0.0
*/
class Core {
/**
* URL to plugin directory.
*
* @since 1.0.0
*
* @var string Without trailing slash.
*/
public $plugin_url;
/**
* URL to Lite plugin assets directory.
*
* @since 1.5.0
*
* @var string Without trailing slash.
*/
public $assets_url;
/**
* Path to plugin directory.
*
* @since 1.0.0
*
* @var string Without trailing slash.
*/
public $plugin_path;
/**
* Shortcut to get access to Pro functionality using wp_mail_smtp()->pro->example().
*
* @since 1.5.0
*
* @var \WPMailSMTP\Pro\Pro
*/
public $pro;
/**
* Core constructor.
*
* @since 1.0.0
*/
public function __construct() {
$this->plugin_url = rtrim( plugin_dir_url( __DIR__ ), '/\\' );
$this->assets_url = $this->plugin_url . '/assets';
$this->plugin_path = rtrim( plugin_dir_path( __DIR__ ), '/\\' );
if ( $this->is_not_loadable() ) {
$this->do_not_load();
return;
}
// Finally, load all the plugin.
$this->hooks();
$this->init_early();
}
/**
* Currently used for Pro version only.
*
* @since 1.5.0
*
* @return bool
*/
protected function is_not_loadable() {
// Check the Pro.
if (
is_readable( $this->plugin_path . '/src/Pro/Pro.php' ) &&
! $this->is_pro_allowed()
) {
// So there is a Pro version, but its PHP version check failed.
return true;
}
return false;
}
/**
* What to do if plugin is not loaded.
*
* @since 1.5.0
*/
protected function do_not_load() {
add_action( 'admin_notices', function () {
?>
<div class="notice notice-error">
<p>
<?php
printf(
wp_kses( /* translators: %1$s - WPBeginner URL for recommended WordPress hosting. */
__( 'Your site is running an <strong>insecure version</strong> of PHP that is no longer supported. Please contact your web hosting provider to update your PHP version or switch to a <a href="%1$s" target="_blank" rel="noopener noreferrer">recommended WordPress hosting company</a>.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'target' => array(),
'rel' => array(),
),
'strong' => array(),
)
),
'https://www.wpbeginner.com/wordpress-hosting/'
);
?>
<br><br>
<?php
printf(
wp_kses( /* translators: %s - WPForms.com docs URL with more details. */
__( '<strong>Note:</strong> WP Mail SMTP plugin is disabled on your site until you fix the issue. <a href="%s" target="_blank" rel="noopener noreferrer">Read more for additional information.</a>', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'target' => array(),
'rel' => array(),
),
'strong' => array(),
)
),
'https://wpforms.com/docs/supported-php-version/'
);
?>
</p>
</div>
<?php
// In case this is on plugin activation.
if ( isset( $_GET['activate'] ) ) { //phpcs:ignore
unset( $_GET['activate'] ); //phpcs:ignore
}
} );
}
/**
* Assign all hooks to proper places.
*
* @since 1.0.0
*/
public function hooks() {
// Activation hook.
add_action( 'activate_plugin', array( $this, 'activate' ), 10, 2 );
// Redefine PHPMailer.
add_action( 'plugins_loaded', array( $this, 'get_processor' ) );
add_action( 'plugins_loaded', array( $this, 'replace_phpmailer' ) );
// Various notifications.
add_action( 'admin_init', array( $this, 'init_notifications' ) );
add_action( 'init', array( $this, 'init' ) );
add_action( 'plugins_loaded', array( $this, 'get_pro' ) );
}
/**
* Initial plugin actions.
*
* @since 1.0.0
*/
public function init() {
// Load translations just in case.
load_plugin_textdomain( 'wp-mail-smtp', false, plugin_basename( wp_mail_smtp()->plugin_path ) . '/assets/languages' );
/*
* Constantly check in admin area, that we don't need to upgrade DB.
* Do not wait for the `admin_init` hook, because some actions are already done
* on `plugins_loaded`, so migration has to be done before.
* We should not fire this in AJAX requests.
*/
if ( WP::in_wp_admin() ) {
$this->get_migration();
$this->get_upgrade();
$this->detect_conflicts();
}
// In admin area, regardless of AJAX or not AJAX request.
if ( is_admin() ) {
$this->get_admin();
$this->get_site_health()->init();
}
// Plugin admin area notices. Display to "admins" only.
if ( current_user_can( 'manage_options' ) ) {
add_action( 'admin_notices', array( '\WPMailSMTP\WP', 'display_admin_notices' ) );
add_action( 'admin_notices', array( $this, 'display_general_notices' ) );
}
}
/**
* Whether the Pro part of the plugin is allowed to be loaded.
*
* @since 1.5.0
* @since 1.6.0 Added a filter.
*
* @return bool
*/
protected function is_pro_allowed() {
$is_allowed = true;
if ( ! is_readable( $this->plugin_path . '/src/Pro/Pro.php' ) ) {
$is_allowed = false;
}
if ( version_compare( phpversion(), '5.6', '<' ) ) {
$is_allowed = false;
}
return apply_filters( 'wp_mail_smtp_core_is_pro_allowed', $is_allowed );
}
/**
* Get/Load the Pro code of the plugin if it exists.
*
* @since 1.6.2
*
* @return \WPMailSMTP\Pro\Pro
*/
public function get_pro() {
if ( ! $this->is_pro_allowed() ) {
return $this->pro;
}
if ( ! $this->is_pro() ) {
$this->pro = new \WPMailSMTP\Pro\Pro();
}
return $this->pro;
}
/**
* This method allows to overwrite certain core WP functions, because it's fired:
* - after `muplugins_loaded` hook,
* - before WordPress own `wp-includes/pluggable.php` file include,
* - before `plugin_loaded` and `plugins_loaded` hooks.
*
* @since 1.5.0
*/
protected function init_early() {
$pro_files = $this->is_pro_allowed() ? \WPMailSMTP\Pro\Pro::PLUGGABLE_FILES : array();
$files = (array) apply_filters( 'wp_mail_smtp_core_init_early_include_files', $pro_files );
foreach ( $files as $file ) {
$path = $this->plugin_path . '/' . $file;
if ( is_readable( $path ) ) {
/** @noinspection PhpIncludeInspection */
include_once $path;
}
}
}
/**
* Load the plugin core processor.
*
* @since 1.0.0
*
* @return Processor
*/
public function get_processor() {
static $processor;
if ( ! isset( $processor ) ) {
$processor = apply_filters( 'wp_mail_smtp_core_get_processor', new Processor() );
}
return $processor;
}
/**
* Load the plugin admin area.
*
* @since 1.0.0
*
* @return Admin\Area
*/
public function get_admin() {
static $admin;
if ( ! isset( $admin ) ) {
$admin = apply_filters( 'wp_mail_smtp_core_get_admin', new Admin\Area() );
}
return $admin;
}
/**
* Load the plugin providers loader.
*
* @since 1.0.0
*
* @return Providers\Loader
*/
public function get_providers() {
static $providers;
if ( ! isset( $providers ) ) {
$providers = apply_filters( 'wp_mail_smtp_core_get_providers', new Providers\Loader() );
}
return $providers;
}
/**
* Load the plugin option migrator.
*
* @since 1.0.0
*
* @return Migration
*/
public function get_migration() {
static $migration;
if ( ! isset( $migration ) ) {
$migration = apply_filters( 'wp_mail_smtp_core_get_migration', new Migration() );
}
return $migration;
}
/**
* Load the plugin upgrader.
*
* @since 1.1.0
*
* @return Upgrade
*/
public function get_upgrade() {
static $upgrade;
if ( ! isset( $upgrade ) ) {
$upgrade = apply_filters( 'wp_mail_smtp_core_get_upgrade', new Upgrade() );
}
return $upgrade;
}
/**
* Get the plugin's WP Site Health object.
*
* @since {VERSION}
*
* @return SiteHealth
*/
public function get_site_health() {
static $site_health;
if ( ! isset( $site_health ) ) {
$site_health = apply_filters( 'wp_mail_smtp_core_get_site_health', new SiteHealth() );
}
return $site_health;
}
/**
* Display various notifications to a user
*
* @since 1.0.0
*/
public function init_notifications() {
// Old PHP version notification.
if (
version_compare( phpversion(), '5.6', '<' ) &&
is_super_admin() &&
(
isset( $GLOBALS['pagenow'] ) &&
$GLOBALS['pagenow'] === 'index.php'
)
) {
WP::add_admin_notice(
sprintf(
wp_kses( /* translators: %1$s - WP Mail SMTP plugin name; %2$s - WPForms.com URL to a related doc. */
__( 'Your site is running an outdated version of PHP that is no longer supported and may cause issues with %1$s. <a href="%2$s" target="_blank" rel="noopener noreferrer">Read more</a> for additional information.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'target' => array(),
'rel' => array(),
),
)
),
'<strong>WP Mail SMTP</strong>',
'https://wpforms.com/docs/supported-php-version/'
) .
'<br><br><em>' .
wp_kses(
__( '<strong>Please Note:</strong> Support for PHP 5.3-5.5 will be discontinued in 2020. After this, if no further action is taken, WP Mail SMTP functionality will be disabled.', 'wp-mail-smtp' ),
array(
'strong' => array(),
'em' => array(),
)
) .
'</em>',
WP::ADMIN_NOTICE_ERROR,
false
);
}
// Awesome Motive Notifications.
if ( Options::init()->get( 'general', 'am_notifications_hidden' ) ) {
return;
}
}
/**
* Display all debug mail-delivery related notices.
*
* @since 1.3.0
* @since 1.6.0 Added a filter that allows to hide debug errors.
*/
public static function display_general_notices() {
if ( wp_mail_smtp()->is_blocked() ) {
?>
<div class="notice <?php echo esc_attr( WP::ADMIN_NOTICE_ERROR ); ?>">
<p>
<?php
$notices[] = sprintf(
wp_kses( /* translators: %s - plugin name and its version. */
__( '<strong>EMAILING DISABLED:</strong> The %s is currently blocking all emails from being sent.', 'wp-mail-smtp' ),
array(
'strong' => true,
)
),
esc_html( 'WP Mail SMTP v' . WPMS_PLUGIN_VER )
);
if ( Options::init()->is_const_defined( 'general', 'do_not_send' ) ) {
$notices[] = sprintf(
wp_kses( /* translators: %1$s - constant name; %2$s - constant value. */
__( 'To send emails, change the value of the %1$s constant to %2$s.', 'wp-mail-smtp' ),
array(
'code' => true,
)
),
'<code>WPMS_DO_NOT_SEND</code>',
'<code>false</code>'
);
} else {
$notices[] = sprintf(
wp_kses( /* translators: %s - plugin Misc settings page URL. */
__( 'To send emails, go to plugin <a href="%s">Misc settings</a> and disable the "Do Not Send" option.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => true,
),
)
),
esc_url( add_query_arg( 'tab', 'misc', wp_mail_smtp()->get_admin()->get_admin_page_url() ) )
);
}
echo implode( ' ', $notices );
?>
</p>
</div>
<?php
return;
}
if ( wp_mail_smtp()->get_admin()->is_error_delivery_notice_enabled() ) {
$notice = Debug::get_last();
if ( ! empty( $notice ) ) {
?>
<div class="notice <?php echo esc_attr( WP::ADMIN_NOTICE_ERROR ); ?>">
<p>
<?php
printf(
wp_kses( /* translators: %s - plugin name and its version. */
__( '<strong>EMAIL DELIVERY ERROR:</strong> the plugin %s logged this error during the last time it tried to send an email:', 'wp-mail-smtp' ),
array(
'strong' => array(),
)
),
esc_html( 'WP Mail SMTP v' . WPMS_PLUGIN_VER )
);
?>
</p>
<blockquote>
<pre><?php echo $notice; ?></pre>
</blockquote>
<p>
<?php
if ( ! wp_mail_smtp()->get_admin()->is_admin_page() ) {
printf(
wp_kses( /* translators: %s - plugin admin page URL. */
__( 'Please review your WP Mail SMTP settings in <a href="%s">plugin admin area</a>.' ) . ' ',
array(
'a' => array(
'href' => array(),
),
)
),
esc_url( wp_mail_smtp()->get_admin()->get_admin_page_url() )
);
}
esc_html_e( 'Consider running an email test after fixing it.', 'wp-mail-smtp' );
?>
</p>
</div>
<?php
}
}
}
/**
* Check whether we are working with a new plugin install.
*
* @since 1.3.0
*
* @return bool
*/
protected function is_new_install() {
/*
* No previously installed 0.*.
* 'wp_mail_smtp_initial_version' option appeared in 1.3.0. So we make sure it exists.
* No previous plugin upgrades.
*/
if (
! get_option( 'mailer', false ) &&
get_option( 'wp_mail_smtp_initial_version', false ) &&
version_compare( WPMS_PLUGIN_VER, get_option( 'wp_mail_smtp_initial_version' ), '=' )
) {
return true;
}
return false;
}
/**
* Detect if there are plugins activated that will cause a conflict.
*
* @since 1.3.0
* @since 1.5.0 Moved the logic to Conflicts class.
*/
public function detect_conflicts() {
// Display only for those who can actually deactivate plugins.
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$conflicts = new Conflicts();
if ( $conflicts->is_detected() ) {
$conflicts->notify();
}
}
/**
* Init the \PHPMailer replacement.
*
* @since 1.0.0
*
* @return \WPMailSMTP\MailCatcher
*/
public function replace_phpmailer() {
global $phpmailer;
return $this->replace_w_fake_phpmailer( $phpmailer );
}
/**
* Overwrite default PhpMailer with our MailCatcher.
*
* @since 1.0.0
* @since 1.5.0 Throw external PhpMailer exceptions, inherits default WP behavior.
*
* @param null $obj PhpMailer object to override with own implementation.
*
* @return \WPMailSMTP\MailCatcher
*/
protected function replace_w_fake_phpmailer( &$obj = null ) {
$obj = new MailCatcher( true );
return $obj;
}
/**
* What to do on plugin activation.
*
* @since 1.0.0
*
* @param string $plugin Path to the plugin file relative to the plugins directory.
* @param bool $network_wide Whether to enable the plugin for all sites in the network
* or just the current site. Multisite only. Default is false.
*/
public function activate( $plugin, $network_wide ) {
// Store the plugin version when initial install occurred.
add_option( 'wp_mail_smtp_initial_version', WPMS_PLUGIN_VER, '', false );
// Store the plugin version activated to reference with upgrades.
update_option( 'wp_mail_smtp_version', WPMS_PLUGIN_VER, false );
// Save default options, only once.
Options::init()->set( Options::get_defaults(), true );
}
/**
* Whether this is a Pro version of a plugin.
*
* @since 1.5.0
*
* @return bool
*/
public function is_pro() {
return apply_filters( 'wp_mail_smtp_core_is_pro', ! empty( $this->pro ) );
}
/**
* Get the current license type.
*
* @since 1.5.0
*
* @return string Default value: lite.
*/
public function get_license_type() {
$type = Options::init()->get( 'license', 'type' );
if ( empty( $type ) ) {
$type = 'lite';
}
return strtolower( $type );
}
/**
* Get the current license key.
*
* @since 1.5.0
*
* @return string
*/
public function get_license_key() {
$key = Options::init()->get( 'license', 'key' );
if ( empty( $key ) ) {
$key = '';
}
return $key;
}
/**
* Upgrade link used within the various admin pages.
*
* @since 1.5.0
* @since 1.5.1 Support all UTM params.
*
* @param array|string $utm Array of UTM params, or if string provided - utm_content URL parameter.
*
* @return string
*/
public function get_upgrade_link( $utm ) {
// Defaults.
$source = 'WordPress';
$medium = 'plugin-settings';
$campaign = 'liteplugin';
$content = 'general';
if ( is_array( $utm ) ) {
if ( isset( $utm['source'] ) ) {
$source = $utm['source'];
}
if ( isset( $utm['medium'] ) ) {
$medium = $utm['medium'];
}
if ( isset( $utm['campaign'] ) ) {
$campaign = $utm['campaign'];
}
if ( isset( $utm['content'] ) ) {
$content = $utm['content'];
}
} elseif ( is_string( $utm ) ) {
$content = $utm;
}
return apply_filters(
'wp_mail_smtp_core_get_upgrade_link',
'https://wpmailsmtp.com/lite-upgrade/?utm_source=' . esc_attr( $source ) . '&utm_medium=' . esc_attr( $medium ) . '&utm_campaign=' . esc_attr( $campaign ) . '&utm_content=' . esc_attr( $content )
);
}
/**
* Whether the emailing functionality is blocked, with either an option or a constatnt.
*
* @since 1.7.0
*
* @return bool
*/
public function is_blocked() {
return (bool) Options::init()->get( 'general', 'do_not_send' );
}
}

View File

@ -0,0 +1,122 @@
<?php
namespace WPMailSMTP;
/**
* Class Debug that will save all errors or warnings generated by APIs or SMTP
* and display in area for administrators.
*
* Usage example:
* Debug::set( 'Some warning: %s', array( '%s' => $e->getMessage() );
* $debug = Debug::get(); // array
* $debug = Debug::get_last(); // string
*
* @since 1.2.0
*/
class Debug {
/**
* Key for options table where all messages will be saved to.
*/
const OPTION_KEY = 'wp_mail_smtp_debug';
/**
* Save unique debug message to a debug log.
* Adds one more to a list, at the end.
*
* @since 1.2.0
*
* @param mixed $message
*/
public static function set( $message ) {
if ( empty( $message ) ) {
return;
}
if ( ! is_string( $message ) ) {
$message = wp_json_encode( $message );
} else {
$message = wp_strip_all_tags( $message, false );
}
$all = self::get();
array_push( $all, $message );
update_option( self::OPTION_KEY, array_unique( $all ), false );
}
/**
* Remove all messages for a debug log.
*
* @since 1.2.0
*/
public static function clear() {
update_option( self::OPTION_KEY, array(), false );
}
/**
* Retrieve all messages from a debug log.
*
* @since 1.2.0
*
* @return array
*/
public static function get() {
$all = get_option( self::OPTION_KEY, array() );
if ( ! is_array( $all ) ) {
$all = (array) $all;
}
return $all;
}
/**
* Get the last message that was saved to a debug log.
*
* @since 1.2.0
*
* @return string
*/
public static function get_last() {
$all = self::get();
if ( ! empty( $all ) && is_array( $all ) ) {
return (string) end( $all );
}
return '';
}
/**
* Get the proper variable content output to debug.
*
* @since 1.2.0
*
* @param mixed $var
*
* @return string
*/
public static function pvar( $var = '' ) {
ob_start();
echo '<code>';
if ( is_bool( $var ) || empty( $var ) ) {
var_dump( $var );
} else {
print_r( $var );
}
echo '</code>';
$output = ob_get_clean();
return str_replace( array( "\r\n", "\r", "\n" ), '', $output );
}
}

View File

@ -0,0 +1,163 @@
<?php
namespace WPMailSMTP;
/**
* Class Geo to work with location, domain, IPs etc.
*
* @since 1.5.0
*/
class Geo {
/**
* Get the current site hostname.
* In case of CLI we don't have SERVER_NAME, so use host name instead, may be not a domain name.
* Examples: example.com, localhost.
*
* @since 1.5.0
*
* @return string
*/
public static function get_site_domain() {
return ! empty( $_SERVER['SERVER_NAME'] ) ? wp_unslash( $_SERVER['SERVER_NAME'] ) : wp_parse_url( get_home_url( get_current_blog_id() ), PHP_URL_HOST );
}
/**
* Get the domain IP address.
* Uses gethostbyname() which is quite slow, but this is done only one time.
*
* @since 1.5.0
*
* @param string $domain
*
* @return string
*/
public static function get_ip_by_domain( $domain ) {
if ( $domain === 'localhost' ) {
return '127.0.0.1';
}
return gethostbyname( $domain );
}
/**
* Get the location coordinates by IP address.
* We make a request to 3rd party services.
*
* @since 1.5.0
* @since 1.6.0 Added new geo API endpoint, provided by WPForms.
*
* @param string $ip
*
* @return array Empty array for localhost.
*/
public static function get_location_by_ip( $ip ) {
// Check for a non-local IP.
if ( empty( $ip ) || in_array( $ip, array( '127.0.0.1', '::1' ), true ) ) {
return array();
}
$request = wp_remote_get( 'https://geo.wpforms.com/v2/geolocate/json/' . $ip );
if ( ! is_wp_error( $request ) ) {
$request = json_decode( wp_remote_retrieve_body( $request ), true );
if ( ! empty( $request['latitude'] ) && ! empty( $request['longitude'] ) ) {
$data = array(
'latitude' => sanitize_text_field( $request['latitude'] ),
'longitude' => sanitize_text_field( $request['longitude'] ),
'city' => sanitize_text_field( $request['city'] ),
'region' => sanitize_text_field( $request['region_name'] ),
'country' => sanitize_text_field( $request['country_code'] ),
'postal' => sanitize_text_field( $request['zip_code'] ),
);
return $data;
}
}
$request = wp_remote_get( 'https://ipapi.co/' . $ip . '/json' );
if ( ! is_wp_error( $request ) ) {
$request = json_decode( wp_remote_retrieve_body( $request ), true );
if ( ! empty( $request['latitude'] ) && ! empty( $request['longitude'] ) ) {
$data = array(
'latitude' => sanitize_text_field( $request['latitude'] ),
'longitude' => sanitize_text_field( $request['longitude'] ),
'city' => sanitize_text_field( $request['city'] ),
'region' => sanitize_text_field( $request['region'] ),
'country' => sanitize_text_field( $request['country'] ),
'postal' => sanitize_text_field( $request['postal'] ),
);
return $data;
}
}
$request = wp_remote_get( 'https://tools.keycdn.com/geo.json?host=' . $ip );
if ( ! is_wp_error( $request ) ) {
$request = json_decode( wp_remote_retrieve_body( $request ), true );
if ( ! empty( $request['data']['geo']['latitude'] ) && ! empty( $request['data']['geo']['longitude'] ) ) {
$data = array(
'latitude' => sanitize_text_field( $request['data']['geo']['latitude'] ),
'longitude' => sanitize_text_field( $request['data']['geo']['longitude'] ),
'city' => sanitize_text_field( $request['data']['geo']['city'] ),
'region' => sanitize_text_field( $request['data']['geo']['region_name'] ),
'country' => sanitize_text_field( $request['data']['geo']['country_code'] ),
'postal' => sanitize_text_field( $request['data']['geo']['postal_code'] ),
);
return $data;
}
}
return array();
}
/**
* This routine calculates the distance between two points (given the latitude/longitude of those points).
* Definitions: South latitudes are negative, east longitudes are positive.
*
* @see https://www.geodatasource.com/developers/php
*
* @since 1.5.0
*
* @param float $lat1 Latitude of point 1 (in decimal degrees).
* @param float $lon1 Longitude of point 1 (in decimal degrees).
* @param float $lat2 Latitude of point 2 (in decimal degrees).
* @param float $lon2 Longitude of point 2 (in decimal degrees).
* @param string $unit Supported values: M, K, N. Miles by default.
*
* @return float|int
*/
public static function get_distance_between( $lat1, $lon1, $lat2, $lon2, $unit = 'M' ) {
if ( ( $lat1 === $lat2 ) && ( $lon1 === $lon2 ) ) {
return 0;
}
$theta = $lon1 - $lon2;
$dist = sin( deg2rad( $lat1 ) ) * sin( deg2rad( $lat2 ) ) + cos( deg2rad( $lat1 ) ) * cos( deg2rad( $lat2 ) ) * cos( deg2rad( $theta ) );
$dist = acos( $dist );
$dist = rad2deg( $dist );
$miles = $dist * 60 * 1.1515;
$unit = strtoupper( $unit );
if ( $unit === 'K' ) {
return ( $miles * 1.609344 );
} elseif ( $unit === 'N' ) {
return ( $miles * 0.8684 );
}
return $miles;
}
}

View File

@ -0,0 +1,145 @@
<?php
namespace WPMailSMTP;
// Load PHPMailer class, so we can subclass it.
if ( ! class_exists( 'PHPMailer', false ) ) {
require_once ABSPATH . WPINC . '/class-phpmailer.php';
}
/**
* Class MailCatcher replaces the \PHPMailer and modifies the email sending logic.
* Thus, we can use other mailers API to do what we need, or stop emails completely.
*
* @since 1.0.0
*/
class MailCatcher extends \PHPMailer {
/**
* Callback Action function name.
*
* The function that handles the result of the send email action.
* It is called out by send() for each email sent.
*
* @since 1.3.0
*
* @var string
*/
public $action_function = '\WPMailSMTP\Processor::send_callback';
/**
* Modify the default send() behaviour.
* For those mailers, that relies on PHPMailer class - call it directly.
* For others - init the correct provider and process it.
*
* @since 1.0.0
* @since 1.4.0 Process "Do Not Send" option, but always allow test email.
*
* @throws \phpmailerException When sending via PhpMailer fails for some reason.
*
* @return bool
*/
public function send() {
$options = new Options();
$mail_mailer = sanitize_key( $options->get( 'mail', 'mailer' ) );
$is_emailing_blocked = false;
if ( wp_mail_smtp()->is_blocked() ) {
$is_emailing_blocked = true;
}
// Always allow a test email - check for the specific header.
foreach ( (array) $this->getCustomHeaders() as $header ) {
if (
! empty( $header[0] ) &&
! empty( $header[1] ) &&
$header[0] === 'X-Mailer-Type' &&
trim( $header[1] ) === 'WPMailSMTP/Admin/Test'
) {
$is_emailing_blocked = false;
}
};
// Do not send emails if admin desired that.
if ( $is_emailing_blocked ) {
return false;
}
// Define a custom header, that will be used to identify the plugin and the mailer.
$this->XMailer = 'WPMailSMTP/Mailer/' . $mail_mailer . ' ' . WPMS_PLUGIN_VER;
// Use the default PHPMailer, as we inject our settings there for certain providers.
if (
$mail_mailer === 'mail' ||
$mail_mailer === 'smtp' ||
$mail_mailer === 'pepipost'
) {
try {
// Prepare all the headers.
if ( ! $this->preSend() ) {
return false;
}
// Allow to hook after all the preparation before the actual sending.
do_action( 'wp_mail_smtp_mailcatcher_smtp_send_before', $this );
return $this->postSend();
} catch ( \phpmailerException $e ) {
$this->mailHeader = '';
$this->setError( $e->getMessage() );
if ( $this->exceptions ) {
throw $e;
}
return false;
}
}
// We need this so that the \PHPMailer class will correctly prepare all the headers.
$this->Mailer = 'mail';
// Prepare everything (including the message) for sending.
if ( ! $this->preSend() ) {
return false;
}
$mailer = wp_mail_smtp()->get_providers()->get_mailer( $mail_mailer, $this );
if ( ! $mailer ) {
return false;
}
if ( ! $mailer->is_php_compatible() ) {
return false;
}
/*
* Send the actual email.
* We reuse everything, that was preprocessed for usage in \PHPMailer.
*/
$mailer->send();
$is_sent = $mailer->is_email_sent();
// Allow to perform any actions with the data.
do_action( 'wp_mail_smtp_mailcatcher_send_after', $mailer, $this );
return $is_sent;
}
/**
* Returns all custom headers.
* In older versions of \PHPMailer class this method didn't exist.
* As we support WordPress 3.6+ - we need to make sure this method is always present.
*
* @since 1.5.0
*
* @return array
*/
public function getCustomHeaders() {
return $this->CustomHeader;
}
}

View File

@ -0,0 +1,257 @@
<?php
namespace WPMailSMTP;
/**
* Class Migration helps migrate all plugin options saved into DB to a new storage location.
*
* @since 1.0.0
*/
class Migration {
/**
* All old values for pre 1.0 version of a plugin.
*
* @since 1.0.0
*
* @var array
*/
protected $old_keys = array(
'pepipost_ssl',
'pepipost_port',
'pepipost_pass',
'pepipost_user',
'smtp_pass',
'smtp_user',
'smtp_auth',
'smtp_ssl',
'smtp_port',
'smtp_host',
'mail_set_return_path',
'mailer',
'mail_from_name',
'mail_from',
'wp_mail_smtp_am_notifications_hidden',
);
/**
* Old values, taken from $old_keys options.
*
* @since 1.0.0
*
* @var array
*/
protected $old_values = array();
/**
* Converted array of data from previous option values.
*
* @since 1.0.0
*
* @var array
*/
protected $new_values = array();
/**
* Migration constructor.
*
* @since 1.0.0
*/
public function __construct() {
if ( $this->is_migrated() ) {
return;
}
$this->old_values = $this->get_old_values();
$this->new_values = $this->get_converted_options();
Options::init()->set( $this->new_values, true );
// Removing all old options will be enabled some time in the future.
// $this->clean_deprecated_data();
}
/**
* Whether we already migrated or not.
*
* @since 1.0.0
*
* @return bool
*/
protected function is_migrated() {
$is_migrated = false;
$new_values = get_option( Options::META_KEY, array() );
if ( ! empty( $new_values ) ) {
$is_migrated = true;
}
return $is_migrated;
}
/**
* Get all old values from DB.
*
* @since 1.0.0
*
* @return array
*/
protected function get_old_values() {
$old_values = array();
foreach ( $this->old_keys as $old_key ) {
$value = get_option( $old_key, '' );
if ( ! empty( $value ) ) {
$old_values[ $old_key ] = $value;
}
}
return $old_values;
}
/**
* Convert old values from key=>value to a multidimensional array of data.
*
* @since 1.0.0
*/
protected function get_converted_options() {
$converted = array();
foreach ( $this->old_keys as $old_key ) {
$old_value = isset( $this->old_values[ $old_key ] ) ? $this->old_values[ $old_key ] : '';
switch ( $old_key ) {
case 'pepipost_user':
case 'pepipost_pass':
case 'pepipost_port':
case 'pepipost_ssl':
// Do not migrate pepipost options if it's not activated at the moment.
if ( isset( $this->old_values['mailer'] ) && $this->old_values['mailer'] === 'pepipost' ) {
$shortcut = explode( '_', $old_key );
if ( $old_key === 'pepipost_ssl' ) {
$converted[ $shortcut[0] ]['encryption'] = $old_value;
} else {
$converted[ $shortcut[0] ][ $shortcut[1] ] = $old_value;
}
}
break;
case 'smtp_host':
case 'smtp_port':
case 'smtp_ssl':
case 'smtp_auth':
case 'smtp_user':
case 'smtp_pass':
$shortcut = explode( '_', $old_key );
if ( $old_key === 'smtp_ssl' ) {
$converted[ $shortcut[0] ]['encryption'] = $old_value;
} elseif ( $old_key === 'smtp_auth' ) {
$converted[ $shortcut[0] ][ $shortcut[1] ] = ( $old_value === 'true' ? 'yes' : 'no' );
} else {
$converted[ $shortcut[0] ][ $shortcut[1] ] = $old_value;
}
break;
case 'mail_from':
$converted['mail']['from_email'] = $old_value;
break;
case 'mail_from_name':
$converted['mail']['from_name'] = $old_value;
break;
case 'mail_set_return_path':
$converted['mail']['return_path'] = ( $old_value === 'true' );
break;
case 'mailer':
$converted['mail']['mailer'] = $old_value;
break;
case 'wp_mail_smtp_am_notifications_hidden':
$converted['general']['am_notifications_hidden'] = ( isset( $old_value ) && $old_value === 'true' );
break;
}
}
$converted = $this->get_converted_constants_options( $converted );
return $converted;
}
/**
* Some users use constants in wp-config.php to define values.
* We need to prioritize them and reapply data to options.
* Use only those that are actually defined.
*
* @since 1.0.0
*
* @param array $converted
*
* @return array
*/
protected function get_converted_constants_options( $converted ) {
// Are we configured via constants?
if ( ! defined( 'WPMS_ON' ) || ! WPMS_ON ) {
return $converted;
}
/*
* Mail settings.
*/
if ( defined( 'WPMS_MAIL_FROM' ) ) {
$converted['mail']['from_email'] = WPMS_MAIL_FROM;
}
if ( defined( 'WPMS_MAIL_FROM_NAME' ) ) {
$converted['mail']['from_name'] = WPMS_MAIL_FROM_NAME;
}
if ( defined( 'WPMS_MAILER' ) ) {
$converted['mail']['mailer'] = WPMS_MAILER;
}
if ( defined( 'WPMS_SET_RETURN_PATH' ) ) {
$converted['mail']['return_path'] = WPMS_SET_RETURN_PATH;
}
/*
* SMTP settings.
*/
if ( defined( 'WPMS_SMTP_HOST' ) ) {
$converted['smtp']['host'] = WPMS_SMTP_HOST;
}
if ( defined( 'WPMS_SMTP_PORT' ) ) {
$converted['smtp']['port'] = WPMS_SMTP_PORT;
}
if ( defined( 'WPMS_SSL' ) ) {
$converted['smtp']['ssl'] = WPMS_SSL;
}
if ( defined( 'WPMS_SMTP_AUTH' ) ) {
$converted['smtp']['auth'] = WPMS_SMTP_AUTH;
}
if ( defined( 'WPMS_SMTP_USER' ) ) {
$converted['smtp']['user'] = WPMS_SMTP_USER;
}
if ( defined( 'WPMS_SMTP_PASS' ) ) {
$converted['smtp']['pass'] = WPMS_SMTP_PASS;
}
return $converted;
}
/**
* Delete all old values that are stored separately each.
*
* @since 1.0.0
*/
protected function clean_deprecated_data() {
foreach ( $this->old_keys as $old_key ) {
delete_option( $old_key );
}
}
}

View File

@ -0,0 +1,937 @@
<?php
namespace WPMailSMTP;
/**
* Class Options to handle all options management.
* WordPress does all the heavy work for caching get_option() data,
* so we don't have to do that. But we want to minimize cyclomatic complexity
* of calling a bunch of WP functions, thus we will cache them in a class as well.
*
* @since 1.0.0
*/
class Options {
/**
* All the options keys.
*
* @since 1.3.0
* @since 1.4.0 Added Mailgun:region.
* @since 1.5.0 Added Outlook/AmazonSES.
* @since 1.8.0 Added Pepipost API.
*
* @since
*
* @var array Map of all the default options of the plugin.
*/
private static $map = array(
'mail' => array(
'from_name',
'from_email',
'mailer',
'return_path',
'from_name_force',
'from_email_force',
),
'smtp' => array(
'host',
'port',
'encryption',
'autotls',
'auth',
'user',
'pass',
),
'gmail' => array(
'client_id',
'client_secret',
),
'outlook' => array(
'client_id',
'client_secret',
),
'amazonses' => array(
'client_id',
'client_secret',
'region',
'emails_pending',
),
'mailgun' => array(
'api_key',
'domain',
'region',
),
'sendgrid' => array(
'api_key',
),
'sendinblue' => array(
'api_key',
),
'pepipostapi' => array(
'api_key',
),
'pepipost' => array(
'host',
'port',
'encryption',
'auth',
'user',
'pass',
),
'license' => array(
'key',
),
);
/**
* That's where plugin options are saved in wp_options table.
*
* @var string
*/
const META_KEY = 'wp_mail_smtp';
/**
* All the plugin options.
*
* @var array
*/
private $_options = array();
/**
* Init the Options class.
* TODO: add a flag to process without retrieving const values.
*
* @since 1.0.0
*/
public function __construct() {
$this->populate_options();
}
/**
* Initialize all the options, used for chaining.
*
* One-liner:
* Options::init()->get('smtp', 'host');
* Options::init()->is_pepipost_active();
*
* Or multiple-usage:
* $options = new Options();
* $options->get('smtp', 'host');
*
* @since 1.0.0
*
* @return Options
*/
public static function init() {
static $instance;
if ( ! $instance ) {
$instance = new self();
}
return $instance;
}
/**
* Default options that are saved on plugin activation.
*
* @since 1.3.0
*
* @return array
*/
public static function get_defaults() {
return array(
'mail' => array(
'from_email' => get_option( 'admin_email' ),
'from_name' => get_bloginfo( 'name' ),
'mailer' => 'mail',
'return_path' => false,
'from_email_force' => false,
'from_name_force' => false,
),
'smtp' => array(
'autotls' => true,
'auth' => true,
),
);
}
/**
* Retrieve all options of the plugin.
*
* @since 1.0.0
*/
protected function populate_options() {
$this->_options = get_option( self::META_KEY, array() );
}
/**
* Get all the options.
*
* Options::init()->get_all();
*
* @since 1.0.0
*
* @return array
*/
public function get_all() {
$options = $this->_options;
foreach ( $options as $group => $g_value ) {
foreach ( $g_value as $key => $value ) {
$options[ $group ][ $key ] = $this->get( $group, $key );
}
}
return apply_filters( 'wp_mail_smtp_options_get_all', $options );
}
/**
* Get all the options for a group.
*
* Options::init()->get_group('smtp') - will return the array of options for the group, including defaults and constants.
*
* @since 1.0.0
* @since 1.5.0 Process values through the get() method which is aware of constants.
*
* @param string $group
*
* @return array
*/
public function get_group( $group ) {
// Just to feel safe.
$group = sanitize_key( $group );
/*
* Get the values saved in DB.
* If plugin is configured with constants right from the start - this will not have all the values.
*/
$options = isset( $this->_options[ $group ] ) ? $this->_options[ $group ] : array();
// We need to process certain constants-aware options through actual constants.
if ( isset( self::$map[ $group ] ) ) {
foreach ( self::$map[ $group ] as $key ) {
$options[ $key ] = $this->get( $group, $key );
}
}
return apply_filters( 'wp_mail_smtp_options_get_group', $options, $group );
}
/**
* Get options by a group and a key.
*
* Options::init()->get( 'smtp', 'host' ) - will return only SMTP 'host' option.
*
* @since 1.0.0
*
* @param string $group
* @param string $key
*
* @return mixed|null Null if value doesn't exist anywhere: in constants, in DB, in a map. So it's completely custom or a typo.
*/
public function get( $group, $key ) {
// Just to feel safe.
$group = sanitize_key( $group );
$key = sanitize_key( $key );
$value = null;
// Get the const value if we have one.
$value = $this->get_const_value( $group, $key, $value );
// We don't have a const value.
if ( $value === null ) {
// Ordinary database or default values.
if ( isset( $this->_options[ $group ] ) ) {
// Get the options key of a group.
if ( isset( $this->_options[ $group ][ $key ] ) ) {
$value = $this->_options[ $group ][ $key ];
} else {
$value = $this->postprocess_key_defaults( $group, $key );
}
} else {
/*
* Fallback to default if it doesn't exist in a map.
* Allow to retrieve only values from a map.
*/
if (
isset( self::$map[ $group ] ) &&
in_array( $key, self::$map[ $group ], true )
) {
$value = $this->postprocess_key_defaults( $group, $key );
}
}
}
// Strip slashes only from values saved in DB. Constants should be processed as is.
if ( is_string( $value ) && ! $this->is_const_defined( $group, $key ) ) {
$value = stripslashes( $value );
}
return apply_filters( 'wp_mail_smtp_options_get', $value, $group, $key );
}
/**
* Some options may be non-empty by default,
* so we need to postprocess them to convert.
*
* @since 1.0.0
* @since 1.4.0 Added Mailgun:region.
* @since 1.5.0 Added Outlook/AmazonSES, license key support.
*
* @param string $group
* @param string $key
*
* @return mixed
*/
protected function postprocess_key_defaults( $group, $key ) {
$value = '';
switch ( $key ) {
case 'from_email_force':
case 'from_name_force':
case 'return_path':
$value = $group === 'mail' ? false : true;
break;
case 'mailer':
$value = 'mail';
break;
case 'encryption':
$value = in_array( $group, array( 'smtp', 'pepipost' ), true ) ? 'none' : $value;
break;
case 'region':
$value = $group === 'mailgun' ? 'US' : $value;
break;
case 'emails_pending':
$value = array();
break;
case 'auth':
case 'autotls':
$value = in_array( $group, array( 'smtp', 'pepipost' ), true ) ? false : true;
break;
case 'pass':
$value = $this->get_const_value( $group, $key, $value );
break;
case 'type':
$value = $group === 'license' ? 'lite' : '';
break;
}
return apply_filters( 'wp_mail_smtp_options_postprocess_key_defaults', $value, $group, $key );
}
/**
* Process the options values through the constants check.
* If we have defined associated constant - use it instead of a DB value.
* Backward compatibility is hard.
* General section of options won't have constants, so we are omitting those checks and just return default value.
*
* @since 1.0.0
* @since 1.4.0 Added WPMS_MAILGUN_REGION.
* @since 1.5.0 Added Outlook/AmazonSES, license key support.
* @since 1.6.0 Added Sendinblue.
* @since 1.7.0 Added Do Not Send.
* @since 1.8.0 Added Pepipost API.
*
* @param string $group
* @param string $key
* @param mixed $value
*
* @return mixed
*/
protected function get_const_value( $group, $key, $value ) {
if ( ! $this->is_const_enabled() ) {
return $value;
}
$return = null;
switch ( $group ) {
case 'mail':
switch ( $key ) {
case 'from_name':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_MAIL_FROM_NAME : $value;
break;
case 'from_email':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_MAIL_FROM : $value;
break;
case 'mailer':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_MAILER : $value;
break;
case 'return_path':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_SET_RETURN_PATH : $value;
break;
case 'from_name_force':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_MAIL_FROM_NAME_FORCE : $value;
break;
case 'from_email_force':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_MAIL_FROM_FORCE : $value;
break;
}
break;
case 'smtp':
switch ( $key ) {
case 'host':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_SMTP_HOST : $value;
break;
case 'port':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_SMTP_PORT : $value;
break;
case 'encryption':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? ( WPMS_SSL === '' ? 'none' : WPMS_SSL ) : $value;
break;
case 'auth':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_SMTP_AUTH : $value;
break;
case 'autotls':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_SMTP_AUTOTLS : $value;
break;
case 'user':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_SMTP_USER : $value;
break;
case 'pass':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_SMTP_PASS : $value;
break;
}
break;
case 'gmail':
switch ( $key ) {
case 'client_id':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_GMAIL_CLIENT_ID : $value;
break;
case 'client_secret':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_GMAIL_CLIENT_SECRET : $value;
break;
}
break;
case 'outlook':
switch ( $key ) {
case 'client_id':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_OUTLOOK_CLIENT_ID : $value;
break;
case 'client_secret':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_OUTLOOK_CLIENT_SECRET : $value;
break;
}
break;
case 'amazonses':
switch ( $key ) {
case 'client_id':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_AMAZONSES_CLIENT_ID : $value;
break;
case 'client_secret':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_AMAZONSES_CLIENT_SECRET : $value;
break;
case 'region':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_AMAZONSES_REGION : $value;
break;
}
break;
case 'mailgun':
switch ( $key ) {
case 'api_key':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_MAILGUN_API_KEY : $value;
break;
case 'domain':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_MAILGUN_DOMAIN : $value;
break;
case 'region':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_MAILGUN_REGION : $value;
break;
}
break;
case 'sendgrid':
switch ( $key ) {
case 'api_key':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_SENDGRID_API_KEY : $value;
break;
}
break;
case 'sendinblue':
switch ( $key ) {
case 'api_key':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_SENDINBLUE_API_KEY : $value;
break;
}
break;
case 'pepipostapi':
switch ( $key ) {
case 'api_key':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_PEPIPOST_API_KEY : $value;
break;
}
break;
case 'license':
switch ( $key ) {
case 'key':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_LICENSE_KEY : $value;
break;
}
break;
case 'general':
switch ( $key ) {
case 'do_not_send':
/** @noinspection PhpUndefinedConstantInspection */
$return = $this->is_const_defined( $group, $key ) ? WPMS_DO_NOT_SEND : $value;
break;
}
break;
default:
// Always return the default value if nothing from above matches the request.
$return = $value;
}
return apply_filters( 'wp_mail_smtp_options_get_const_value', $return, $group, $key, $value );
}
/**
* Whether constants redefinition is enabled or not.
*
* @since 1.0.0
* @since 1.5.0 Added filter to redefine the value.
*
* @return bool
*/
public function is_const_enabled() {
$return = defined( 'WPMS_ON' ) && WPMS_ON === true;
return apply_filters( 'wp_mail_smtp_options_is_const_enabled', $return );
}
/**
* We need this check to reuse later in admin area,
* to distinguish settings fields that were redefined,
* and display them differently.
*
* @since 1.0.0
* @since 1.5.0 Added a filter, Outlook/AmazonSES, license key support.
* @since 1.6.0 Added Sendinblue.
* @since 1.7.0 Added Do Not Send.
* @since 1.8.0 Added Pepipost API.
*
* @param string $group
* @param string $key
*
* @return bool
*/
public function is_const_defined( $group, $key ) {
if ( ! $this->is_const_enabled() ) {
return false;
}
// Just to feel safe.
$group = sanitize_key( $group );
$key = sanitize_key( $key );
$return = false;
switch ( $group ) {
case 'mail':
switch ( $key ) {
case 'from_name':
$return = defined( 'WPMS_MAIL_FROM_NAME' ) && WPMS_MAIL_FROM_NAME;
break;
case 'from_email':
$return = defined( 'WPMS_MAIL_FROM' ) && WPMS_MAIL_FROM;
break;
case 'mailer':
$return = defined( 'WPMS_MAILER' ) && WPMS_MAILER;
break;
case 'return_path':
$return = defined( 'WPMS_SET_RETURN_PATH' ) && ( WPMS_SET_RETURN_PATH === 'true' || WPMS_SET_RETURN_PATH === true );
break;
case 'from_name_force':
$return = defined( 'WPMS_MAIL_FROM_NAME_FORCE' ) && ( WPMS_MAIL_FROM_NAME_FORCE === 'true' || WPMS_MAIL_FROM_NAME_FORCE === true );
break;
case 'from_email_force':
$return = defined( 'WPMS_MAIL_FROM_FORCE' ) && ( WPMS_MAIL_FROM_FORCE === 'true' || WPMS_MAIL_FROM_FORCE === true );
break;
}
break;
case 'smtp':
switch ( $key ) {
case 'host':
$return = defined( 'WPMS_SMTP_HOST' ) && WPMS_SMTP_HOST;
break;
case 'port':
$return = defined( 'WPMS_SMTP_PORT' ) && WPMS_SMTP_PORT;
break;
case 'encryption':
$return = defined( 'WPMS_SSL' );
break;
case 'auth':
$return = defined( 'WPMS_SMTP_AUTH' ) && WPMS_SMTP_AUTH;
break;
case 'autotls':
$return = defined( 'WPMS_SMTP_AUTOTLS' ) && ( WPMS_SMTP_AUTOTLS === 'true' || WPMS_SMTP_AUTOTLS === true );
break;
case 'user':
$return = defined( 'WPMS_SMTP_USER' ) && WPMS_SMTP_USER;
break;
case 'pass':
$return = defined( 'WPMS_SMTP_PASS' ) && WPMS_SMTP_PASS;
break;
}
break;
case 'gmail':
switch ( $key ) {
case 'client_id':
$return = defined( 'WPMS_GMAIL_CLIENT_ID' ) && WPMS_GMAIL_CLIENT_ID;
break;
case 'client_secret':
$return = defined( 'WPMS_GMAIL_CLIENT_SECRET' ) && WPMS_GMAIL_CLIENT_SECRET;
break;
}
break;
case 'outlook':
switch ( $key ) {
case 'client_id':
$return = defined( 'WPMS_OUTLOOK_CLIENT_ID' ) && WPMS_OUTLOOK_CLIENT_ID;
break;
case 'client_secret':
$return = defined( 'WPMS_OUTLOOK_CLIENT_SECRET' ) && WPMS_OUTLOOK_CLIENT_SECRET;
break;
}
break;
case 'amazonses':
switch ( $key ) {
case 'client_id':
$return = defined( 'WPMS_AMAZONSES_CLIENT_ID' ) && WPMS_AMAZONSES_CLIENT_ID;
break;
case 'client_secret':
$return = defined( 'WPMS_AMAZONSES_CLIENT_SECRET' ) && WPMS_AMAZONSES_CLIENT_SECRET;
break;
case 'region':
$return = defined( 'WPMS_AMAZONSES_REGION' ) && WPMS_AMAZONSES_REGION;
break;
}
break;
case 'mailgun':
switch ( $key ) {
case 'api_key':
$return = defined( 'WPMS_MAILGUN_API_KEY' ) && WPMS_MAILGUN_API_KEY;
break;
case 'domain':
$return = defined( 'WPMS_MAILGUN_DOMAIN' ) && WPMS_MAILGUN_DOMAIN;
break;
case 'region':
$return = defined( 'WPMS_MAILGUN_REGION' ) && WPMS_MAILGUN_REGION;
break;
}
break;
case 'sendgrid':
switch ( $key ) {
case 'api_key':
$return = defined( 'WPMS_SENDGRID_API_KEY' ) && WPMS_SENDGRID_API_KEY;
break;
}
break;
case 'sendinblue':
switch ( $key ) {
case 'api_key':
$return = defined( 'WPMS_SENDINBLUE_API_KEY' ) && WPMS_SENDINBLUE_API_KEY;
break;
}
break;
case 'pepipostapi':
switch ( $key ) {
case 'api_key':
$return = defined( 'WPMS_PEPIPOST_API_KEY' ) && WPMS_PEPIPOST_API_KEY;
break;
}
break;
case 'license':
switch ( $key ) {
case 'key':
$return = defined( 'WPMS_LICENSE_KEY' ) && WPMS_LICENSE_KEY;
break;
}
break;
case 'general':
switch ( $key ) {
case 'do_not_send':
/** @noinspection PhpUndefinedConstantInspection */
$return = defined( 'WPMS_DO_NOT_SEND' ) && WPMS_DO_NOT_SEND;
break;
}
break;
}
return apply_filters( 'wp_mail_smtp_options_is_const_defined', $return, $group, $key );
}
/**
* Set plugin options, all at once.
*
* @since 1.0.0
* @since 1.3.0 Added $once argument to save options only if they don't exist already.
* @since 1.4.0 Added Mailgun:region.
* @since 1.5.0 Added Outlook/AmazonSES, Email Log. Stop saving const values into DB.
*
* @param array $options Plugin options to save.
* @param bool $once Whether to update existing options or to add these options only once.
*/
public function set( $options, $once = false ) {
/*
* Process generic options.
*/
foreach ( (array) $options as $group => $keys ) {
foreach ( $keys as $option_name => $option_value ) {
switch ( $group ) {
case 'mail':
switch ( $option_name ) {
case 'from_name':
case 'mailer':
$options[ $group ][ $option_name ] = sanitize_text_field( $option_value );
break;
case 'from_email':
if ( filter_var( $option_value, FILTER_VALIDATE_EMAIL ) ) {
$options[ $group ][ $option_name ] = sanitize_email( $option_value );
} else {
$options[ $group ][ $option_name ] = sanitize_email(
wp_mail_smtp()->get_processor()->get_default_email()
);
}
break;
case 'return_path':
case 'from_name_force':
case 'from_email_force':
$options[ $group ][ $option_name ] = (bool) $option_value;
break;
}
break;
case 'general':
switch ( $option_name ) {
case 'do_not_send':
case 'am_notifications_hidden':
case 'email_delivery_errors_hidden':
case 'uninstall':
$options[ $group ][ $option_name ] = (bool) $option_value;
break;
}
}
}
}
/*
* Process mailers-specific options.
*/
if (
! empty( $options['mail']['mailer'] ) &&
isset( $options[ $options['mail']['mailer'] ] ) &&
in_array( $options['mail']['mailer'], array( 'pepipost', 'pepipostapi', 'smtp', 'sendgrid', 'sendinblue', 'mailgun', 'gmail', 'outlook' ), true )
) {
$mailer = $options['mail']['mailer'];
foreach ( $options[ $mailer ] as $option_name => $option_value ) {
switch ( $option_name ) {
case 'host': // smtp.
case 'user': // smtp.
case 'encryption': // smtp.
case 'region': // mailgun/amazonses.
$options[ $mailer ][ $option_name ] = $this->is_const_defined( $mailer, $option_name ) ? '' : sanitize_text_field( $option_value );
break; // smtp.
case 'port':
$options[ $mailer ][ $option_name ] = $this->is_const_defined( $mailer, $option_name ) ? 25 : (int) $option_value;
break;
case 'auth': // smtp.
case 'autotls': // smtp.
$option_value = (bool) $option_value;
$options[ $mailer ][ $option_name ] = $this->is_const_defined( $mailer, $option_name ) ? false : $option_value;
break;
case 'pass': // smtp.
// Do not process as they may contain certain special characters, but allow to be overwritten using constants.
$options[ $mailer ][ $option_name ] = $this->is_const_defined( $mailer, $option_name ) ? '' : trim( (string) $option_value );
break;
case 'api_key': // mailgun/sendgrid/sendinblue/pepipostapi.
case 'domain': // mailgun.
case 'client_id': // gmail/outlook/amazonses.
case 'client_secret': // gmail/outlook/amazonses.
case 'auth_code': // gmail/outlook.
$options[ $mailer ][ $option_name ] = $this->is_const_defined( $mailer, $option_name ) ? '' : sanitize_text_field( $option_value );
break;
case 'access_token': // gmail/outlook, array().
case 'user_details': // outlook, array().
case 'emails_pending': // amazonses, array().
// These options don't support constants.
$options[ $mailer ][ $option_name ] = $option_value;
break;
}
}
}
$options = apply_filters( 'wp_mail_smtp_options_set', $options );
// Whether to update existing options or to add these options only once if they don't exist yet.
if ( $once ) {
add_option( self::META_KEY, $options, '', 'no' ); // Do not autoload these options.
} else {
update_option( self::META_KEY, $options, 'no' );
}
// Now we need to re-cache values.
$this->populate_options();
}
/**
* Merge recursively, including a proper substitution of values in sub-arrays when keys are the same.
* It's more like array_merge() and array_merge_recursive() combined.
*
* @since 1.0.0
*
* @return array
*/
public static function array_merge_recursive() {
$arrays = func_get_args();
if ( count( $arrays ) < 2 ) {
return isset( $arrays[0] ) ? $arrays[0] : array();
}
$merged = array();
while ( $arrays ) {
$array = array_shift( $arrays );
if ( ! is_array( $array ) ) {
return array();
}
if ( empty( $array ) ) {
continue;
}
foreach ( $array as $key => $value ) {
if ( is_string( $key ) ) {
if (
is_array( $value ) &&
array_key_exists( $key, $merged ) &&
is_array( $merged[ $key ] )
) {
$merged[ $key ] = call_user_func( __METHOD__, $merged[ $key ], $value );
} else {
$merged[ $key ] = $value;
}
} else {
$merged[] = $value;
}
}
}
return $merged;
}
/**
* Check whether the site is using Pepipost SMTP or not.
*
* @since 1.0.0
*
* @return bool
*/
public function is_pepipost_active() {
return apply_filters( 'wp_mail_smtp_options_is_pepipost_active', $this->get( 'mail', 'mailer' ) === 'pepipost' );
}
/**
* Check whether the site is using Pepipost/SMTP as a mailer or not.
*
* @since 1.1.0
*
* @return bool
*/
public function is_mailer_smtp() {
return apply_filters( 'wp_mail_smtp_options_is_mailer_smtp', in_array( $this->get( 'mail', 'mailer' ), array( 'pepipost', 'smtp' ), true ) );
}
}

View File

@ -0,0 +1,252 @@
<?php
namespace WPMailSMTP;
/**
* Class Processor modifies the behaviour of wp_mail() function.
*
* @since 1.0.0
*/
class Processor {
/**
* Processor constructor.
*
* @since 1.0.0
*/
public function __construct() {
$this->hooks();
}
/**
* Assign all hooks to proper places.
*
* @since 1.0.0
*/
public function hooks() {
add_action( 'phpmailer_init', array( $this, 'phpmailer_init' ) );
add_filter( 'wp_mail_from', array( $this, 'filter_mail_from_email' ), 1000 );
add_filter( 'wp_mail_from_name', array( $this, 'filter_mail_from_name' ), 1000 );
}
/**
* Redefine certain PHPMailer options with our custom ones.
*
* @since 1.0.0
*
* @param \PHPMailer $phpmailer It's passed by reference, so no need to return anything.
*/
public function phpmailer_init( $phpmailer ) {
$options = new Options();
$mailer = $options->get( 'mail', 'mailer' );
// Check that mailer is not blank, and if mailer=smtp, host is not blank.
if (
! $mailer ||
( 'smtp' === $mailer && ! $options->get( 'smtp', 'host' ) )
) {
return;
}
// If the mailer is pepipost, make sure we have a username and password.
if (
'pepipost' === $mailer &&
( ! $options->get( 'pepipost', 'user' ) && ! $options->get( 'pepipost', 'pass' ) )
) {
return;
}
// Set the mailer type as per config above, this overrides the already called isMail method.
// It's basically always 'smtp'.
$phpmailer->Mailer = $mailer;
// Set the Sender (return-path) if required.
if ( $options->get( 'mail', 'return_path' ) ) {
$phpmailer->Sender = $phpmailer->From;
}
// Set the SMTPSecure value, if set to none, leave this blank. Possible values: 'ssl', 'tls', ''.
if ( 'none' === $options->get( $mailer, 'encryption' ) ) {
$phpmailer->SMTPSecure = '';
} else {
$phpmailer->SMTPSecure = $options->get( $mailer, 'encryption' );
}
// Check if user has disabled SMTPAutoTLS.
if ( $options->get( $mailer, 'encryption' ) !== 'tls' && ! $options->get( $mailer, 'autotls' ) ) {
$phpmailer->SMTPAutoTLS = false;
}
// If we're sending via SMTP, set the host.
if ( 'smtp' === $mailer ) {
// Set the other options.
$phpmailer->Host = $options->get( $mailer, 'host' );
$phpmailer->Port = $options->get( $mailer, 'port' );
// If we're using smtp auth, set the username & password.
if ( $options->get( $mailer, 'auth' ) ) {
$phpmailer->SMTPAuth = true;
$phpmailer->Username = $options->get( $mailer, 'user' );
$phpmailer->Password = $options->get( $mailer, 'pass' );
}
} elseif ( 'pepipost' === $mailer ) {
// Set the Pepipost settings for BC.
$phpmailer->Mailer = 'smtp';
$phpmailer->Host = 'smtp.pepipost.com';
$phpmailer->Port = $options->get( $mailer, 'port' );
$phpmailer->SMTPSecure = $options->get( $mailer, 'encryption' ) === 'none' ? '' : $options->get( $mailer, 'encryption' );
$phpmailer->SMTPAuth = true;
$phpmailer->Username = $options->get( $mailer, 'user' );
$phpmailer->Password = $options->get( $mailer, 'pass' );
}
// You can add your own options here.
// See the phpmailer documentation for more info: https://github.com/PHPMailer/PHPMailer/tree/5.2-stable.
/** @noinspection PhpUnusedLocalVariableInspection It's passed by reference. */
$phpmailer = apply_filters( 'wp_mail_smtp_custom_options', $phpmailer );
}
/**
* This method will be called every time 'smtp' and 'mail' mailers will be used to send emails.
*
* @since 1.3.0
* @since 1.5.0 Added a do_action() to be able to hook into.
*
* @param bool $is_sent
* @param array $to
* @param array $cc
* @param array $bcc
* @param string $subject
* @param string $body
* @param string $from
*/
public static function send_callback( $is_sent, $to, $cc, $bcc, $subject, $body, $from ) {
if ( ! $is_sent ) {
// Add mailer to the beginning and save to display later.
Debug::set(
'Mailer: ' . esc_html( wp_mail_smtp()->get_providers()->get_options( Options::init()->get( 'mail', 'mailer' ) )->get_title() ) . "\r\n" .
'PHPMailer was able to connect to SMTP server but failed while trying to send an email.'
);
} else {
Debug::clear();
}
do_action( 'wp_mail_smtp_mailcatcher_smtp_send_after', $is_sent, $to, $cc, $bcc, $subject, $body, $from );
}
/**
* Modify the email address that is used for sending emails.
*
* @since 1.0.0
* @since 1.3.0 Forcing email rewrite if option is selected.
* @since 1.7.0 Default email may be empty, so pay attention to that as well.
*
* @param string $wp_email
*
* @return string
*/
public function filter_mail_from_email( $wp_email ) {
$options = new Options();
$forced = $options->get( 'mail', 'from_email_force' );
$from_email = $options->get( 'mail', 'from_email' );
$def_email = $this->get_default_email();
// Return FROM EMAIL if forced in settings.
if ( $forced & ! empty( $from_email ) ) {
return $from_email;
}
// If the FROM EMAIL is not the default, return it unchanged.
if ( ! empty( $def_email ) && $wp_email !== $def_email ) {
return $wp_email;
}
return ! empty( $from_email ) ? $from_email : $wp_email;
}
/**
* Modify the sender name that is used for sending emails.
*
* @since 1.0.0
* @since 1.3.0 Forcing name rewrite if option is selected.
*
* @param string $name
*
* @return string
*/
public function filter_mail_from_name( $name ) {
$options = new Options();
$force = $options->get( 'mail', 'from_name_force' );
// If the FROM NAME is not the default and not forced, return it unchanged.
if ( ! $force && $name !== $this->get_default_name() ) {
return $name;
}
$name = $options->get( 'mail', 'from_name' );
return $name;
}
/**
* Get the default email address based on domain name.
*
* @since 1.0.0
* @since 1.7.0 May return an empty string.
*
* @return string Empty string when we aren't able to get the site domain (CLI, misconfigured server etc).
*/
public function get_default_email() {
$server_name = Geo::get_site_domain();
if ( empty( $server_name ) ) {
return '';
}
// Get rid of www.
$sitename = strtolower( $server_name );
if ( substr( $sitename, 0, 4 ) === 'www.' ) {
$sitename = substr( $sitename, 4 );
}
return 'wordpress@' . $sitename;
}
/**
* Get the default email FROM NAME generated by WordPress.
*
* @since 1.3.0
*
* @return string
*/
public function get_default_name() {
return 'WordPress';
}
/**
* Get or create the phpmailer.
*
* @since {VERSION}
*
* @return \WPMailSMTP\MailCatcher
*/
public function get_phpmailer() {
global $phpmailer;
// Make sure the PHPMailer class has been instantiated.
if ( ! is_object( $phpmailer ) || ! is_a( $phpmailer, 'PHPMailer' ) ) {
require_once ABSPATH . WPINC . '/class-phpmailer.php';
$phpmailer = new MailCatcher( true ); // phpcs:ignore
}
return $phpmailer;
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace WPMailSMTP\Providers\AmazonSES;
use WPMailSMTP\Providers\OptionsAbstract;
/**
* Class Options.
*
* @since 1.7.0
*/
class Options extends OptionsAbstract {
/**
* AmazonSES Options constructor.
*
* @since 1.7.0
*/
public function __construct() {
parent::__construct(
array(
'logo_url' => wp_mail_smtp()->assets_url . '/images/providers/aws.svg',
'slug' => 'amazonses',
'title' => esc_html__( 'Amazon SES', 'wp-mail-smtp' ),
'disabled' => true,
)
);
}
/**
* @inheritdoc
*/
public function display_options() {
?>
<p>
<?php esc_html_e( 'We\'re sorry, the Amazon SES mailer is not available on your plan. Please upgrade to the PRO plan to unlock all these awesome features.', 'wp-mail-smtp' ); ?>
</p>
<?php
}
}

View File

@ -0,0 +1,148 @@
<?php
namespace WPMailSMTP\Providers;
use WPMailSMTP\Options as PluginOptions;
/**
* Class AuthAbstract.
*
* @since 1.0.0
*/
abstract class AuthAbstract implements AuthInterface {
/**
* Mailer DB options.
*
* @since 1.0.0
*
* @var array
*/
protected $options = array();
/**
* @since 1.0.0
*
* @var mixed
*/
protected $client;
/**
* Mailer slug.
*
* @since 1.0.0
*
* @var string
*/
protected $mailer_slug = '';
/**
* Key for a stored unique state value.
*
* @since 1.5.0
*
* @var string
*/
public $state_key = 'wp_mail_smtp_provider_client_state';
/**
* Use the composer autoloader to include the auth library and all dependencies.
*
* @since 1.0.0
*/
protected function include_vendor_lib() {
require_once wp_mail_smtp()->plugin_path . '/vendor/autoload.php';
}
/**
* Get the url, that users will be redirected back to finish the OAuth process.
*
* @since 1.0.0
*
* @return string
*/
public static function get_plugin_auth_url() {
return add_query_arg( 'tab', 'auth', wp_mail_smtp()->get_admin()->get_admin_page_url() );
}
/**
* Update auth code in our DB.
*
* @since 1.0.0
*
* @param string $code
*/
protected function update_auth_code( $code ) {
$options = new PluginOptions();
$all = $options->get_all();
// To save in DB.
$all[ $this->mailer_slug ]['auth_code'] = $code;
// To save in currently retrieved options array.
$this->options['auth_code'] = $code;
$options->set( $all );
}
/**
* Update access token in our DB.
*
* @since 1.0.0
*
* @param mixed $token
*/
protected function update_access_token( $token ) {
$options = new PluginOptions();
$all = $options->get_all();
// To save in DB.
$all[ $this->mailer_slug ]['access_token'] = $token;
// To save in currently retrieved options array.
$this->options['access_token'] = $token;
$options->set( $all );
}
/**
* Update refresh token in our DB.
*
* @since 1.0.0
*
* @param mixed $token
*/
protected function update_refresh_token( $token ) {
$options = new PluginOptions();
$all = $options->get_all();
// To save in DB.
$all[ $this->mailer_slug ]['refresh_token'] = $token;
// To save in currently retrieved options array.
$this->options['refresh_token'] = $token;
$options->set( $all );
}
/**
* @inheritdoc
*/
public function is_clients_saved() {
return ! empty( $this->options['client_id'] ) && ! empty( $this->options['client_secret'] );
}
/**
* @inheritdoc
*/
public function is_auth_required() {
return empty( $this->options['access_token'] ) || empty( $this->options['refresh_token'] );
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace WPMailSMTP\Providers;
/**
* Interface AuthInterface.
*
* @since 1.0.0
*/
interface AuthInterface {
/**
* Whether user saved Client ID/App ID and Client Secret/App Password or not.
* Both options are required.
*
* @since 1.0.0
*
* @return bool
*/
public function is_clients_saved();
/**
* Whether we have an access and refresh tokens or not.
*
* @since 1.0.0
*
* @return bool
*/
public function is_auth_required();
}

View File

@ -0,0 +1,283 @@
<?php
namespace WPMailSMTP\Providers\Gmail;
use WPMailSMTP\Admin\Area;
use WPMailSMTP\Debug;
use WPMailSMTP\Options as PluginOptions;
use WPMailSMTP\Providers\AuthAbstract;
/**
* Class Auth to request access and refresh tokens.
*
* @since 1.0.0
*/
class Auth extends AuthAbstract {
/**
* Auth constructor.
*
* @since 1.0.0
*/
public function __construct() {
$options = new PluginOptions();
$this->mailer_slug = $options->get( 'mail', 'mailer' );
if ( $this->mailer_slug !== Options::SLUG ) {
return;
}
$this->options = $options->get_group( $this->mailer_slug );
if ( $this->is_clients_saved() ) {
$this->include_vendor_lib();
$this->client = $this->get_client();
}
}
/**
* Get the url, that users will be redirected back to finish the OAuth process.
*
* @since 1.5.2 Returned to the old, pre-1.5, structure of the link to preserve BC.
*
* @return string
*/
public static function get_plugin_auth_url() {
return add_query_arg(
array(
'page' => Area::SLUG,
'tab' => 'auth',
),
admin_url( 'options-general.php' )
);
}
/**
* Init and get the Google Client object.
*
* @since 1.0.0
* @since 1.5.0 Add ability to apply custom options to the client via a filter.
*
* @return \Google_Client
*/
public function get_client() {
// Doesn't load client twice + gives ability to overwrite.
if ( ! empty( $this->client ) ) {
return $this->client;
}
$this->include_vendor_lib();
$client = new \Google_Client(
array(
'client_id' => $this->options['client_id'],
'client_secret' => $this->options['client_secret'],
'redirect_uris' => array(
self::get_plugin_auth_url(),
),
)
);
$client->setApplicationName( 'WP Mail SMTP v' . WPMS_PLUGIN_VER );
$client->setAccessType( 'offline' );
$client->setApprovalPrompt( 'force' );
$client->setIncludeGrantedScopes( true );
// We request only the sending capability, as it's what we only need to do.
$client->setScopes( array( \Google_Service_Gmail::MAIL_GOOGLE_COM ) );
$client->setRedirectUri( self::get_plugin_auth_url() );
// Apply custom options to the client.
$client = apply_filters( 'wp_mail_smtp_providers_gmail_auth_get_client_custom_options', $client );
if (
$this->is_auth_required() &&
! empty( $this->options['auth_code'] )
) {
try {
$creds = $client->fetchAccessTokenWithAuthCode( $this->options['auth_code'] );
} catch ( \Exception $e ) {
$creds['error'] = $e->getMessage();
Debug::set(
'Mailer: Gmail' . "\r\n" .
$creds['error']
);
}
// Bail if we have an error.
if ( ! empty( $creds['error'] ) ) {
return $client;
}
$this->update_access_token( $client->getAccessToken() );
$this->update_refresh_token( $client->getRefreshToken() );
}
if ( ! empty( $this->options['access_token'] ) ) {
$client->setAccessToken( $this->options['access_token'] );
}
// Refresh the token if it's expired.
if ( $client->isAccessTokenExpired() ) {
$refresh = $client->getRefreshToken();
if ( empty( $refresh ) && isset( $this->options['refresh_token'] ) ) {
$refresh = $this->options['refresh_token'];
}
if ( ! empty( $refresh ) ) {
try {
$creds = $client->fetchAccessTokenWithRefreshToken( $refresh );
} catch ( \Exception $e ) {
$creds['error'] = $e->getMessage();
Debug::set(
'Mailer: Gmail' . "\r\n" .
$e->getMessage()
);
}
// Bail if we have an error.
if ( ! empty( $creds['error'] ) ) {
return $client;
}
$this->update_access_token( $client->getAccessToken() );
$this->update_refresh_token( $client->getRefreshToken() );
}
}
return $client;
}
/**
* Get the auth code from the $_GET and save it.
* Redirect user back to settings with an error message, if failed.
*
* @since 1.0.0
*/
public function process() {
if ( ! ( isset( $_GET['tab'] ) && $_GET['tab'] === 'auth' ) ) {
wp_safe_redirect( wp_mail_smtp()->get_admin()->get_admin_page_url() );
exit;
}
// We can't process without saved client_id/secret.
if ( ! $this->is_clients_saved() ) {
Debug::set(
esc_html__( 'There was an error while processing the Google authentication request. Please make sure that you have Client ID and Client Secret both valid and saved.', 'wp-mail-smtp' )
);
wp_safe_redirect(
add_query_arg(
'error',
'google_no_clients',
wp_mail_smtp()->get_admin()->get_admin_page_url()
)
);
exit;
}
$this->include_vendor_lib();
$code = '';
$scope = '';
$error = '';
if ( isset( $_GET['error'] ) ) {
$error = sanitize_key( $_GET['error'] );
}
// In case of any error: display a message to a user.
if ( ! empty( $error ) ) {
wp_safe_redirect(
add_query_arg(
'error',
'google_' . $error,
wp_mail_smtp()->get_admin()->get_admin_page_url()
)
);
exit;
}
if ( isset( $_GET['code'] ) ) {
$code = $_GET['code'];
}
if ( isset( $_GET['scope'] ) ) {
$scope = urldecode( $_GET['scope'] );
}
// Let's try to get the access token.
if (
! empty( $code ) &&
(
$scope === \Google_Service_Gmail::MAIL_GOOGLE_COM . ' ' . \Google_Service_Gmail::GMAIL_SEND ||
$scope === \Google_Service_Gmail::GMAIL_SEND . ' ' . \Google_Service_Gmail::MAIL_GOOGLE_COM ||
$scope === \Google_Service_Gmail::GMAIL_SEND ||
$scope === \Google_Service_Gmail::MAIL_GOOGLE_COM
)
) {
// Save the auth code. So \Google_Client can reuse it to retrieve the access token.
$this->update_auth_code( $code );
} else {
wp_safe_redirect(
add_query_arg(
'error',
'google_no_code_scope',
wp_mail_smtp()->get_admin()->get_admin_page_url()
)
);
exit;
}
wp_safe_redirect(
add_query_arg(
'success',
'google_site_linked',
wp_mail_smtp()->get_admin()->get_admin_page_url()
)
);
exit;
}
/**
* Get the auth URL used to proceed to Provider to request access to send emails.
*
* @since 1.0.0
*
* @return string
*/
public function get_auth_url() {
if (
! empty( $this->client ) &&
class_exists( 'Google_Client', false ) &&
$this->client instanceof \Google_Client
) {
return filter_var( $this->client->createAuthUrl(), FILTER_SANITIZE_URL );
}
return '#';
}
/**
* Get user information (like email etc) that is associated with the current connection.
*
* @since 1.5.0
*
* @return array
*/
public function get_user_info() {
$gmail = new \Google_Service_Gmail( $this->get_client() );
try {
$email = $gmail->users->getProfile( 'me' )->getEmailAddress();
} catch ( \Exception $e ) {
$email = '';
}
return array( 'email' => $email );
}
}

View File

@ -0,0 +1,222 @@
<?php
namespace WPMailSMTP\Providers\Gmail;
use WPMailSMTP\Debug;
use WPMailSMTP\MailCatcher;
use WPMailSMTP\Providers\MailerAbstract;
/**
* Class Mailer.
*
* @since 1.0.0
*/
class Mailer extends MailerAbstract {
/**
* URL to make an API request to.
* Not used for Gmail, as we are using its API.
*
* @since 1.0.0
*
* @var string
*/
protected $url = 'https://www.googleapis.com/upload/gmail/v1/users/{userId}/messages/send';
/**
* Gmail message.
*
* @since 1.0.0
*
* @var \Google_Service_Gmail_Message
*/
protected $message;
/**
* Mailer constructor.
*
* @since 1.0.0
*
* @param \WPMailSMTP\MailCatcher $phpmailer
*/
public function __construct( $phpmailer ) {
parent::__construct( $phpmailer );
if ( ! $this->is_php_compatible() ) {
return;
}
}
/**
* Re-use the MailCatcher class methods and properties.
*
* @since 1.2.0
*
* @param \WPMailSMTP\MailCatcher $phpmailer
*/
public function process_phpmailer( $phpmailer ) {
// Make sure that we have access to MailCatcher class methods.
if (
! $phpmailer instanceof MailCatcher &&
! $phpmailer instanceof \PHPMailer
) {
return;
}
$this->phpmailer = $phpmailer;
}
/**
* Use Google API Services to send emails.
*
* @since 1.0.0
*/
public function send() {
// Include the Google library.
require_once wp_mail_smtp()->plugin_path . '/vendor/autoload.php';
$auth = new Auth();
$message = new \Google_Service_Gmail_Message();
/*
* Right now Gmail doesn't allow to redefine From and Sender email headers.
* It always uses the email address that was used to connect to its API.
* With code below we are making sure that Email Log archive and single Email Log
* have the save value for From email header.
*/
$gmail_creds = $auth->get_user_info();
if ( ! empty( $gmail_creds['email'] ) ) {
$this->phpmailer->From = $gmail_creds['email'];
$this->phpmailer->Sender = $gmail_creds['email'];
}
// Get the raw MIME email using MailCatcher data.
// We need here to make base64URL-safe string.
$base64 = str_replace(
array( '+', '/', '=' ),
array( '-', '_', '' ),
base64_encode( $this->phpmailer->getSentMIMEMessage() )
);
$message->setRaw( $base64 );
$service = new \Google_Service_Gmail( $auth->get_client() );
try {
$response = $service->users_messages->send( 'me', $message );
$this->process_response( $response );
} catch ( \Exception $e ) {
Debug::set(
'Mailer: Gmail' . "\r\n" .
$e->getMessage()
);
return;
}
}
/**
* Save response from the API to use it later.
*
* @since 1.0.0
* @since 1.5.0 Added action "wp_mail_smtp_providers_gmail_mailer_process_response" with $response.
*
* @param \Google_Service_Gmail_Message $response
*/
protected function process_response( $response ) {
$this->response = $response;
do_action( 'wp_mail_smtp_providers_gmail_mailer_process_response', $this->response, $this->phpmailer );
}
/**
* Check whether the email was sent.
*
* @since 1.0.0
*
* @return bool
*/
public function is_email_sent() {
$is_sent = false;
if ( method_exists( $this->response, 'getId' ) ) {
$message_id = $this->response->getId();
if ( ! empty( $message_id ) ) {
$is_sent = true;
}
}
// Clear debug messages if email is successfully sent.
if ( $is_sent ) {
Debug::clear();
}
return $is_sent;
}
/**
* @inheritdoc
*/
public function get_debug_info() {
$gmail_text = array();
$options = new \WPMailSMTP\Options();
$gmail = $options->get_group( 'gmail' );
$curl_ver = 'No';
if ( function_exists( 'curl_version' ) ) {
$curl = curl_version(); // phpcs:ignore
$curl_ver = $curl['version'];
}
$gmail_text[] = '<strong>Client ID/Secret:</strong> ' . ( ! empty( $gmail['client_id'] ) && ! empty( $gmail['client_secret'] ) ? 'Yes' : 'No' );
$gmail_text[] = '<strong>Auth Code:</strong> ' . ( ! empty( $gmail['auth_code'] ) ? 'Yes' : 'No' );
$gmail_text[] = '<strong>Access Token:</strong> ' . ( ! empty( $gmail['access_token'] ) ? 'Yes' : 'No' );
$gmail_text[] = '<br><strong>Server:</strong>';
$gmail_text[] = '<strong>OpenSSL:</strong> ' . ( extension_loaded( 'openssl' ) && defined( 'OPENSSL_VERSION_TEXT' ) ? OPENSSL_VERSION_TEXT : 'No' );
$gmail_text[] = '<strong>PHP.allow_url_fopen:</strong> ' . ( ini_get( 'allow_url_fopen' ) ? 'Yes' : 'No' );
$gmail_text[] = '<strong>PHP.stream_socket_client():</strong> ' . ( function_exists( 'stream_socket_client' ) ? 'Yes' : 'No' );
$gmail_text[] = '<strong>PHP.fsockopen():</strong> ' . ( function_exists( 'fsockopen' ) ? 'Yes' : 'No' );
$gmail_text[] = '<strong>PHP.curl_version():</strong> ' . $curl_ver; // phpcs:ignore
if ( function_exists( 'apache_get_modules' ) ) {
$modules = apache_get_modules();
$gmail_text[] = '<strong>Apache.mod_security:</strong> ' . ( in_array( 'mod_security', $modules, true ) || in_array( 'mod_security2', $modules, true ) ? 'Yes' : 'No' );
}
if ( function_exists( 'selinux_is_enabled' ) ) {
$gmail_text[] = '<strong>OS.SELinux:</strong> ' . ( selinux_is_enabled() ? 'Yes' : 'No' );
}
if ( function_exists( 'grsecurity_is_enabled' ) ) {
$gmail_text[] = '<strong>OS.grsecurity:</strong> ' . ( grsecurity_is_enabled() ? 'Yes' : 'No' );
}
return implode( '<br>', $gmail_text );
}
/**
* @inheritdoc
*/
public function is_mailer_complete() {
if ( ! $this->is_php_compatible() ) {
return false;
}
$auth = new Auth();
if (
$auth->is_clients_saved() &&
! $auth->is_auth_required()
) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,234 @@
<?php
namespace WPMailSMTP\Providers\Gmail;
use WPMailSMTP\Providers\OptionsAbstract;
/**
* Class Option.
*
* @since 1.0.0
*/
class Options extends OptionsAbstract {
/**
* Mailer slug.
*
* @since 1.5.0
*/
const SLUG = 'gmail';
/**
* Gmail Options constructor.
*
* @since 1.0.0
*/
public function __construct() {
parent::__construct(
array(
'logo_url' => wp_mail_smtp()->assets_url . '/images/providers/google.svg',
'slug' => self::SLUG,
'title' => esc_html__( 'Gmail', 'wp-mail-smtp' ),
'description' => sprintf(
wp_kses( /* translators: %s - URL to our Gmail doc. */
__( 'Send emails using your Gmail or G Suite (formerly Google Apps) account, all while keeping your login credentials safe. Other Google SMTP methods require enabling less secure apps in your account and entering your password. However, this integration uses the Google API to improve email delivery issues while keeping your site secure.<br><br>Read our <a href="%s" target="_blank" rel="noopener noreferrer">Gmail documentation</a> to learn how to configure Gmail or G Suite.', 'wp-mail-smtp' ),
array(
'br' => array(),
'a' => array(
'href' => array(),
'rel' => array(),
'target' => array(),
),
)
),
'https://wpmailsmtp.com/docs/how-to-set-up-the-gmail-mailer-in-wp-mail-smtp/'
),
'notices' => array(
'educational' => esc_html__( 'The Gmail mailer works well for sites that send low numbers of emails. However, Gmail\'s API has rate limitations and a number of additional restrictions that can lead to challenges during setup. If you expect to send a high volume of emails, or if you find that your web host is not compatible with the Gmail API restrictions, then we recommend considering a different mailer option.', 'wp-mail-smtp' ),
),
'php' => '5.5',
)
);
}
/**
* @inheritdoc
*/
public function display_options() {
// Do not display options if PHP version is not correct.
if ( ! $this->is_php_correct() ) {
$this->display_php_warning();
return;
}
?>
<!-- Client ID -->
<div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-client_id"
class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
<div class="wp-mail-smtp-setting-label">
<label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-client_id"><?php esc_html_e( 'Client ID', 'wp-mail-smtp' ); ?></label>
</div>
<div class="wp-mail-smtp-setting-field">
<input name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][client_id]" type="text"
value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'client_id' ) ); ?>"
<?php echo $this->options->is_const_defined( $this->get_slug(), 'client_id' ) ? 'disabled' : ''; ?>
id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-client_id" spellcheck="false"
/>
</div>
</div>
<!-- Client Secret -->
<div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-client_secret"
class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
<div class="wp-mail-smtp-setting-label">
<label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-client_secret"><?php esc_html_e( 'Client Secret', 'wp-mail-smtp' ); ?></label>
</div>
<div class="wp-mail-smtp-setting-field">
<?php if ( $this->options->is_const_defined( $this->get_slug(), 'client_secret' ) ) : ?>
<input type="text" disabled value="****************************************"
id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-client_secret"
/>
<?php $this->display_const_set_message( 'WPMS_GMAIL_CLIENT_SECRET' ); ?>
<?php else : ?>
<input type="password" spellcheck="false"
name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][client_secret]"
value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'client_secret' ) ); ?>"
id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-client_secret"
/>
<?php endif; ?>
</div>
</div>
<!-- Authorized redirect URI -->
<div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-client_redirect"
class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
<div class="wp-mail-smtp-setting-label">
<label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-client_redirect"><?php esc_html_e( 'Authorized redirect URI', 'wp-mail-smtp' ); ?></label>
</div>
<div class="wp-mail-smtp-setting-field">
<input type="text" readonly="readonly"
value="<?php echo esc_attr( Auth::get_plugin_auth_url() ); ?>"
id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-client_redirect"
/>
<button type="button" class="wp-mail-smtp-btn wp-mail-smtp-btn-md wp-mail-smtp-btn-light-grey wp-mail-smtp-setting-copy"
title="<?php esc_attr_e( 'Copy URL to clipboard', 'wp-mail-smtp' ); ?>"
data-source_id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-client_redirect">
<span class="dashicons dashicons-admin-page"></span>
</button>
<p class="desc">
<?php esc_html_e( 'Please copy this URL into the "Authorized redirect URIs" field of your Google web application.', 'wp-mail-smtp' ); ?>
</p>
</div>
</div>
<!-- Auth users button -->
<div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-authorize"
class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
<div class="wp-mail-smtp-setting-label">
<label><?php esc_html_e( 'Authorization', 'wp-mail-smtp' ); ?></label>
</div>
<div class="wp-mail-smtp-setting-field">
<?php $this->display_auth_setting_action(); ?>
</div>
</div>
<?php
}
/**
* Display either an "Allow..." or "Remove..." button.
*
* @since 1.3.0
*/
protected function display_auth_setting_action() {
// Do the processing on the fly, as having ajax here is too complicated.
$this->process_provider_remove();
$auth = new Auth();
?>
<?php if ( $auth->is_clients_saved() ) : ?>
<?php if ( $auth->is_auth_required() ) : ?>
<a href="<?php echo esc_url( $auth->get_auth_url() ); ?>" class="wp-mail-smtp-btn wp-mail-smtp-btn-md wp-mail-smtp-btn-orange">
<?php esc_html_e( 'Allow plugin to send emails using your Google account', 'wp-mail-smtp' ); ?>
</a>
<p class="desc">
<?php esc_html_e( 'Click the button above to confirm authorization.', 'wp-mail-smtp' ); ?>
</p>
<?php else : ?>
<a href="<?php echo esc_url( wp_nonce_url( wp_mail_smtp()->get_admin()->get_admin_page_url(), 'gmail_remove', 'gmail_remove_nonce' ) ); ?>#wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-authorize" class="wp-mail-smtp-btn wp-mail-smtp-btn-md wp-mail-smtp-btn-red js-wp-mail-smtp-provider-remove">
<?php esc_html_e( 'Remove Connection', 'wp-mail-smtp' ); ?>
</a>
<span class="connected-as">
<?php
$user = $auth->get_user_info();
if ( ! empty( $user['email'] ) ) {
printf(
/* translators: %s - email address, as received from Google API. */
esc_html__( 'Connected as %s', 'wp-mail-smtp' ),
'<code>' . esc_html( $user['email'] ) . '</code>'
);
}
?>
</span>
<p class="desc">
<?php esc_html_e( 'Removing the connection will give you an ability to redo the connection or link to another Google account.', 'wp-mail-smtp' ); ?>
</p>
<?php endif; ?>
<?php else : ?>
<p class="inline-notice inline-error">
<?php esc_html_e( 'You need to save settings with Client ID and Client Secret before you can proceed.', 'wp-mail-smtp' ); ?>
</p>
<?php
endif;
}
/**
* Remove Provider connection.
*
* @since 1.3.0
*/
public function process_provider_remove() {
if ( ! is_super_admin() ) {
return;
}
if (
! isset( $_GET['gmail_remove_nonce'] ) ||
! wp_verify_nonce( $_GET['gmail_remove_nonce'], 'gmail_remove' ) // phpcs:ignore
) {
return;
}
$options = new \WPMailSMTP\Options();
if ( $options->get( 'mail', 'mailer' ) !== $this->get_slug() ) {
return;
}
$old_opt = $options->get_all();
foreach ( $old_opt[ $this->get_slug() ] as $key => $value ) {
// Unset everything except Client ID and Secret.
if ( ! in_array( $key, array( 'client_id', 'client_secret' ), true ) ) {
unset( $old_opt[ $this->get_slug() ][ $key ] );
}
}
$options->set( $old_opt );
}
}

View File

@ -0,0 +1,205 @@
<?php
namespace WPMailSMTP\Providers;
use WPMailSMTP\Debug;
use WPMailSMTP\MailCatcher;
use WPMailSMTP\Options;
/**
* Class Loader.
*
* @since 1.0.0
*/
class Loader {
/**
* Key is the mailer option, value is the path to its classes.
*
* @since 1.0.0
* @since 1.6.0 Added Sendinblue.
* @since 1.7.0 Added AmazonSES/Outlook as indication of the Pro mailers.
*
* @var array
*/
protected $providers = array(
'mail' => 'WPMailSMTP\Providers\Mail\\',
'pepipostapi' => 'WPMailSMTP\Providers\PepipostAPI\\',
'sendinblue' => 'WPMailSMTP\Providers\Sendinblue\\',
'mailgun' => 'WPMailSMTP\Providers\Mailgun\\',
'sendgrid' => 'WPMailSMTP\Providers\Sendgrid\\',
'amazonses' => 'WPMailSMTP\Providers\AmazonSES\\',
'gmail' => 'WPMailSMTP\Providers\Gmail\\',
'outlook' => 'WPMailSMTP\Providers\Outlook\\',
'smtp' => 'WPMailSMTP\Providers\SMTP\\',
'pepipost' => 'WPMailSMTP\Providers\Pepipost\\',
);
/**
* @since 1.0.0
*
* @var MailCatcher
*/
private $phpmailer;
/**
* Get all the supported providers.
*
* @since 1.0.0
*
* @return array
*/
public function get_providers() {
if ( ! Options::init()->is_pepipost_active() ) {
unset( $this->providers['pepipost'] );
}
return apply_filters( 'wp_mail_smtp_providers_loader_get_providers', $this->providers );
}
/**
* Get a single provider FQN-path based on its name.
*
* @since 1.0.0
*
* @param string $provider
*
* @return string|null
*/
public function get_provider_path( $provider ) {
$provider = sanitize_key( $provider );
$providers = $this->get_providers();
return apply_filters(
'wp_mail_smtp_providers_loader_get_provider_path',
isset( $providers[ $provider ] ) ? $providers[ $provider ] : null,
$provider
);
}
/**
* Get the provider options, if exists.
*
* @since 1.0.0
*
* @param string $provider
*
* @return OptionsAbstract|null
*/
public function get_options( $provider ) {
return $this->get_entity( $provider, 'Options' );
}
/**
* Get all options of all providers.
*
* @since 1.0.0
*
* @return OptionsAbstract[]
*/
public function get_options_all() {
$options = array();
foreach ( $this->get_providers() as $provider => $path ) {
$option = $this->get_options( $provider );
if ( ! $option instanceof OptionsAbstract ) {
continue;
}
$slug = $option->get_slug();
$title = $option->get_title();
if ( empty( $title ) || empty( $slug ) ) {
continue;
}
$options[] = $option;
}
return apply_filters( 'wp_mail_smtp_providers_loader_get_providers_all', $options );
}
/**
* Get the provider mailer, if exists.
*
* @since 1.0.0
*
* @param string $provider
* @param MailCatcher $phpmailer
*
* @return MailerAbstract|null
*/
public function get_mailer( $provider, $phpmailer ) {
if (
$phpmailer instanceof MailCatcher ||
$phpmailer instanceof \PHPMailer
) {
$this->phpmailer = $phpmailer;
}
return $this->get_entity( $provider, 'Mailer' );
}
/**
* Get the provider auth, if exists.
*
* @param string $provider
*
* @return AuthAbstract|null
*/
public function get_auth( $provider ) {
return $this->get_entity( $provider, 'Auth' );
}
/**
* Get a generic entity based on the request.
*
* @uses \ReflectionClass
*
* @since 1.0.0
*
* @param string $provider
* @param string $request
*
* @return OptionsAbstract|MailerAbstract|AuthAbstract|null
*/
protected function get_entity( $provider, $request ) {
$provider = sanitize_key( $provider );
$request = sanitize_text_field( $request );
$path = $this->get_provider_path( $provider );
$entity = null;
if ( empty( $path ) ) {
return $entity;
}
try {
$reflection = new \ReflectionClass( $path . $request );
if ( file_exists( $reflection->getFileName() ) ) {
$class = $path . $request;
if ( $this->phpmailer ) {
$entity = new $class( $this->phpmailer );
} else {
$entity = new $class();
}
}
}
catch ( \Exception $e ) {
Debug::set( "There was a problem while retrieving {$request} for {$provider}: {$e->getMessage()}" );
$entity = null;
}
return apply_filters( 'wp_mail_smtp_providers_loader_get_entity', $entity, $provider, $request );
}
}

View File

@ -0,0 +1,49 @@
<?php
namespace WPMailSMTP\Providers\Mail;
use WPMailSMTP\Providers\MailerAbstract;
/**
* Class Mailer inherits everything from parent abstract class.
* This file is required for a proper work of Loader and \ReflectionClass.
*
* @package WPMailSMTP\Providers\Mail
*/
class Mailer extends MailerAbstract {
/**
* @inheritdoc
*/
public function get_debug_info() {
$mail_text = array();
$mail_text[] = '<br><strong>Server:</strong>';
$disabled_functions = ini_get( 'disable_functions' );
$disabled = (array) explode( ',', trim( $disabled_functions ) );
$mail_text[] = '<strong>PHP.mail():</strong> ' . ( in_array( 'mail', $disabled, true ) || ! function_exists( 'mail' ) ? 'No' : 'Yes' );
if ( function_exists( 'apache_get_modules' ) ) {
$modules = apache_get_modules();
$mail_text[] = '<strong>Apache.mod_security:</strong> ' . ( in_array( 'mod_security', $modules, true ) || in_array( 'mod_security2', $modules, true ) ? 'Yes' : 'No' );
}
if ( function_exists( 'selinux_is_enabled' ) ) {
$mail_text[] = '<strong>OS.SELinux:</strong> ' . ( selinux_is_enabled() ? 'Yes' : 'No' );
}
if ( function_exists( 'grsecurity_is_enabled' ) ) {
$mail_text[] = '<strong>OS.grsecurity:</strong> ' . ( grsecurity_is_enabled() ? 'Yes' : 'No' );
}
return implode( '<br>', $mail_text );
}
/**
* @inheritdoc
*/
public function is_mailer_complete() {
return true;
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace WPMailSMTP\Providers\Mail;
use WPMailSMTP\Providers\OptionsAbstract;
/**
* Class Option.
*
* @since 1.0.0
*/
class Options extends OptionsAbstract {
/**
* Mail constructor.
*
* @since 1.0.0
*/
public function __construct() {
parent::__construct(
array(
'logo_url' => wp_mail_smtp()->assets_url . '/images/providers/php.svg',
'slug' => 'mail',
'title' => esc_html__( 'Default (none)', 'wp-mail-smtp' ),
)
);
}
/**
* @inheritdoc
*/
public function display_options() {
?>
<blockquote>
<?php esc_html_e( 'You currently have the native WordPress option selected. Please select any other Mailer option above to continue the setup.', 'wp-mail-smtp' ); ?>
</blockquote>
<?php
}
}

View File

@ -0,0 +1,417 @@
<?php
namespace WPMailSMTP\Providers;
use WPMailSMTP\Conflicts;
use WPMailSMTP\Debug;
use WPMailSMTP\MailCatcher;
use WPMailSMTP\Options;
use WPMailSMTP\WP;
/**
* Class MailerAbstract.
*
* @since 1.0.0
*/
abstract class MailerAbstract implements MailerInterface {
/**
* Which response code from HTTP provider is considered to be successful?
*
* @since 1.0.0
*
* @var int
*/
protected $email_sent_code = 200;
/**
* @since 1.0.0
*
* @var Options
*/
protected $options;
/**
* @since 1.0.0
*
* @var MailCatcher
*/
protected $phpmailer;
/**
* @since 1.0.0
*
* @var string
*/
protected $mailer = '';
/**
* URL to make an API request to.
*
* @since 1.0.0
*
* @var string
*/
protected $url = '';
/**
* @since 1.0.0
*
* @var array
*/
protected $headers = array();
/**
* @since 1.0.0
*
* @var array
*/
protected $body = array();
/**
* @since 1.0.0
*
* @var mixed
*/
protected $response = array();
/**
* Mailer constructor.
*
* @since 1.0.0
*
* @param MailCatcher $phpmailer
*/
public function __construct( MailCatcher $phpmailer ) {
$this->options = new Options();
$this->mailer = $this->options->get( 'mail', 'mailer' );
// Only non-SMTP mailers need URL and extra processing for PHPMailer class.
if ( ! $this->options->is_mailer_smtp() && empty( $this->url ) ) {
return;
}
$this->process_phpmailer( $phpmailer );
}
/**
* Re-use the MailCatcher class methods and properties.
*
* @since 1.0.0
*
* @param MailCatcher $phpmailer
*/
public function process_phpmailer( $phpmailer ) {
// Make sure that we have access to MailCatcher class methods.
if (
! $phpmailer instanceof MailCatcher &&
! $phpmailer instanceof \PHPMailer
) {
return;
}
$this->phpmailer = $phpmailer;
// Prevent working with those methods, as they are not needed for SMTP-like mailers.
if ( $this->options->is_mailer_smtp() ) {
return;
}
$this->set_headers( $this->phpmailer->getCustomHeaders() );
$this->set_from( $this->phpmailer->From, $this->phpmailer->FromName );
$this->set_recipients(
array(
'to' => $this->phpmailer->getToAddresses(),
'cc' => $this->phpmailer->getCcAddresses(),
'bcc' => $this->phpmailer->getBccAddresses(),
)
);
$this->set_subject( $this->phpmailer->Subject );
if ( $this->phpmailer->ContentType === 'text/plain' ) {
$this->set_content( $this->phpmailer->Body );
} else {
$this->set_content(
array(
'text' => $this->phpmailer->AltBody,
'html' => $this->phpmailer->Body,
)
);
}
$this->set_return_path( $this->phpmailer->From );
$this->set_reply_to( $this->phpmailer->getReplyToAddresses() );
/*
* In some cases we will need to modify the internal structure
* of the body content, if attachments are present.
* So lets make this call the last one.
*/
$this->set_attachments( $this->phpmailer->getAttachments() );
}
/**
* Set the email headers.
*
* @since 1.0.0
*
* @param array $headers List of key=>value pairs.
*/
public function set_headers( $headers ) {
foreach ( $headers as $header ) {
$name = isset( $header[0] ) ? $header[0] : false;
$value = isset( $header[1] ) ? $header[1] : false;
if ( empty( $name ) || empty( $value ) ) {
continue;
}
$this->set_header( $name, $value );
}
}
/**
* Set individual header key=>value pair for the email.
*
* @since 1.0.0
*
* @param string $name
* @param string $value
*/
public function set_header( $name, $value ) {
$name = sanitize_text_field( $name );
$this->headers[ $name ] = WP::sanitize_value( $value );
}
/**
* Set email subject.
*
* @since 1.0.0
*
* @param string $subject
*/
public function set_subject( $subject ) {
$this->set_body_param(
array(
'subject' => $subject,
)
);
}
/**
* Set the request params, that goes to the body of the HTTP request.
*
* @since 1.0.0
*
* @param array $param Key=>value of what should be sent to a 3rd party API.
*
* @internal param array $params
*/
protected function set_body_param( $param ) {
$this->body = Options::array_merge_recursive( $this->body, $param );
}
/**
* Get the email body.
*
* @since 1.0.0
*
* @return string|array
*/
public function get_body() {
return apply_filters( 'wp_mail_smtp_providers_mailer_get_body', $this->body, $this->mailer );
}
/**
* Get the email headers.
*
* @since 1.0.0
*
* @return array
*/
public function get_headers() {
return apply_filters( 'wp_mail_smtp_providers_mailer_get_headers', $this->headers, $this->mailer );
}
/**
* Send the email.
*
* @since 1.0.0
* @since 1.8.0 Added timeout for requests, same as max_execution_time.
*/
public function send() {
$timeout = (int) ini_get( 'max_execution_time' );
$params = Options::array_merge_recursive(
$this->get_default_params(),
array(
'headers' => $this->get_headers(),
'body' => $this->get_body(),
'timeout' => $timeout ? $timeout : 30,
)
);
$response = wp_safe_remote_post( $this->url, $params );
$this->process_response( $response );
}
/**
* We might need to do something after the email was sent to the API.
* In this method we preprocess the response from the API.
*
* @since 1.0.0
*
* @param mixed $response
*/
protected function process_response( $response ) {
if ( is_wp_error( $response ) ) {
// Save the error text.
$errors = $response->get_error_messages();
foreach ( $errors as $error ) {
Debug::set( $error );
}
return;
}
if ( isset( $response['body'] ) && WP::is_json( $response['body'] ) ) {
$response['body'] = \json_decode( $response['body'] );
}
$this->response = $response;
}
/**
* Get the default params, required for wp_safe_remote_post().
*
* @since 1.0.0
*
* @return array
*/
protected function get_default_params() {
return apply_filters(
'wp_mail_smtp_providers_mailer_get_default_params',
array(
'timeout' => 15,
'httpversion' => '1.1',
'blocking' => true,
),
$this->mailer
);
}
/**
* Whether the email is sent or not.
* We basically check the response code from a request to provider.
* Might not be 100% correct, not guarantees that email is delivered.
*
* @since 1.0.0
*
* @return bool
*/
public function is_email_sent() {
$is_sent = false;
if ( wp_remote_retrieve_response_code( $this->response ) === $this->email_sent_code ) {
$is_sent = true;
} else {
$error = $this->get_response_error();
if ( ! empty( $error ) ) {
// Add mailer to the beginning and save to display later.
$message = 'Mailer: ' . esc_html( wp_mail_smtp()->get_providers()->get_options( $this->mailer )->get_title() ) . "\r\n";
$conflicts = new Conflicts();
if ( $conflicts->is_detected() ) {
$message .= 'Conflicts: ' . esc_html( $conflicts->get_conflict_name() ) . "\r\n";
}
Debug::set( $message . $error );
}
}
// Clear debug messages if email is successfully sent.
if ( $is_sent ) {
Debug::clear();
}
return apply_filters( 'wp_mail_smtp_providers_mailer_is_email_sent', $is_sent, $this->mailer );
}
/**
* Should be overwritten when appropriate.
*
* @since 1.2.0
*
* @return string
*/
protected function get_response_error() {
return '';
}
/**
* Whether the mailer supports the current PHP version or not.
*
* @since 1.0.0
*
* @return bool
*/
public function is_php_compatible() {
$options = wp_mail_smtp()->get_providers()->get_options( $this->mailer );
return version_compare( phpversion(), $options->get_php_version(), '>=' );
}
/**
* This method is relevant to SMTP and Pepipost.
* All other custom mailers should override it with own information.
*
* @since 1.2.0
*
* @return string
*/
public function get_debug_info() {
global $phpmailer;
$smtp_text = array();
// Mail mailer has nothing to return.
if ( $this->options->is_mailer_smtp() ) {
// phpcs:disable
$smtp_text[] = '<strong>ErrorInfo:</strong> ' . make_clickable( wp_strip_all_tags( $phpmailer->ErrorInfo ) );
$smtp_text[] = '<strong>Host:</strong> ' . $phpmailer->Host;
$smtp_text[] = '<strong>Port:</strong> ' . $phpmailer->Port;
$smtp_text[] = '<strong>SMTPSecure:</strong> ' . Debug::pvar( $phpmailer->SMTPSecure );
$smtp_text[] = '<strong>SMTPAutoTLS:</strong> ' . Debug::pvar( $phpmailer->SMTPAutoTLS );
$smtp_text[] = '<strong>SMTPAuth:</strong> ' . Debug::pvar( $phpmailer->SMTPAuth );
if ( ! empty( $phpmailer->SMTPOptions ) ) {
$smtp_text[] = '<strong>SMTPOptions:</strong> <code>' . wp_json_encode( $phpmailer->SMTPOptions ) . '</code>';
}
// phpcs:enable
}
$smtp_text[] = '<br><strong>Server:</strong>';
$smtp_text[] = '<strong>OpenSSL:</strong> ' . ( extension_loaded( 'openssl' ) && defined( 'OPENSSL_VERSION_TEXT' ) ? OPENSSL_VERSION_TEXT : 'No' );
if ( function_exists( 'apache_get_modules' ) ) {
$modules = apache_get_modules();
$smtp_text[] = '<strong>Apache.mod_security:</strong> ' . ( in_array( 'mod_security', $modules, true ) || in_array( 'mod_security2', $modules, true ) ? 'Yes' : 'No' );
}
if ( function_exists( 'selinux_is_enabled' ) ) {
$smtp_text[] = '<strong>OS.SELinux:</strong> ' . ( selinux_is_enabled() ? 'Yes' : 'No' );
}
if ( function_exists( 'grsecurity_is_enabled' ) ) {
$smtp_text[] = '<strong>OS.grsecurity:</strong> ' . ( grsecurity_is_enabled() ? 'Yes' : 'No' );
}
return implode( '<br>', $smtp_text );
}
}

View File

@ -0,0 +1,83 @@
<?php
namespace WPMailSMTP\Providers;
/**
* Interface MailerInterface.
*
* @since 1.0.0
*/
interface MailerInterface {
/**
* Send the email.
*
* @since 1.0.0
*/
public function send();
/**
* Whether the email is sent or not.
* We basically check the response code from a request to provider.
* Might not be 100% correct, not guarantees that email is delivered.
*
* @since 1.0.0
*
* @return bool
*/
public function is_email_sent();
/**
* Whether the mailer supports the current PHP version or not.
*
* @since 1.0.0
*
* @return bool
*/
public function is_php_compatible();
/**
* Whether the mailer has all its settings correctly set up and saved.
*
* @since 1.4.0
*
* @return bool
*/
public function is_mailer_complete();
/**
* Get the email body.
*
* @since 1.0.0
*
* @return string|array
*/
public function get_body();
/**
* Get the email headers.
*
* @since 1.0.0
*
* @return array
*/
public function get_headers();
/**
* Get an array of all debug information relevant to the mailer.
*
* @since 1.2.0
*
* @return array
*/
public function get_debug_info();
/**
* Re-use the MailCatcher class methods and properties.
*
* @since 1.2.0
*
* @param \WPMailSMTP\MailCatcher $phpmailer
*/
public function process_phpmailer( $phpmailer );
}

View File

@ -0,0 +1,431 @@
<?php
namespace WPMailSMTP\Providers\Mailgun;
use WPMailSMTP\Providers\MailerAbstract;
use WPMailSMTP\WP;
/**
* Class Mailer.
*
* @since 1.0.0
*/
class Mailer extends MailerAbstract {
/**
* Which response code from HTTP provider is considered to be successful?
*
* @since 1.0.0
*
* @var int
*/
protected $email_sent_code = 200;
/**
* API endpoint used for sites from all regions.
*
* @since 1.4.0
*
* @var string
*/
const API_BASE_US = 'https://api.mailgun.net/v3/';
/**
* API endpoint used for sites from EU region.
*
* @since 1.4.0
*
* @var string
*/
const API_BASE_EU = 'https://api.eu.mailgun.net/v3/';
/**
* URL to make an API request to.
*
* @since 1.0.0
*
* @var string
*/
protected $url = '';
/**
* @inheritdoc
*/
public function __construct( $phpmailer ) {
// Default value should be defined before the parent class contructor fires.
$this->url = self::API_BASE_US;
// We want to prefill everything from \WPMailSMTP\MailCatcher class, which extends \PHPMailer.
parent::__construct( $phpmailer );
// We have a special API URL to query in case of EU region.
if ( 'EU' === $this->options->get( $this->mailer, 'region' ) ) {
$this->url = self::API_BASE_EU;
}
/*
* Append the url with a domain,
* to avoid passing the domain name as a query parameter with all requests.
*/
$this->url .= sanitize_text_field( $this->options->get( $this->mailer, 'domain' ) . '/messages' );
$this->set_header( 'Authorization', 'Basic ' . base64_encode( 'api:' . $this->options->get( $this->mailer, 'api_key' ) ) );
}
/**
* @inheritdoc
*/
public function set_from( $email, $name = '' ) {
if ( ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) {
return;
}
if ( ! empty( $name ) ) {
$this->set_body_param(
array(
'from' => $name . ' <' . $email . '>',
)
);
} else {
$this->set_body_param(
array(
'from' => $email,
)
);
}
}
/**
* @inheritdoc
*/
public function set_recipients( $recipients ) {
if ( empty( $recipients ) ) {
return;
}
$default = array( 'to', 'cc', 'bcc' );
foreach ( $recipients as $kind => $emails ) {
if (
! in_array( $kind, $default, true ) ||
empty( $emails ) ||
! is_array( $emails )
) {
continue;
}
$data = array();
foreach ( $emails as $email ) {
$addr = isset( $email[0] ) ? $email[0] : false;
$name = isset( $email[1] ) ? $email[1] : false;
if ( ! filter_var( $addr, FILTER_VALIDATE_EMAIL ) ) {
continue;
}
if ( ! empty( $name ) ) {
$data[] = $name . ' <' . $addr . '>';
} else {
$data[] = $addr;
}
}
if ( ! empty( $data ) ) {
$this->set_body_param(
array(
$kind => implode( ', ', $data ),
)
);
}
}
}
/**
* @inheritdoc
*/
public function set_content( $content ) {
if ( is_array( $content ) ) {
$default = array( 'text', 'html' );
foreach ( $content as $type => $mail ) {
if (
! in_array( $type, $default, true ) ||
empty( $mail )
) {
continue;
}
$this->set_body_param(
array(
$type => $mail,
)
);
}
} else {
$type = 'html';
if ( $this->phpmailer->ContentType === 'text/plain' ) {
$type = 'text';
}
if ( ! empty( $content ) ) {
$this->set_body_param(
array(
$type => $content,
)
);
}
}
}
/**
* Redefine the way custom headers are process for this mailer - they should be in body.
*
* @since 1.5.0
*
* @param array $headers
*/
public function set_headers( $headers ) {
foreach ( $headers as $header ) {
$name = isset( $header[0] ) ? $header[0] : false;
$value = isset( $header[1] ) ? $header[1] : false;
$this->set_body_header( $name, $value );
}
// Add custom PHPMailer-specific header.
$this->set_body_header( 'X-Mailer', 'WPMailSMTP/Mailer/' . $this->mailer . ' ' . WPMS_PLUGIN_VER );
}
/**
* This mailer supports email-related custom headers inside a body of the message with a special prefix "h:".
*
* @since 1.5.0
*/
public function set_body_header( $name, $value ) {
$name = sanitize_text_field( $name );
$this->set_body_param(
array(
'h:' . $name => WP::sanitize_value( $value ),
)
);
}
/**
* It's the last one, so we can modify the whole body.
*
* @since 1.0.0
*
* @param array $attachments
*/
public function set_attachments( $attachments ) {
if ( empty( $attachments ) ) {
return;
}
$payload = '';
$data = array();
foreach ( $attachments as $attachment ) {
$file = false;
/*
* We are not using WP_Filesystem API as we can't reliably work with it.
* It is not always available, same as credentials for FTP.
*/
try {
if ( is_file( $attachment[0] ) && is_readable( $attachment[0] ) ) {
$file = file_get_contents( $attachment[0] );
}
}
catch ( \Exception $e ) {
$file = false;
}
if ( $file === false ) {
continue;
}
$data[] = array(
'content' => $file,
'name' => $attachment[2],
);
}
if ( ! empty( $data ) ) {
// First, generate a boundary for the multipart message.
$boundary = base_convert( uniqid( 'boundary', true ), 10, 36 );
// Iterate through pre-built params and build a payload.
foreach ( $this->body as $key => $value ) {
if ( is_array( $value ) ) {
foreach ( $value as $child_key => $child_value ) {
$payload .= '--' . $boundary;
$payload .= "\r\n";
$payload .= 'Content-Disposition: form-data; name="' . $key . "\"\r\n\r\n";
$payload .= $child_value;
$payload .= "\r\n";
}
} else {
$payload .= '--' . $boundary;
$payload .= "\r\n";
$payload .= 'Content-Disposition: form-data; name="' . $key . '"' . "\r\n\r\n";
$payload .= $value;
$payload .= "\r\n";
}
}
// Now iterate through our attachments, and add them too.
foreach ( $data as $key => $attachment ) {
$payload .= '--' . $boundary;
$payload .= "\r\n";
$payload .= 'Content-Disposition: form-data; name="attachment[' . $key . ']"; filename="' . $attachment['name'] . '"' . "\r\n\r\n";
$payload .= $attachment['content'];
$payload .= "\r\n";
}
$payload .= '--' . $boundary . '--';
// Redefine the body the "dirty way".
$this->body = $payload;
$this->set_header( 'Content-Type', 'multipart/form-data; boundary=' . $boundary );
}
}
/**
* @inheritdoc
*/
public function set_reply_to( $reply_to ) {
if ( empty( $reply_to ) ) {
return;
}
$data = array();
foreach ( $reply_to as $key => $emails ) {
if (
empty( $emails ) ||
! is_array( $emails )
) {
continue;
}
$addr = isset( $emails[0] ) ? $emails[0] : false;
$name = isset( $emails[1] ) ? $emails[1] : false;
if ( ! filter_var( $addr, FILTER_VALIDATE_EMAIL ) ) {
continue;
}
if ( ! empty( $name ) ) {
$data[] = $name . ' <' . $addr . '>';
} else {
$data[] = $addr;
}
}
if ( ! empty( $data ) ) {
$this->set_body_param(
array(
'h:Reply-To' => implode( ',', $data ),
)
);
}
}
/**
* @inheritdoc
*/
public function set_return_path( $email ) {
if (
$this->options->get( 'mail', 'return_path' ) !== true ||
! filter_var( $email, FILTER_VALIDATE_EMAIL )
) {
return;
}
$this->set_body_param(
array(
'sender' => $email,
)
);
}
/**
* Get a Mailgun-specific response with a helpful error.
*
* @since 1.2.0
*
* @return string
*/
protected function get_response_error() {
$body = (array) wp_remote_retrieve_body( $this->response );
$error_text = array();
if ( ! empty( $body['message'] ) ) {
if ( is_string( $body['message'] ) ) {
$error_text[] = $body['message'];
} else {
$error_text[] = \json_encode( $body['message'] );
}
} elseif ( ! empty( $body[0] ) ) {
if ( is_string( $body[0] ) ) {
$error_text[] = $body[0];
} else {
$error_text[] = \json_encode( $body[0] );
}
}
return implode( '<br>', array_map( 'esc_textarea', $error_text ) );
}
/**
* @inheritdoc
*/
public function get_debug_info() {
$mg_text = array();
$options = new \WPMailSMTP\Options();
$mailgun = $options->get_group( 'mailgun' );
$mg_text[] = '<strong>Api Key / Domain:</strong> ' . ( ! empty( $mailgun['api_key'] ) && ! empty( $mailgun['domain'] ) ? 'Yes' : 'No' );
return implode( '<br>', $mg_text );
}
/**
* @inheritdoc
*/
public function is_mailer_complete() {
$options = $this->options->get_group( $this->mailer );
// API key is the only required option.
if (
! empty( $options['api_key'] ) &&
! empty( $options['domain'] )
) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,161 @@
<?php
namespace WPMailSMTP\Providers\Mailgun;
use WPMailSMTP\Providers\OptionsAbstract;
/**
* Class Option.
*
* @since 1.0.0
*/
class Options extends OptionsAbstract {
/**
* Mailgun constructor.
*
* @since 1.0.0
*/
public function __construct() {
parent::__construct(
array(
'logo_url' => wp_mail_smtp()->assets_url . '/images/providers/mailgun.svg',
'slug' => 'mailgun',
'title' => esc_html__( 'Mailgun', 'wp-mail-smtp' ),
'description' => sprintf(
wp_kses(
/* translators: %1$s - opening link tag; %2$s - closing link tag; %3$s - opening link tag; %4$s - closing link tag. */
__( '%1$sMailgun%2$s is one of the leading transactional email services trusted by over 150,000+ businesses. They provide 5,000 free emails per month for 3 months.<br><br>Read our %3$sMailgun documentation%4$s to learn how to configure Mailgun and improve your email deliverability.', 'wp-mail-smtp' ),
array(
'br' => array(),
'a' => array(
'href' => array(),
'rel' => array(),
'target' => array(),
),
)
),
'<a href="https://www.mailgun.com" target="_blank" rel="noopener noreferrer">',
'</a>',
'<a href="https://wpmailsmtp.com/docs/how-to-set-up-the-mailgun-mailer-in-wp-mail-smtp/" target="_blank" rel="noopener noreferrer">',
'</a>'
),
)
);
}
/**
* @inheritdoc
*/
public function display_options() {
?>
<!-- API Key -->
<div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-api_key" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
<div class="wp-mail-smtp-setting-label">
<label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-api_key"><?php esc_html_e( 'Private API Key', 'wp-mail-smtp' ); ?></label>
</div>
<div class="wp-mail-smtp-setting-field">
<?php if ( $this->options->is_const_defined( $this->get_slug(), 'api_key' ) ) : ?>
<input type="text" disabled value="****************************************"
id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-api_key"
/>
<?php $this->display_const_set_message( 'WPMS_MAILGUN_API_KEY' ); ?>
<?php else : ?>
<input type="password" spellcheck="false"
name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][api_key]"
value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'api_key' ) ); ?>"
id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-api_key"
/>
<?php endif; ?>
<p class="desc">
<?php
printf(
/* translators: %s - API key link. */
esc_html__( 'Follow this link to get an API Key from Mailgun: %s.', 'wp-mail-smtp' ),
'<a href="https://app.mailgun.com/app/account/security/api_keys" target="_blank" rel="noopener noreferrer">' .
esc_html__( 'Get a Private API Key', 'wp-mail-smtp' ) .
'</a>'
);
?>
</p>
</div>
</div>
<!-- Domain -->
<div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-domain" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
<div class="wp-mail-smtp-setting-label">
<label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-domain"><?php esc_html_e( 'Domain Name', 'wp-mail-smtp' ); ?></label>
</div>
<div class="wp-mail-smtp-setting-field">
<input name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][domain]" type="text"
value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'domain' ) ); ?>"
<?php echo $this->options->is_const_defined( $this->get_slug(), 'domain' ) ? 'disabled' : ''; ?>
id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-domain" spellcheck="false"
/>
<p class="desc">
<?php
printf(
/* translators: %s - Domain Name link. */
esc_html__( 'Follow this link to get a Domain Name from Mailgun: %s.', 'wp-mail-smtp' ),
'<a href="https://app.mailgun.com/app/domains" target="_blank" rel="noopener noreferrer">' .
esc_html__( 'Get a Domain Name', 'wp-mail-smtp' ) .
'</a>'
);
?>
</p>
</div>
</div>
<!-- Region -->
<div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-region" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-radio wp-mail-smtp-clear">
<div class="wp-mail-smtp-setting-label">
<label><?php esc_html_e( 'Region', 'wp-mail-smtp' ); ?></label>
</div>
<div class="wp-mail-smtp-setting-field">
<label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-region-us">
<input type="radio" id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-region-us"
name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][region]" value="US"
<?php echo $this->options->is_const_defined( $this->get_slug(), 'region' ) ? 'disabled' : ''; ?>
<?php checked( 'US', $this->options->get( $this->get_slug(), 'region' ) ); ?>
/>
<?php esc_html_e( 'US', 'wp-mail-smtp' ); ?>
</label>
<label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-region-eu">
<input type="radio" id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-region-eu"
name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][region]" value="EU"
<?php echo $this->options->is_const_defined( $this->get_slug(), 'region' ) ? 'disabled' : ''; ?>
<?php checked( 'EU', $this->options->get( $this->get_slug(), 'region' ) ); ?>
/>
<?php esc_html_e( 'EU', 'wp-mail-smtp' ); ?>
</label>
<p class="desc">
<?php esc_html_e( 'Define which endpoint you want to use for sending messages.', 'wp-mail-smtp' ); ?><br>
<?php esc_html_e( 'If you are operating under EU laws, you may be required to use EU region.', 'wp-mail-smtp' ); ?>
<?php
printf(
wp_kses(
/* translators: %s - URL to Mailgun.com page. */
__( '<a href="%s" rel="" target="_blank">More information</a> on Mailgun.com.', 'wp-mail-smtp' ),
array(
'a' => array(
'href' => array(),
'rel' => array(),
'target' => array(),
),
)
),
'https://www.mailgun.com/regions'
);
?>
</p>
</div>
</div>
<?php
}
}

View File

@ -0,0 +1,477 @@
<?php
namespace WPMailSMTP\Providers;
use WPMailSMTP\Options;
/**
* Abstract Class ProviderAbstract to contain common providers functionality.
*
* @since 1.0.0
*/
abstract class OptionsAbstract implements OptionsInterface {
/**
* @var string
*/
private $logo_url = '';
/**
* @var string
*/
private $slug = '';
/**
* @var string
*/
private $title = '';
/**
* @var string
*/
private $description = '';
/**
* @since 1.6.0
*
* @var array
*/
private $notices = array();
/**
* @since 1.6.0
*
* @var bool
*/
private $recommended = false;
/**
* @since 1.7.0
*
* @var bool
*/
private $disabled = false;
/**
* @var string
*/
private $php = WPMS_PHP_VER;
/**
* @var Options
*/
protected $options;
/**
* ProviderAbstract constructor.
*
* @since 1.0.0
*
* @param array $params
*/
public function __construct( $params ) {
if (
empty( $params['slug'] ) ||
empty( $params['title'] )
) {
return;
}
$this->slug = sanitize_key( $params['slug'] );
$this->title = sanitize_text_field( $params['title'] );
if ( ! empty( $params['description'] ) ) {
$this->description = wp_kses_post( $params['description'] );
}
if ( ! empty( $params['notices'] ) ) {
foreach ( (array) $params['notices'] as $key => $notice ) {
$key = sanitize_key( $key );
if ( empty( $key ) ) {
continue;
}
$notice = wp_kses(
$notice,
array(
'br' => true,
'strong' => true,
'em' => true,
'a' => array(
'href' => true,
'rel' => true,
'target' => true,
),
)
);
if ( empty( $notice ) ) {
continue;
}
$this->notices[ $key ] = $notice;
}
}
if ( isset( $params['recommended'] ) ) {
$this->recommended = (bool) $params['recommended'];
}
if ( isset( $params['disabled'] ) ) {
$this->disabled = (bool) $params['disabled'];
}
if ( ! empty( $params['php'] ) ) {
$this->php = sanitize_text_field( $params['php'] );
}
if ( ! empty( $params['logo_url'] ) ) {
$this->logo_url = esc_url_raw( $params['logo_url'] );
}
$this->options = new Options();
}
/**
* @inheritdoc
*/
public function get_logo_url() {
return apply_filters( 'wp_mail_smtp_providers_provider_get_logo_url', $this->logo_url, $this );
}
/**
* @inheritdoc
*/
public function get_slug() {
return apply_filters( 'wp_mail_smtp_providers_provider_get_slug', $this->slug, $this );
}
/**
* @inheritdoc
*/
public function get_title() {
return apply_filters( 'wp_mail_smtp_providers_provider_get_title', $this->title, $this );
}
/**
* @inheritdoc
*/
public function get_description() {
return apply_filters( 'wp_mail_smtp_providers_provider_get_description', $this->description, $this );
}
/**
* Some mailers may display a notice above its options.
*
* @since 1.6.0
*
* @param string $type
*
* @return string
*/
public function get_notice( $type ) {
$type = sanitize_key( $type );
return apply_filters( 'wp_mail_smtp_providers_provider_get_notice', isset( $this->notices[ $type ] ) ? $this->notices[ $type ] : '', $this );
}
/**
* @inheritdoc
*/
public function get_php_version() {
return apply_filters( 'wp_mail_smtp_providers_provider_get_php_version', $this->php, $this );
}
/**
* @inheritdoc
*/
public function display_options() {
?>
<!-- SMTP Host -->
<div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-host" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
<div class="wp-mail-smtp-setting-label">
<label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-host"><?php esc_html_e( 'SMTP Host', 'wp-mail-smtp' ); ?></label>
</div>
<div class="wp-mail-smtp-setting-field">
<input name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][host]" type="text"
value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'host' ) ); ?>"
<?php echo $this->options->is_const_defined( $this->get_slug(), 'host' ) ? 'disabled' : ''; ?>
id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-host" spellcheck="false"
/>
</div>
</div>
<!-- SMTP Encryption -->
<div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-encryption" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-radio wp-mail-smtp-clear">
<div class="wp-mail-smtp-setting-label">
<label><?php esc_html_e( 'Encryption', 'wp-mail-smtp' ); ?></label>
</div>
<div class="wp-mail-smtp-setting-field">
<label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-enc-none">
<input type="radio" id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-enc-none"
name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][encryption]" value="none"
<?php echo $this->options->is_const_defined( $this->get_slug(), 'encryption' ) ? 'disabled' : ''; ?>
<?php checked( 'none', $this->options->get( $this->get_slug(), 'encryption' ) ); ?>
/>
<?php esc_html_e( 'None', 'wp-mail-smtp' ); ?>
</label>
<label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-enc-ssl">
<input type="radio" id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-enc-ssl"
name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][encryption]" value="ssl"
<?php echo $this->options->is_const_defined( $this->get_slug(), 'encryption' ) ? 'disabled' : ''; ?>
<?php checked( 'ssl', $this->options->get( $this->get_slug(), 'encryption' ) ); ?>
/>
<?php esc_html_e( 'SSL', 'wp-mail-smtp' ); ?>
</label>
<label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-enc-tls">
<input type="radio" id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-enc-tls"
name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][encryption]" value="tls"
<?php echo $this->options->is_const_defined( $this->get_slug(), 'encryption' ) ? 'disabled' : ''; ?>
<?php checked( 'tls', $this->options->get( $this->get_slug(), 'encryption' ) ); ?>
/>
<?php esc_html_e( 'TLS', 'wp-mail-smtp' ); ?>
</label>
<p class="desc">
<?php esc_html_e( 'For most servers TLS is the recommended option. If your SMTP provider offers both SSL and TLS options, we recommend using TLS.', 'wp-mail-smtp' ); ?>
</p>
</div>
</div>
<!-- SMTP Port -->
<div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-port" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-number wp-mail-smtp-clear">
<div class="wp-mail-smtp-setting-label">
<label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-port"><?php esc_html_e( 'SMTP Port', 'wp-mail-smtp' ); ?></label>
</div>
<div class="wp-mail-smtp-setting-field">
<input name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][port]" type="number"
value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'port' ) ); ?>"
<?php echo $this->options->is_const_defined( $this->get_slug(), 'port' ) ? 'disabled' : ''; ?>
id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-port" class="small-text" spellcheck="false"
/>
</div>
</div>
<!-- PHPMailer SMTPAutoTLS -->
<div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-autotls" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-checkbox-toggle wp-mail-smtp-clear <?php echo $this->options->is_const_defined( $this->get_slug(), 'encryption' ) || 'tls' === $this->options->get( $this->get_slug(), 'encryption' ) ? 'inactive' : ''; ?>">
<div class="wp-mail-smtp-setting-label">
<label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-autotls"><?php esc_html_e( 'Auto TLS', 'wp-mail-smtp' ); ?></label>
</div>
<div class="wp-mail-smtp-setting-field">
<label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-autotls">
<input type="checkbox" id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-autotls"
name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][autotls]" value="yes"
<?php echo $this->options->is_const_defined( $this->get_slug(), 'autotls' ) ? 'disabled' : ''; ?>
<?php checked( true, (bool) $this->options->get( $this->get_slug(), 'autotls' ) ); ?>
/>
<span class="wp-mail-smtp-setting-toggle-switch"></span>
<span class="wp-mail-smtp-setting-toggle-checked-label"><?php esc_html_e( 'On', 'wp-mail-smtp' ); ?></span>
<span class="wp-mail-smtp-setting-toggle-unchecked-label"><?php esc_html_e( 'Off', 'wp-mail-smtp' ); ?></span>
</label>
<p class="desc">
<?php esc_html_e( 'By default TLS encryption is automatically used if the server supports it, which is recommended. In some cases, due to server misconfigurations, this can cause issues and may need to be disabled.', 'wp-mail-smtp' ); ?>
</p>
</div>
</div>
<!-- SMTP Authentication -->
<div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-auth" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-checkbox-toggle wp-mail-smtp-clear">
<div class="wp-mail-smtp-setting-label">
<label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-auth"><?php esc_html_e( 'Authentication', 'wp-mail-smtp' ); ?></label>
</div>
<div class="wp-mail-smtp-setting-field">
<label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-auth">
<input type="checkbox" id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-auth"
name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][auth]" value="yes"
<?php echo $this->options->is_const_defined( $this->get_slug(), 'auth' ) ? 'disabled' : ''; ?>
<?php checked( true, (bool) $this->options->get( $this->get_slug(), 'auth' ) ); ?>
/>
<span class="wp-mail-smtp-setting-toggle-switch"></span>
<span class="wp-mail-smtp-setting-toggle-checked-label"><?php esc_html_e( 'On', 'wp-mail-smtp' ); ?></span>
<span class="wp-mail-smtp-setting-toggle-unchecked-label"><?php esc_html_e( 'Off', 'wp-mail-smtp' ); ?></span>
</label>
</div>
</div>
<!-- SMTP Username -->
<div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-user" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear <?php echo ! $this->options->is_const_defined( $this->get_slug(), 'auth' ) && ! $this->options->get( $this->get_slug(), 'auth' ) ? 'inactive' : ''; ?>">
<div class="wp-mail-smtp-setting-label">
<label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-user"><?php esc_html_e( 'SMTP Username', 'wp-mail-smtp' ); ?></label>
</div>
<div class="wp-mail-smtp-setting-field">
<input name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][user]" type="text"
value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'user' ) ); ?>"
<?php echo $this->options->is_const_defined( $this->get_slug(), 'user' ) ? 'disabled' : ''; ?>
id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-user" spellcheck="false" autocomplete="new-password"
/>
</div>
</div>
<!-- SMTP Password -->
<div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-pass" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-password wp-mail-smtp-clear <?php echo ! $this->options->is_const_defined( $this->get_slug(), 'auth' ) && ! $this->options->get( $this->get_slug(), 'auth' ) ? 'inactive' : ''; ?>">
<div class="wp-mail-smtp-setting-label">
<label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-pass"><?php esc_html_e( 'SMTP Password', 'wp-mail-smtp' ); ?></label>
</div>
<div class="wp-mail-smtp-setting-field">
<?php if ( $this->options->is_const_defined( $this->get_slug(), 'pass' ) ) : ?>
<input type="text" value="*************" disabled id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-pass"/>
<?php $this->display_const_set_message( 'WPMS_SMTP_PASS' ); ?>
<p class="desc">
<?php
printf(
/* translators: %s - constant name: WPMS_SMTP_PASS. */
esc_html__( 'To change the password you need to change the value of the constant there: %s', 'wp-mail-smtp' ),
'<code>define( \'WPMS_SMTP_PASS\', \'your_old_password\' );</code>'
);
?>
<br>
<?php
printf(
/* translators: %1$s - wp-config.php file, %2$s - WPMS_ON constant name. */
esc_html__( 'If you want to disable the use of constants, find in %1$s file the constant %2$s and turn if off:', 'wp-mail-smtp' ),
'<code>wp-config.php</code>',
'<code>WPMS_ON</code>'
);
?>
</p>
<pre>
define( 'WPMS_ON', false );
</pre>
<p class="desc">
<?php esc_html_e( 'All the defined constants will stop working and you will be able to change all the values on this page.', 'wp-mail-smtp' ); ?>
</p>
<?php else : ?>
<input name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][pass]" type="password"
value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'pass' ) ); ?>"
id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-pass" spellcheck="false" autocomplete="new-password"
/>
<p class="desc">
<?php esc_html_e( 'The password is stored in plain text. We highly recommend you set up your password in your WordPress configuration file for improved security.', 'wp-mail-smtp' ); ?>
<br>
<?php
printf(
/* translators: %s - wp-config.php. */
esc_html__( 'To do this add the lines below to your %s file:', 'wp-mail-smtp' ),
'<code>wp-config.php</code>'
);
?>
</p>
<pre>
define( 'WPMS_ON', true );
define( 'WPMS_SMTP_PASS', 'your_password' );
</pre>
<?php endif; ?>
</div>
</div>
<?php
}
/**
* Whether this mailer is recommended or not.
*
* @since 1.6.0
*
* @return bool
*/
public function is_recommended() {
return (bool) apply_filters( 'wp_mail_smtp_providers_provider_is_recommended', $this->recommended, $this );
}
/**
* Whether this mailer is disabled or not.
* Used for displaying Pro mailers inside Lite plugin.
*
* @since 1.7.0
*
* @return bool
*/
public function is_disabled() {
return (bool) apply_filters( 'wp_mail_smtp_providers_provider_is_disabled', $this->disabled, $this );
}
/**
* Check whether we can use this provider based on the PHP version.
* Valid for those, that use SDK.
*
* @since 1.0.0
*
* @return bool
*/
public function is_php_correct() {
return version_compare( phpversion(), $this->php, '>=' );
}
/**
* Display a helpful message to those users, that are using an outdated version of PHP,
* which is not supported by the currently selected Provider.
*
* @since 1.0.0
*/
protected function display_php_warning() {
?>
<blockquote>
<?php
printf(
/* translators: %1$s - Provider name; %2$s - PHP version required by Provider; %3$s - current PHP version. */
esc_html__( '%1$s requires PHP %2$s to work and does not support your current PHP version %3$s. Please contact your host and request a PHP upgrade to the latest one.', 'wp-mail-smtp' ),
esc_html( $this->get_title() ),
esc_html( $this->php ),
esc_html( phpversion() )
);
?>
<br>
<?php esc_html_e( 'Meanwhile you can switch to some other mailers.', 'wp-mail-smtp' ); ?>
</blockquote>
<?php
}
/**
* Display a helpful message to those users, that are using an outdated version of PHP,
* which is not supported by the currently selected Provider.
*
* @since 1.5.0
*/
protected function display_ssl_warning() {
?>
<blockquote>
<?php
printf(
/* translators: %s - Provider name. */
esc_html__( '%s requires a SSL certificate on a site to work and does not support your current installation. Please contact your host and request a SSL certificate or install a free one, like Let\'s Encrypt.', 'wp-mail-smtp' ),
esc_html( $this->get_title() )
);
?>
<br>
<?php esc_html_e( 'Meanwhile you can switch to some other mailers.', 'wp-mail-smtp' ); ?>
</blockquote>
<?php
}
/**
* Display a message of a constant that was set inside wp-config.php file.
*
* @since 1.5.0
*
* @param string $constant Constant name.
*/
protected function display_const_set_message( $constant ) {
?>
<p class="desc">
<?php
printf( /* translators: %1$s - constant name, %2$s - file name. */
esc_html__( 'The value of this field was set using a constant %1$s most likely inside %2$s of your WordPress installation.', 'wp-mail-smtp' ),
'<code>' . esc_attr( $constant ) . '</code>',
'<code>wp-config.php</code>'
);
?>
</p>
<?php
}
}

View File

@ -0,0 +1,64 @@
<?php
namespace WPMailSMTP\Providers;
/**
* Interface ProviderInterface, shared between all current and future providers.
* Defines required methods across all providers.
*
* @since 1.0.0
*/
interface OptionsInterface {
/**
* Get the mailer provider slug.
*
* @since 1.0.0
*
* @return string
*/
public function get_slug();
/**
* Get the mailer provider title (or name).
*
* @since 1.0.0
*
* @return string
*/
public function get_title();
/**
* Get the mailer provider description.
*
* @since 1.0.0
*
* @return string
*/
public function get_description();
/**
* Get the mailer provider minimum PHP version.
*
* @since 1.0.0
*
* @return string
*/
public function get_php_version();
/**
* Get the mailer provider logo URL.
*
* @since 1.0.0
*
* @return string
*/
public function get_logo_url();
/**
* Output the mailer provider options.
*
* @since 1.0.0
*/
public function display_options();
}

View File

@ -0,0 +1,44 @@
<?php
namespace WPMailSMTP\Providers\Outlook;
use WPMailSMTP\Providers\OptionsAbstract;
/**
* Class Options.
*
* @since 1.7.0
*/
class Options extends OptionsAbstract {
/**
* Outlook Options constructor.
*
* @since 1.7.0
*/
public function __construct() {
parent::__construct(
array(
'logo_url' => wp_mail_smtp()->assets_url . '/images/providers/microsoft.svg',
'slug' => 'outlook',
'title' => esc_html__( 'Outlook', 'wp-mail-smtp' ),
'disabled' => true,
)
);
}
/**
* @inheritdoc
*/
public function display_options() {
?>
<p>
<?php esc_html_e( 'We\'re sorry, the Microsoft Outlook mailer is not available on your plan. Please upgrade to the PRO plan to unlock all these awesome features.', 'wp-mail-smtp' ); ?>
</p>
<?php
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace WPMailSMTP\Providers\Pepipost;
use WPMailSMTP\Providers\MailerAbstract;
/**
* Class Mailer inherits everything from parent abstract class.
* This file is required for a proper work of Loader and \ReflectionClass.
*
* @package WPMailSMTP\Providers\Pepipost
*/
class Mailer extends MailerAbstract {
/**
* @inheritdoc
*/
public function is_mailer_complete() {
$options = $this->options->get_group( $this->mailer );
// Host and Port are the only really required options.
if (
! empty( $options['host'] ) &&
! empty( $options['port'] )
) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace WPMailSMTP\Providers\Pepipost;
use WPMailSMTP\Providers\OptionsAbstract;
/**
* Class Options.
*
* @since 1.0.0
*/
class Options extends OptionsAbstract {
/**
* Pepipost constructor.
*
* @since 1.0.0
*/
public function __construct() {
parent::__construct(
array(
'logo_url' => wp_mail_smtp()->assets_url . '/images/providers/pepipost-smtp.png',
'slug' => 'pepipost',
'title' => esc_html__( 'Pepipost SMTP', 'wp-mail-smtp' ),
)
);
}
}

View File

@ -0,0 +1,440 @@
<?php
namespace WPMailSMTP\Providers\PepipostAPI;
use WPMailSMTP\Providers\MailerAbstract;
use WPMailSMTP\WP;
/**
* Class Mailer is basically a Sendgrid copy-paste, as Pepipost support SG migration.
* In the future we may rewrite the class to use the native Pepipost API.
*
* @since 1.8.0
*/
class Mailer extends MailerAbstract {
/**
* Which response code from HTTP provider is considered to be successful?
*
* @since 1.8.0
*
* @var int
*/
protected $email_sent_code = 202;
/**
* URL to make an API request to.
*
* @since 1.8.0
*
* @var string
*/
protected $url = 'https://sgapi.pepipost.com/v3/mail/send';
/**
* Mailer constructor.
*
* @since 1.8.0
*
* @param \WPMailSMTP\MailCatcher $phpmailer
*/
public function __construct( $phpmailer ) {
// We want to prefill everything from \WPMailSMTP\MailCatcher class, which extends \PHPMailer.
parent::__construct( $phpmailer );
$this->set_header( 'Authorization', 'Bearer ' . $this->options->get( $this->mailer, 'api_key' ) );
$this->set_header( 'content-type', 'application/json' );
}
/**
* Redefine the way email body is returned.
* By default we are sending an array of data.
* Pepipost requires a JSON, so we encode the body.
*
* @since 1.8.0
*
* @return string
*/
public function get_body() {
$body = parent::get_body();
return wp_json_encode( $body );
}
/**
* Set the FROM header of the email.
*
* @since 1.8.0
*
* @param string $email From mail.
* @param string $name From name.
*/
public function set_from( $email, $name = '' ) {
if ( ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) {
return;
}
$from['email'] = $email;
if ( ! empty( $name ) ) {
$from['name'] = $name;
}
$this->set_body_param(
array(
'from' => $from,
)
);
}
/**
* Set the names/emails of people who will receive the email.
*
* @since 1.8.0
*
* @param array $recipients List of recipients: cc/bcc/to.
*/
public function set_recipients( $recipients ) {
if ( empty( $recipients ) ) {
return;
}
// Allow for now only these recipient types.
$default = array( 'to', 'cc', 'bcc' );
$data = array();
foreach ( $recipients as $type => $emails ) {
if (
! in_array( $type, $default, true ) ||
empty( $emails ) ||
! is_array( $emails )
) {
continue;
}
$data[ $type ] = array();
// Iterate over all emails for each type.
// There might be multiple cc/to/bcc emails.
foreach ( $emails as $email ) {
$holder = array();
$addr = isset( $email[0] ) ? $email[0] : false;
$name = isset( $email[1] ) ? $email[1] : false;
if ( ! filter_var( $addr, FILTER_VALIDATE_EMAIL ) ) {
continue;
}
$holder['email'] = $addr;
if ( ! empty( $name ) ) {
$holder['name'] = $name;
}
array_push( $data[ $type ], $holder );
}
}
if ( ! empty( $data ) ) {
$this->set_body_param(
array(
'personalizations' => array( $data ),
)
);
if ( ! empty( $data['bcc'] ) ) {
// Only the 1st BCC email address, ignore the rest - is not supported by Pepipost.
$bcc['mail_settings']['bcc']['email'] = $data['bcc'][0]['email'];
$this->set_body_param(
$bcc
);
}
}
}
/**
* Set the email content.
*
* @since 1.8.0
*
* @param array|string $content Email content.
*/
public function set_content( $content ) {
if ( empty( $content ) ) {
return;
}
if ( is_array( $content ) ) {
$default = array( 'text', 'html' );
$data = array();
foreach ( $content as $type => $body ) {
if (
! in_array( $type, $default, true ) ||
empty( $body )
) {
continue;
}
$content_type = 'text/plain';
$content_value = $body;
if ( $type === 'html' ) {
$content_type = 'text/html';
}
$data[] = array(
'type' => $content_type,
'value' => $content_value,
);
}
$this->set_body_param(
array(
'content' => $data,
)
);
} else {
$data['type'] = 'text/html';
$data['value'] = $content;
if ( $this->phpmailer->ContentType === 'text/plain' ) {
$data['type'] = 'text/plain';
}
$this->set_body_param(
array(
'content' => array( $data ),
)
);
}
}
/**
* Redefine the way custom headers are processed for this mailer - they should be in body.
*
* @since 1.8.0
*
* @param array $headers
*/
public function set_headers( $headers ) {
foreach ( $headers as $header ) {
$name = isset( $header[0] ) ? $header[0] : false;
$value = isset( $header[1] ) ? $header[1] : false;
$this->set_body_header( $name, $value );
}
// Add custom PHPMailer-specific header.
$this->set_body_header( 'X-Mailer', 'WPMailSMTP/Mailer/' . $this->mailer . ' ' . WPMS_PLUGIN_VER );
}
/**
* This mailer supports email-related custom headers inside a body of the message.
*
* @since 1.8.0
*
* @param string $name
* @param string $value
*/
public function set_body_header( $name, $value ) {
$name = sanitize_text_field( $name );
if ( empty( $name ) ) {
return;
}
$headers = isset( $this->body['headers'] ) ? (array) $this->body['headers'] : array();
$headers[ $name ] = WP::sanitize_value( $value );
$this->set_body_param(
array(
'headers' => $headers,
)
);
}
/**
* Pepipost accepts an array of files content in body, so we will include all files and send.
* Doesn't handle exceeding the limits etc, as this is done and reported by SendGrid API.
*
* @since 1.8.0
*
* @param array $attachments
*/
public function set_attachments( $attachments ) {
if ( empty( $attachments ) ) {
return;
}
$data = array();
foreach ( $attachments as $attachment ) {
$file = false;
/*
* We are not using WP_Filesystem API as we can't reliably work with it.
* It is not always available, same as credentials for FTP.
*/
try {
if ( is_file( $attachment[0] ) && is_readable( $attachment[0] ) ) {
$file = file_get_contents( $attachment[0] ); // phpcs:ignore
}
}
catch ( \Exception $e ) {
$file = false;
}
if ( $file === false ) {
continue;
}
$data[] = array(
'content' => base64_encode( $file ),
'type' => $attachment[4],
'filename' => $attachment[2],
'disposition' => $attachment[6],
);
}
if ( ! empty( $data ) ) {
$this->set_body_param(
array(
'attachments' => $data,
)
);
}
}
/**
* Set the reply-to property of the email.
*
* @since 1.8.0
*
* @param array $reply_to Name/email for reply-to feature.
*/
public function set_reply_to( $reply_to ) {
if ( empty( $reply_to ) ) {
return;
}
$data = array();
foreach ( $reply_to as $key => $emails ) {
if (
empty( $emails ) ||
! is_array( $emails )
) {
continue;
}
$addr = isset( $emails[0] ) ? $emails[0] : false;
$name = isset( $emails[1] ) ? $emails[1] : false;
if ( ! filter_var( $addr, FILTER_VALIDATE_EMAIL ) ) {
continue;
}
$data['email'] = $addr;
if ( ! empty( $name ) ) {
$data['name'] = $name;
}
}
if ( ! empty( $data ) ) {
$this->set_body_param(
array(
'reply_to' => $data,
)
);
}
}
/**
* Pepipost doesn't support sender or return_path params.
* So we do nothing.
*
* @since 1.8.0
*
* @param string $from_email
*/
public function set_return_path( $from_email ) {}
/**
* Get a Pepipost-specific response with a helpful error.
*
* @see https://developers.pepipost.com/migration-api/new-subpage/errorcodes
*
* @since 1.8.0
*
* @return string
*/
protected function get_response_error() {
$body = (array) wp_remote_retrieve_body( $this->response );
$error_text = array();
if ( ! empty( $body['errors'] ) ) {
foreach ( $body['errors'] as $error ) {
if ( property_exists( $error, 'message' ) ) {
// Prepare additional information from SendGrid API.
$extra = '';
if ( property_exists( $error, 'field' ) && ! empty( $error->field ) ) {
$extra .= $error->field . '; ';
}
if ( property_exists( $error, 'help' ) && ! empty( $error->help ) ) {
$extra .= $error->help;
}
// Assign both the main message and perhaps extra information, if exists.
$error_text[] = $error->message . ( ! empty( $extra ) ? ' - ' . $extra : '' );
}
}
}
return implode( '<br>', array_map( 'esc_textarea', $error_text ) );
}
/**
* Get mailer debug information, that is helpful during support.
*
* @since 1.8.0
*
* @return string
*/
public function get_debug_info() {
$sendgrid_text[] = '<strong>Api Key:</strong> ' . ( $this->is_mailer_complete() ? 'Yes' : 'No' );
return implode( '<br>', $sendgrid_text );
}
/**
* Whether the mailer has all its settings correctly set up and saved.
*
* @since 1.8.0
*
* @return bool
*/
public function is_mailer_complete() {
$options = $this->options->get_group( $this->mailer );
// API key is the only required option.
if ( ! empty( $options['api_key'] ) ) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,119 @@
<?php
namespace WPMailSMTP\Providers\PepipostAPI;
use WPMailSMTP\Providers\OptionsAbstract;
use WPMailSMTP\Options as PluginOptions;
/**
* Class Options.
*
* @since 1.8.0
*/
class Options extends OptionsAbstract {
/**
* Mailer slug.
*
* @since 1.8.0
*/
const SLUG = 'pepipostapi';
/**
* Options constructor.
*
* @since 1.8.0
*/
public function __construct() {
$description = sprintf(
wp_kses( /* translators: %1$s - URL to pepipost.com site. */
__( '<strong><a href="%1$s" target="_blank" rel="noopener noreferrer">Pepipost</a> is a recommended transactional email service.</strong> Every month Pepipost delivers over 8 billion emails from 20,000+ customers. Their mission is to reliably send emails in the most efficient way and at the most disruptive pricing ever. Pepipost provides users 30,000 free emails the first 30 days.', 'wp-mail-smtp' ) .
'<br><br>' .
/* translators: %1$s - URL to wpmailsmtp.com doc. */
__( 'Read our <a href="%2$s" target="_blank" rel="noopener noreferrer">Pepipost documentation</a> to learn how to configure Pepipost and improve your email deliverability.', 'wp-mail-smtp' ),
array(
'br' => true,
'strong' => true,
'a' => array(
'href' => true,
'rel' => true,
'target' => true,
),
)
),
'https://wpmailsmtp.com/go/pepipost/',
'https://wpmailsmtp.com/docs/how-to-set-up-the-pepipost-mailer-in-wp-mail-smtp'
);
$api_key = PluginOptions::init()->get( self::SLUG, 'api_key' );
if ( empty( $api_key ) ) {
$description .= '</p><p class="buttonned"><a href="https://wpmailsmtp.com/go/pepipost/" target="_blank" rel="noopener noreferrer" class="wp-mail-smtp-btn wp-mail-smtp-btn-md wp-mail-smtp-btn-blueish">' .
esc_html__( 'Get Pepipost Now (Free)', 'wp-mail-smtp' ) .
'</a></p>';
}
parent::__construct(
array(
'logo_url' => wp_mail_smtp()->assets_url . '/images/providers/pepipost.png',
'slug' => self::SLUG,
'title' => esc_html__( 'Pepipost', 'wp-mail-smtp' ),
'description' => $description,
'recommended' => true,
'php' => '5.3',
)
);
}
/**
* Output the mailer provider options.
*
* @since 1.8.0
*/
public function display_options() {
// Do not display options if PHP version is not correct.
if ( ! $this->is_php_correct() ) {
$this->display_php_warning();
return;
}
?>
<!-- API Key -->
<div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-client_id"
class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
<div class="wp-mail-smtp-setting-label">
<label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-api_key"><?php esc_html_e( 'API Key', 'wp-mail-smtp' ); ?></label>
</div>
<div class="wp-mail-smtp-setting-field">
<?php if ( $this->options->is_const_defined( $this->get_slug(), 'api_key' ) ) : ?>
<input type="text" disabled value="****************************************"
id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-api_key"
/>
<?php $this->display_const_set_message( 'WPMS_PEPIPOST_API_KEY' ); ?>
<?php else : ?>
<input type="password" spellcheck="false"
name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][api_key]"
value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'api_key' ) ); ?>"
id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-api_key"
/>
<?php endif; ?>
<p class="desc">
<?php
printf( /* translators: %s - pepipost.com link to get an API Key. */
esc_html__( 'Follow this link to get an API Key: %s.', 'wp-mail-smtp' ),
'<a href="https://app.pepipost.com/app/settings/integration" target="_blank" rel="noopener noreferrer">' .
esc_html__( 'Get the API Key', 'wp-mail-smtp' ) .
'</a>'
);
?>
</p>
</div>
</div>
<?php
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace WPMailSMTP\Providers\SMTP;
use WPMailSMTP\Providers\MailerAbstract;
/**
* Class Mailer inherits everything from parent abstract class.
* This file is required for a proper work of Loader and \ReflectionClass.
*
* @package WPMailSMTP\Providers\SMTP
*/
class Mailer extends MailerAbstract {
/**
* @inheritdoc
*/
public function is_mailer_complete() {
$options = $this->options->get_group( $this->mailer );
// Host and Port are the only really required options.
if (
! empty( $options['host'] ) &&
! empty( $options['port'] )
) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace WPMailSMTP\Providers\SMTP;
use WPMailSMTP\Providers\OptionsAbstract;
/**
* Class SMTP.
*
* @since 1.0.0
*/
class Options extends OptionsAbstract {
/**
* SMTP constructor.
*
* @since 1.0.0
*/
public function __construct() {
parent::__construct(
array(
'logo_url' => wp_mail_smtp()->assets_url . '/images/providers/smtp.svg',
'slug' => 'smtp',
'title' => esc_html__( 'Other SMTP', 'wp-mail-smtp' ),
'description' => sprintf(
wp_kses(
/* translators: %s - URL to a related article on WPForms.com. */
__( 'Use the SMTP details provided by your hosting provider or email service.<br><br>To see recommended settings for the popular services as well as troubleshooting tips, check out our <a href="%s" target="_blank" rel="noopener noreferrer">SMTP documentation</a>.', 'wp-mail-smtp' ),
array(
'br' => array(),
'a' => array(
'href' => array(),
'rel' => array(),
'target' => array(),
),
)
),
'https://wpmailsmtp.com/docs/how-to-set-up-the-other-smtp-mailer-in-wp-mail-smtp/'
),
)
);
}
}

View File

@ -0,0 +1,409 @@
<?php
namespace WPMailSMTP\Providers\Sendgrid;
use WPMailSMTP\Providers\MailerAbstract;
use WPMailSMTP\WP;
/**
* Class Mailer.
*
* @since 1.0.0
*/
class Mailer extends MailerAbstract {
/**
* Which response code from HTTP provider is considered to be successful?
*
* @since 1.0.0
*
* @var int
*/
protected $email_sent_code = 202;
/**
* URL to make an API request to.
*
* @since 1.0.0
*
* @var string
*/
protected $url = 'https://api.sendgrid.com/v3/mail/send';
/**
* Mailer constructor.
*
* @since 1.0.0
*
* @param \WPMailSMTP\MailCatcher $phpmailer
*/
public function __construct( $phpmailer ) {
// We want to prefill everything from \WPMailSMTP\MailCatcher class, which extends \PHPMailer.
parent::__construct( $phpmailer );
$this->set_header( 'Authorization', 'Bearer ' . $this->options->get( $this->mailer, 'api_key' ) );
$this->set_header( 'content-type', 'application/json' );
}
/**
* Redefine the way email body is returned.
* By default we are sending an array of data.
* SendGrid requires a JSON, so we encode the body.
*
* @since 1.0.0
*/
public function get_body() {
$body = parent::get_body();
return wp_json_encode( $body );
}
/**
* @inheritdoc
*/
public function set_from( $email, $name = '' ) {
if ( ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) {
return;
}
$from['email'] = $email;
if ( ! empty( $name ) ) {
$from['name'] = $name;
}
$this->set_body_param(
array(
'from' => $from,
)
);
}
/**
* @inheritdoc
*/
public function set_recipients( $recipients ) {
if ( empty( $recipients ) ) {
return;
}
// Allow for now only these recipient types.
$default = array( 'to', 'cc', 'bcc' );
$data = array();
foreach ( $recipients as $type => $emails ) {
if (
! in_array( $type, $default, true ) ||
empty( $emails ) ||
! is_array( $emails )
) {
continue;
}
$data[ $type ] = array();
// Iterate over all emails for each type.
// There might be multiple cc/to/bcc emails.
foreach ( $emails as $email ) {
$holder = array();
$addr = isset( $email[0] ) ? $email[0] : false;
$name = isset( $email[1] ) ? $email[1] : false;
if ( ! filter_var( $addr, FILTER_VALIDATE_EMAIL ) ) {
continue;
}
$holder['email'] = $addr;
if ( ! empty( $name ) ) {
$holder['name'] = $name;
}
array_push( $data[ $type ], $holder );
}
}
if ( ! empty( $data ) ) {
$this->set_body_param(
array(
'personalizations' => array( $data ),
)
);
}
}
/**
* @inheritdoc
*/
public function set_content( $content ) {
if ( empty( $content ) ) {
return;
}
if ( is_array( $content ) ) {
$default = array( 'text', 'html' );
$data = array();
foreach ( $content as $type => $body ) {
if (
! in_array( $type, $default, true ) ||
empty( $body )
) {
continue;
}
$content_type = 'text/plain';
$content_value = $body;
if ( $type === 'html' ) {
$content_type = 'text/html';
}
$data[] = array(
'type' => $content_type,
'value' => $content_value,
);
}
$this->set_body_param(
array(
'content' => $data,
)
);
} else {
$data['type'] = 'text/html';
$data['value'] = $content;
if ( $this->phpmailer->ContentType === 'text/plain' ) {
$data['type'] = 'text/plain';
}
$this->set_body_param(
array(
'content' => array( $data ),
)
);
}
}
/**
* Redefine the way custom headers are processed for this mailer - they should be in body.
*
* @since 1.5.0
*
* @param array $headers
*/
public function set_headers( $headers ) {
foreach ( $headers as $header ) {
$name = isset( $header[0] ) ? $header[0] : false;
$value = isset( $header[1] ) ? $header[1] : false;
$this->set_body_header( $name, $value );
}
// Add custom PHPMailer-specific header.
$this->set_body_header( 'X-Mailer', 'WPMailSMTP/Mailer/' . $this->mailer . ' ' . WPMS_PLUGIN_VER );
}
/**
* This mailer supports email-related custom headers inside a body of the message.
*
* @since 1.5.0
*
* @param string $name
* @param string $value
*/
public function set_body_header( $name, $value ) {
$name = sanitize_text_field( $name );
if ( empty( $name ) ) {
return;
}
$headers = isset( $this->body['headers'] ) ? (array) $this->body['headers'] : array();
$headers[ $name ] = WP::sanitize_value( $value );
$this->set_body_param(
array(
'headers' => $headers,
)
);
}
/**
* SendGrid accepts an array of files content in body, so we will include all files and send.
* Doesn't handle exceeding the limits etc, as this is done and reported by SendGrid API.
*
* @since 1.0.0
*
* @param array $attachments
*/
public function set_attachments( $attachments ) {
if ( empty( $attachments ) ) {
return;
}
$data = array();
foreach ( $attachments as $attachment ) {
$file = false;
/*
* We are not using WP_Filesystem API as we can't reliably work with it.
* It is not always available, same as credentials for FTP.
*/
try {
if ( is_file( $attachment[0] ) && is_readable( $attachment[0] ) ) {
$file = file_get_contents( $attachment[0] ); // phpcs:ignore
}
}
catch ( \Exception $e ) {
$file = false;
}
if ( $file === false ) {
continue;
}
$filetype = str_replace( ';', '', trim( $attachment[4] ) );
$data[] = array(
'content' => base64_encode( $file ), // string, 1 character.
'type' => $filetype, // string, no ;, no CRLF.
'filename' => empty( $attachment[2] ) ? 'file-' . wp_hash( microtime() ) . '.' . $filetype : trim( $attachment[2] ), // required string, no CRLF.
'disposition' => in_array( $attachment[6], array( 'inline', 'attachment' ), true ) ? $attachment[6] : 'attachment', // either inline or attachment.
'content_id' => empty( $attachment[7] ) ? '' : trim( (string) $attachment[7] ), // string, no CRLF.
);
}
if ( ! empty( $data ) ) {
$this->set_body_param(
array(
'attachments' => $data,
)
);
}
}
/**
* @inheritdoc
*/
public function set_reply_to( $reply_to ) {
if ( empty( $reply_to ) ) {
return;
}
$data = array();
foreach ( $reply_to as $key => $emails ) {
if (
empty( $emails ) ||
! is_array( $emails )
) {
continue;
}
$addr = isset( $emails[0] ) ? $emails[0] : false;
$name = isset( $emails[1] ) ? $emails[1] : false;
if ( ! filter_var( $addr, FILTER_VALIDATE_EMAIL ) ) {
continue;
}
$data['email'] = $addr;
if ( ! empty( $name ) ) {
$data['name'] = $name;
}
}
if ( ! empty( $data ) ) {
$this->set_body_param(
array(
'reply_to' => $data,
)
);
}
}
/**
* SendGrid doesn't support sender or return_path params.
* So we do nothing.
*
* @since 1.0.0
*
* @param string $from_email
*/
public function set_return_path( $from_email ) {}
/**
* Get a SendGrid-specific response with a helpful error.
*
* @since 1.2.0
*
* @return string
*/
protected function get_response_error() {
$body = (array) wp_remote_retrieve_body( $this->response );
$error_text = array();
if ( ! empty( $body['errors'] ) ) {
foreach ( $body['errors'] as $error ) {
if ( property_exists( $error, 'message' ) ) {
// Prepare additional information from SendGrid API.
$extra = '';
if ( property_exists( $error, 'field' ) && ! empty( $error->field ) ) {
$extra .= $error->field . '; ';
}
if ( property_exists( $error, 'help' ) && ! empty( $error->help ) ) {
$extra .= $error->help;
}
// Assign both the main message and perhaps extra information, if exists.
$error_text[] = $error->message . ( ! empty( $extra ) ? ' - ' . $extra : '' );
}
}
}
return implode( '<br>', array_map( 'esc_textarea', $error_text ) );
}
/**
* Get mailer debug information, that is helpful during support.
*
* @since 1.2.0
*
* @return string
*/
public function get_debug_info() {
$sendgrid_text[] = '<strong>Api Key:</strong> ' . ( $this->is_mailer_complete() ? 'Yes' : 'No' );
return implode( '<br>', $sendgrid_text );
}
/**
* @inheritdoc
*/
public function is_mailer_complete() {
$options = $this->options->get_group( $this->mailer );
// API key is the only required option.
if ( ! empty( $options['api_key'] ) ) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,96 @@
<?php
namespace WPMailSMTP\Providers\Sendgrid;
use WPMailSMTP\Providers\OptionsAbstract;
/**
* Class Option.
*
* @since 1.0.0
*/
class Options extends OptionsAbstract {
/**
* Options constructor.
*
* @since 1.0.0
*/
public function __construct() {
parent::__construct(
array(
'logo_url' => wp_mail_smtp()->assets_url . '/images/providers/sendgrid.svg',
'slug' => 'sendgrid',
'title' => esc_html__( 'SendGrid', 'wp-mail-smtp' ),
'description' => sprintf(
wp_kses(
/* translators: %1$s - opening link tag; %2$s - closing link tag; %3$s - opening link tag; %4$s - closing link tag. */
__( '%1$sSendGrid%2$s is one of the leading transactional email services, sending over 35 billion emails every month. They provide users 100 free emails per day.<br><br>Read our %3$sSendGrid documentation%4$s to learn how to set up SendGrid and improve your email deliverability.', 'wp-mail-smtp' ),
array(
'br' => array(),
'a' => array(
'href' => array(),
'rel' => array(),
'target' => array(),
),
)
),
'<a href="https://sendgrid.com" target="_blank" rel="noopener noreferrer">',
'</a>',
'<a href="https://wpmailsmtp.com/docs/how-to-set-up-the-sendgrid-mailer-in-wp-mail-smtp/" target="_blank" rel="noopener noreferrer">',
'</a>'
),
)
);
}
/**
* @inheritdoc
*/
public function display_options() {
?>
<!-- API Key -->
<div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-api_key" class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
<div class="wp-mail-smtp-setting-label">
<label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-api_key"><?php esc_html_e( 'API Key', 'wp-mail-smtp' ); ?></label>
</div>
<div class="wp-mail-smtp-setting-field">
<?php if ( $this->options->is_const_defined( $this->get_slug(), 'api_key' ) ) : ?>
<input type="text" disabled value="****************************************"
id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-api_key"
/>
<?php $this->display_const_set_message( 'WPMS_SENDGRID_API_KEY' ); ?>
<?php else : ?>
<input type="password" spellcheck="false"
name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][api_key]"
value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'api_key' ) ); ?>"
id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-api_key"
/>
<?php endif; ?>
<p class="desc">
<?php
printf(
/* translators: %s - API key link. */
esc_html__( 'Follow this link to get an API Key from SendGrid: %s.', 'wp-mail-smtp' ),
'<a href="https://app.sendgrid.com/settings/api_keys" target="_blank" rel="noopener noreferrer">' .
esc_html__( 'Create API Key', 'wp-mail-smtp' ) .
'</a>'
);
?>
<br/>
<?php
printf(
/* translators: %s - SendGrid access level. */
esc_html__( 'To send emails you will need only a %s access level for this API key.', 'wp-mail-smtp' ),
'<code>Mail Send</code>'
);
?>
</p>
</div>
</div>
<?php
}
}

View File

@ -0,0 +1,93 @@
<?php
namespace WPMailSMTP\Providers\Sendinblue;
/**
* Class Api is a wrapper for Sendinblue library with handy methods.
*
* @since 1.6.0
*/
class Api {
/**
* Contains mailer options, constants + DB values.
*
* @since 1.6.0
*
* @var array
*/
private $options;
/**
* API constructor that inits defaults and retrieves options.
*
* @since 1.6.0
*/
public function __construct() {
$this->options = \WPMailSMTP\Options::init()->get_group( Options::SLUG );
}
/**
* Configure API key authorization: api-key.
*
* @since 1.6.0
*
* @return \SendinBlue\Client\Configuration
*/
protected function get_api_config() {
return \SendinBlue\Client\Configuration::getDefaultConfiguration()->setApiKey( 'api-key', isset( $this->options['api_key'] ) ? $this->options['api_key'] : '' );
}
/**
* Get the mailer client instance for Account API.
*
* @since 1.6.0
*/
public function get_account_client() {
// Include the library.
require_once wp_mail_smtp()->plugin_path . '/vendor/autoload.php';
return new \SendinBlue\Client\Api\AccountApi( null, $this->get_api_config() );
}
/**
* Get the mailer client instance for Sender API.
*
* @since 1.6.0
*/
public function get_sender_client() {
// Include the library.
require_once wp_mail_smtp()->plugin_path . '/vendor/autoload.php';
return new \SendinBlue\Client\Api\SendersApi( null, $this->get_api_config() );
}
/**
* Get the mailer client instance for SMTP API.
*
* @since 1.6.0
*/
public function get_smtp_client() {
// Include the library.
require_once wp_mail_smtp()->plugin_path . '/vendor/autoload.php';
return new \SendinBlue\Client\Api\SMTPApi( null, $this->get_api_config() );
}
/**
* Whether the mailer is ready to be used in API calls.
*
* @since 1.6.0
*
* @return bool
*/
public function is_ready() {
return ! empty( $this->options['api_key'] );
}
}

View File

@ -0,0 +1,393 @@
<?php
namespace WPMailSMTP\Providers\Sendinblue;
use WPMailSMTP\Debug;
use WPMailSMTP\Providers\MailerAbstract;
use WPMailSMTP\WP;
/**
* Class Mailer.
*
* @since 1.6.0
*/
class Mailer extends MailerAbstract {
/**
* Which response code from HTTP provider is considered to be successful?
*
* @since 1.6.0
*
* @var int
*/
protected $email_sent_code = 201;
/**
* URL to make an API request to.
* Not actually used, because we use a lib to make requests.
*
* @since 1.6.0
*
* @var string
*/
protected $url = 'https://api.sendinblue.com/v3';
/**
* The list of allowed attachment files extensions.
*
* @see https://developers.sendinblue.com/reference#sendTransacEmail_attachment__title
*
* @since 1.6.0
*
* @var array
*/
// @formatter:off
protected $allowed_attach_ext = array( 'xlsx', 'xls', 'ods', 'docx', 'docm', 'doc', 'csv', 'pdf', 'txt', 'gif', 'jpg', 'jpeg', 'png', 'tif', 'tiff', 'rtf', 'bmp', 'cgm', 'css', 'shtml', 'html', 'htm', 'zip', 'xml', 'ppt', 'pptx', 'tar', 'ez', 'ics', 'mobi', 'msg', 'pub', 'eps', 'odt', 'mp3', 'm4a', 'm4v', 'wma', 'ogg', 'flac', 'wav', 'aif', 'aifc', 'aiff', 'mp4', 'mov', 'avi', 'mkv', 'mpeg', 'mpg', 'wmv' );
// @formatter:on
/**
* Mailer constructor.
*
* @since 1.6.0
*
* @param \WPMailSMTP\MailCatcher $phpmailer
*/
public function __construct( $phpmailer ) {
parent::__construct( $phpmailer );
if ( ! $this->is_php_compatible() ) {
return;
}
}
/**
* @inheritDoc
*
* @since 1.6.0
*/
public function set_header( $name, $value ) {
$name = sanitize_text_field( $name );
$this->body['headers'][ $name ] = WP::sanitize_value( $value );
}
/**
* Set the From information for an email.
*
* @since 1.6.0
*
* @param string $email
* @param string $name
*/
public function set_from( $email, $name ) {
if ( ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) {
return;
}
$this->body['sender'] = array(
'email' => $email,
'name' => ! empty( $name ) ? WP::sanitize_value( $name ) : '',
);
}
/**
* Set email recipients: to, cc, bcc.
*
* @since 1.6.0
*
* @param array $recipients
*/
public function set_recipients( $recipients ) {
if ( empty( $recipients ) ) {
return;
}
// Allow for now only these recipient types.
$default = array( 'to', 'cc', 'bcc' );
$data = array();
foreach ( $recipients as $type => $emails ) {
if (
! in_array( $type, $default, true ) ||
empty( $emails ) ||
! is_array( $emails )
) {
continue;
}
$data[ $type ] = array();
// Iterate over all emails for each type.
// There might be multiple cc/to/bcc emails.
foreach ( $emails as $email ) {
$holder = array();
$addr = isset( $email[0] ) ? $email[0] : false;
$name = isset( $email[1] ) ? $email[1] : false;
if ( ! filter_var( $addr, FILTER_VALIDATE_EMAIL ) ) {
continue;
}
$holder['email'] = $addr;
if ( ! empty( $name ) ) {
$holder['name'] = $name;
}
array_push( $data[ $type ], $holder );
}
}
foreach ( $data as $type => $type_recipients ) {
$this->body[ $type ] = $type_recipients;
}
}
/**
* @inheritDoc
*
* @since 1.6.0
*/
public function set_subject( $subject ) {
$this->body['subject'] = $subject;
}
/**
* Set email content.
*
* @since 1.6.0
*
* @param string|array $content
*/
public function set_content( $content ) {
if ( empty( $content ) ) {
return;
}
if ( is_array( $content ) ) {
if ( ! empty( $content['text'] ) ) {
$this->body['textContent'] = $content['text'];
}
if ( ! empty( $content['html'] ) ) {
$this->body['htmlContent'] = $content['html'];
}
} else {
if ( $this->phpmailer->ContentType === 'text/plain' ) {
$this->body['textContent'] = $content;
} else {
$this->body['htmlContent'] = $content;
}
}
}
/**
* Doesn't support this.
*
* @since 1.6.0
*
* @param string $email
*/
public function set_return_path( $email ) {
}
/**
* Set the Reply To headers if not set already.
*
* @since 1.6.0
*
* @param array $emails
*/
public function set_reply_to( $emails ) {
if ( empty( $emails ) ) {
return;
}
$data = array();
foreach ( $emails as $user ) {
$holder = array();
$addr = isset( $user[0] ) ? $user[0] : false;
$name = isset( $user[1] ) ? $user[1] : false;
if ( ! filter_var( $addr, FILTER_VALIDATE_EMAIL ) ) {
continue;
}
$holder['email'] = $addr;
if ( ! empty( $name ) ) {
$holder['name'] = $name;
}
$data[] = $holder;
}
if ( ! empty( $data ) ) {
$this->body['replyTo'] = $data[0];
}
}
/**
* Set attachments for an email.
*
* @since 1.6.0
*
* @param array $attachments
*/
public function set_attachments( $attachments ) {
if ( empty( $attachments ) ) {
return;
}
foreach ( $attachments as $attachment ) {
$file = false;
/*
* We are not using WP_Filesystem API as we can't reliably work with it.
* It is not always available, same as credentials for FTP.
*/
try {
if ( is_file( $attachment[0] ) && is_readable( $attachment[0] ) ) {
$ext = pathinfo( $attachment[0], PATHINFO_EXTENSION );
if ( in_array( $ext, $this->allowed_attach_ext, true ) ) {
$file = file_get_contents( $attachment[0] ); // phpcs:ignore
}
}
}
catch ( \Exception $e ) {
$file = false;
}
if ( $file === false ) {
continue;
}
$this->body['attachment'][] = array(
'name' => $attachment[2],
'content' => base64_encode( $file ),
);
}
}
/**
* @inheritDoc
*
* @since 1.6.0
*
* @return \SendinBlue\Client\Model\SendSmtpEmail
*/
public function get_body() {
return new \SendinBlue\Client\Model\SendSmtpEmail( $this->body );
}
/**
* Use a library to send emails.
*
* @since 1.6.0
*/
public function send() {
try {
$api = new Api();
$response = $api->get_smtp_client()->sendTransacEmail( $this->get_body() );
$this->process_response( $response );
}
catch ( \SendinBlue\Client\ApiException $e ) {
$error = json_decode( $e->getResponseBody() );
if ( json_last_error() === JSON_ERROR_NONE ) {
Debug::set(
'Mailer: Sendinblue' . "\r\n" .
'[' . sanitize_key( $error->code ) . ']: ' . esc_html( $error->message )
);
}
}
catch ( \Exception $e ) {
Debug::set(
'Mailer: Sendinblue' . "\r\n" .
$e->getMessage()
);
return;
}
}
/**
* Save response from the API to use it later.
* All the actually response processing is done in send() method,
* because SendinBlue throws exception if any error occurs.
*
* @since 1.6.0
*
* @param \SendinBlue\Client\Model\CreateSmtpEmail $response
*/
protected function process_response( $response ) {
$this->response = $response;
}
/**
* Check whether the email was sent.
*
* @since 1.6.0
*
* @return bool
*/
public function is_email_sent() {
$is_sent = false;
if ( $this->response instanceof \SendinBlue\Client\Model\CreateSmtpEmail ) {
$is_sent = $this->response->valid();
}
// Clear debug messages if email is successfully sent.
if ( $is_sent ) {
Debug::clear();
}
return $is_sent;
}
/**
* @inheritdoc
*
* @since 1.6.0
*/
public function get_debug_info() {
$mailjet_text[] = '<strong>API Key:</strong> ' . ( $this->is_mailer_complete() ? 'Yes' : 'No' );
return implode( '<br>', $mailjet_text );
}
/**
* @inheritdoc
*
* @since 1.6.0
*/
public function is_mailer_complete() {
$options = $this->options->get_group( $this->mailer );
// API key is the only required option.
if ( ! empty( $options['api_key'] ) ) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,119 @@
<?php
namespace WPMailSMTP\Providers\Sendinblue;
use WPMailSMTP\Providers\OptionsAbstract;
use WPMailSMTP\Options as PluginOptions;
/**
* Class Options.
*
* @since 1.6.0
*/
class Options extends OptionsAbstract {
/**
* Mailer slug.
*
* @since 1.6.0
*/
const SLUG = 'sendinblue';
/**
* Options constructor.
*
* @since 1.6.0
*/
public function __construct() {
$description = sprintf(
wp_kses( /* translators: %1$s - URL to sendinblue.com site. */
__( '<strong><a href="%1$s" target="_blank" rel="noopener noreferrer">Sendinblue</a> is a recommended transactional email service.</strong> Founded in 2012, they serve 80,000+ growing companies around the world and send over 30 million emails each day. They understand that transactional emails are the heart of your customer relationships. Their email deliverability experts are constantly at work optimizing the reliability and speed of their SMTP infrastructure. Sendinblue provides users 300 free emails per day.', 'wp-mail-smtp' ) .
'<br><br>' .
/* translators: %2$s - URL to wpmailsmtp.com doc. */
__( 'Read our <a href="%2$s" target="_blank" rel="noopener noreferrer">Sendinblue documentation</a> to learn how to configure Sendinblue and improve your email deliverability.', 'wp-mail-smtp' ),
array(
'br' => true,
'strong' => true,
'a' => array(
'href' => true,
'rel' => true,
'target' => true,
),
)
),
'https://wpmailsmtp.com/go/sendinblue/',
'https://wpmailsmtp.com/docs/how-to-set-up-the-sendinblue-mailer-in-wp-mail-smtp'
);
$api_key = PluginOptions::init()->get( self::SLUG, 'api_key' );
if ( empty( $api_key ) ) {
$description .= '</p><p class="buttonned"><a href="https://wpmailsmtp.com/go/sendinblue/" target="_blank" rel="noopener noreferrer" class="wp-mail-smtp-btn wp-mail-smtp-btn-md wp-mail-smtp-btn-blueish">' .
esc_html__( 'Get Sendinblue Now (Free)', 'wp-mail-smtp' ) .
'</a></p>';
}
parent::__construct(
array(
'logo_url' => wp_mail_smtp()->assets_url . '/images/providers/sendinblue.svg',
'slug' => self::SLUG,
'title' => esc_html__( 'Sendinblue', 'wp-mail-smtp' ),
'description' => $description,
'recommended' => true,
'php' => '5.6',
)
);
}
/**
* Output the mailer provider options.
*
* @since 1.6.0
*/
public function display_options() {
// Do not display options if PHP version is not correct.
if ( ! $this->is_php_correct() ) {
$this->display_php_warning();
return;
}
?>
<!-- API Key -->
<div id="wp-mail-smtp-setting-row-<?php echo esc_attr( $this->get_slug() ); ?>-client_id"
class="wp-mail-smtp-setting-row wp-mail-smtp-setting-row-text wp-mail-smtp-clear">
<div class="wp-mail-smtp-setting-label">
<label for="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-api_key"><?php esc_html_e( 'API Key', 'wp-mail-smtp' ); ?></label>
</div>
<div class="wp-mail-smtp-setting-field">
<?php if ( $this->options->is_const_defined( $this->get_slug(), 'api_key' ) ) : ?>
<input type="text" disabled value="****************************************"
id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-api_key"
/>
<?php $this->display_const_set_message( 'WPMS_SENDINBLUE_API_KEY' ); ?>
<?php else : ?>
<input type="password" spellcheck="false"
name="wp-mail-smtp[<?php echo esc_attr( $this->get_slug() ); ?>][api_key]"
value="<?php echo esc_attr( $this->options->get( $this->get_slug(), 'api_key' ) ); ?>"
id="wp-mail-smtp-setting-<?php echo esc_attr( $this->get_slug() ); ?>-api_key"
/>
<?php endif; ?>
<p class="desc">
<?php
printf( /* translators: %s - sendinblue.com link to get an API Key. */
esc_html__( 'Follow this link to get an API Key: %s.', 'wp-mail-smtp' ),
'<a href="https://account.sendinblue.com/advanced/api" target="_blank" rel="noopener noreferrer">' .
esc_html__( 'Get v3 API Key', 'wp-mail-smtp' ) .
'</a>'
);
?>
</p>
</div>
</div>
<?php
}
}

View File

@ -0,0 +1,180 @@
<?php
namespace WPMailSMTP;
/**
* Class SiteHealth adds the plugin status and information to the WP Site Health admin page.
*
* @since {VERSION}
*/
class SiteHealth {
/**
* String of a badge color.
* Options: blue, green, red, orange, purple and gray.
*
* @see https://make.wordpress.org/core/2019/04/25/site-health-check-in-5-2/
*
* @since {VERSION}
*/
const BADGE_COLOR = 'blue';
/**
* Debug info plugin slug.
* This should be a plugin unique string, which will be used in the WP Site Health page,
* for the "info" tab and will present the plugin info section.
*
* @since {VERSION}
*/
const DEBUG_INFO_SLUG = 'wp_mail_smtp';
/**
* Translatable string for the plugin label.
*
* @since {VERSION}
*
* @return string
*/
public function get_label() {
return esc_html__( 'WP Mail SMTP', 'wp-mail-smtp' );
}
/**
* Initialize the site heath functionality.
*
* @since {VERSION}
*/
public function init() {
add_filter( 'site_status_tests', array( $this, 'register_site_status_tests' ) );
add_filter( 'debug_information', array( $this, 'register_debug_information' ) );
}
/**
* Register plugin WP site health tests.
* This will be displayed in the "Status" tab of the WP Site Health page.
*
* @since {VERSION}
*
* @param array $tests The array with all WP site health tests.
*
* @return array
*/
public function register_site_status_tests( $tests ) {
$tests['direct']['wp_mail_smtp_mailer_setup_complete'] = array(
'label' => esc_html__( 'Is WP Mail SMTP mailer setup complete?', 'wp-mail-smtp' ),
'test' => array( $this, 'mailer_setup_complete_test' ),
);
return $tests;
}
/**
* Register plugin WP Site Health debug information.
* This will be displayed in the "Info" tab of the WP Site Health page.
*
* @since {VERSION}
*
* @param array $debug_info Array of existing debug information.
*
* @return array
*/
public function register_debug_information( $debug_info ) {
$debug_notices = Debug::get();
$debug_info[ self::DEBUG_INFO_SLUG ] = array(
'label' => $this->get_label(),
'fields' => array(
'version' => array(
'label' => esc_html__( 'Version', 'wp-mail-smtp' ),
'value' => WPMS_PLUGIN_VER,
),
'license_key_type' => array(
'label' => esc_html__( 'License key type', 'wp-mail-smtp' ),
'value' => wp_mail_smtp()->get_license_type(),
),
'debug' => array(
'label' => esc_html__( 'Debug', 'wp-mail-smtp' ),
'value' => ! empty( $debug_notices ) ? implode( '. ', $debug_notices ) : esc_html__( 'No debug notices found.', 'wp-mail-smtp' ),
),
),
);
return $debug_info;
}
/**
* Perform the WP site health test for checking, if the mailer setup is complete.
*
* @since {VERSION}
*/
public function mailer_setup_complete_test() {
$mailer = Options::init()->get( 'mail', 'mailer' );
$mailer_complete = wp_mail_smtp()
->get_providers()
->get_mailer(
$mailer,
wp_mail_smtp()->get_processor()->get_phpmailer()
)->is_mailer_complete();
// The default mailer should be considered as a non-complete mailer.
if ( $mailer === 'mail' ) {
$mailer_complete = false;
}
$mailer_text = sprintf(
'%s: <strong>%s</strong>',
esc_html__( 'Current mailer', 'wp-mail-smtp' ),
esc_html( wp_mail_smtp()->get_providers()->get_options( $mailer )->get_title() )
);
$result = array(
'label' => esc_html__( 'WP Mail SMTP mailer setup is complete', 'wp-mail-smtp' ),
'status' => 'good',
'badge' => array(
'label' => $this->get_label(),
'color' => self::BADGE_COLOR,
),
'description' => sprintf(
'<p>%s</p><p>%s</p>',
$mailer_text,
esc_html__( 'The WP Mail SMTP plugin mailer setup is complete. You can send a test email, to make sure it\'s working properly.', 'wp-mail-smtp' )
),
'actions' => sprintf(
'<p><a href="%s">%s</a></p>',
esc_url( add_query_arg( 'tab', 'test', wp_mail_smtp()->get_admin()->get_admin_page_url() ) ),
esc_html__( 'Test email sending', 'wp-mail-smtp' )
),
'test' => 'wp_mail_smtp_mailer_setup_complete',
);
if ( $mailer === 'mail' ) {
$mailer_text .= sprintf( /* translators: %s - explanation why default mailer is not a valid mailer option. */
'<p>%s</p>',
esc_html__( 'You currently have the default mailer selected, which means that you havent set up SMTP yet.', 'wp-mail-smtp' )
);
}
if ( $mailer_complete === false ) {
$result['label'] = esc_html__( 'WP Mail SMTP mailer setup is incomplete', 'wp-mail-smtp' );
$result['status'] = 'recommended';
$result['badge']['color'] = 'orange';
$result['description'] = sprintf(
'<p>%s</p><p>%s</p>',
$mailer_text,
esc_html__( 'The WP Mail SMTP plugin mailer setup is incomplete. Please click on the link below to access plugin settings and configure the mailer.', 'wp-mail-smtp' )
);
$result['actions'] = sprintf(
'<p><a href="%s">%s</a></p>',
esc_url( wp_mail_smtp()->get_admin()->get_admin_page_url() ),
esc_html__( 'Configure mailer', 'wp-mail-smtp' )
);
}
return $result;
}
}

View File

@ -0,0 +1,71 @@
<?php
namespace WPMailSMTP;
/**
* Class Upgrade helps upgrade plugin options and similar tasks when the
* occasion arises.
*
* @since 1.1.0
*/
class Upgrade {
/**
* Upgrade constructor.
*
* @since 1.1.0
*/
public function __construct() {
$upgrades = $this->upgrades();
if ( empty( $upgrades ) ) {
return;
}
// Run any available upgrades.
foreach ( $upgrades as $upgrade ) {
$this->{$upgrade}();
}
// Update version post upgrade(s).
update_option( 'wp_mail_smtp_version', WPMS_PLUGIN_VER );
}
/**
* Whether we need to perform an upgrade.
*
* @since 1.1.0
*
* @return array
*/
protected function upgrades() {
$version = get_option( 'wp_mail_smtp_version' );
$upgrades = array();
// Version 1.1.0 upgrade; prior to this the option was not available.
if ( empty( $version ) ) {
$upgrades[] = 'v110_upgrade';
}
return $upgrades;
}
/**
* Upgrade routine for v1.1.0.
*
* Set SMTPAutoTLS to true.
*
* @since 1.1.0
*/
public function v110_upgrade() {
$values = Options::init()->get_all();
// Enable SMTPAutoTLS option.
$values['smtp']['autotls'] = true;
Options::init()->set( $values );
}
}

View File

@ -0,0 +1,234 @@
<?php
namespace WPMailSMTP;
/**
* Class WP provides WordPress shortcuts.
*
* @since 1.0.0
*/
class WP {
/**
* The "queue" of notices.
*
* @since 1.0.0
*
* @var array
*/
protected static $admin_notices = array();
/**
* @since 1.0.0
*
* @var string
*/
const ADMIN_NOTICE_SUCCESS = 'notice-success';
/**
* @since 1.0.0
*
* @var string
*/
const ADMIN_NOTICE_ERROR = 'notice-error';
/**
* @since 1.0.0
*
* @var string
*/
const ADMIN_NOTICE_INFO = 'notice-info';
/**
* @since 1.0.0
*
* @var string
*/
const ADMIN_NOTICE_WARNING = 'notice-warning';
/**
* True is WP is processing an AJAX call.
*
* @since 1.0.0
*
* @return bool
*/
public static function is_doing_ajax() {
if ( function_exists( 'wp_doing_ajax' ) ) {
return wp_doing_ajax();
}
return ( defined( 'DOING_AJAX' ) && DOING_AJAX );
}
/**
* True if I am in the Admin Panel, not doing AJAX.
*
* @since 1.0.0
*
* @return bool
*/
public static function in_wp_admin() {
return ( is_admin() && ! self::is_doing_ajax() );
}
/**
* Add a notice to the "queue of notices".
*
* @since 1.0.0
* @since 1.5.0 Added `$is_dismissible` param.
*
* @param string $message Message text (HTML is OK).
* @param string $class Display class (severity).
* @param bool $is_dismissible Whether the message should be dismissible.
*/
public static function add_admin_notice( $message, $class = self::ADMIN_NOTICE_INFO, $is_dismissible = true ) {
self::$admin_notices[] = array(
'message' => $message,
'class' => $class,
'is_dismissible' => (bool) $is_dismissible,
);
}
/**
* Display all notices.
*
* @since 1.0.0
* @since 1.5.0 Allow the notice to be dismissible, remove the id attribute, which is not unique.
*/
public static function display_admin_notices() {
foreach ( (array) self::$admin_notices as $notice ) :
$dismissible = $notice['is_dismissible'] ? 'is-dismissible' : '';
?>
<div class="notice wp-mail-smtp-notice <?php echo esc_attr( $notice['class'] ); ?> notice <?php echo esc_attr( $dismissible ); ?>">
<p>
<?php echo $notice['message']; ?>
</p>
</div>
<?php
endforeach;
}
/**
* Check whether WP_DEBUG is active.
*
* @since 1.0.0
*
* @return bool
*/
public static function is_debug() {
return defined( 'WP_DEBUG' ) && WP_DEBUG;
}
/**
* Shortcut to global $wpdb.
*
* @since 1.0.0
*
* @return \wpdb
*/
public static function wpdb() {
global $wpdb;
return $wpdb;
}
/**
* Get the postfix for assets files - ".min" or empty.
* ".min" if in production mode.
*
* @since 1.0.0
*
* @return string
*/
public static function asset_min() {
$min = '.min';
if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) {
$min = '';
}
return $min;
}
/**
* Check whether the string is a JSON or not.
*
* @since 1.5.0
*
* @param string $string
*
* @return bool
*/
public static function is_json( $string ) {
return is_string( $string ) && is_array( json_decode( $string, true ) ) && ( json_last_error() === JSON_ERROR_NONE ) ? true : false;
}
/**
* Get the full date format as per WP options.
*
* @since 1.5.0
*
* @return string
*/
public static function datetime_format() {
return sprintf(
/* translators: %1$s - date, \a\t - specially escaped "at", %2$s - time. */
esc_html__( '%1$s \a\t %2$s', 'wp-mail-smtp' ),
get_option( 'date_format' ),
get_option( 'time_format' )
);
}
/**
* Get the full date form as per MySQL format.
*
* @since 1.5.0
*
* @return string
*/
public static function datetime_mysql_format() {
return 'Y-m-d H:i:s';
}
/**
* Sanitize the value, similar to sanitize_text_field(), but a bit differently.
* It preserves < and > for non-HTML tags.
*
* @since 1.5.0
*
* @param string $value
*
* @return mixed|string|string[]|null
*/
public static function sanitize_value( $value ) {
// Remove HTML tags.
$filtered = wp_strip_all_tags( $value, false );
// Remove multi-lines/tabs.
$filtered = preg_replace( '/[\r\n\t ]+/', ' ', $filtered );
// Remove whitespaces.
$filtered = trim( $filtered );
// Remove octets.
$found = false;
while ( preg_match( '/%[a-f0-9]{2}/i', $filtered, $match ) ) {
$filtered = str_replace( $match[0], '', $filtered );
$found = true;
}
if ( $found ) {
// Strip out the whitespace that may now exist after removing the octets.
$filtered = trim( preg_replace( '/ +/', ' ', $filtered ) );
}
return $filtered;
}
}

View File

@ -0,0 +1,80 @@
<?php
/**
* Uninstall all WP Mail SMTP data.
*
* @since 1.3.0
*/
// Exit if accessed directly.
if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
exit;
}
// Load plugin file.
require_once 'wp_mail_smtp.php';
// Confirm user has decided to remove all data, otherwise stop.
$settings = get_option( 'wp_mail_smtp', array() );
if ( empty( $settings['general']['uninstall'] ) ) {
return;
}
/*
* Remove options.
*/
$options = array(
'wp_mail_smtp_initial_version',
'wp_mail_smtp_version',
'wp_mail_smtp_debug',
'wp_mail_smtp',
'_amn_smtp_last_checked',
// Legacy options.
'pepipost_ssl',
'pepipost_port',
'pepipost_pass',
'pepipost_user',
'smtp_pass',
'smtp_user',
'smtp_auth',
'smtp_ssl',
'smtp_port',
'smtp_host',
'mail_set_return_path',
'mailer',
'mail_from_name',
'mail_from',
'wp_mail_smtp_am_notifications_hidden',
);
foreach ( $options as $option ) {
delete_option( $option );
}
/*
* Remove product announcements.
*/
$announcements = get_posts(
array(
'post_type' => array( 'amn_smtp' ),
'post_status' => 'any',
'numberposts' => - 1,
'fields' => 'ids',
)
);
if ( ! empty( $announcements ) ) {
foreach ( $announcements as $announcement ) {
wp_delete_post( $announcement, true );
}
}
/*
* Logs for Pro plugin only.
*/
if ( function_exists( 'wp_mail_smtp' ) && wp_mail_smtp()->is_pro() ) {
// DB version.
delete_option( 'wp_mail_smtp_logs_db_version' );
// DB table.
global $wpdb;
$table = \WPMailSMTP\Pro\Emails\Logs\Logs::get_table_name();
$wpdb->query( "DROP TABLE $table;" ); // phpcs:ignore
}

View File

@ -0,0 +1,7 @@
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit4589a9f05a03f0a29add21e0e493a064::getLoader();

View File

@ -0,0 +1,445 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see http://www.php-fig.org/psr/psr-0/
* @see http://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
// PSR-4
private $prefixLengthsPsr4 = array();
private $prefixDirsPsr4 = array();
private $fallbackDirsPsr4 = array();
// PSR-0
private $prefixesPsr0 = array();
private $fallbackDirsPsr0 = array();
private $useIncludePath = false;
private $classMap = array();
private $classMapAuthoritative = false;
private $missingClasses = array();
private $apcuPrefix;
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', $this->prefixesPsr0);
}
return array();
}
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array $classMap Class to filename map
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*/
public function add($prefix, $paths, $prepend = false)
{
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 base directories
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}
/**
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*/
public function setPsr4($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}
/**
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}
/**
* Should class lookup fail if not found in the current class map?
*
* @return bool
*/
public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}
/**
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*/
public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
}
/**
* The APCu prefix in use, or null if APCu caching is not enabled.
*
* @return string|null
*/
public function getApcuPrefix()
{
return $this->apcuPrefix;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}
/**
* Unregisters this instance as an autoloader.
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return bool|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
return true;
}
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
return false;
}
if (null !== $this->apcuPrefix) {
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
if ($hit) {
return $file;
}
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if (null !== $this->apcuPrefix) {
apcu_add($this->apcuPrefix.$class, $file);
}
if (false === $file) {
// Remember that this class does not exist.
$this->missingClasses[$class] = true;
}
return $file;
}
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
if (file_exists($file = $dir . $pathEnd)) {
return $file;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
}
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
// PSR-0 include paths.
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
return false;
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*/
function includeFile($file)
{
include $file;
}

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