Commit inicial - WordPress Análisis de Precios Unitarios

- WordPress core y plugins
- Tema Twenty Twenty-Four configurado
- Plugin allow-unfiltered-html.php simplificado
- .gitignore configurado para excluir wp-config.php y uploads

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2025-11-03 21:04:30 -06:00
commit a22573bf0b
24068 changed files with 4993111 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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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,107 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Generated by IcoMoon</metadata>
<defs>
<font id="Rank-Math" horiz-adv-x="1024">
<font-face units-per-em="1024" ascent="1024" descent="0" />
<missing-glyph horiz-adv-x="1024" />
<glyph unicode="&#x20;" horiz-adv-x="0" d="" />
<glyph unicode="&#xe900;" glyph-name="bank-3" d="M501.76 652.954c16.97 0 30.72-13.754 30.72-30.72v-6.921c30.659-7.748 53.346-35.515 53.346-68.578 0-16.966-13.754-30.72-30.72-30.72s-30.72 13.754-30.72 30.72c0 5.132-4.162 9.29-9.29 9.29h-16.183c-10.92 0-19.775-8.851-19.775-19.775 0-8.241 5.116-15.618 12.833-18.514l41.157-15.438c31.699-11.887 52.699-42.189 52.699-76.042 0-35.062-22.221-64.934-53.346-76.304v-9.675c0-16.966-13.75-30.72-30.72-30.72-16.966 0-30.72 13.754-30.72 30.72v6.918c-30.654 7.746-53.342 35.512-53.342 68.575 0 16.966 13.754 30.72 30.72 30.72s30.72-13.754 30.72-30.72c0-5.128 4.162-9.29 9.29-9.29h16.183c10.92 0 19.775 8.856 19.775 19.775 0 8.245-5.116 15.622-12.833 18.518l-41.157 15.434c-31.699 11.887-52.699 42.189-52.699 76.042 0 35.062 22.221 64.938 53.342 76.308v9.677c0 16.966 13.754 30.72 30.72 30.72zM141.314 556.384c-13.573-10.179-32.828-7.43-43.008 6.144s-7.429 32.829 6.144 43.008l342.014 256.512c32.768 24.576 77.824 24.576 110.592 0l342.016-256.512c13.574-10.179 16.327-29.434 6.144-43.008-10.179-13.574-29.434-16.323-43.008-6.144l-22.528 16.896v-317.305c0-50.901-41.259-92.16-92.16-92.16h-491.518c-50.899 0-92.16 41.259-92.16 92.16v317.305l-22.528-16.896zM520.192 812.896c-10.92 8.192-25.94 8.192-36.864 0l-258.046-193.536v-363.384c0-16.966 13.754-30.72 30.72-30.72h491.518c16.97 0 30.72 13.754 30.72 30.72v363.384l-258.048 193.536z" />
<glyph unicode="&#xe901;" glyph-name="map-marker-11" d="M374.435 645.212c0 75.683 61.355 137.037 137.037 137.037s137.036-61.353 137.036-137.037c0-75.683-61.354-137.037-137.036-137.037s-137.037 61.354-137.037 137.037zM511.472 720.808c-41.751 0-75.596-33.846-75.596-75.597s33.845-75.597 75.596-75.597 75.596 33.845 75.596 75.597c0 41.751-33.845 75.597-75.596 75.597zM509.927 354.693h5.153l-2.568-2.826-2.585 2.826zM249.087 645.141c0 144.908 117.471 262.379 262.38 262.379s262.377-117.471 262.377-262.379c0-94.933-35.009-181.408-77.165-251.327-42.234-70.038-92.733-125.28-126.415-158.351-32.616-32.018-83.71-32.076-116.404-0.156-33.841 33.038-84.634 88.281-127.12 158.339-42.412 69.939-77.654 156.471-77.654 251.495zM511.468 846.080c-110.977 0-200.94-89.963-200.94-200.939 0-79.938 29.774-155.366 68.749-219.636 38.901-64.143 85.866-115.347 117.503-146.235 8.79-8.577 21.688-8.557 30.441 0.037 31.486 30.908 78.176 82.108 116.842 146.235 38.74 64.246 68.342 139.661 68.342 219.599 0 110.976-89.965 200.939-200.937 200.939zM701.137 290.447c12.976 17.056 26.001 35.492 38.556 55.157l70.545-117.576c36.86-61.428-7.389-139.575-79.024-139.575h-438.272c-71.635 0-115.882 78.148-79.027 139.575l70.757 117.928c12.572-19.624 25.615-38.023 38.616-55.058l-56.689-94.482c-12.285-20.476 2.464-46.522 26.342-46.522h438.272c23.88 0 38.625 26.051 26.341 46.522l-56.418 94.032z" />
<glyph unicode="&#xe902;" glyph-name="wallet-1-dollar" d="M532.48 571.060c0 16.966-13.754 30.718-30.72 30.718s-30.72-13.753-30.72-30.718v-9.679c-31.126-11.37-53.342-41.243-53.342-76.308 0-33.853 21-64.156 52.695-76.042l41.161-15.434c7.717-2.896 12.829-10.273 12.829-18.518 0-10.92-8.851-19.775-19.775-19.775h-16.179c-5.132 0-9.29 4.162-9.29 9.29 0 16.966-13.754 30.72-30.72 30.72s-30.72-13.754-30.72-30.72c0-33.063 22.688-60.826 53.342-68.575v-6.918c0-16.966 13.754-30.72 30.72-30.72s30.72 13.754 30.72 30.72v9.675c31.126 11.37 53.342 41.243 53.342 76.304 0 33.853-21 64.156-52.695 76.046l-41.161 15.434c-7.717 2.896-12.829 10.273-12.829 18.514 0 10.924 8.851 19.775 19.775 19.775h16.179c5.132 0 9.29-4.157 9.29-9.29 0-16.966 13.754-30.72 30.72-30.72s30.72 13.754 30.72 30.72c0 33.067-22.688 60.83-53.342 68.579v6.922zM235.52 870.4h430.080c50.897 0 92.16-41.261 92.16-92.16v-71.68h10.24c50.897 0 92.16-41.261 92.16-92.16v-368.64c0-50.897-41.263-92.16-92.16-92.16h-532.48c-50.899 0-92.16 41.263-92.16 92.16v532.48c0 50.899 41.261 92.16 92.16 92.16zM696.32 706.56v71.68c0 16.966-13.754 30.72-30.72 30.72h-430.080c-16.966 0-30.72-13.754-30.72-30.72v-71.68h491.52zM204.8 645.12v-399.36c0-16.966 13.754-30.72 30.72-30.72h532.48c16.966 0 30.72 13.754 30.72 30.72v368.64c0 16.966-13.754 30.72-30.72 30.72h-563.2z" />
<glyph unicode="&#xe903;" glyph-name="info-circle" d="M473.57 654.088c0-21.208 17.195-38.4 38.4-38.4 21.21 0 38.434 17.192 38.434 38.4s-17.195 38.4-38.4 38.4c-21.21 0-38.434-17.193-38.434-38.4zM512.004 333.261c-17.673 0-32 14.327-32 32v180.241c0 17.673 14.323 32 32 32 17.673 0 32-14.327 32-32v-180.241c0-17.673-14.327-32-32-32zM512 938.667c-235.642 0-426.667-191.025-426.667-426.667 0-235.639 191.025-426.667 426.667-426.667 235.639 0 426.667 191.027 426.667 426.667 0 235.642-191.027 426.667-426.667 426.667zM149.333 512c0 200.295 162.371 362.667 362.667 362.667s362.667-162.371 362.667-362.667c0-200.294-162.372-362.667-362.667-362.667s-362.667 162.372-362.667 362.667z" />
<glyph unicode="&#xe904;" glyph-name="rank-math" d="M1024 503.533l-168.827-7.602 29.767-46.545-281.489-179.932-279.273 117.317-324.178-135.137 22.474-53.948 301.658 125.695 284.969-119.689 307.4 196.4 29.767-46.545zM119.91 330.783l204.312 85.133 9.952-4.189v120.974h-214.264zM587.359 826.314v-520.977l16.091-6.649 198.217 126.448v401.177zM353.657 403.438l214.264-90.032v366.136h-214.264z" />
<glyph unicode="&#xe905;" glyph-name="google" d="M984 556.8h-459.2v-136h329.6c-17.6-188.8-171.2-270.4-320-270.4-188.8 0-356.8 147.2-356.8 360 0 204.8 160 360 356.8 360 150.4 0 241.6-97.6 241.6-97.6l92.8 97.6s-124.8 136-340.8 136c-284.8 1.6-502.4-236.8-502.4-494.4 0-249.6 204.8-496 507.2-496 267.2 0 459.2 180.8 459.2 451.2 1.6 56-8 89.6-8 89.6z" />
<glyph unicode="&#xe906;" glyph-name="copy" d="M803.2 75.2h-129.6c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h129.6c16 0 28.8 12.8 28.8 28.8s-14.4 28.8-28.8 28.8zM572.8 75.2h-124.8c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h124.8c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8zM812.8 755.2h-11.2v155.2c0 51.2-41.6 94.4-94.4 94.4h-593.6c-51.2 0-94.4-41.6-94.4-94.4v-593.6c0-51.2 41.6-94.4 94.4-94.4h152v-6.4c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v444.8c0 20.8 17.6 38.4 38.4 38.4h452.8c16 0 28.8 12.8 28.8 28.8s-14.4 27.2-30.4 27.2zM265.6 660.8v-382.4h-152c-20.8 0-38.4 17.6-38.4 38.4v593.6c0 20.8 17.6 38.4 38.4 38.4h593.6c20.8 0 38.4-17.6 38.4-38.4v-155.2h-385.6c-51.2 0-94.4-41.6-94.4-94.4zM913.6 702.4c19.2 0 35.2-16 35.2-35.2 0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8c0 49.6-40 91.2-91.2 91.2-16 0-28.8-12.8-28.8-28.8s11.2-27.2 27.2-27.2zM976 595.2c-16 0-28.8-12.8-28.8-28.8v-124.8c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v124.8c0 16-12.8 28.8-28.8 28.8zM976 368c-16 0-28.8-12.8-28.8-28.8v-124.8c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v124.8c0 16-12.8 28.8-28.8 28.8zM976 139.2c-16 0-28.8-12.8-28.8-28.8 0-19.2-16-35.2-35.2-35.2-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8c49.6 0 91.2 40 91.2 91.2 1.6 17.6-11.2 30.4-27.2 30.4zM356.8 75.2c-19.2 0-35.2 16-35.2 35.2 0 16-12.8 28.8-28.8 28.8s-28.8-12.8-28.8-28.8c0-49.6 40-91.2 91.2-91.2 16 0 28.8 12.8 28.8 28.8s-11.2 27.2-27.2 27.2z" />
<glyph unicode="&#xe907;" glyph-name="send" d="M953.598 548.786c-6.4 11.2-16 19.2-27.2 25.6l-737.6 412.8c-12.8 6.4-27.2 9.6-41.6 8s-27.2-6.4-38.4-16c-11.2-9.6-19.2-22.4-22.4-35.2-4.8-14.4-3.2-28.8 1.6-43.2l137.6-388.8-137.6-388.8c-4.8-14.4-4.8-28.8-1.6-41.6 3.2-14.4 11.2-25.6 22.4-35.2s24-14.4 38.4-16c1.6 0 4.8 0 6.4 0 11.2 0 24 3.2 35.2 9.6l737.6 412.8c11.2 6.4 20.8 14.4 27.2 25.6s9.6 24 9.6 35.2c0 11.2-3.2 24-9.6 35.2zM156.798 923.186l668.8-374.4h-536l-132.8 374.4zM156.798 100.786l134.4 374.4h536l-670.4-374.4z" />
<glyph unicode="&#xe908;" glyph-name="enter-key" d="M984.615 945.231h-630.154c-21.701 0-39.385-17.684-39.385-39.385 0 0 0-275.692 0-354.462s-78.769-78.769-78.769-78.769h-196.923c-21.701 0-39.385-17.684-39.385-39.385v-315.077c0-21.701 17.684-39.385 39.385-39.385h945.231c21.701 0 39.385 17.684 39.385 39.385v787.692c0 21.701-17.684 39.385-39.385 39.385zM866.462 472.615c0-56.556-52.618-157.538-157.538-157.538h-141.233l70.617-70.617c15.399-15.399 15.399-40.29 0-55.69-7.68-7.68-17.762-11.54-27.845-11.54s-20.165 3.86-27.845 11.54l-137.846 137.846c-15.399 15.399-15.399 40.29 0 55.69l137.846 137.846c15.399 15.399 40.29 15.399 55.69 0s15.399-40.29 0-55.69l-70.617-70.617h141.233c55.060 0 78.769 59.786 78.769 78.769v78.769c0 21.78 17.605 39.385 39.385 39.385s39.385-17.605 39.385-39.385v-78.769z" />
<glyph unicode="&#xe909;" glyph-name="content-ai" horiz-adv-x="971" d="M946.149 337.134c-6.216 3.299-13.59 5.236-21.416 5.236-17.86 0-33.365-10.087-41.127-24.875l-0.122-0.255c-71.62-134.316-210.801-224.182-370.972-224.182-231.424 0-419.030 187.606-419.030 419.030s187.606 419.030 419.030 419.030c34.885 0 68.774-4.263 101.175-12.296l-2.88 0.604c9.56 34.736 33.501 62.584 64.849 77.212l0.734 0.307c-48.958 17.132-105.399 27.028-164.152 27.028-282.77 0-512-229.23-512-512s229.23-512 512-512c195.805 0 365.937 109.914 452.065 271.407l1.342 2.757c3.437 6.322 5.458 13.845 5.458 21.839 0 17.791-10.009 33.244-24.703 41.036l-0.252 0.122zM805.699 888.59c0-43.948-35.627-79.575-79.575-79.575s-79.575 35.627-79.575 79.575c0 43.948 35.627 79.575 79.575 79.575s79.575-35.627 79.575-79.575zM775.46 780.036c-14.472-6.825-31.436-10.809-49.33-10.809-0.002 0-0.005 0-0.007 0v0c-60.177 0.048-109.93 44.62-118.096 102.551l-0.073 0.632c-26.937 6.982-57.862 10.99-89.723 10.99-205.311 0-371.749-166.438-371.749-371.749s166.438-371.749 371.749-371.749c205.311 0 371.749 166.438 371.749 371.749 0 105.43-43.889 200.608-114.392 268.263l-0.128 0.122zM603.445 363.261c0-27.468-22.267-49.734-49.734-49.734s-49.734 22.267-49.734 49.734v4.244c-28.052-27.488-66.357-44.604-108.658-45.092l-0.094-0.001c-94.23 0-170.556 86.803-170.556 193.965s76.326 193.898 170.556 193.898c42.706-0.355 81.322-17.575 109.572-45.315l-0.024 0.023c3.108 24.641 23.934 43.508 49.167 43.508 26.754 0 48.554-21.209 49.503-47.731l0.002-0.087zM772.609 363.261c0-27.468-22.267-49.734-49.734-49.734s-49.734 22.267-49.734 49.734v297.412c0 27.468 22.267 49.734 49.734 49.734s49.734-22.267 49.734-49.734v0zM415.648 622.808c-53.979 0-97.679-47.679-97.679-106.1s43.7-106.498 97.679-106.498 97.679 47.679 97.679 106.498-43.7 106.1-97.679 106.1z" />
<glyph unicode="&#xe90a;" glyph-name="refresh-bulb-1" d="M116.628 612.69c-4.391-16.388 5.334-33.233 21.722-37.624s33.233 5.333 37.624 21.722c18.668 69.671 59.804 131.234 117.027 175.143s127.334 67.709 199.465 67.709c72.126 0 142.242-23.8 199.463-67.709 49.893-38.282 87.552-89.986 108.757-148.781l-68.612 38.636c-14.782 8.325-33.518 3.088-41.841-11.695s-3.088-33.516 11.694-41.841l126.185-71.055c7.102-3.998 15.499-5.009 23.343-2.818 7.848 2.195 14.504 7.414 18.502 14.516l71.049 126.199c8.323 14.784 3.084 33.517-11.698 41.84s-33.518 3.086-41.841-11.698l-31.162-55.35c-25.539 67.384-69.399 126.613-126.972 170.792-67.957 52.142-151.216 80.405-236.868 80.405-85.654 0-168.913-28.263-236.867-80.405s-116.802-125.25-138.971-207.985zM868.413 411.312c4.391 16.388-5.333 33.231-21.721 37.622s-33.235-5.333-37.626-21.721c-18.665-69.669-59.802-131.236-117.027-175.145-57.221-43.909-127.332-67.707-199.463-67.707-72.126 0-142.241 23.798-199.464 67.707-49.805 38.22-87.423 89.809-108.648 148.48l68.103-38.351c14.783-8.323 33.516-3.088 41.841 11.694 8.325 14.787 3.088 33.518-11.695 41.845l-126.185 71.053c-7.1 3.998-15.497 5.009-23.344 2.818-7.847-2.195-14.501-7.418-18.498-14.516l-71.050-126.198c-8.323-14.787-3.086-33.518 11.698-41.841s33.516-3.088 41.84 11.698l31.406 55.779c25.515-67.551 69.437-126.935 127.131-171.205 67.953-52.142 151.213-80.404 236.866-80.404 85.656 0 168.915 28.262 236.868 80.404s116.802 125.252 138.969 207.987zM568.975 443.998v-27.255c0-42.217-34.222-76.444-76.44-76.444-42.222 0-76.444 34.226-76.444 76.444v27.255c-33.645 23.929-55.592 63.234-55.592 107.667 0 72.919 59.114 132.033 132.035 132.033 72.917 0 132.030-59.113 132.030-132.033 0-44.433-21.946-83.739-55.591-107.667zM492.536 622.259c-38.99 0-70.595-31.607-70.595-70.593 0-38.965 31.564-70.554 70.517-70.595h0.152c38.953 0.041 70.517 31.629 70.517 70.595 0 38.986-31.605 70.593-70.59 70.593zM477.532 419.631v-2.888c0-8.286 6.717-15.004 15.004-15.004 8.282 0 15 6.717 15 15.004v2.888h-30.003z" />
<glyph unicode="&#xea20;" glyph-name="bot" d="M675.2 964.8c-46.4 25.6-100.8 40-158.4 40h-1.6c-83.2-1.6-161.6-27.2-220.8-76.8-78.4-64-123.2-160-123.2-260.8v-264c0-27.2 22.4-49.6 49.6-49.6h38.4c19.2-75.2 80-136 156.8-156.8l24-6.4v-121.6c0-27.2 22.4-49.6 49.6-49.6h316.8c27.2 0 49.6 22.4 49.6 49.6v598.4c-3.2 124.8-68.8 235.2-180.8 297.6zM796.8 75.2h-304v158.4l-64 17.6c-62.4 17.6-108.8 68.8-120 132.8l-3.2 25.6h-78.4v257.6c0 84.8 36.8 163.2 102.4 217.6 49.6 41.6 115.2 64 187.2 64 48 0 94.4-11.2 131.2-32 92.8-52.8 148.8-145.6 148.8-248v-593.6zM675.2 667.2c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-28.8c0 24-19.2 43.2-43.2 43.2v36.8c0 16-12.8 28.8-28.8 28.8s-28.8-12.8-28.8-28.8v-36.8h-65.6v36.8c0 16-12.8 28.8-28.8 28.8s-28.8-12.8-28.8-28.8v-36.8c-24 0-43.2-19.2-43.2-43.2h-28.8c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h28.8v-67.2h-28.8c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h28.8c0-24 19.2-43.2 43.2-43.2v-28.8c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v28.8h67.2v-28.8c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v28.8c24 0 43.2 19.2 43.2 43.2h28.8c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-28.8v67.2h27.2zM435.2 555.2v155.2h155.2v-155.2h-155.2z" />
<glyph unicode="&#xea2e;" glyph-name="mobile" d="M512 251.2c-32 0-56-25.6-56-56 0-32 25.6-56 56-56s56 25.6 56 56-24 56-56 56zM560 875.2h-96c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h96c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8zM720 1003.2h-416c-51.2 0-92.8-41.6-92.8-92.8v-800c0-51.2 41.6-92.8 92.8-92.8h416c51.2 0 92.8 41.6 92.8 92.8v801.6c0 51.2-41.6 91.2-92.8 91.2zM756.8 112c0-19.2-16-36.8-36.8-36.8h-416c-19.2 0-36.8 16-36.8 36.8v800c0 19.2 16 36.8 36.8 36.8h416c19.2 0 36.8-16 36.8-36.8v-800z" />
<glyph unicode="&#xea35;" glyph-name="seo-description" d="M91.2 225.6v572.8c0 16-12.8 28.8-28.8 28.8s-28.8-12.8-28.8-28.8v-572.8c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8zM288 564.8h409.6c54.4 0 97.6 43.2 97.6 97.6v30.4c0 54.4-43.2 97.6-97.6 97.6h-409.6c-54.4 0-97.6-43.2-97.6-97.6v-30.4c0-52.8 43.2-97.6 97.6-97.6zM246.4 694.4c0 22.4 19.2 41.6 41.6 41.6h409.6c22.4 0 41.6-19.2 41.6-41.6v-30.4c0-22.4-19.2-41.6-41.6-41.6h-409.6c-22.4 0-41.6 19.2-41.6 41.6v30.4zM190.4 329.6c0-54.4 43.2-97.6 97.6-97.6h286.4c54.4 0 97.6 43.2 97.6 97.6v30.4c0 54.4-43.2 97.6-97.6 97.6h-286.4c-54.4 0-97.6-43.2-97.6-97.6v-30.4zM246.4 361.6c0 22.4 19.2 41.6 41.6 41.6h286.4c22.4 0 41.6-19.2 41.6-41.6v-30.4c0-22.4-19.2-41.6-41.6-41.6h-286.4c-22.4 0-41.6 19.2-41.6 41.6v30.4zM891.2 1003.2h-812.8c-14.4 0-27.2-11.2-27.2-27.2s12.8-28.8 27.2-28.8h812.8c22.4 0 41.6-19.2 41.6-41.6v-788.8c0-22.4-19.2-41.6-41.6-41.6h-812.8c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h812.8c54.4 0 97.6 43.2 97.6 97.6v790.4c0 54.4-44.8 97.6-97.6 97.6z" />
<glyph unicode="&#xea3a;" glyph-name="role-manager" d="M454.4 587.2c118.4 0 214.4 92.8 214.4 208s-96 208-214.4 208-214.4-92.8-214.4-208 96-208 214.4-208zM454.4 947.2c88 0 158.4-68.8 158.4-152s-72-152-158.4-152c-88 0-158.4 68.8-158.4 152s70.4 152 158.4 152zM454.4 504c-208 0-377.6-168-377.6-376v-48c0-32 27.2-59.2 59.2-59.2h304c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-304c-1.6 0-3.2 1.6-3.2 3.2v48c0 174.4 144 318.4 321.6 318.4 16 0 28.8 12.8 28.8 28.8s-12.8 27.2-28.8 27.2zM737.6 438.4c-115.2 0-209.6-94.4-209.6-209.6s94.4-209.6 209.6-209.6c115.2 0 209.6 94.4 209.6 209.6s-94.4 209.6-209.6 209.6zM737.6 382.4c35.2 0 68.8-12.8 94.4-33.6l-220.8-204.8c-16 24-25.6 52.8-25.6 84.8 0 84.8 67.2 153.6 152 153.6zM737.6 75.2c-32 0-62.4 9.6-88 27.2l219.2 203.2c12.8-22.4 20.8-49.6 20.8-76.8 1.6-84.8-67.2-153.6-152-153.6z" />
<glyph unicode="&#xea43;" glyph-name="calendar" d="M912 857.6h-97.6v46.4c0 16-12.8 28.8-28.8 28.8s-28.8-12.8-28.8-28.8v-46.4h-491.2v46.4c0 16-12.8 28.8-28.8 28.8s-28.8-12.8-28.8-28.8v-46.4h-96c-51.2 0-92.8-41.6-92.8-92.8v-580.8c0-51.2 41.6-92.8 92.8-92.8h800c51.2 0 92.8 41.6 92.8 92.8v580.8c0 51.2-41.6 92.8-92.8 92.8zM76.8 568h160v-182.4h-160v182.4zM291.2 568h192v-182.4h-192v182.4zM484.8 329.6v-180.8h-192v180.8h192zM540.8 329.6h192v-180.8h-192v180.8zM540.8 385.6v182.4h192v-182.4h-192zM788.8 568h160v-182.4h-160v182.4zM112 801.6h97.6v-44.8c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v44.8h492.8v-44.8c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v44.8h94.4c19.2 0 36.8-16 36.8-36.8v-140.8h-872v140.8c0 20.8 16 36.8 35.2 36.8zM76.8 184v145.6h160v-180.8h-124.8c-19.2 0-35.2 16-35.2 35.2zM912 148.8h-123.2v180.8h160v-145.6c0-19.2-17.6-35.2-36.8-35.2z" />
<glyph unicode="&#xea4f;" glyph-name="sitemap" d="M313.6 868.8c-16 0-28.8-12.8-28.8-28.8v-1.6c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v1.6c-1.6 16-14.4 28.8-28.8 28.8zM739.2 867.2h-81.6c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h81.6c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8zM928 275.2h-17.6v139.2c0 54.4-44.8 99.2-99.2 99.2h-272c0 3.2 1.6 4.8 1.6 8v158.4h275.2c41.6 0 76.8 33.6 76.8 76.8v160c0 41.6-33.6 76.8-76.8 76.8h-606.4c-41.6 0-76.8-33.6-76.8-76.8v-160c0-41.6 33.6-76.8 76.8-76.8h275.2v-158.4c0-3.2 0-4.8 1.6-8h-272c-54.4 0-99.2-44.8-99.2-99.2v-139.2h-19.2c-41.6 0-76.8-33.6-76.8-76.8v-91.2c0-41.6 33.6-76.8 76.8-76.8h91.2c41.6 0 76.8 33.6 76.8 76.8v91.2c0 41.6-33.6 76.8-76.8 76.8h-17.6v139.2c0 24 19.2 43.2 43.2 43.2h270.4v-184h-17.6c-41.6 0-76.8-33.6-76.8-76.8v-91.2c0-41.6 33.6-76.8 76.8-76.8h91.2c41.6 0 76.8 33.6 76.8 76.8v91.2c0 41.6-33.6 76.8-76.8 76.8h-17.6v185.6h270.4c24 0 43.2-19.2 43.2-43.2v-139.2h-17.6c-41.6 0-76.8-33.6-76.8-76.8v-91.2c0-41.6 33.6-76.8 76.8-76.8h92.8c41.6 0 76.8 33.6 76.8 76.8v91.2c0 40-35.2 75.2-76.8 75.2zM188.8 756.8v160c0 11.2 9.6 20.8 20.8 20.8h606.4c11.2 0 20.8-9.6 20.8-20.8v-160c0-11.2-9.6-20.8-20.8-20.8h-606.4c-11.2 1.6-20.8 9.6-20.8 20.8zM208 198.4v-91.2c0-11.2-9.6-20.8-20.8-20.8h-91.2c-11.2 0-20.8 9.6-20.8 20.8v91.2c0 11.2 9.6 20.8 20.8 20.8h91.2c11.2 0 20.8-9.6 20.8-20.8zM577.6 198.4v-91.2c0-11.2-9.6-20.8-20.8-20.8h-91.2c-11.2 0-20.8 9.6-20.8 20.8v91.2c0 11.2 9.6 20.8 20.8 20.8h91.2c12.8 0 20.8-9.6 20.8-20.8zM948.8 107.2c0-11.2-9.6-20.8-20.8-20.8h-91.2c-11.2 0-20.8 9.6-20.8 20.8v91.2c0 11.2 9.6 20.8 20.8 20.8h91.2c11.2 0 20.8-9.6 20.8-20.8v-91.2z" />
<glyph unicode="&#xea5a;" glyph-name="import" d="M468.8 372.8c9.6-9.6 24-16 36.8-16 14.4 0 27.2 4.8 36.8 16l118.4 118.4c11.2 11.2 11.2 28.8 0 40s-28.8 11.2-40 0l-88-88v406.4c0 16-12.8 28.8-28.8 28.8s-28.8-12.8-28.8-28.8v-406.4l-88 88c-11.2 11.2-28.8 11.2-40 0s-11.2-28.8 0-40l121.6-118.4zM934.4 540.8h-147.2c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h147.2c8 0 14.4-6.4 14.4-14.4v-187.2c0-44.8-36.8-80-80-80h-712c-44.8 0-80 36.8-80 80v188.8c0 8 6.4 14.4 14.4 14.4h147.2c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-148.8c-38.4 0-70.4-32-70.4-70.4v-187.2c0-75.2 60.8-136 136-136h710.4c75.2 0 136 60.8 136 136v185.6c3.2 38.4-28.8 70.4-67.2 70.4z" />
<glyph unicode="&#xea5d;" glyph-name="export" d="M371.2 694.4c6.4 0 14.4 3.2 19.2 8l92.8 92.8v-411.2c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v403.2l83.2-84.8c11.2-11.2 28.8-11.2 40 0s11.2 28.8 0 40l-118.4 118.4c-9.6 9.6-24 16-36.8 16-14.4 0-27.2-4.8-36.8-16l-120-118.4c-11.2-11.2-11.2-28.8 0-40 6.4-4.8 12.8-8 19.2-8zM934.4 540.8h-147.2c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h147.2c8 0 14.4-6.4 14.4-14.4v-187.2c0-44.8-36.8-80-80-80h-712c-44.8 0-80 36.8-80 80v188.8c0 8 6.4 14.4 14.4 14.4h147.2c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-148.8c-38.4 0-70.4-32-70.4-70.4v-187.2c0-75.2 60.8-136 136-136h710.4c75.2 0 136 60.8 136 136v185.6c3.2 38.4-28.8 70.4-67.2 70.4z" />
<glyph unicode="&#xea60;" glyph-name="settings" d="M513.6 708.8c-108.8 0-196.8-88-196.8-196.8s88-196.8 196.8-196.8c108.8 0 196.8 88 196.8 196.8-1.6 107.2-89.6 196.8-196.8 196.8zM513.6 371.2c-76.8 0-140.8 62.4-140.8 140.8s62.4 140.8 140.8 140.8 140.8-62.4 140.8-140.8c-1.6-78.4-64-140.8-140.8-140.8zM984 401.6l-99.2 54.4c3.2 20.8 4.8 40 4.8 59.2 0 22.4-1.6 41.6-4.8 60.8l100.8 56c17.6 9.6 24 30.4 16 49.6l-96 161.6c-9.6 16-30.4 22.4-49.6 16l-104-57.6c-6.4 4.8-12.8 11.2-19.2 16-17.6 16-35.2 30.4-59.2 41.6-4.8 1.6-8 8-8 12.8v62.4c0 38.4-32 70.4-70.4 70.4h-166.4c-38.4 0-70.4-32-70.4-70.4v-64c0-4.8-3.2-9.6-8-12.8-24-11.2-41.6-25.6-60.8-43.2-4.8-4.8-11.2-9.6-17.6-14.4l-92.8 52.8c-30.4 16-51.2 4.8-60.8-11.2l-91.2-156.8c-4.8-9.6-6.4-20.8-3.2-30.4s9.6-19.2 19.2-24l99.2-56c-3.2-17.6-4.8-36.8-4.8-59.2 0-20.8 1.6-40 3.2-59.2l-102.4-56c-17.6-9.6-24-30.4-16-49.6l94.4-161.6c9.6-16 30.4-22.4 49.6-16l104 57.6c6.4-4.8 12.8-9.6 17.6-14.4 19.2-16 35.2-30.4 60.8-41.6 4.8-1.6 8-8 8-12.8v-70.4c0-38.4 32-70.4 70.4-70.4h168c38.4 0 70.4 32 70.4 70.4v73.6c0 4.8 3.2 9.6 8 12.8 24 11.2 40 25.6 59.2 41.6 6.4 4.8 11.2 9.6 17.6 16l92.8-52.8c30.4-16 51.2-4.8 59.2 9.6l92.8 156.8c4.8 9.6 6.4 19.2 4.8 30.4 0 9.6-8 17.6-16 22.4zM865.6 233.6l-88 49.6c-19.2 11.2-43.2 8-59.2-4.8-8-6.4-14.4-12.8-20.8-17.6-17.6-14.4-28.8-25.6-46.4-33.6-24-11.2-40-36.8-40-62.4v-73.6c0-8-6.4-14.4-14.4-14.4h-168c-8 0-14.4 6.4-14.4 14.4v70.4c0 27.2-16 51.2-40 62.4-17.6 8-32 19.2-48 33.6-6.4 4.8-12.8 11.2-20.8 17.6-9.6 8-22.4 12.8-33.6 12.8-9.6 0-17.6-1.6-25.6-6.4l-88-49.6-75.2 128 84.8 48c20.8 11.2 30.4 33.6 28.8 56-1.6 16-3.2 33.6-3.2 51.2 0 19.2 1.6 35.2 3.2 49.6 4.8 24-6.4 48-27.2 59.2l-84.8 46.4 75.2 128 88-49.6c19.2-11.2 43.2-8 59.2 4.8 6.4 6.4 12.8 11.2 19.2 16 17.6 14.4 30.4 25.6 48 35.2 24 11.2 40 36.8 40 62.4v64c0 8 6.4 14.4 14.4 14.4h168c8 0 14.4-6.4 14.4-14.4v-62.4c0-27.2 16-51.2 40-62.4 17.6-8 30.4-19.2 46.4-33.6 6.4-6.4 14.4-11.2 22.4-17.6 16-12.8 40-16 59.2-4.8l88 49.6 75.2-128-84.8-46.4c-20.8-11.2-32-35.2-27.2-59.2 3.2-14.4 3.2-32 3.2-49.6 0-16-1.6-33.6-4.8-51.2-4.8-24 8-48 28.8-59.2l83.2-44.8-75.2-128z" />
<glyph unicode="&#xea67;" glyph-name="desktop" d="M912 969.6h-800c-51.2 0-91.2-41.6-91.2-91.2v-505.6c0-51.2 41.6-92.8 92.8-92.8h273.6l-46.4-171.2h-81.6c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h505.6c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-81.6l-46.4 171.2h275.2c51.2 0 92.8 41.6 92.8 92.8v505.6c0 49.6-41.6 91.2-92.8 91.2zM625.6 110.4h-227.2l46.4 171.2h136l44.8-171.2zM948.8 372.8c0-19.2-16-36.8-36.8-36.8h-800c-19.2 0-36.8 16-36.8 36.8v505.6c0 19.2 16 36.8 36.8 36.8h800c19.2 0 36.8-16 36.8-36.8v-505.6z" />
<glyph unicode="&#xea6f;" glyph-name="htaccess" d="M300.8 566.4h307.2c16 0 28.8 12.8 28.8 28.8s-12.8 27.2-28.8 27.2h-307.2c-16 0-28.8-12.8-28.8-28.8s12.8-27.2 28.8-27.2zM300.8 396.8h307.2c16 0 28.8 12.8 28.8 28.8s-12.8 27.2-28.8 27.2h-307.2c-16 0-28.8-12.8-28.8-28.8s12.8-27.2 28.8-27.2zM723.2 283.2h-422.4c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h424c16 0 28.8 12.8 28.8 28.8s-14.4 28.8-30.4 28.8zM929.6 817.6h-403.2l-46.4 134.4c-9.6 30.4-38.4 49.6-70.4 49.6h-315.2c-41.6 0-73.6-32-73.6-73.6v-832c0-40 33.6-73.6 73.6-73.6h836.8c40 0 73.6 33.6 73.6 73.6v648c0 40-33.6 73.6-75.2 73.6zM948.8 96c0-9.6-8-17.6-17.6-17.6h-836.8c-9.6 0-17.6 8-17.6 17.6v832c0 9.6 8 17.6 17.6 17.6h316.8c8 0 14.4-4.8 16-11.2l52.8-153.6c3.2-11.2 14.4-19.2 27.2-19.2h424c9.6 0 17.6-8 17.6-17.6v-648z" />
<glyph unicode="&#xea70;" glyph-name="robots" d="M659.2 561.6l-134.4 68.8c-8 4.8-17.6 4.8-25.6 0l-134.4-68.8c-9.6-4.8-14.4-14.4-14.4-25.6v-76.8c0-91.2 44.8-177.6 118.4-228.8l28.8-19.2c4.8-3.2 9.6-4.8 16-4.8s11.2 1.6 16 4.8l28.8 19.2c73.6 51.2 118.4 136 118.4 228.8v76.8c-1.6 11.2-8 20.8-17.6 25.6zM619.2 460.8c0-73.6-35.2-142.4-94.4-182.4l-12.8-9.6-12.8 8c-59.2 40-94.4 108.8-94.4 182.4v59.2l107.2 54.4 107.2-54.4v-57.6zM929.6 817.6h-403.2l-46.4 134.4c-9.6 30.4-38.4 49.6-70.4 49.6h-315.2c-41.6 0-73.6-32-73.6-73.6v-832c0-40 33.6-73.6 73.6-73.6h836.8c40 0 73.6 33.6 73.6 73.6v648c0 40-33.6 73.6-75.2 73.6zM948.8 96c0-9.6-8-17.6-17.6-17.6h-836.8c-9.6 0-17.6 8-17.6 17.6v832c0 9.6 8 17.6 17.6 17.6h316.8c8 0 14.4-4.8 16-11.2l52.8-153.6c3.2-11.2 14.4-19.2 27.2-19.2h424c9.6 0 17.6-8 17.6-17.6v-648z" />
<glyph unicode="&#xea76;" glyph-name="category" d="M968 691.2v92.8c0 36.8-30.4 67.2-67.2 67.2h-408l-9.6 25.6c-6.4 14.4-20.8 24-35.2 24h-316.8c-46.4-1.6-83.2-40-83.2-84.8v-608c0-46.4 36.8-83.2 83.2-83.2h761.6c46.4 0 83.2 36.8 83.2 83.2v459.2c0 8-3.2 16-8 24zM900.8 793.6c6.4 0 11.2-4.8 11.2-11.2v-76.8h-361.6l-35.2 88h385.6zM920 208c0-14.4-12.8-27.2-27.2-27.2h-761.6c-14.4 0-27.2 12.8-27.2 27.2v608c0 14.4 12.8 27.2 27.2 27.2h304l64-158.4c8-20.8 28.8-35.2 51.2-35.2h369.6v-441.6z" />
<glyph unicode="&#xea83;" glyph-name="link" d="M469.503 779.315l-132.214 130.64c-70.829 70.829-185.729 70.829-256.558 0-34.627-34.627-53.515-80.273-53.515-127.492s18.888-94.438 53.515-127.492l130.64-132.214c34.627-34.627 81.847-53.515 127.492-53.515s92.864 17.314 127.492 53.515c34.627 33.053 53.515 78.699 53.515 127.492 1.574 48.793-17.314 94.438-50.367 129.066zM250.72 562.107l-130.64 132.214c-23.61 23.61-37.775 55.089-37.775 89.716s12.592 64.533 37.775 89.716c25.184 25.184 56.663 36.201 89.716 36.201 31.479 0 64.533-12.592 89.716-36.201l130.64-130.64c23.61-23.61 36.201-55.089 36.201-89.716 0-26.758-7.87-50.367-22.036-70.829l-48.793 48.793c-11.018 11.018-28.332 11.018-39.349 0s-11.018-28.332 0-39.349l47.219-45.645c-48.793-31.479-111.752-25.184-152.675 15.74zM943.269 305.549l-132.214 130.64c-70.829 70.829-185.729 70.829-256.558 0-34.627-34.627-53.515-80.273-53.515-127.492 0-48.793 18.888-94.438 53.515-127.492l130.64-132.214c34.627-34.627 81.847-53.515 127.492-53.515s92.864 17.314 127.492 53.515c34.627 33.053 53.515 78.699 53.515 125.918 3.148 50.367-15.74 96.012-50.367 130.64zM903.919 88.341c-48.793-48.793-129.066-48.793-177.859 0l-130.64 132.214c-23.61 23.61-37.775 55.089-37.775 89.716 0 22.036 6.296 44.071 17.314 62.959l45.645-45.645c4.722-4.722 12.592-7.87 18.888-7.87s14.166 3.148 18.888 7.87c11.018 11.018 11.018 28.332 0 39.349l-47.219 47.219c22.036 14.166 47.219 22.036 72.403 22.036 31.479 0 64.533-12.592 89.716-36.201l130.64-130.64c23.61-23.61 36.201-56.663 36.201-89.716 0-36.201-12.592-67.681-36.201-91.29zM636.344 743.114c15.74 0 28.332 12.592 28.332 28.332v124.344c0 15.74-12.592 28.332-28.332 28.332s-28.332-12.592-28.332-28.332v-124.344c1.574-15.74 14.166-28.332 28.332-28.332zM774.854 604.604c0-15.74 12.592-28.332 28.332-28.332h124.344c15.74 0 28.332 12.592 28.332 28.332s-12.592 28.332-28.332 28.332h-124.344c-15.74 0-28.332-12.592-28.332-28.332zM697.729 664.415c7.87 0 14.166 3.148 18.888 7.87l105.456 107.030c11.018 11.018 11.018 28.332 0 39.349s-28.332 11.018-39.349 0l-105.456-107.030c-11.018-11.018-11.018-28.332 0-39.349 6.296-4.722 12.592-7.87 20.462-7.87zM387.656 215.833c-15.74 0-28.332-12.592-28.332-28.332v-124.344c0-15.74 12.592-28.332 28.332-28.332s28.332 12.592 28.332 28.332v124.344c-1.574 17.314-12.592 28.332-28.332 28.332zM208.223 355.916c0 15.74-12.592 28.332-28.332 28.332h-83.421c-15.74 0-28.332-12.592-28.332-28.332s12.592-28.332 28.332-28.332h83.421c15.74 0 28.332 12.592 28.332 28.332zM271.182 305.549l-105.456-105.456c-11.018-11.018-11.018-28.332 0-39.349 4.722-4.722 12.592-7.87 18.888-7.87s14.166 3.148 18.888 7.87l105.456 105.456c11.018 11.018 11.018 28.332 0 39.349-9.444 11.018-26.758 11.018-37.775 0z" />
<glyph unicode="&#xea87;" glyph-name="local-seo" d="M512 1003.2c-222.4 0-404.8-176-404.8-390.4 0-171.2 244.8-454.4 350.4-569.6 14.4-16 33.6-24 54.4-24s40 8 54.4 24c105.6 113.6 350.4 398.4 350.4 569.6 0 216-182.4 390.4-404.8 390.4zM524.8 81.6c-8-8-19.2-8-25.6 0-78.4 84.8-336 376-336 531.2 0 185.6 156.8 334.4 348.8 334.4s348.8-150.4 348.8-334.4c0-155.2-257.6-444.8-336-531.2zM512 772.8c-94.4 0-172.8-76.8-172.8-172.8 0-94.4 76.8-172.8 172.8-172.8s172.8 76.8 172.8 172.8c0 96-78.4 172.8-172.8 172.8zM512 484.8c-64 0-116.8 52.8-116.8 116.8s52.8 116.8 116.8 116.8 116.8-52.8 116.8-116.8-52.8-116.8-116.8-116.8z" />
<glyph unicode="&#xea8f;" glyph-name="misc" d="M512 1003.2c-272 0-491.2-219.2-491.2-491.2s219.2-492.8 491.2-492.8 492.8 220.8 492.8 492.8-220.8 491.2-492.8 491.2zM512 75.2c-240 0-435.2 196.8-435.2 436.8s195.2 435.2 435.2 435.2 436.8-195.2 436.8-435.2-196.8-436.8-436.8-436.8zM678.4 732.8h-332.8c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h332.8c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8zM678.4 539.2h-332.8c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h332.8c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8zM678.4 347.2h-332.8c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h332.8c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8z" />
<glyph unicode="&#xea9a;" glyph-name="software" d="M963.2 790.4c0 1.6-1.6 1.6-1.6 3.2-11.2 16-27.2 28.8-44.8 36.8l-356.8 163.2c-30.4 14.4-64 14.4-94.4 0l-358.4-163.2c-17.6-8-33.6-20.8-44.8-36.8-1.6-1.6-3.2-3.2-3.2-4.8 0 0 0-1.6-1.6-1.6-11.2-17.6-17.6-38.4-17.6-60.8v-414.4c0-43.2 24-81.6 62.4-100.8l358.4-179.2c16-8 33.6-12.8 51.2-12.8s35.2 4.8 51.2 12.8l356.8 179.2c38.4 19.2 62.4 57.6 62.4 100.8v414.4c0 24-6.4 44.8-19.2 64zM488 942.4c8 3.2 16 4.8 24 4.8s16-1.6 24-4.8l353.6-161.6-155.2-75.2-364.8 182.4 118.4 54.4zM512 596.8l-377.6 184 169.6 78.4 368-184-160-78.4zM129.6 262.4c-19.2 9.6-32 30.4-32 51.2v412.8c0 3.2 0 6.4 1.6 9.6l385.6-188.8v-465.6l-355.2 180.8zM926.4 313.6c0-22.4-12.8-41.6-32-51.2l-355.2-179.2v464l164.8 80v-150.4c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v177.6l164.8 81.6c0-3.2 1.6-6.4 1.6-9.6v-412.8z" />
<glyph unicode="&#xeaa0;" glyph-name="image" d="M138.232 998.076c-21.252-7.628-33.916-17.552-48.232-37.796l-12-16.968-1.188-422.656c-0.844-300.132 0.096-427.076 3.236-437.904 5.688-19.612 29.512-45.98 49.952-55.288 15.1-6.88 36.576-7.292 382.216-7.376l366.212-0.088 20.868 10.4c24.072 11.992 42.312 35.372 48.484 62.14 5.792 25.132 5.656 808.376-0.148 835.436-5.46 25.452-24.484 50.924-47.82 64.024l-17.812 10-364 0.868c-305.348 0.728-366.54-0.044-379.768-4.792M882.912 934.912l11.088-11.088 1.124-225.104 1.128-225.108-33.26-22.588c-18.288-12.428-54.796-40.972-81.124-63.436-56.872-48.524-88.132-69.576-115.296-77.644-43.172-12.82-76.42-4.54-116.196 28.936-143.732 120.968-215.088 126.672-367.916 29.412-21.304-13.556-41.368-25.66-44.596-26.896-5.12-1.968-5.864 34.776-5.864 289.288 0 316.544-0.836 304.312 21.428 313.384 4.716 1.92 168.28 3.14 363.484 2.712l354.908-0.78 11.092-11.088M606 788.528c-37.272-9.792-72.26-38.044-88.776-71.672-9.64-19.632-11.22-27.652-11.184-56.856 0.044-40.428 8.096-61.476 34.444-90.060 25.212-27.352 50.484-38.932 89.516-41.012 43.38-2.308 70.548 7.796 99.912 37.16 35.904 35.9 47.612 87.504 31.308 137.984-8.732 27.036-38.668 60.136-66.876 73.936-22.788 11.148-66.26 16.324-88.344 10.52M674.536 724.324c6.896-4.204 17.696-14.408 24-22.672 10.148-13.304 11.464-18.312 11.464-43.632 0-35.656-10.304-53.288-39.784-68.088-30.040-15.080-59.088-11.46-84.064 10.472-38.356 33.676-31.46 99.932 12.84 123.32 20.364 10.748 58.404 11.052 75.544 0.6M892 251.692v-152.308l-23.384-23.384h-712.004l-24.612 20.712v174.388l65 40.004c76.752 47.236 89.62 53.944 120.832 63.020 49.4 14.36 94.94-0.4 163.516-53.008 66.116-50.72 76.436-57.412 98.548-63.92 32.68-9.62 77.284-7.696 110.372 4.76 33.328 12.544 62.688 32.272 121.732 81.788 54.72 45.888 72.96 60.152 77 60.212 1.648 0.024 3-68.496 3-152.264" />
<glyph unicode="&#xeaa9;" glyph-name="analyzer" d="M48 753.6c16 0 28.8 12.8 28.8 28.8v139.2c0 9.6 8 16 16 16h137.6c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-137.6c-40 0-72-32-72-72v-139.2c0-17.6 11.2-30.4 27.2-30.4zM931.2 993.6h-137.6c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h137.6c9.6 0 16-8 16-16v-139.2c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v140.8c0 40-33.6 72-73.6 72zM976 270.4c-16 0-28.8-12.8-28.8-28.8v-139.2c0-9.6-8-16-16-16h-137.6c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h137.6c40 0 72 32 72 72v139.2c1.6 17.6-11.2 30.4-27.2 30.4zM230.4 86.4h-137.6c-9.6 0-16 8-16 16v139.2c0 16-12.8 28.8-28.8 28.8s-28.8-12.8-28.8-28.8v-139.2c0-40 32-72 72-72h137.6c16 0 28.8 12.8 28.8 28.8s-12.8 27.2-27.2 27.2zM830.4 512c0 12.8-4.8 25.6-14.4 35.2-44.8 43.2-161.6 145.6-304 145.6s-259.2-102.4-304-145.6c-9.6-9.6-14.4-22.4-14.4-35.2s4.8-25.6 14.4-35.2c44.8-43.2 161.6-145.6 304-145.6s259.2 102.4 304 145.6c9.6 9.6 14.4 22.4 14.4 35.2zM512 387.2c-116.8 0-217.6 84.8-259.2 124.8 41.6 41.6 142.4 124.8 259.2 124.8s217.6-84.8 259.2-124.8c-41.6-41.6-142.4-124.8-259.2-124.8zM454.4 512c0-32 25.6-57.6 57.6-57.6s57.6 25.6 57.6 57.6-25.6 57.6-57.6 57.6-57.6-25.6-57.6-57.6z" />
<glyph unicode="&#xeaab;" glyph-name="search" d="M993.6 112l-281.6 227.2c116.8 152 105.6 369.6-33.6 508.8-73.6 73.6-169.6 113.6-273.6 113.6s-198.4-40-272-113.6c-150.4-150.4-150.4-396.8 0-547.2 73.6-73.6 169.6-113.6 273.6-113.6 100.8 0 196.8 38.4 268.8 108.8l283.2-230.4c4.8-4.8 11.2-6.4 17.6-6.4 8 0 16 3.2 22.4 9.6 9.6 16 8 33.6-4.8 43.2zM406.4 244.8c-88 0-171.2 35.2-233.6 97.6-129.6 129.6-129.6 339.2 0 467.2 62.4 62.4 145.6 97.6 233.6 97.6s171.2-33.6 233.6-97.6c129.6-129.6 129.6-339.2 0-467.2-62.4-64-145.6-97.6-233.6-97.6z" />
<glyph unicode="&#xeab3;" glyph-name="star-filled" d="M955.2 641.6l-289.6 44.8-131.2 275.2c-9.6 19.2-35.2 19.2-44.8 0l-131.2-276.8-288-43.2c-20.8-3.2-28.8-30.4-12.8-44.8l209.6-216-49.6-302.4c-3.2-20.8 17.6-38.4 36.8-25.6l260.8 142.4 259.2-142.4c17.6-9.6 40 6.4 35.2 25.6l-49.6 302.4 209.6 216c12.8 14.4 6.4 41.6-14.4 44.8z" />
<glyph unicode="&#xeab5;" glyph-name="star" d="M248 20.8c-12.8 0-25.6 3.2-36.8 11.2-20.8 14.4-32 40-27.2 65.6l43.2 272-187.2 193.6c-17.6 17.6-24 44.8-16 68.8s27.2 40 51.2 44.8l260.8 41.6 116.8 248c11.2 22.4 33.6 36.8 57.6 36.8 25.6 0 46.4-14.4 57.6-36.8l120-246.4 260.8-41.6c24-3.2 43.2-20.8 51.2-44.8s1.6-51.2-16-68.8l-188.8-193.6 44.8-273.6c4.8-25.6-6.4-51.2-27.2-65.6-19.2-14.4-44.8-16-67.2-4.8l-233.6 128-233.6-128c-9.6-4.8-19.2-6.4-30.4-6.4zM80 601.6l193.6-198.4c9.6-9.6 14.4-24 11.2-38.4l-44.8-276.8c-1.6-6.4 3.2-9.6 4.8-11.2 3.2-3.2 6.4-1.6 8 0l240 131.2c12.8 6.4 27.2 6.4 40 0l240-129.6c1.6 0 3.2-1.6 8 0 1.6 1.6 4.8 4.8 4.8 11.2l-44.8 278.4c-1.6 14.4 1.6 27.2 11.2 38.4l192 198.4c4.8 4.8 3.2 9.6 3.2 12.8 0 1.6-3.2 6.4-6.4 6.4l-268.8 41.6c-14.4 1.6-25.6 11.2-32 24l-120 252.8c-1.6 4.8-4.8 4.8-8 4.8-1.6 0-4.8-1.6-8-4.8l-120-254.4c-6.4-12.8-17.6-22.4-32-24l-267.2-43.2c-4.8 0-6.4-4.8-6.4-6.4-1.6-1.6-3.2-8 1.6-12.8z" />
<glyph unicode="&#xeaba;" glyph-name="trash" d="M811.2 886.4h-155.2v57.6c0 33.6-27.2 60.8-60.8 60.8h-166.4c-33.6-1.6-60.8-27.2-60.8-60.8v-57.6h-155.2c-33.6 0-60.8-27.2-60.8-60.8v-116.8c0-16 12.8-28.8 28.8-28.8h24v-542.4c0-65.6 54.4-120 120-120h376c65.6 0 120 54.4 120 120v545.6h24c16 0 28.8 12.8 28.8 28.8v116.8c-3.2 32-28.8 57.6-62.4 57.6zM424 944c0 1.6 1.6 4.8 4.8 4.8h166.4c1.6 0 4.8-1.6 4.8-4.8v-57.6h-176v57.6zM209.6 827.2c0 1.6 1.6 4.8 4.8 4.8h598.4c1.6 0 4.8-1.6 4.8-4.8v-88h-608v88zM763.2 139.2c0-35.2-28.8-64-64-64h-374.4c-35.2 0-64 28.8-64 64v544h504v-544zM512 251.2c16 0 28.8 12.8 28.8 28.8v209.6c0 16-12.8 28.8-28.8 28.8s-28.8-12.8-28.8-28.8v-211.2c1.6-16 12.8-27.2 28.8-27.2zM646.4 251.2c16 0 28.8 12.8 28.8 28.8v209.6c0 16-12.8 28.8-28.8 28.8s-28.8-12.8-28.8-28.8v-211.2c1.6-16 14.4-27.2 28.8-27.2zM377.6 251.2c16 0 28.8 12.8 28.8 28.8v209.6c0 16-12.8 28.8-28.8 28.8s-28.8-12.8-28.8-28.8v-211.2c0-16 12.8-27.2 28.8-27.2z" />
<glyph unicode="&#xeac4;" glyph-name="users" d="M328 566.4c97.6 0 177.6 76.8 177.6 172.8s-80 172.8-177.6 172.8-177.6-76.8-177.6-172.8 80-172.8 177.6-172.8zM328 856c67.2 0 121.6-52.8 121.6-116.8s-54.4-116.8-121.6-116.8-121.6 52.8-121.6 116.8 54.4 116.8 121.6 116.8zM744 488c83.2 0 152 65.6 152 147.2s-68.8 147.2-152 147.2-152-65.6-152-147.2c0-80 68.8-147.2 152-147.2zM744 728c52.8 0 96-41.6 96-91.2 0-51.2-43.2-91.2-96-91.2s-96 41.6-96 91.2 43.2 91.2 96 91.2zM752 452.8h-14.4c-49.6 0-97.6-14.4-139.2-41.6-40 60.8-110.4 100.8-188.8 100.8h-163.2c-124.8 0-225.6-102.4-225.6-227.2v-126.4c0-25.6 20.8-46.4 46.4-46.4h891.2c27.2 0 48 22.4 48 48v40c-1.6 139.2-115.2 252.8-254.4 252.8zM532.8 168h-456v116.8c0 94.4 76.8 171.2 171.2 171.2h161.6c94.4 0 171.2-76.8 171.2-171.2v-116.8h-48zM948.8 168h-312v116.8c0 25.6-4.8 51.2-12.8 75.2 33.6 24 72 36.8 113.6 36.8h14.4c108.8 0 196.8-88 196.8-196.8v-32z" />
<glyph unicode="&#xeb6a;" glyph-name="images" d="M369.6 360c49.6 0 91.2 40 91.2 89.6s-40 89.6-91.2 89.6-91.2-40-91.2-89.6c1.6-49.6 41.6-89.6 91.2-89.6zM369.6 484.8c19.2 0 35.2-16 35.2-33.6 0-19.2-16-33.6-35.2-33.6-17.6-1.6-33.6 14.4-33.6 32 0 19.2 16 35.2 33.6 35.2zM787.2 689.6c49.6 0 91.2 40 91.2 89.6s-40 89.6-91.2 89.6-91.2-40-91.2-89.6c0-49.6 41.6-89.6 91.2-89.6zM787.2 812.8c19.2 0 35.2-16 35.2-33.6s-16-33.6-35.2-33.6-35.2 16-35.2 33.6 16 33.6 35.2 33.6zM888 1000h-328c-64 0-115.2-51.2-115.2-115.2v-212.8h-324.8c-51.2 0-92.8-41.6-92.8-92.8v-464c0-51.2 41.6-92.8 92.8-92.8h376c51.2 0 92.8 41.6 92.8 92.8v236.8h300.8c64 0 115.2 51.2 115.2 115.2v416c0 65.6-52.8 116.8-116.8 116.8zM560 944h329.6c33.6 0 59.2-27.2 59.2-59.2v-241.6c-12.8-8-32-20.8-35.2-24-14.4-9.6-28.8-22.4-43.2-33.6-41.6-36.8-70.4-57.6-108.8-43.2-6.4 3.2-14.4 9.6-22.4 16l-6.4 4.8c-24 19.2-51.2 41.6-84.8 51.2-20.8 6.4-43.2 6.4-65.6 1.6-12.8 32-44.8 56-81.6 57.6v211.2c-1.6 33.6 25.6 59.2 59.2 59.2zM120 616h376c19.2 0 36.8-16 36.8-36.8v-264c-8-4.8-19.2-12.8-35.2-24-14.4-9.6-28.8-22.4-43.2-33.6-41.6-36.8-70.4-57.6-108.8-43.2-8 3.2-16 9.6-25.6 17.6l-3.2 3.2c-24 19.2-51.2 41.6-84.8 51.2-56 17.6-105.6-11.2-147.2-36.8v329.6c-1.6 20.8 14.4 36.8 35.2 36.8zM496 80h-376c-19.2 0-36.8 16-36.8 36.8v65.6c8 4.8 14.4 9.6 22.4 12.8 38.4 24 73.6 46.4 108.8 35.2 24-6.4 44.8-24 65.6-41.6l3.2-3.2c11.2-9.6 24-20.8 41.6-27.2 14.4-4.8 28.8-8 43.2-8 49.6 0 89.6 33.6 121.6 62.4 12.8 11.2 25.6 22.4 36.8 30.4 1.6 1.6 3.2 1.6 4.8 3.2v-131.2c0-19.2-16-35.2-35.2-35.2zM888 408h-300.8v150.4c16 4.8 28.8 4.8 43.2 1.6 24-6.4 44.8-24 65.6-41.6l4.8-3.2c11.2-9.6 24-20.8 40-25.6s28.8-8 43.2-8c49.6 0 89.6 33.6 121.6 62.4 12.8 11.2 25.6 22.4 38.4 30.4 1.6 1.6 3.2 1.6 4.8 3.2v-108.8c0-33.6-27.2-60.8-60.8-60.8z" />
<glyph unicode="&#xeb70;" glyph-name="redirection" d="M971.2 588.8l-384 384c-20.8 20.8-48 32-76.8 32s-56-11.2-76.8-32l-384-384c-20.8-20.8-32-48-32-76.8s11.2-56 32-76.8l384-384c20.8-20.8 48-32 76.8-32s56 11.2 76.8 32l384 384c43.2 43.2 43.2 110.4 0 153.6zM932.8 475.2l-384-384c-20.8-20.8-52.8-20.8-73.6 0l-384 384c-9.6 9.6-16 22.4-16 36.8s4.8 27.2 16 36.8l384 384c9.6 9.6 22.4 16 36.8 16s27.2-4.8 36.8-16l384-384c19.2-20.8 19.2-52.8 0-73.6zM540.8 667.2c-11.2 11.2-28.8 11.2-40 0s-11.2-28.8 0-40l88-88h-220.8c-16 0-28.8-12.8-28.8-28.8v-136c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v107.2h193.6l-88-88c-11.2-11.2-11.2-28.8 0-40 4.8-4.8 12.8-8 19.2-8s14.4 3.2 19.2 8l136 136c11.2 11.2 11.2 28.8 0 40l-136 137.6z" />
<glyph unicode="&#xeb73;" glyph-name="video" d="M880 1003.2h-736c-68.8 0-123.2-54.4-123.2-123.2v-736c0-68.8 56-124.8 124.8-124.8h736c68.8 0 124.8 56 124.8 124.8v736c-1.6 68.8-57.6 123.2-126.4 123.2zM248 539.2h-171.2v180.8h172.8v-180.8zM76.8 483.2h172.8v-179.2h-172.8v179.2zM304 947.2h416v-872h-416v872zM948.8 539.2h-172.8v180.8h172.8v-180.8zM776 483.2h172.8v-179.2h-172.8v179.2zM948.8 880v-104h-172.8v171.2h104c36.8 0 68.8-30.4 68.8-67.2zM144 947.2h104v-172.8h-171.2v105.6c0 36.8 30.4 67.2 67.2 67.2zM76.8 144v104h172.8v-172.8h-105.6c-36.8 0-67.2 32-67.2 68.8zM880 75.2h-104v172.8h172.8v-104c0-36.8-32-68.8-68.8-68.8zM636.8 555.2l-152 92.8c-16 9.6-35.2 9.6-51.2 1.6-16-9.6-25.6-25.6-25.6-44.8v-184c0-17.6 9.6-35.2 25.6-44.8 8-4.8 16-6.4 25.6-6.4s17.6 3.2 25.6 8l152 92.8c16 9.6 24 25.6 24 43.2s-8 32-24 41.6zM464 430.4v163.2l136-81.6-136-81.6z" />
<glyph unicode="&#xeb97;" glyph-name="schema" d="M419.2 582.4l-11.2-64c-1.6-11.2 3.2-20.8 11.2-27.2s20.8-6.4 28.8-1.6l57.6 30.4 57.6-30.4c4.8-1.6 8-3.2 12.8-3.2 6.4 0 11.2 1.6 16 4.8 8 6.4 12.8 17.6 11.2 27.2l-11.2 64 46.4 44.8c8 8 9.6 19.2 6.4 28.8s-12.8 17.6-22.4 19.2l-64 9.6-28.8 59.2c-4.8 9.6-14.4 16-25.6 16s-20.8-6.4-25.6-16l-28.8-59.2-64-9.6c-11.2-1.6-19.2-9.6-22.4-19.2s0-20.8 6.4-28.8l49.6-44.8zM475.2 632c9.6 1.6 17.6 6.4 20.8 16l9.6 20.8 9.6-20.8c4.8-8 11.2-14.4 20.8-16l22.4-3.2-16-16c-6.4-6.4-9.6-16-8-24l3.2-22.4-20.8 11.2c-8 4.8-17.6 4.8-25.6 0l-20.8-11.2 3.2 22.4c1.6 9.6-1.6 17.6-8 24l-16 16 25.6 3.2zM928 886.4h-832c-41.6 0-76.8-33.6-76.8-76.8v-596.8c0-41.6 33.6-76.8 76.8-76.8h832c41.6 0 76.8 33.6 76.8 76.8v596.8c0 43.2-35.2 76.8-76.8 76.8zM774.4 193.6h-534.4c3.2 11.2 3.2 20.8 3.2 32 0 76.8-62.4 139.2-139.2 139.2-9.6 0-19.2-1.6-28.8-3.2v318.4c9.6-1.6 19.2-3.2 28.8-3.2 76.8 0 139.2 62.4 139.2 139.2v14.4h528v-14.4c0-76.8 62.4-139.2 139.2-139.2 12.8 0 25.6 1.6 38.4 6.4v-323.2c-12.8 3.2-25.6 6.4-38.4 6.4-76.8 0-139.2-62.4-139.2-139.2 0-12.8 0-22.4 3.2-33.6zM948.8 809.6v-67.2c-11.2-6.4-25.6-9.6-38.4-9.6-44.8 0-83.2 36.8-83.2 83.2 0 4.8 0 9.6 1.6 14.4h99.2c11.2 0 20.8-9.6 20.8-20.8zM96 830.4h89.6c0-4.8 1.6-9.6 1.6-14.4 0-46.4-36.8-83.2-83.2-83.2-9.6 0-19.2 1.6-28.8 4.8v72c1.6 11.2 9.6 20.8 20.8 20.8zM76.8 214.4v89.6c9.6 3.2 19.2 4.8 28.8 4.8 44.8 0 83.2-36.8 83.2-83.2 0-11.2-1.6-20.8-6.4-30.4v-1.6h-86.4c-11.2 0-19.2 9.6-19.2 20.8zM928 193.6h-94.4v1.6c-4.8 9.6-6.4 20.8-6.4 30.4 0 46.4 36.8 83.2 83.2 83.2 14.4 0 27.2-3.2 38.4-9.6v-84.8c0-11.2-9.6-20.8-20.8-20.8zM728 417.6h-443.2c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h443.2c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8zM622.4 313.6h-230.4c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h228.8c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-27.2 28.8z" />
<glyph unicode="&#xeb99;" glyph-name="adsense" d="M912 942.4h-800c-51.2 0-92.8-41.6-92.8-92.8v-360c0-51.2 41.6-92.8 92.8-92.8h57.6v-288c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v288h259.2v-288c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v288h259.2v-288c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v288h51.2c51.2 0 92.8 41.6 92.8 92.8v360c0 51.2-41.6 92.8-92.8 92.8zM948.8 489.6c0-19.2-16-36.8-36.8-36.8h-800c-19.2 0-36.8 16-36.8 36.8v360c0 19.2 16 36.8 36.8 36.8h800c19.2 0 36.8-16 36.8-36.8v-360zM398.4 806.4c-4.8 9.6-14.4 16-25.6 16s-20.8-6.4-25.6-16l-112-228.8c-6.4-14.4-1.6-30.4 12.8-36.8 3.2-1.6 8-3.2 12.8-3.2 9.6 0 20.8 6.4 25.6 16l86.4 176 86.4-176c6.4-14.4 24-19.2 36.8-12.8 14.4 6.4 19.2 24 12.8 36.8l-110.4 228.8zM667.2 825.6h-54.4c-16 0-28.8-12.8-28.8-28.8v-233.6c0-16 12.8-28.8 28.8-28.8h54.4c68.8 0 124.8 56 124.8 124.8v41.6c-1.6 68.8-57.6 124.8-124.8 124.8zM734.4 659.2c0-38.4-30.4-68.8-68.8-68.8h-25.6v179.2h27.2c38.4 0 68.8-30.4 68.8-68.8v-41.6z" />
<glyph unicode="&#xeb9d;" glyph-name="tick" d="M996.8 820.8c-11.2 11.2-28.8 11.2-40 0l-584-566.4c-4.8-4.8-11.2-4.8-16 0l-289.6 281.6c-11.2 11.2-28.8 11.2-40 0s-11.2-28.8 0-40l289.6-281.6c12.8-12.8 30.4-19.2 46.4-19.2 17.6 0 33.6 6.4 46.4 19.2l584 566.4c12.8 11.2 12.8 28.8 3.2 40z" />
<glyph unicode="&#xeb9f;" glyph-name="circle-plus" d="M681.6 540.8s-1.6 0 0 0h-140.8v140.8c0 16-12.8 27.2-28.8 27.2s-27.2-12.8-27.2-28.8v-140.8h-140.8c-16 0-27.2-12.8-27.2-28.8s12.8-27.2 28.8-27.2h140.8v-140.8c0-16 12.8-27.2 28.8-27.2s27.2 12.8 27.2 28.8v140.8h140.8c16 0 27.2 12.8 27.2 28.8-1.6 14.4-14.4 27.2-28.8 27.2zM512 1003.2c-272 0-491.2-219.2-491.2-491.2s219.2-492.8 491.2-492.8 492.8 220.8 492.8 492.8-220.8 491.2-492.8 491.2zM512 75.2c-240 0-435.2 196.8-435.2 436.8s195.2 435.2 435.2 435.2 436.8-195.2 436.8-435.2-196.8-436.8-436.8-436.8z" />
<glyph unicode="&#xeba4;" glyph-name="eye" d="M512 624c-62.4 0-112-51.2-112-112s51.2-112 112-112 112 51.2 112 112-49.6 112-112 112zM512 456c-30.4 0-56 25.6-56 56s25.6 56 56 56 56-25.6 56-56-25.6-56-56-56zM998.4 531.2c-105.6 166.4-288 265.6-486.4 265.6s-380.8-99.2-486.4-265.6c-6.4-11.2-6.4-25.6 0-36.8 105.6-166.4 288-265.6 486.4-265.6s380.8 99.2 486.4 265.6c8 11.2 8 25.6 0 36.8zM512 284.8c-174.4 0-336 84.8-432 228.8 96 142.4 257.6 227.2 432 227.2s336-84.8 432-227.2c-96-144-257.6-228.8-432-228.8z" />
<glyph unicode="&#xebac;" glyph-name="heart-filled" d="M512 102.4c-12.8 0-25.6 4.8-35.2 12.8-36.8 32-73.6 62.4-105.6 89.6-92.8 78.4-174.4 147.2-230.4 214.4-64 76.8-92.8 147.2-92.8 225.6 0 75.2 25.6 145.6 73.6 196.8s113.6 80 185.6 80c52.8 0 102.4-17.6 145.6-49.6 17.6-12.8 32-28.8 46.4-46.4 6.4-8 17.6-8 24 0 14.4 17.6 30.4 32 46.4 46.4 43.2 33.6 92.8 49.6 145.6 49.6 72 0 137.6-28.8 185.6-80s73.6-121.6 73.6-196.8c0-78.4-28.8-148.8-92.8-224-56-67.2-137.6-136-230.4-214.4-32-27.2-68.8-57.6-105.6-89.6-8-9.6-20.8-14.4-33.6-14.4z" />
<glyph unicode="&#xebb4;" glyph-name="info" d="M436.8 913.6c0-34.463 27.937-62.4 62.4-62.4s62.4 27.937 62.4 62.4v0c0 34.463-27.937 62.4-62.4 62.4s-62.4-27.937-62.4-62.4v0M619.2 75.2h-80v620.8c0 35.2-28.8 64-64 64h-72c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h72c4.8 0 8-3.2 8-8v-619.2h-80c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h216c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8z" />
<glyph unicode="&#xebbc;" glyph-name="howto" d="M220.8 891.2h-140.8c-33.6 0-60.8-27.2-60.8-60.8v-140.8c0-33.6 27.2-60.8 60.8-60.8h140.8c33.6 0 60.8 27.2 60.8 60.8v140.8c-1.6 33.6-28.8 60.8-60.8 60.8zM224 691.2c0-1.6-1.6-4.8-4.8-4.8h-139.2c-1.6 0-4.8 1.6-4.8 4.8v140.8c0 1.6 1.6 4.8 4.8 4.8h140.8c1.6 0 4.8-1.6 4.8-4.8v-140.8zM220.8 393.6h-140.8c-33.6 0-60.8-27.2-60.8-60.8v-140.8c0-33.6 27.2-60.8 60.8-60.8h140.8c33.6 0 60.8 27.2 60.8 60.8v140.8c-1.6 33.6-28.8 60.8-60.8 60.8zM224 193.6c0-1.6-1.6-4.8-4.8-4.8h-139.2c-1.6 0-4.8 1.6-4.8 4.8v140.8c0 1.6 1.6 4.8 4.8 4.8h140.8c1.6 0 4.8-1.6 4.8-4.8v-140.8zM457.6 803.2h518.4c16 0 28.8 12.8 28.8 28.8s-12.8 27.2-28.8 27.2h-518.4c-16 0-28.8-12.8-28.8-28.8s12.8-27.2 28.8-27.2zM976 718.4h-518.4c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h518.4c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8zM976 361.6h-518.4c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h518.4c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8zM976 220.8h-518.4c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h518.4c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8z" />
<glyph unicode="&#xebbd;" glyph-name="faq" d="M187.2 974.4h-107.2c-33.6 0-60.8-27.2-60.8-60.8v-107.2c0-33.6 27.2-60.8 60.8-60.8h107.2c33.6 0 60.8 27.2 60.8 60.8v108.8c-1.6 33.6-28.8 59.2-60.8 59.2zM190.4 808c0-1.6-1.6-4.8-4.8-4.8h-105.6c-1.6 0-4.8 1.6-4.8 4.8v107.2c0 1.6 1.6 4.8 4.8 4.8h107.2c1.6 0 4.8-1.6 4.8-4.8v-107.2zM408 833.6h568c16 0 28.8 12.8 28.8 28.8s-12.8 27.2-28.8 27.2h-568c-16 0-28.8-12.8-28.8-28.8s12.8-27.2 28.8-27.2zM187.2 635.2h-107.2c-33.6 0-60.8-27.2-60.8-60.8v-107.2c0-33.6 27.2-60.8 60.8-60.8h107.2c33.6 0 60.8 27.2 60.8 60.8v107.2c-1.6 33.6-28.8 60.8-60.8 60.8zM190.4 467.2c0-1.6-1.6-4.8-4.8-4.8h-105.6c-1.6 0-4.8 1.6-4.8 4.8v107.2c0 1.6 1.6 4.8 4.8 4.8h107.2c1.6 0 4.8-1.6 4.8-4.8v-107.2zM976 548.8h-568c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h568c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8zM187.2 276.8h-107.2c-33.6 0-60.8-27.2-60.8-60.8v-107.2c0-33.6 27.2-60.8 60.8-60.8h107.2c33.6 0 60.8 27.2 60.8 60.8v107.2c-1.6 33.6-28.8 60.8-60.8 60.8zM190.4 108.8c0-1.6-1.6-4.8-4.8-4.8h-105.6c-1.6 0-4.8 1.6-4.8 4.8v107.2c0 1.6 1.6 4.8 4.8 4.8h107.2c1.6 0 4.8-1.6 4.8-4.8v-107.2zM976 190.4h-568c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h568c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8z" />
<glyph unicode="&#xebc8;" glyph-name="music" d="M979.2 897.6c-16 14.4-38.4 22.4-60.8 20.8l-571.2-43.2c-41.6-3.2-73.6-38.4-73.6-80v-491.2c-27.2 16-60.8 25.6-99.2 25.6-86.4 0-155.2-49.6-155.2-112s67.2-112 155.2-112 155.2 49.6 155.2 112v374.4l619.2 48v-291.2c-27.2 16-60.8 25.6-99.2 25.6-86.4 0-155.2-49.6-155.2-112s67.2-112 155.2-112 155.2 49.6 155.2 112v579.2c0 19.2-9.6 41.6-25.6 56zM174.4 161.6c-57.6 0-99.2 30.4-99.2 56s40 56 99.2 56 99.2-30.4 99.2-56-41.6-56-99.2-56zM849.6 203.2c-57.6 0-99.2 30.4-99.2 56s40 56 99.2 56 99.2-30.4 99.2-56-41.6-56-99.2-56zM329.6 795.2c0 12.8 9.6 22.4 22.4 24l572.8 43.2c6.4 0 11.2-1.6 16-6.4s8-11.2 8-17.6v-144l-619.2-48v148.8z" />
<glyph unicode="&#xebce;" glyph-name="plus" d="M976 539.2h-435.2v436.8c0 16-12.8 28.8-28.8 28.8s-27.2-12.8-27.2-28.8v-436.8h-436.8c-16 0-28.8-12.8-28.8-28.8s12.8-27.2 28.8-27.2h436.8v-435.2c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v435.2h433.6c16 0 28.8 12.8 28.8 28.8s-12.8 27.2-28.8 27.2z" />
<glyph unicode="&#xebd2;" glyph-name="help" d="M512 1003.2c-272 0-491.2-219.2-491.2-491.2s219.2-492.8 491.2-492.8 492.8 220.8 492.8 492.8-220.8 491.2-492.8 491.2zM512 75.2c-240 0-435.2 196.8-435.2 436.8s195.2 435.2 435.2 435.2 436.8-195.2 436.8-435.2-196.8-436.8-436.8-436.8zM539.2 833.6c-46.4 8-92.8-4.8-126.4-33.6-35.2-28.8-56-72-56-118.4 0-17.6 3.2-35.2 9.6-51.2 4.8-14.4 20.8-22.4 35.2-17.6s22.4 20.8 17.6 35.2c-3.2 11.2-6.4 20.8-6.4 33.6 0 28.8 12.8 56 35.2 75.2s51.2 27.2 81.6 20.8c40-6.4 72-40 78.4-78.4 8-46.4-16-91.2-59.2-108.8-40-16-65.6-56-65.6-102.4v-102.4c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v102.4c0 22.4 12.8 43.2 30.4 49.6 67.2 27.2 105.6 97.6 92.8 171.2-11.2 62.4-62.4 113.6-124.8 124.8zM513.6 275.2h-4.8c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h4.8c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8z" />
<glyph unicode="&#xebe1;" glyph-name="instant-indexing" d="M403.2 19.2c-6.4 0-11.2 1.6-17.6 3.2-20.8 8-32 27.2-28.8 49.6l41.6 348.8-137.6-27.2c-19.2-3.2-38.4 4.8-48 20.8-11.2 16-9.6 36.8 1.6 52.8l369.6 516.8c12.8 17.6 35.2 24 56 16s32-28.8 28.8-49.6l-49.6-361.6 142.4 35.2c19.2 4.8 38.4-3.2 49.6-19.2s11.2-38.4-1.6-54.4l-371.2-512c-8-11.2-20.8-19.2-35.2-19.2zM408 480c11.2 0 24-4.8 32-12.8 11.2-9.6 16-25.6 14.4-40l-38.4-328 336 464-131.2-33.6c-14.4-3.2-30.4 0-43.2 11.2-11.2 11.2-17.6 25.6-14.4 41.6l46.4 339.2-339.2-467.2 128 25.6h9.6z" />
<glyph unicode="&#xebe8;" glyph-name="404" d="M977.6 352l-355.2 483.2c-25.6 35.2-67.2 56-110.4 56-44.8 0-84.8-20.8-110.4-56l-355.2-483.2c-30.4-41.6-35.2-97.6-11.2-144s70.4-75.2 123.2-75.2h708.8c52.8 0 99.2 28.8 123.2 75.2s17.6 102.4-12.8 144zM939.2 233.6c-14.4-27.2-41.6-44.8-72-44.8h-708.8c-32 0-59.2 16-72 44.8-14.4 27.2-11.2 59.2 6.4 84.8l353.6 483.2c16 20.8 40 33.6 65.6 33.6s49.6-12.8 65.6-33.6l353.6-483.2c19.2-25.6 22.4-56 8-84.8zM512 416c16 0 28.8 12.8 28.8 28.8v179.2c0 16-12.8 28.8-28.8 28.8s-28.8-12.8-28.8-28.8v-180.8c0-14.4 12.8-27.2 28.8-27.2zM512 363.2c-25.6 0-46.4-20.8-46.4-46.4s20.8-46.4 46.4-46.4c25.6 0 46.4 20.8 46.4 46.4s-20.8 46.4-46.4 46.4z" />
<glyph unicode="&#xebea;" glyph-name="cross" d="M552 512l443.2 444.8c11.2 11.2 11.2 28.8 0 40s-28.8 11.2-40 0l-443.2-444.8-444.8 443.2c-11.2 11.2-28.8 11.2-40 0s-11.2-28.8 0-40l444.8-443.2-443.2-444.8c-11.2-11.2-11.2-28.8 0-40 4.8-4.8 12.8-8 19.2-8s14.4 3.2 19.2 8l444.8 444.8 443.2-444.8c4.8-4.8 12.8-8 19.2-8s14.4 3.2 19.2 8c11.2 11.2 11.2 28.8 0 40l-441.6 444.8z" />
<glyph unicode="&#xebf7;" glyph-name="fact-check" d="M913.6 913.6h-803.2c-49.6 0-91.2-40-91.2-91.2v-462.4c0-49.6 40-91.2 91.2-91.2h243.2l134.4-148.8c4.8-6.4 12.8-9.6 20.8-9.6s16 3.2 20.8 9.6l137.6 150.4h244.8c49.6 0 91.2 40 91.2 91.2v460.8c1.6 49.6-40 91.2-89.6 91.2zM948.8 360c0-19.2-16-35.2-35.2-35.2h-257.6c-8 0-16-3.2-20.8-9.6l-126.4-136-123.2 136c-4.8 6.4-12.8 9.6-20.8 9.6h-256c-19.2 0-35.2 16-35.2 35.2v462.4c0 19.2 16 35.2 35.2 35.2h803.2c19.2 0 35.2-16 35.2-35.2v-462.4zM627.2 689.6l-169.6-171.2-60.8 60.8c-11.2 11.2-28.8 11.2-40 0s-11.2-28.8 0-40l80-80c4.8-4.8 12.8-8 19.2-8s14.4 3.2 19.2 8l190.4 190.4c11.2 11.2 11.2 28.8 0 40-9.6 11.2-27.2 11.2-38.4 0z" />
<glyph unicode="&#xec3b;" glyph-name="recipe" d="M809.6 784c-27.2 0-54.4-6.4-80-17.6-8 118.4-104 211.2-219.2 211.2s-211.2-92.8-219.2-209.6c-24 9.6-49.6 16-75.2 16-108.8 0-195.2-89.6-195.2-201.6 0-100.8 72-185.6 166.4-198.4v-243.2c0-28.8 12.8-54.4 33.6-72s49.6-25.6 76.8-20.8l57.6 9.6c104 17.6 208 17.6 312 0l57.6-9.6c4.8-1.6 9.6-1.6 16-1.6 22.4 0 44.8 8 62.4 22.4 20.8 17.6 33.6 44.8 33.6 72v243.2c94.4 14.4 166.4 97.6 166.4 198.4 1.6 112-86.4 201.6-193.6 201.6zM766.4 112c-9.6-8-20.8-11.2-32-9.6l-57.6 9.6c-54.4 9.6-110.4 12.8-164.8 12.8s-110.4-4.8-164.8-12.8l-57.6-9.6c-11.2-1.6-22.4 1.6-32 9.6s-14.4 19.2-14.4 30.4v84.8l113.6 19.2c104 17.6 208 17.6 312 0l113.6-19.2v-84.8c-1.6-12.8-6.4-24-16-30.4zM809.6 438.4c-16 0-28.8-12.8-28.8-28.8v-126.4l-104 17.6c-1.6 0-4.8 0-6.4 1.6v129.6c0 16-12.8 28.8-28.8 28.8s-27.2-12.8-27.2-28.8v-123.2c-67.2 6.4-136 6.4-203.2 0v123.2c0 16-12.8 28.8-28.8 28.8s-28.8-12.8-28.8-28.8v-131.2c-1.6 0-4.8 0-6.4-1.6l-104-17.6v126.4c0 16-12.8 28.8-28.8 28.8-76.8 0-139.2 65.6-139.2 145.6s62.4 145.6 139.2 145.6c32 0 62.4-11.2 86.4-32 9.6-8 22.4-8 32-3.2 9.6 6.4 16 17.6 12.8 28.8-1.6 8-1.6 17.6-1.6 28.8 0 94.4 73.6 171.2 164.8 171.2s164.8-76.8 164.8-171.2c0-11.2-1.6-22.4-3.2-32-1.6-11.2 3.2-24 14.4-30.4s24-4.8 32 3.2c25.6 24 57.6 36.8 91.2 36.8 76.8 0 139.2-65.6 139.2-145.6 1.6-80-62.4-144-137.6-144z" />
<glyph unicode="&#xec56;" glyph-name="restaurant" d="M958.4 734.4l-131.2 232c-12.8 22.4-36.8 36.8-62.4 36.8h-505.6c-25.6 0-49.6-14.4-62.4-36.8l-131.2-232c0-1.6-1.6-1.6-1.6-3.2-1.6-3.2-1.6-6.4-1.6-9.6v-628.8c0-40 32-72 72-72h753.6c40 0 72 32 72 72v627.2c1.6 4.8 0 9.6-1.6 14.4zM272 694.4c-3.2-40-36.8-70.4-76.8-70.4s-73.6 30.4-76.8 70.4h153.6zM483.2 694.4c-3.2-40-36.8-70.4-76.8-70.4s-73.6 30.4-76.8 70.4h153.6zM694.4 694.4c-3.2-40-36.8-70.4-76.8-70.4s-73.6 30.4-76.8 70.4h153.6zM904 694.4c-3.2-40-36.8-70.4-76.8-70.4s-73.6 30.4-76.8 70.4h153.6zM246.4 939.2c3.2 4.8 8 8 14.4 8h504c6.4 0 11.2-3.2 14.4-8l107.2-190.4h-745.6l105.6 190.4zM288 75.2v265.6c0 9.6 8 16 16 16h80c9.6 0 16-8 16-16v-264h-112zM889.6 75.2h-433.6v265.6c0 40-32 72-72 72h-80c-40 0-72-32-72-72v-264h-96c-9.6 0-16 8-16 16v499.2c22.4-16 48-25.6 76.8-25.6 43.2 0 81.6 20.8 105.6 51.2 24-32 62.4-51.2 105.6-51.2s81.6 20.8 105.6 51.2c24-32 62.4-51.2 105.6-51.2s81.6 20.8 105.6 51.2c24-32 62.4-51.2 105.6-51.2 28.8 0 56 9.6 76.8 25.6v-500.8c-1.6-8-9.6-16-17.6-16zM742.4 412.8h-81.6c-27.2 0-49.6-22.4-49.6-49.6v-81.6c0-27.2 22.4-49.6 49.6-49.6h81.6c27.2 0 49.6 22.4 49.6 49.6v81.6c0 27.2-22.4 49.6-49.6 49.6zM736 286.4h-70.4v70.4h70.4v-70.4z" />
<glyph unicode="&#xec64;" glyph-name="post-format" d="M857.6 844.8l-156.8 134.4c-19.2 16-43.2 25.6-67.2 25.6h-400c-57.6 0-104-46.4-104-104v-777.6c0-57.6 46.4-104 104-104h206.4c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-206.4c-25.6 0-48 20.8-48 48v776c0 25.6 20.8 48 48 48h400c11.2 0 22.4-4.8 30.4-11.2l156.8-134.4c11.2-9.6 16-22.4 16-36.8v-675.2c0-8-6.4-16-16-16-16 0-27.2-12.8-27.2-28.8s12.8-28.8 28.8-28.8c40 0 72 32 72 72v676.8c0 30.4-14.4 59.2-36.8 78.4zM308.8 779.2h220.8c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-220.8c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8zM308.8 636.8h377.6c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-377.6c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8zM308.8 499.2h377.6c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-377.6c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8zM627.2 425.6c-68.8 0-126.4-56-126.4-126.4 0-36.8 16-72 43.2-94.4v-156.8c0-9.6 4.8-19.2 14.4-24 4.8-3.2 9.6-3.2 14.4-3.2s9.6 1.6 14.4 3.2l41.6 24 41.6-24c8-4.8 19.2-4.8 27.2 0s14.4 14.4 14.4 24v156.8c25.6 22.4 43.2 56 43.2 94.4-1.6 70.4-57.6 126.4-128 126.4zM627.2 369.6c38.4 0 70.4-32 70.4-70.4s-32-70.4-70.4-70.4-70.4 32-70.4 70.4 32 70.4 70.4 70.4zM654.4 96l-12.8 8c-8 4.8-19.2 4.8-27.2 0l-14.4-8v80c8-1.6 17.6-3.2 27.2-3.2s17.6 1.6 27.2 3.2v-80z" />
<glyph unicode="&#xec66;" glyph-name="service" d="M892.8 937.6h-761.6c-60.8 0-110.4-49.6-110.4-110.4v-326.4c0-60.8 49.6-110.4 110.4-110.4h1.6c16-44.8 60.8-78.4 112-78.4s96 32 112 78.4h310.4c16-44.8 60.8-78.4 112-78.4s96 32 112 78.4h1.6c60.8 0 110.4 49.6 110.4 110.4v326.4c1.6 60.8-48 110.4-110.4 110.4zM244.8 369.6c-33.6 0-62.4 25.6-62.4 57.6s27.2 57.6 62.4 57.6 62.4-25.6 62.4-57.6-28.8-57.6-62.4-57.6zM779.2 369.6c-33.6 0-62.4 25.6-62.4 57.6s27.2 57.6 62.4 57.6 62.4-25.6 62.4-57.6-27.2-57.6-62.4-57.6zM948.8 500.8c0-28.8-22.4-52.8-52.8-54.4-9.6 52.8-57.6 94.4-116.8 94.4-57.6 0-107.2-40-116.8-94.4h-300.8c-9.6 52.8-57.6 94.4-116.8 94.4-57.6 0-107.2-40-116.8-94.4-28.8 1.6-52.8 24-52.8 54.4v326.4c0 30.4 24 54.4 54.4 54.4h763.2c30.4 0 54.4-24 54.4-54.4v-326.4zM244.8 249.6c-89.6 0-174.4-44.8-220.8-118.4-8-12.8-4.8-30.4 8-38.4s30.4-4.8 38.4 8c36.8 57.6 102.4 92.8 172.8 92.8 72 0 136-35.2 172.8-92.8 4.8-8 14.4-12.8 24-12.8 4.8 0 9.6 1.6 14.4 4.8 12.8 8 17.6 25.6 8 38.4-44.8 73.6-126.4 118.4-217.6 118.4zM779.2 249.6c-89.6 0-174.4-44.8-220.8-118.4-8-12.8-4.8-30.4 8-38.4s30.4-4.8 38.4 8c36.8 57.6 102.4 92.8 172.8 92.8s136-35.2 172.8-92.8c4.8-8 14.4-12.8 24-12.8 4.8 0 9.6 1.6 14.4 4.8 12.8 8 17.6 25.6 8 38.4-44.8 73.6-126.4 118.4-217.6 118.4z" />
<glyph unicode="&#xec67;" glyph-name="code" d="M297.6 768c9.6 11.2 9.6 28.8-1.6 40-11.2 9.6-28.8 9.6-40-1.6l-217.6-244.8c-24-27.2-24-70.4 0-97.6l217.6-246.4c4.8-6.4 12.8-9.6 20.8-9.6 6.4 0 12.8 1.6 19.2 6.4 11.2 9.6 12.8 28.8 1.6 40l-217.6 246.4c-4.8 6.4-4.8 17.6 0 24l217.6 243.2zM985.6 561.6l-217.6 244.8c-9.6 11.2-27.2 12.8-40 1.6-11.2-9.6-12.8-27.2-1.6-40l217.6-244.8c4.8-6.4 4.8-17.6 0-24l-217.6-243.2c-9.6-11.2-9.6-28.8 1.6-40 4.8-4.8 12.8-6.4 19.2-6.4 8 0 16 3.2 20.8 9.6l217.6 244.8c24 27.2 24 68.8 0 97.6zM608 800c-14.4 4.8-30.4-3.2-35.2-17.6l-176-523.2c-3.2-14.4 3.2-30.4 19.2-35.2 3.2-1.6 6.4-1.6 9.6-1.6 11.2 0 22.4 8 27.2 19.2l176 523.2c1.6 14.4-4.8 30.4-20.8 35.2z" />
<glyph unicode="&#xec70;" glyph-name="course" d="M985.6 792l-464 168c-6.4 1.6-12.8 1.6-19.2 0l-464-168c-11.2-4.8-19.2-14.4-19.2-25.6s8-22.4 19.2-25.6l128-46.4v-296c0-12.8 8-22.4 19.2-27.2 137.6-46.4 241.6-65.6 337.6-65.6 48 0 94.4 4.8 140.8 14.4v-48c-44.8-12.8-78.4-52.8-78.4-102.4 0-57.6 48-105.6 105.6-105.6s105.6 48 105.6 105.6c0 48-33.6 89.6-78.4 102.4v62.4c38.4 9.6 76.8 24 120 38.4 11.2 4.8 19.2 14.4 19.2 25.6v294.4l128 46.4c11.2 4.8 19.2 14.4 19.2 25.6s-8 22.4-19.2 27.2zM742.4 169.6c0-27.2-22.4-49.6-49.6-49.6s-49.6 22.4-49.6 49.6 22.4 49.6 49.6 49.6c27.2 0 49.6-22.4 49.6-49.6zM222.4 417.6v254.4l280-100.8c3.2-1.6 6.4-1.6 9.6-1.6s6.4 0 9.6 1.6l142.4 51.2v-246.4c-129.6-27.2-252.8-19.2-441.6 41.6zM801.6 417.6c-28.8-9.6-56-19.2-81.6-25.6v251.2l81.6 30.4v-256zM696 694.4l-120 44.8c-14.4 4.8-30.4-1.6-36.8-16-4.8-14.4 1.6-30.4 16-36.8l57.6-22.4-100.8-36.8-380.8 137.6 380.8 137.6 380.8-137.6-196.8-70.4z" />
<glyph unicode="&#xec73;" glyph-name="book" d="M929.6 876.8h-364.8c-20.8 0-38.4-8-52.8-19.2-14.4 12.8-32 19.2-52.8 19.2h-364.8c-40 0-73.6-33.6-73.6-73.6v-540.8c0-40 33.6-73.6 73.6-73.6h390.4v-14.4c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v14.4h390.4c40 0 73.6 33.6 73.6 73.6v540.8c-1.6 41.6-35.2 73.6-76.8 73.6zM94.4 244.8c-9.6 0-17.6 8-17.6 17.6v540.8c0 9.6 8 17.6 17.6 17.6h366.4c12.8 0 24-11.2 24-24v-552h-390.4zM948.8 262.4c0-9.6-8-17.6-17.6-17.6h-390.4v552c0 12.8 11.2 24 24 24h364.8c9.6 0 17.6-8 17.6-17.6v-540.8zM217.6 659.2h123.2c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-123.2c-16 0-28.8-12.8-28.8-28.8s14.4-28.8 28.8-28.8zM678.4 659.2h123.2c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-123.2c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8zM803.2 579.2h-123.2c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h123.2c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8zM344 579.2h-123.2c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h123.2c16 0 28.8 12.8 28.8 28.8s-14.4 28.8-28.8 28.8zM344 432h-123.2c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h123.2c16 0 28.8 12.8 28.8 28.8s-14.4 28.8-28.8 28.8zM803.2 432h-123.2c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h123.2c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8z" />
<glyph unicode="&#xec76;" glyph-name="social" d="M1003.2 822.4c-3.2 28.8-16 56-40 75.2-22.4 19.2-51.2 27.2-81.6 25.6-28.8-3.2-56-16-75.2-40s-25.6-51.2-22.4-80c0-8 1.6-16 4.8-22.4l-158.4-92.8c-30.4 48-83.2 81.6-144 81.6-48 0-91.2-20.8-123.2-52.8l-136 123.2c9.6 16 14.4 35.2 14.4 54.4 0 60.8-49.6 110.4-110.4 110.4s-110.4-51.2-110.4-112 49.6-110.4 110.4-110.4c20.8 0 40 6.4 56 16l142.4-129.6c-9.6-20.8-16-44.8-16-70.4 0-92.8 76.8-169.6 169.6-169.6h14.4l36.8-136c-44.8-25.6-75.2-72-75.2-128 0-80 65.6-145.6 145.6-145.6s145.6 65.6 145.6 145.6-65.6 145.6-145.6 145.6c-6.4 0-11.2 0-17.6-1.6l-36.8 132.8c59.2 25.6 100.8 86.4 100.8 155.2 0 12.8-1.6 24-3.2 35.2l168 97.6 4.8-4.8c20.8-16 44.8-25.6 70.4-25.6h11.2c28.8 3.2 56 16 75.2 40s28.8 54.4 25.6 83.2zM131.2 838.4c-30.4 0-54.4 24-54.4 54.4s24 54.4 54.4 54.4 54.4-24 54.4-54.4-25.6-54.4-54.4-54.4zM696 166.4c0-49.6-40-89.6-89.6-89.6s-89.6 40-89.6 89.6 40 89.6 89.6 89.6 89.6-40 89.6-89.6zM484.8 484.8c-62.4 0-113.6 51.2-113.6 113.6s51.2 113.6 113.6 113.6 113.6-51.2 113.6-113.6-51.2-113.6-113.6-113.6zM936 777.6c-9.6-11.2-22.4-17.6-36.8-19.2s-28.8 3.2-40 12.8c-11.2 9.6-17.6 22.4-19.2 36.8s3.2 28.8 12.8 40c9.6 11.2 22.4 17.6 36.8 19.2h4.8c12.8 0 25.6-4.8 35.2-12.8 11.2-9.6 17.6-22.4 19.2-36.8 0-14.4-4.8-28.8-12.8-40z" />
<glyph unicode="&#xec78;" glyph-name="edit" d="M1003.2 844.8c0 11.2-4.8 20.8-12.8 28.8l-59.2 59.2c-17.6 17.6-35.2 35.2-52.8 54.4-6.4 8-16 14.4-25.6 16-11.2 1.6-24-1.6-33.6-9.6l-115.2-115.2h-564.8c-65.6 0-118.4-52.8-118.4-118.4v-622.4c0-65.6 52.8-118.4 118.4-118.4h622.4c65.6 0 118.4 52.8 118.4 118.4v568l110.4 110.4c8 8 12.8 19.2 12.8 28.8zM532.8 438.4c-1.6-1.6-4.8-3.2-6.4-4.8l-137.6-46.4 44.8 137.6c1.6 3.2 1.6 4.8 4.8 6.4l304 304 96-94.4-305.6-302.4zM824 137.6c0-33.6-27.2-62.4-62.4-62.4h-622.4c-33.6 0-62.4 27.2-62.4 62.4v624c0 33.6 27.2 62.4 62.4 62.4h510.4l-251.2-251.2c-8-8-14.4-17.6-17.6-28.8l-60.8-185.6c-3.2-9.6-1.6-19.2 3.2-27.2 4.8-6.4 11.2-12.8 25.6-12.8h4.8l190.4 62.4c11.2 3.2 20.8 9.6 28.8 17.6l252.8 251.2v-512zM876.8 782.4l-96 94.4 64 64 46.4-46.4c16-16 32-32 48-49.6l-62.4-62.4z" />
<glyph unicode="&#xec7f;" glyph-name="comments-reply" d="M910.4 904h-796.8c-51.2 0-94.4-41.6-94.4-94.4v-569.6c0-35.2 19.2-67.2 49.6-83.2 14.4-8 28.8-11.2 44.8-11.2 17.6 0 36.8 4.8 52.8 16l142.4 96h57.6c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-65.6c-4.8 0-11.2-1.6-16-4.8l-148.8-99.2c-11.2-8-25.6-8-38.4-1.6s-20.8 19.2-20.8 33.6v568c0 20.8 16 36.8 36.8 36.8h796.8c20.8 0 38.4-17.6 38.4-38.4v-524.8c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v526.4c-1.6 51.2-44.8 92.8-96 92.8zM854.4 312c-40 38.4-89.6 65.6-147.2 75.2v44.8c0 17.6-9.6 33.6-25.6 41.6s-35.2 6.4-49.6-6.4l-166.4-131.2c-11.2-9.6-17.6-22.4-17.6-36.8s6.4-27.2 17.6-36.8l166.4-134.4c8-6.4 19.2-9.6 28.8-9.6 6.4 0 14.4 1.6 20.8 4.8 16 8 25.6 24 25.6 41.6v32c38.4-8 84.8-27.2 131.2-56 14.4-9.6 33.6-9.6 48 0 14.4 8 24 25.6 22.4 41.6 0 12.8-1.6 22.4-3.2 28.8-8 41.6-22.4 72-51.2 100.8zM707.2 254.4c-14.4 1.6-28.8-1.6-40-11.2s-17.6-22.4-17.6-36.8v-20.8l-142.4 113.6 142.4 113.6v-30.4c0-24 17.6-43.2 41.6-48 48-8 89.6-28.8 121.6-60.8 20.8-22.4 30.4-41.6 36.8-72v-3.2c-36.8 22.4-89.6 46.4-142.4 56zM164.8 630.4c0-51.2 41.6-94.4 94.4-94.4 51.2 0 94.4 41.6 94.4 94.4 0 51.2-41.6 94.4-94.4 94.4s-94.4-43.2-94.4-94.4zM296 630.4c0-20.8-17.6-38.4-38.4-38.4s-38.4 17.6-38.4 38.4 17.6 38.4 38.4 38.4 38.4-17.6 38.4-38.4zM606.4 630.4c0 51.2-41.6 94.4-94.4 94.4s-94.4-41.6-94.4-94.4c0-51.2 41.6-94.4 94.4-94.4s94.4 43.2 94.4 94.4zM473.6 630.4c0 20.8 17.6 38.4 38.4 38.4s38.4-17.6 38.4-38.4-17.6-38.4-38.4-38.4c-20.8 0-38.4 17.6-38.4 38.4zM764.8 536c51.2 0 94.4 41.6 94.4 94.4 0 51.2-41.6 94.4-94.4 94.4s-92.8-43.2-92.8-94.4 41.6-94.4 92.8-94.4zM764.8 668.8c20.8 0 38.4-17.6 38.4-38.4s-17.6-38.4-38.4-38.4-38.4 17.6-38.4 38.4 17.6 38.4 38.4 38.4z" />
<glyph unicode="&#xec86;" glyph-name="page" d="M862.4 862.4h-46.4v22.4c0 65.6-52.8 118.4-118.4 118.4h-456c-65.6 0-118.4-52.8-118.4-118.4v-542.4c0-19.2 8-36.8 20.8-51.2l243.2-249.6c14.4-14.4 33.6-22.4 52.8-22.4h302.4c40 0 73.6 33.6 73.6 73.6v17.6l80 163.2c1.6 3.2 3.2 8 3.2 12.8l1.6 537.6c0 19.2-17.6 36.8-38.4 38.4zM844.8 728h-112v80c36.8 0 73.6 0 112-1.6v-78.4zM384 124.8l-166.4 171.2h166.4v-171.2zM742.4 75.2h-302.4v238.4c0 20.8-17.6 38.4-38.4 38.4h-222.4v532.8c0 35.2 28.8 62.4 62.4 62.4h454.4c35.2 0 62.4-28.8 62.4-62.4v-22.4h-43.2c-22.4 0-41.6-17.6-41.6-38.4l-1.6-537.6c0-4.8 1.6-8 3.2-12.8l81.6-163.2v-17.6c3.2-9.6-4.8-17.6-14.4-17.6zM787.2 180.8l-56 112v379.2h112v-379.2l-56-112z" />
<glyph unicode="&#xecc9;" glyph-name="direction" d="M940.8 747.2l-80 102.4c-14.4 17.6-35.2 28.8-57.6 28.8h-384v97.6c0 16-12.8 28.8-28.8 28.8s-27.2-12.8-27.2-28.8v-99.2h-224c-40 0-72-32-72-72v-206.4c0-40 32-72 72-72h222.4v-478.4c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v478.4h385.6c22.4 0 43.2 9.6 57.6 28.8l80 102.4c19.2 25.6 19.2 62.4-1.6 89.6zM897.6 691.2l-80-102.4c-3.2-4.8-8-6.4-12.8-6.4h-665.6c-9.6 0-16 8-16 16v206.4c0 9.6 8 16 16 16h664c4.8 0 9.6-1.6 12.8-6.4l80-102.4c6.4-6.4 6.4-14.4 1.6-20.8z" />
<glyph unicode="&#xece7;" glyph-name="stories" d="M961.6 406.4l-64 40c-12.8 8-30.4 4.8-38.4-8s-4.8-30.4 8-38.4l56-35.2-411.2-260.8-411.2 259.2 56 35.2c12.8 8 17.6 25.6 8 38.4-8 12.8-25.6 17.6-38.4 8l-64-40c-14.4-9.6-24-25.6-24-41.6 0-17.6 8-33.6 24-41.6l422.4-265.6c8-4.8 17.6-8 27.2-8s19.2 3.2 27.2 8l422.4 265.6c14.4 9.6 24 25.6 24 41.6-1.6 17.6-9.6 33.6-24 43.2zM422.4 387.2l75.2-46.4c4.8-3.2 9.6-4.8 14.4-4.8s9.6 1.6 14.4 4.8l75.2 46.4c12.8 8 17.6 25.6 8 38.4-8 12.8-25.6 17.6-38.4 8l-59.2-36.8-59.2 36.8c-12.8 8-30.4 4.8-38.4-8-9.6-12.8-4.8-30.4 8-38.4zM350.4 499.2l-112 70.4c-12.8 8-30.4 4.8-38.4-8s-4.8-30.4 8-38.4l112-70.4c6.4-4.8 11.2-4.8 16-4.8 9.6 0 17.6 4.8 24 12.8 8 12.8 3.2 30.4-9.6 38.4zM123.2 580.8c9.6 0 17.6 4.8 24 12.8 8 12.8 4.8 30.4-8 38.4l-38.4 24 36.8 22.4c12.8 8 17.6 25.6 8 38.4-8 12.8-25.6 17.6-38.4 8l-75.2-46.4c-8-4.8-12.8-14.4-12.8-24s4.8-19.2 12.8-24l75.2-46.4c4.8-1.6 9.6-3.2 16-3.2zM224 739.2c4.8 0 9.6 1.6 14.4 4.8l112 70.4c12.8 8 17.6 25.6 8 38.4s-25.6 17.6-38.4 8l-112-70.4c-12.8-8-17.6-25.6-8-38.4 6.4-8 14.4-12.8 24-12.8zM452.8 878.4l59.2 36.8 59.2-36.8c4.8-3.2 9.6-4.8 14.4-4.8 9.6 0 19.2 4.8 24 12.8 8 12.8 4.8 30.4-8 38.4l-75.2 46.4c-9.6 6.4-20.8 6.4-30.4 0l-75.2-46.4c-12.8-8-17.6-25.6-8-38.4s27.2-17.6 40-8zM673.6 814.4l112-70.4c4.8-3.2 9.6-4.8 14.4-4.8 9.6 0 19.2 4.8 24 12.8 8 12.8 4.8 30.4-8 38.4l-112 70.4c-12.8 8-30.4 4.8-38.4-8-9.6-12.8-4.8-30.4 8-38.4zM990.4 680l-75.2 46.4c-12.8 8-30.4 4.8-38.4-8s-4.8-30.4 8-38.4l36.8-22.4-36.8-22.4c-12.8-8-17.6-25.6-8-38.4 4.8-8 14.4-12.8 24-12.8 4.8 0 9.6 1.6 14.4 4.8l75.2 46.4c8 4.8 12.8 14.4 12.8 24s-4.8 16-12.8 20.8zM688 448c4.8 0 9.6 1.6 14.4 4.8l112 70.4c12.8 8 17.6 25.6 8 38.4-8 12.8-25.6 17.6-38.4 8l-112-70.4c-12.8-8-17.6-25.6-8-38.4 6.4-9.6 14.4-12.8 24-12.8z" />
<glyph unicode="&#xeceb;" glyph-name="acf" d="M912 1003.2h-800c-51.2 0-91.2-40-91.2-91.2v-435.2c0-51.2 40-92.8 91.2-92.8h800c51.2 0 92.8 41.6 92.8 92.8v435.2c0 51.2-41.6 91.2-92.8 91.2zM948.8 476.8c0-19.2-16-36.8-36.8-36.8h-800c-19.2 0-36.8 16-36.8 36.8v435.2c0 19.2 16 36.8 36.8 36.8h800c19.2 0 36.8-16 36.8-36.8v-435.2zM886.4 249.6h-748.8c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h748.8c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8zM886.4 75.2h-748.8c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h748.8c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8z" />
<glyph unicode="&#xecf8;" glyph-name="dataset" d="M934.4 392h-140.8c-6.4 0-11.2 3.2-12.8 8l-17.6 43.2v380.8c0 99.2-187.2 150.4-371.2 150.4-182.4 0-368-51.2-371.2-148.8v-435.2c0-97.6 192-152 371.2-152 32 0 64 1.6 94.4 4.8 1.6 0 3.2 0 3.2 1.6v-126.4c0-38.4 32-70.4 70.4-70.4h374.4c38.4 0 70.4 32 70.4 70.4v204.8c0 38.4-32 68.8-70.4 68.8zM494.4 441.6c-33.6-3.2-67.2-6.4-102.4-6.4-193.6 0-315.2 56-315.2 94.4v54.4c68.8-44.8 193.6-67.2 315.2-67.2 123.2 0 246.4 22.4 315.2 67.2v-97.6h-148.8c-30.4 1.6-56-17.6-64-44.8zM707.2 668.8c-1.6-38.4-123.2-94.4-315.2-94.4-193.6 0-315.2 56-315.2 94.4v72c68.8-44.8 192-68.8 315.2-68.8s246.4 22.4 315.2 67.2v-70.4zM392 918.4c192 0 315.2-56 315.2-94.4-1.6-38.4-123.2-94.4-315.2-94.4-193.6 0-315.2 56-315.2 94.4s121.6 94.4 315.2 94.4zM480 300.8c-28.8-3.2-57.6-4.8-88-4.8-190.4 0-315.2 57.6-315.2 96v54.4c68.8-44.8 193.6-67.2 315.2-67.2 33.6 0 65.6 1.6 97.6 4.8v-84.8c-3.2 1.6-6.4 1.6-9.6 1.6zM948.8 120c0-8-6.4-14.4-14.4-14.4h-376c-8 0-14.4 6.4-14.4 14.4v299.2c0 8 6.4 14.4 14.4 14.4h140.8c6.4 0 11.2-3.2 12.8-8l17.6-43.2c11.2-27.2 36.8-43.2 64-43.2h140.8c8 0 14.4-6.4 14.4-14.4v-204.8z" />
<glyph unicode="&#xed0d;" glyph-name="home" d="M891.2 587.2c-16 0-28.8-12.8-28.8-28.8v-436.8c0-22.4-17.6-40-40-40h-158.4v286.4c0 51.2-41.6 92.8-92.8 92.8h-121.6c-51.2 0-92.8-41.6-92.8-92.8v-284.8h-158.4c-22.4 0-40 17.6-40 40v436.8c0 16-12.8 28.8-28.8 28.8s-24-14.4-24-28.8v-436.8c0-52.8 43.2-96 96-96h624c52.8 0 96 43.2 96 96v436.8c-3.2 14.4-16 27.2-30.4 27.2zM416 83.2v284.8c0 19.2 16 36.8 36.8 36.8h121.6c19.2 0 36.8-16 36.8-36.8v-284.8h-195.2zM990.4 707.2l-427.2 275.2c-32 20.8-72 20.8-104 0l-425.6-275.2c-12.8-8-16-25.6-8-38.4s25.6-16 38.4-8l427.2 273.6c12.8 8 30.4 8 43.2 0l427.2-275.2c4.8-3.2 9.6-4.8 14.4-4.8 9.6 0 17.6 4.8 24 12.8 8 14.4 4.8 30.4-9.6 40z" />
<glyph unicode="&#xed1f;" glyph-name="toolbox" d="M880 793.6h-171.2v56c0 62.4-51.2 112-112 112h-169.6c-62.4 0-112-51.2-112-112v-56h-171.2c-68.8 0-124.8-56-124.8-124.8v-156.8c0-16 12.8-28.8 28.8-28.8h14.4v-304c0-65.6 52.8-118.4 118.4-118.4h662.4c65.6 0 118.4 52.8 118.4 118.4v304h14.4c16 0 28.8 12.8 28.8 28.8v156.8c0 68.8-56 124.8-124.8 124.8zM371.2 849.6c0 30.4 25.6 56 56 56h168c30.4 0 56-25.6 56-56v-56h-280v56zM76.8 668.8c0 36.8 30.4 68.8 68.8 68.8h736c36.8 0 68.8-30.4 68.8-68.8v-129.6h-873.6v129.6zM905.6 180.8c0-35.2-28.8-62.4-62.4-62.4h-662.4c-35.2 0-62.4 28.8-62.4 62.4v304h196.8v-99.2c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v99.2h281.6v-99.2c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v99.2h196.8v-304z" />
<glyph unicode="&#xed35;" glyph-name="comments" d="M292.8 657.6c-54.4 0-99.2-44.8-99.2-99.2s44.8-99.2 99.2-99.2 99.2 44.8 99.2 99.2c0 54.4-44.8 99.2-99.2 99.2zM292.8 515.2c-24 0-43.2 19.2-43.2 43.2s19.2 43.2 43.2 43.2 43.2-19.2 43.2-43.2c0-24-20.8-43.2-43.2-43.2zM512 657.6c-54.4 0-99.2-44.8-99.2-99.2s44.8-99.2 99.2-99.2 99.2 44.8 99.2 99.2c0 54.4-44.8 99.2-99.2 99.2zM512 515.2c-24 0-43.2 19.2-43.2 43.2s19.2 43.2 43.2 43.2 43.2-19.2 43.2-43.2c0-24-19.2-43.2-43.2-43.2zM732.8 657.6c-54.4 0-99.2-44.8-99.2-99.2s44.8-99.2 99.2-99.2 99.2 44.8 99.2 99.2c0 54.4-44.8 99.2-99.2 99.2zM732.8 515.2c-24 0-43.2 19.2-43.2 43.2s19.2 43.2 43.2 43.2 43.2-19.2 43.2-43.2c0-24-20.8-43.2-43.2-43.2zM908.8 864h-793.6c-52.8 0-96-43.2-96-96v-512c0-35.2 17.6-65.6 48-83.2 14.4-8 32-12.8 48-12.8s32 4.8 48 12.8l140.8 81.6c6.4 3.2 12.8 4.8 19.2 4.8h584c52.8 0 96 43.2 96 96v412.8c1.6 52.8-41.6 96-94.4 96zM948.8 355.2c0-22.4-17.6-40-40-40h-584c-16 0-33.6-4.8-48-12.8l-140.8-81.6c-12.8-6.4-27.2-6.4-40 0s-19.2 19.2-19.2 33.6v513.6c0 22.4 17.6 40 40 40h793.6c22.4 0 40-17.6 40-40v-412.8z" />
<glyph unicode="&#xed3a;" glyph-name="job" d="M947.2 977.6c-30.4 24-68.8 32-107.2 22.4l-564.8-139.2h-113.6c-72 0-131.2-59.2-131.2-131.2v-243.2c0-60.8 40-110.4 96-126.4l70.4-284.8c8-33.6 36.8-56 72-56h30.4c22.4 0 43.2 9.6 57.6 27.2s19.2 40 14.4 62.4l-54.4 235.2 524.8-128c9.6-3.2 20.8-3.2 30.4-3.2 27.2 0 54.4 9.6 76.8 27.2 30.4 24 46.4 57.6 46.4 96v545.6c-1.6 38.4-19.2 72-48 96zM305.6 811.2l216 52.8v-512l-216 52.8v406.4zM86.4 486.4v243.2c0 41.6 33.6 75.2 75.2 75.2h88v-393.6h-88c-41.6 0-75.2 33.6-75.2 75.2zM312 83.2c-1.6-3.2-6.4-6.4-14.4-6.4h-30.4c-8 0-14.4 4.8-17.6 12.8l-65.6 265.6h72l60.8-257.6c0-8-1.6-12.8-4.8-14.4zM937.6 334.4c0-19.2-9.6-38.4-25.6-51.2s-38.4-17.6-59.2-12.8l-275.2 67.2v540.8l275.2 67.2c20.8 4.8 41.6 0 59.2-12.8 16-12.8 25.6-30.4 25.6-51.2v-547.2z" />
<glyph unicode="&#xed4d;" glyph-name="post" d="M825.6 1003.2h-627.2c-51.2 0-91.2-40-91.2-91.2v-800c0-51.2 41.6-92.8 92.8-92.8h627.2c51.2 0 92.8 41.6 92.8 92.8v800c-3.2 51.2-43.2 91.2-94.4 91.2zM860.8 112c0-19.2-16-36.8-36.8-36.8h-625.6c-19.2 0-36.8 16-36.8 36.8v800c0 19.2 16 36.8 36.8 36.8h627.2c19.2 0 36.8-16 36.8-36.8v-800zM736 878.4h-182.4c-24 0-44.8-19.2-44.8-44.8v-220.8c0-24 19.2-44.8 44.8-44.8h182.4c24 0 44.8 19.2 44.8 44.8v222.4c-1.6 24-20.8 43.2-44.8 43.2zM723.2 625.6h-156.8v196.8h156.8v-196.8zM275.2 795.2h121.6c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-121.6c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8zM275.2 584h121.6c16 0 28.8 12.8 28.8 28.8s-12.8 27.2-28.8 27.2h-121.6c-16 0-28.8-12.8-28.8-28.8s12.8-27.2 28.8-27.2zM752 430.4h-476.8c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h476.8c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8zM752 219.2h-476.8c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h476.8c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8z" />
<glyph unicode="&#xed64;" glyph-name="support" d="M489.6 723.2h-268.8c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h268.8c16 0 28.8 12.8 28.8 28.8s-14.4 28.8-28.8 28.8zM220.8 540.8h123.2c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-123.2c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8zM427.2 470.4h-208c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h208c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8zM774.4 747.2c-36.8 4.8-70.4-12.8-88-44.8-8-14.4-1.6-30.4 11.2-38.4 14.4-8 30.4-1.6 38.4 11.2 6.4 11.2 19.2 17.6 32 16 14.4-1.6 25.6-12.8 27.2-25.6s-4.8-24-16-28.8c-24-11.2-41.6-40-41.6-67.2v-20.8c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v20.8c0 4.8 6.4 14.4 11.2 16 32 16 51.2 49.6 46.4 86.4-6.4 40-38.4 70.4-78.4 75.2zM764.8 465.6c-24 0-41.6-19.2-41.6-41.6 0-24 19.2-41.6 41.6-41.6 24 0 41.6 19.2 41.6 41.6 1.6 22.4-17.6 41.6-41.6 41.6zM884.8 873.6h-745.6c-65.6 0-118.4-52.8-118.4-118.4v-532.8c0-25.6 12.8-48 35.2-60.8 11.2-6.4 22.4-9.6 35.2-9.6s24 3.2 35.2 9.6l185.6 107.2c1.6 1.6 4.8 1.6 6.4 1.6h568c65.6 0 118.4 52.8 118.4 118.4v364.8c0 65.6-54.4 120-120 120zM948.8 387.2c0-35.2-28.8-62.4-62.4-62.4h-569.6c-12.8 0-24-3.2-35.2-9.6l-184-107.2c-6.4-3.2-12.8-1.6-14.4 0s-6.4 4.8-6.4 12.8v532.8c0 35.2 28.8 62.4 62.4 62.4h745.6c35.2 0 62.4-28.8 62.4-62.4v-366.4z" />
<glyph unicode="&#xed71;" glyph-name="search-console" d="M928 1003.2h-832c-41.6 0-75.2-33.6-75.2-75.2v-832c0-41.6 33.6-76.8 76.8-76.8h832c41.6 0 76.8 33.6 76.8 76.8v832c-1.6 41.6-36.8 75.2-78.4 75.2zM948.8 96c0-11.2-9.6-20.8-20.8-20.8h-832c-11.2 0-20.8 9.6-20.8 20.8v305.6l142.4 120c14.4-9.6 32-14.4 49.6-14.4 28.8 0 54.4 12.8 70.4 33.6l78.4-44.8c-1.6-8-3.2-14.4-3.2-22.4 0-49.6 40-91.2 91.2-91.2s91.2 40 91.2 91.2v8l120 110.4c16-12.8 35.2-20.8 57.6-20.8 49.6 0 91.2 40 91.2 91.2s-41.6 89.6-92.8 89.6c-49.6 0-91.2-40-91.2-91.2 0-8 1.6-16 3.2-22.4l-113.6-104c-16 17.6-40 28.8-67.2 28.8-22.4 0-41.6-8-57.6-20.8l-86.4 52.8v3.2c0 49.6-40 91.2-91.2 91.2s-91.2-40-91.2-91.2c0-11.2 1.6-22.4 6.4-32l-107.2-91.2v452.8c0 11.2 9.6 20.8 20.8 20.8h832c11.2 0 20.8-9.6 20.8-20.8v-832zM268.8 563.2c-19.2 0-35.2 16-35.2 35.2s16 35.2 35.2 35.2 35.2-16 35.2-35.2-16-35.2-35.2-35.2zM539.2 472c0-19.2-16-35.2-35.2-35.2s-35.2 16-35.2 35.2 16 35.2 35.2 35.2 35.2-16 35.2-35.2zM736 660.8c0 19.2 16 35.2 35.2 35.2s35.2-16 35.2-35.2-16-35.2-35.2-35.2-35.2 16-35.2 35.2z" />
<glyph unicode="&#xed73;" glyph-name="cart" d="M936 836.8c-17.6 22.4-43.2 33.6-72 33.6h-580.8l-4.8 72c-1.6 25.6-22.4 44.8-48 44.8h-134.4c-16 0-28.8-11.2-28.8-27.2s12.8-28.8 28.8-28.8h128l35.2-585.6c1.6-35.2 32-64 67.2-64h540.8c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-540.8c-6.4 0-11.2 4.8-11.2 11.2l-6.4 110.4h507.2c43.2 0 81.6 30.4 89.6 72l49.6 227.2c4.8 27.2-1.6 54.4-19.2 76.8zM899.2 771.2l-49.6-227.2c-3.2-16-19.2-28.8-35.2-28.8h-510.4l-17.6 299.2h577.6c11.2 0 20.8-4.8 28.8-12.8 6.4-8 9.6-19.2 6.4-30.4zM379.2 198.4c-52.8 0-94.4-43.2-94.4-96s43.2-96 94.4-96 94.4 43.2 94.4 96-43.2 96-94.4 96zM379.2 64c-20.8 0-38.4 17.6-38.4 40s17.6 40 38.4 40c20.8 0 38.4-17.6 38.4-40s-17.6-40-38.4-40zM769.6 198.4c-52.8 0-94.4-43.2-94.4-96s43.2-96 94.4-96 94.4 43.2 94.4 96c1.6 52.8-41.6 96-94.4 96zM769.6 64c-20.8 0-38.4 17.6-38.4 40s17.6 40 38.4 40c20.8 0 38.4-17.6 38.4-40 1.6-22.4-16-40-38.4-40z" />
<glyph unicode="&#xed83;" glyph-name="attachment" d="M526.4 19.2h-8c-75.2 0-155.2 30.4-204.8 76.8-52.8 49.6-81.6 116.8-81.6 185.6v515.2c0 68.8 33.6 131.2 92.8 169.6 57.6 40 128 49.6 195.2 25.6l4.8-1.6c8-3.2 17.6-4.8 27.2-11.2 73.6-38.4 116.8-107.2 116.8-184v-438.4c0-43.2-14.4-83.2-41.6-113.6-4.8-6.4-8-9.6-11.2-11.2-28.8-27.2-64-41.6-102.4-41.6-43.2 0-86.4 19.2-113.6 52.8-27.2 32-41.6 72-41.6 115.2v368c0 16 12.8 28.8 28.8 28.8s28.8-12.8 28.8-28.8v-368c0-28.8 9.6-57.6 28.8-78.4 17.6-20.8 43.2-33.6 70.4-33.6 24 0 44.8 9.6 62.4 25.6 1.6 1.6 3.2 3.2 6.4 8 17.6 20.8 28.8 48 28.8 78.4v436.8c0 57.6-32 105.6-88 134.4l-1.6 1.6c-3.2 1.6-8 3.2-14.4 6.4l-4.8 1.6c-51.2 17.6-104 9.6-147.2-19.2s-67.2-72-67.2-123.2v-513.6c0-52.8 24-105.6 64-145.6 40-38.4 105.6-62.4 166.4-62.4 57.6-1.6 115.2 20.8 156.8 60.8s64 91.2 62.4 147.2v400c0 16 12.8 28.8 28.8 28.8s28.8-12.8 28.8-28.8v-398.4c1.6-68.8-27.2-136-80-187.2-54.4-49.6-121.6-78.4-190.4-78.4z" />
<glyph unicode="&#xed8e;" glyph-name="mail" d="M912 849.6h-800c-51.2 0-92.8-41.6-92.8-92.8v-491.2c0-51.2 41.6-92.8 92.8-92.8h800c51.2 0 92.8 41.6 92.8 92.8v491.2c0 51.2-41.6 92.8-92.8 92.8zM912 793.6c8 0 14.4-1.6 20.8-6.4l-398.4-241.6c-14.4-8-30.4-8-44.8 0l-398.4 241.6c6.4 3.2 12.8 6.4 20.8 6.4h800zM912 230.4h-800c-19.2 0-36.8 16-36.8 36.8v464l384-233.6c16-9.6 33.6-14.4 51.2-14.4s35.2 4.8 51.2 14.4l384 233.6v-464c3.2-20.8-14.4-36.8-33.6-36.8z" />
<glyph unicode="&#xed91;" glyph-name="tag" d="M928 830.4c-16 16-40 24-62.4 20.8l-172.8-24c-64 94.4-177.6 200-364.8 171.2-16-1.6-25.6-16-24-32s16-25.6 32-24c145.6 22.4 238.4-49.6 296-124.8l-113.6-16c-16-1.6-28.8-9.6-40-19.2l-380.8-356.8c-14.4-14.4-22.4-33.6-22.4-52.8 0-20.8 8-40 22.4-52.8l294.4-278.4c14.4-12.8 32-20.8 51.2-20.8s36.8 6.4 51.2 20.8l382.4 361.6c11.2 11.2 19.2 25.6 22.4 41.6l49.6 323.2c3.2 24-4.8 46.4-20.8 62.4zM892.8 776l-51.2-324.8c0-3.2-3.2-8-4.8-9.6l-382.4-361.6c-6.4-6.4-17.6-6.4-24 0l-294.4 280c-3.2 3.2-4.8 8-4.8 12.8s1.6 9.6 4.8 12.8l379.2 358.4c3.2 3.2 6.4 4.8 9.6 4.8l140.8 19.2c25.6-44.8 36.8-80 38.4-84.8 3.2-12.8 14.4-19.2 27.2-19.2 3.2 0 4.8 0 8 1.6 14.4 4.8 22.4 20.8 19.2 35.2 0 1.6-11.2 33.6-33.6 76.8l148.8 20.8h3.2c6.4 0 9.6-3.2 12.8-4.8 1.6-4.8 4.8-9.6 3.2-17.6z" />
<glyph unicode="&#xed95;" glyph-name="target" d="M371.2 99.2c-176 60.8-294.4 225.6-294.4 412.8 0 240 195.2 435.2 435.2 435.2 179.2 0 342.4-112 406.4-278.4 4.8-14.4 22.4-20.8 36.8-16s20.8 22.4 16 36.8c-73.6 187.2-257.6 313.6-459.2 313.6-272 0-491.2-219.2-491.2-491.2 0-211.2 134.4-398.4 332.8-465.6 3.2-1.6 6.4-1.6 9.6-1.6 11.2 0 22.4 8 27.2 19.2 3.2 14.4-4.8 30.4-19.2 35.2zM512 636.8c27.2 0 52.8-9.6 75.2-25.6 12.8-9.6 30.4-8 40 4.8s8 30.4-4.8 40c-32 24-68.8 36.8-108.8 36.8-97.6 0-177.6-80-177.6-177.6 0-40 12.8-78.4 38.4-108.8 4.8-6.4 14.4-11.2 22.4-11.2 6.4 0 12.8 1.6 17.6 6.4 12.8 9.6 14.4 27.2 4.8 40-17.6 20.8-25.6 48-25.6 75.2-3.2 65.6 51.2 120 118.4 120zM732.8 563.2c-150.4 0-272-121.6-272-272s121.6-272 272-272 272 121.6 272 272-123.2 272-272 272zM732.8 75.2c-118.4 0-216 97.6-216 216s97.6 216 216 216 216-97.6 216-216-97.6-216-216-216zM396.8 260.8c-99.2 44.8-163.2 145.6-163.2 254.4 0 153.6 124.8 278.4 278.4 278.4 108.8 0 209.6-64 254.4-164.8 6.4-14.4 22.4-20.8 36.8-14.4s20.8 22.4 14.4 36.8c-54.4 121.6-174.4 198.4-305.6 198.4-184 0-334.4-150.4-334.4-334.4 0-131.2 76.8-251.2 196.8-304 3.2-1.6 8-3.2 11.2-3.2 11.2 0 20.8 6.4 25.6 16 6.4 14.4 0 30.4-14.4 36.8zM817.6 361.6l-110.4-110.4-44.8 44.8c-11.2 11.2-28.8 11.2-40 0s-11.2-28.8 0-40l64-64c4.8-4.8 12.8-8 19.2-8s14.4 3.2 19.2 8l129.6 129.6c11.2 11.2 11.2 28.8 0 40s-25.6 11.2-36.8 0z" />
<glyph unicode="&#xeda5;" glyph-name="facebook" d="M579.2 3.2h-124.8c-32 0-57.6 27.2-57.6 60.8v380.8h-102.4c-32 0-57.6 27.2-57.6 60.8v110.4c0 33.6 25.6 60.8 57.6 60.8h99.2v100.8c0 145.6 86.4 243.2 214.4 243.2h96c32 0 57.6-27.2 57.6-60.8v-129.6c0-33.6-25.6-60.8-57.6-60.8h-68.8v-91.2h91.2c19.2-1.6 35.2-9.6 46.4-22.4 11.2-14.4 16-33.6 12.8-51.2l-19.2-108.8c-3.2-28.8-27.2-49.6-57.6-49.6h-73.6v-382.4c0-32-25.6-60.8-56-60.8zM424 500.8c16 0 28.8-12.8 28.8-28.8v-408c0-3.2 1.6-4.8 1.6-4.8h124.8s1.6 1.6 1.6 4.8v411.2c0 16 12.8 28.8 28.8 28.8h100.8s1.6 0 1.6 1.6v1.6l19.2 107.2c0 3.2 0 4.8-1.6 6.4 0 0-1.6 1.6-3.2 1.6h-118.4c-16 0-28.8 12.8-28.8 28.8v113.6c0 28.8 4.8 60.8 59.2 60.8h65.6s1.6 1.6 1.6 4.8v128c0 3.2-1.6 4.8-1.6 4.8h-94.4c-96 0-158.4-73.6-158.4-187.2v-129.6c0-16-12.8-28.8-28.8-28.8h-128s-1.6-1.6-1.6-4.8v-110.4c0-3.2 1.6-4.8 1.6-4.8l129.6 3.2z" />
<glyph unicode="&#xedc1;" glyph-name="movie" d="M358.4 766.4c-60.8 0-110.4-49.6-110.4-110.4s49.6-110.4 110.4-110.4 110.4 49.6 110.4 110.4-48 110.4-110.4 110.4zM358.4 600c-30.4 0-54.4 24-54.4 54.4s24 54.4 54.4 54.4 54.4-24 54.4-54.4c1.6-30.4-24-54.4-54.4-54.4zM665.6 544c60.8 0 110.4 49.6 110.4 110.4s-49.6 110.4-110.4 110.4-110.4-49.6-110.4-110.4 48-110.4 110.4-110.4zM665.6 710.4c30.4 0 54.4-24 54.4-54.4s-24-54.4-54.4-54.4-54.4 24-54.4 54.4c-1.6 28.8 24 54.4 54.4 54.4zM358.4 480c-60.8 0-110.4-49.6-110.4-110.4s49.6-110.4 110.4-110.4 110.4 49.6 110.4 110.4-48 110.4-110.4 110.4zM358.4 313.6c-30.4 0-54.4 24-54.4 54.4s24 54.4 54.4 54.4 54.4-24 54.4-54.4-24-54.4-54.4-54.4zM665.6 257.6c60.8 0 110.4 49.6 110.4 110.4s-49.6 112-110.4 112-110.4-49.6-110.4-110.4 48-112 110.4-112zM665.6 424c30.4 0 54.4-24 54.4-54.4s-24-54.4-54.4-54.4-54.4 24-54.4 54.4 24 54.4 54.4 54.4zM976 75.2h-236.8c156.8 83.2 265.6 248 265.6 436.8 0 272-220.8 491.2-492.8 491.2s-491.2-219.2-491.2-491.2 219.2-492.8 491.2-492.8h464c16 0 28.8 12.8 28.8 28.8s-12.8 27.2-28.8 27.2zM76.8 512c0 240 195.2 435.2 435.2 435.2s436.8-195.2 436.8-435.2-196.8-436.8-436.8-436.8-435.2 196.8-435.2 436.8z" />
<glyph unicode="&#xeefa;" glyph-name="instagram" d="M512 747.2c-129.6 0-235.2-105.6-235.2-235.2s105.6-235.2 235.2-235.2 235.2 105.6 235.2 235.2-105.6 235.2-235.2 235.2zM512 332.8c-99.2 0-179.2 80-179.2 179.2s80 179.2 179.2 179.2c99.2 0 179.2-80 179.2-179.2s-80-179.2-179.2-179.2zM769.6 862.4c-33.6 0-60.8-27.2-60.8-60.8s27.2-60.8 60.8-60.8c33.6 0 60.8 27.2 60.8 60.8s-27.2 60.8-60.8 60.8zM768 1019.2h-512c-139.2 0-251.2-112-251.2-251.2v-512c0-139.2 113.6-251.2 252.8-251.2h512c139.2 0 251.2 113.6 251.2 252.8v510.4c0 139.2-113.6 251.2-252.8 251.2zM964.8 256c0-108.8-88-196.8-195.2-196.8h-513.6c-107.2 0-195.2 88-195.2 196.8v512c0 107.2 88 195.2 195.2 195.2h512c108.8 0 196.8-88 196.8-196.8v-510.4z" />
<glyph unicode="&#xef60;" glyph-name="light-bulb" d="M808 784s0 1.6-1.6 1.6c-8 22.4-27.2 70.4-70.4 116.8-46.4 49.6-102.4 81.6-164.8 94.4-40 8-78.4 8-118.4 0-62.4-11.2-118.4-43.2-164.8-92.8-43.2-46.4-60.8-94.4-70.4-118.4-11.2-28.8-28.8-76.8-24-142.4 3.2-48 19.2-96 48-142.4 11.2-17.6 25.6-41.6 46.4-70.4 6.4-9.6 11.2-16 16-22.4l1.6-1.6c12.8-17.6 20.8-28.8 28.8-44.8 8-17.6 14.4-35.2 19.2-52.8 3.2-12.8 14.4-20.8 27.2-20.8h265.6c12.8 0 24 8 27.2 20.8 4.8 19.2 11.2 36.8 19.2 51.2 8 16 16 27.2 27.2 43.2l25.6 35.2c16 22.4 28.8 41.6 40 60.8s41.6 72 46.4 142.4c3.2 65.6-14.4 113.6-24 142.4zM755.2 764.8c9.6-25.6 24-64 19.2-116.8-4.8-57.6-30.4-102.4-40-118.4s-22.4-35.2-36.8-56l-24-35.2c-12.8-17.6-22.4-32-32-51.2-6.4-12.8-12.8-27.2-17.6-41.6h-224c-4.8 14.4-9.6 27.2-16 41.6-9.6 20.8-19.2 35.2-33.6 52.8l-1.6 1.6c-4.8 6.4-9.6 12.8-16 22.4-19.2 27.2-33.6 49.6-44.8 67.2-8 14.4-35.2 59.2-40 118.4-4.8 52.8 9.6 91.2 20.8 118.4 8 20.8 22.4 60.8 59.2 99.2 40 40 84.8 65.6 136 76.8 32 6.4 64 6.4 96 0 51.2-11.2 96-36.8 136-78.4 36.8-38.4 51.2-78.4 59.2-99.2v-1.6zM614.4 214.4h-204.8c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h203.2c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-27.2 28.8zM579.2 75.2h-134.4c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h134.4c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8z" />
<glyph unicode="&#xefde;" glyph-name="mail-reply" d="M990.4 408l-76.8 76.8c-8 8-19.2 12.8-32 12.8s-24-4.8-32-12.8l-163.2-164.8c-6.4-6.4-9.6-14.4-12.8-22.4l-20.8-97.6c-3.2-14.4 1.6-30.4 12.8-41.6 8-8 20.8-12.8 32-12.8 3.2 0 6.4 0 9.6 1.6l97.6 20.8c8 1.6 16 6.4 22.4 12.8l163.2 163.2c8 8 12.8 19.2 12.8 32 1.6 11.2-3.2 24-12.8 32zM788.8 222.4l-78.4-17.6 17.6 78.4 153.6 153.6 60.8-60.8-153.6-153.6zM539.2 264h-427.2c-19.2 0-35.2 16-35.2 35.2v484.8l371.2-225.6c16-9.6 32-14.4 49.6-14.4s35.2 4.8 49.6 14.4l374.4 225.6v-220.8c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v224c0 49.6-41.6 91.2-91.2 91.2h-776c-49.6 0-91.2-41.6-91.2-91.2v-488c0-49.6 40-91.2 91.2-91.2h428.8c16 0 28.8 12.8 28.8 28.8s-14.4 27.2-30.4 27.2zM520 606.4c-12.8-8-28.8-8-41.6 0l-358.4 216h756.8l-356.8-216z" />
<glyph unicode="&#xefee;" glyph-name="podcast" d="M512 323.2c51.2 0 99.2 19.2 134.4 56 35.2 35.2 54.4 81.6 52.8 131.2v305.6c0 104-84.8 187.2-187.2 187.2-104 0-187.2-84.8-187.2-187.2v-304c-1.6-104 83.2-188.8 187.2-188.8zM379.2 816c0 72 59.2 131.2 131.2 131.2s131.2-59.2 131.2-131.2v-305.6c0-35.2-12.8-67.2-36.8-92.8-25.6-25.6-59.2-40-94.4-40-72 0-131.2 59.2-131.2 131.2v307.2zM843.2 520c0 16-12.8 28.8-28.8 28.8s-28.8-12.8-28.8-28.8c0-152-123.2-275.2-276.8-275.2-152 0-275.2 123.2-275.2 275.2 0 16-12.8 28.8-28.8 28.8s-28.8-12.8-28.8-28.8c0-172.8 132.8-315.2 302.4-329.6v-113.6h-112c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h280c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-112v113.6c174.4 12.8 308.8 155.2 308.8 329.6z" />
<glyph unicode="&#xf0a8;" glyph-name="pencil" d="M990.4 819.2c-54.4 56-108.8 113.6-166.4 168-9.6 9.6-20.8 16-33.6 16s-24-4.8-33.6-12.8l-624-620.8c-8-8-14.4-19.2-19.2-30.4l-91.2-278.4c-3.2-9.6-1.6-20.8 3.2-28.8 3.2-4.8 11.2-12.8 27.2-12.8h4.8l281.6 94.4c11.2 3.2 20.8 9.6 30.4 19.2l620.8 620.8c9.6 9.6 14.4 20.8 14.4 33.6-1.6 11.2-6.4 24-14.4 32zM329.6 172.8c-1.6-1.6-4.8-4.8-8-4.8l-232-78.4 76.8 230.4c1.6 3.2 3.2 6.4 4.8 8l462.4 460.8 156.8-156.8-460.8-459.2zM830.4 673.6l-156.8 156.8 115.2 113.6c52.8-51.2 105.6-105.6 155.2-156.8l-113.6-113.6z" />
<glyph unicode="&#xf335;" glyph-name="text-align-left" d="M48 904h928c16 0 28.8 12.8 28.8 28.8s-12.8 27.2-28.8 27.2h-928c-16 0-27.2-12.8-27.2-27.2s11.2-28.8 27.2-28.8zM976 680h-928c-16 0-28.8-12.8-28.8-28.8s12.8-27.2 28.8-27.2h928c16 0 28.8 12.8 28.8 28.8s-12.8 27.2-28.8 27.2zM976 400h-928c-16 0-28.8-12.8-28.8-28.8s12.8-27.2 28.8-27.2h928c16 0 28.8 12.8 28.8 28.8s-12.8 27.2-28.8 27.2zM686.4 120h-638.4c-16 0-28.8-12.8-28.8-28.8s12.8-27.2 28.8-27.2h638.4c16 0 28.8 12.8 28.8 28.8s-14.4 27.2-28.8 27.2z" />
<glyph unicode="&#xf338;" glyph-name="text" d="M844.8 1003.2h-665.6c-54.4 0-97.6-43.2-97.6-96v-91.2c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v91.2c0 22.4 17.6 41.6 41.6 41.6h216v-872h-104c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h443.2c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-104v870.4h216c22.4 0 41.6-17.6 41.6-41.6v-91.2c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v92.8c-4.8 52.8-48 96-102.4 96zM572.8 75.2h-121.6v872h121.6v-872z" />
<glyph unicode="&#xf33b;" glyph-name="heading" d="M806.4 1003.2h-588.8c-51.2 0-94.4-41.6-94.4-94.4v-92.8c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v94.4c0 20.8 17.6 38.4 38.4 38.4h180.8v-622.4h-92.8c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h408c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-91.2v620.8h184c20.8 0 38.4-17.6 38.4-38.4v-92.8c0-16 12.8-28.8 28.8-28.8s28.8 12.8 28.8 28.8v94.4c-3.2 51.2-44.8 92.8-97.6 92.8zM568 324.8h-112v622.4h112v-622.4zM856 75.2h-688c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h689.6c16 0 28.8 12.8 28.8 28.8s-14.4 28.8-30.4 28.8z" />
<glyph unicode="&#xf345;" glyph-name="thumbs-up" d="M153.6 632h-51.2c-46.4 0-83.2-36.8-83.2-83.2v-368c0-46.4 36.8-83.2 83.2-83.2h49.6c46.4 0 83.2 36.8 83.2 83.2v368c1.6 46.4-35.2 83.2-81.6 83.2zM180.8 180.8c0-14.4-12.8-27.2-27.2-27.2h-51.2c-14.4 0-27.2 12.8-27.2 27.2v368c0 14.4 12.8 27.2 27.2 27.2h49.6c14.4 0 27.2-12.8 27.2-27.2v-368zM1001.6 568c-1.6 6.4-1.6 12.8-3.2 17.6-9.6 33.6-30.4 59.2-57.6 73.6-27.2 12.8-54.4 12.8-78.4 12.8h-187.2l27.2 124.8c4.8 19.2 9.6 43.2 3.2 68.8-12.8 43.2-59.2 70.4-102.4 59.2-27.2-6.4-48-27.2-62.4-41.6-8-8-20.8-20.8-38.4-36.8-155.2-152-185.6-184-190.4-200-8-20.8-8-41.6-8-62.4v-350.4c0-27.2 0-73.6 30.4-104s75.2-32 104-32h320c19.2 0 44.8 0 67.2 12.8 32 17.6 46.4 51.2 56 73.6 75.2 174.4 115.2 281.6 121.6 318.4 1.6 24 1.6 46.4-1.6 65.6zM945.6 510.4c-3.2-17.6-22.4-83.2-116.8-305.6-8-20.8-17.6-38.4-30.4-46.4-9.6-4.8-25.6-4.8-40-4.8h-316.8c-27.2 0-52.8 1.6-67.2 14.4-12.8 12.8-14.4 40-14.4 65.6v350.4c0 16 0 28.8 4.8 40 14.4 22.4 129.6 132.8 179.2 180.8 16 16 30.4 28.8 38.4 36.8 11.2 11.2 24 24 36.8 27.2s30.4-6.4 35.2-20.8c3.2-11.2 0-27.2-3.2-41.6l-35.2-160c-1.6-8 0-17.6 4.8-24s12.8-11.2 22.4-9.6l220.8 3.2c19.2 0 38.4 0 51.2-6.4s24-20.8 28.8-38.4c1.6-3.2 1.6-8 3.2-11.2 1.6-14.4 1.6-30.4-1.6-49.6z" />
<glyph unicode="&#xf3c1;" glyph-name="twitter" d="M329.6 97.6c-113.6 0-222.4 32-313.6 94.4-11.2 8-16 20.8-11.2 33.6s17.6 19.2 30.4 17.6c14.4-1.6 28.8-3.2 43.2-3.2 59.2 0 116.8 14.4 168 40-62.4 22.4-112 73.6-134.4 140.8-3.2 9.6 0 20.8 6.4 27.2 1.6 1.6 3.2 3.2 4.8 3.2-49.6 41.6-80 102.4-80 171.2v1.6c0 9.6 4.8 19.2 14.4 24 4.8 3.2 11.2 4.8 16 3.2-19.2 33.6-28.8 70.4-28.8 110.4s9.6 78.4 30.4 112c4.8 8 12.8 12.8 22.4 14.4 9.6 0 17.6-3.2 24-9.6 86.4-107.2 211.2-174.4 347.2-188.8v12.8c0 123.2 99.2 222.4 222.4 222.4 56 0 108.8-20.8 150.4-59.2 22.4 6.4 44.8 20.8 67.2 35.2 9.6 6.4 20.8 12.8 30.4 19.2 9.6 4.8 20.8 4.8 28.8 0 9.6-6.4 14.4-16 12.8-27.2-1.6-8-4.8-40-16-72h24c11.2 1.6 22.4-3.2 28.8-12.8s6.4-22.4 0-30.4c-22.4-35.2-56-57.6-89.6-80l-14.4-9.6v-11.2c-1.6-283.2-219.2-579.2-584-579.2zM142.4 188.8c59.2-22.4 121.6-35.2 187.2-35.2 329.6 0 526.4 267.2 526.4 526.4v20.8c-1.6 9.6 3.2 19.2 11.2 25.6 9.6 6.4 19.2 12.8 27.2 19.2l33.6 24c-4.8 0-8 1.6-12.8 1.6-9.6 1.6-17.6 8-20.8 17.6s-3.2 19.2 3.2 27.2c3.2 4.8 8 12.8 11.2 20.8-22.4-12.8-46.4-25.6-73.6-30.4-9.6-1.6-19.2 1.6-25.6 8-32 33.6-75.2 52.8-121.6 52.8-91.2 0-166.4-75.2-166.4-166.4 0-11.2 1.6-24 4.8-38.4 1.6-8 0-17.6-6.4-24-4.8-6.4-14.4-9.6-22.4-9.6-148.8 9.6-289.6 73.6-392 180.8-4.8-14.4-6.4-30.4-6.4-46.4 0-56 27.2-107.2 73.6-137.6 11.2-6.4 14.4-19.2 11.2-32-3.2-11.2-16-19.2-27.2-19.2-17.6 0-36.8 3.2-54.4 8 16-60.8 64-108.8 128-121.6 12.8-3.2 22.4-14.4 22.4-27.2s-8-24-20.8-27.2c-17.6-4.8-33.6-6.4-48-8 30.4-44.8 80-73.6 136-75.2 11.2 0 22.4-8 25.6-19.2s0-24-9.6-30.4c-56-46.4-123.2-73.6-193.6-84.8z" />
<glyph unicode="&#xf3d0;" glyph-name="seo-title" d="M225.6 932.8h572.8c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-572.8c-16 0-28.8-12.8-28.8-28.8s14.4-28.8 28.8-28.8zM716.8 817.6h-409.6c-54.4 0-97.6-43.2-97.6-97.6v-30.4c0-54.4 43.2-97.6 97.6-97.6h409.6c54.4 0 97.6 43.2 97.6 97.6v30.4c0 54.4-43.2 97.6-97.6 97.6zM758.4 689.6c0-22.4-19.2-41.6-41.6-41.6h-409.6c-22.4 0-41.6 19.2-41.6 41.6v30.4c0 22.4 19.2 41.6 41.6 41.6h409.6c22.4 0 41.6-19.2 41.6-41.6v-30.4zM976 972.8c-16 0-28.8-12.8-28.8-28.8v-812.8c0-22.4-19.2-41.6-41.6-41.6h-787.2c-22.4 0-41.6 19.2-41.6 41.6v814.4c0 14.4-12.8 27.2-28.8 27.2s-27.2-12.8-27.2-27.2v-812.8c0-54.4 43.2-97.6 97.6-97.6h788.8c54.4 0 97.6 43.2 97.6 97.6v812.8c0 14.4-12.8 27.2-28.8 27.2z" />
<glyph unicode="&#xf3d8;" glyph-name="user" d="M512 587.2c118.4 0 214.4 92.8 214.4 208s-96 208-214.4 208-214.4-92.8-214.4-208 96-208 214.4-208zM512 947.2c88 0 158.4-68.8 158.4-152s-72-152-158.4-152c-88 0-158.4 68.8-158.4 152s70.4 152 158.4 152zM612.8 504h-201.6c-152 0-276.8-123.2-276.8-276.8v-158.4c0-27.2 22.4-49.6 49.6-49.6h654.4c27.2 0 49.6 22.4 49.6 49.6v158.4c1.6 153.6-123.2 276.8-275.2 276.8zM833.6 75.2h-643.2v152c0 121.6 99.2 220.8 220.8 220.8h201.6c121.6 0 220.8-99.2 220.8-220.8v-152z" />
<glyph unicode="&#xf43b;" glyph-name="seo" d="M251.2 544h49.6c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-49.6c-43.2 0-78.4-35.2-78.4-78.4v-49.6c0-43.2 35.2-78.4 78.4-78.4 11.2 0 22.4-9.6 22.4-22.4v-49.6c0-11.2-9.6-22.4-22.4-22.4h-49.6c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8h49.6c43.2 0 78.4 35.2 78.4 78.4v49.6c0 43.2-35.2 78.4-78.4 78.4-11.2 0-22.4 9.6-22.4 22.4v49.6c0 12.8 11.2 22.4 22.4 22.4zM492.8 544h70.4c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-70.4c-43.2 0-78.4-35.2-78.4-78.4v-198.4c0-43.2 35.2-78.4 78.4-78.4h70.4c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-70.4c-11.2 0-22.4 9.6-22.4 22.4v72h51.2c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-51.2v72c0 6.4 9.6 16 22.4 16zM772.8 600h-38.4c-43.2 0-78.4-35.2-78.4-78.4v-196.8c0-43.2 35.2-78.4 78.4-78.4h38.4c43.2 0 78.4 35.2 78.4 78.4v196.8c0 43.2-35.2 78.4-78.4 78.4zM795.2 324.8c0-12.8-9.6-22.4-22.4-22.4h-38.4c-12.8 0-22.4 9.6-22.4 22.4v196.8c0 12.8 9.6 22.4 22.4 22.4h38.4c12.8 0 22.4-9.6 22.4-22.4v-196.8zM928 939.2h-832c-41.6 0-76.8-33.6-76.8-76.8v-700.8c0-41.6 33.6-76.8 76.8-76.8h832c41.6 0 76.8 33.6 76.8 76.8v700.8c0 41.6-35.2 76.8-76.8 76.8zM96 883.2h832c11.2 0 20.8-9.6 20.8-20.8v-132.8h-872v132.8c0 11.2 8 20.8 19.2 20.8zM928 140.8h-832c-11.2 0-20.8 9.6-20.8 20.8v512h872v-512c1.6-11.2-8-20.8-19.2-20.8zM587.2 779.2h1.6c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-1.6c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8zM697.6 779.2h1.6c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-1.6c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8zM808 779.2h1.6c16 0 28.8 12.8 28.8 28.8s-12.8 28.8-28.8 28.8h-1.6c-16 0-28.8-12.8-28.8-28.8s12.8-28.8 28.8-28.8z" />
<glyph unicode="&#xf485;" glyph-name="youtube" d="M987.2 750.4c-11.2 43.2-44.8 76.8-88 88-76.8 20.8-387.2 20.8-387.2 20.8s-310.4 0-387.2-20.8c-43.2-11.2-76.8-44.8-88-88-20.8-78.4-20.8-238.4-20.8-238.4s0-161.6 20.8-238.4c11.2-43.2 44.8-76.8 88-88 76.8-20.8 387.2-20.8 387.2-20.8s310.4 0 387.2 20.8c43.2 11.2 76.8 44.8 88 88 20.8 76.8 20.8 238.4 20.8 238.4s0 160-20.8 238.4zM412.8 363.2v297.6l257.6-148.8-257.6-148.8z" />
</font></defs></svg>

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@@ -0,0 +1 @@
<svg width="38" height="38" viewBox="0 0 38 38" xmlns="http://www.w3.org/2000/svg" stroke="#6c7781"><g fill="none" fill-rule="evenodd"><g transform="translate(1 1)" stroke-width="2"><circle stroke-opacity=".5" cx="18" cy="18" r="18"/><path d="M36 18c0-9.94-8.06-18-18-18"><animateTransform attributeName="transform" type="rotate" from="0 18 18" to="360 18 18" dur="1s" repeatCount="indefinite"/></path></g></g></svg>

After

Width:  |  Height:  |  Size: 417 B

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<svg viewBox="0 0 630 101.88" xmlns="http://www.w3.org/2000/svg"><g fill="#636eb9"><path d="m235.33 89.2-12.02-17.2a19.23 19.23 0 0 1 -2.27.09h-13.28v17.11h-10.93v-58.84h24.17c15.46 0 25.05 7.9 25.05 20.93 0 8.91-4.54 15.47-12.53 18.58l13.58 19.33zm-14.8-49.59h-12.77v23.45h12.77c9.59 0 14.54-4.37 14.54-11.77s-4.95-11.68-14.54-11.68z"/><path d="m294.41 62.89v26.31h-9.92v-5.46c-2.52 3.87-7.4 6.05-14.12 6.05-10.25 0-16.73-5.63-16.73-13.45 0-7.48 5.05-13.36 18.66-13.36h11.6v-.68c0-6.13-3.7-9.75-11.18-9.75-5 0-10.25 1.68-13.61 4.46l-4.11-7.65c4.79-3.7 11.77-5.55 19-5.55 12.93 0 20.41 6.19 20.41 19.08zm-10.51 12.28v-5.17h-10.84c-7.14 0-9.08 2.69-9.08 6 0 3.78 3.2 6.22 8.58 6.22 5.12-.08 9.58-2.43 11.34-7.05z"/><path d="m352.07 63.48v25.72h-10.51v-24.37c0-8-3.95-11.86-10.68-11.86-7.48 0-12.52 4.54-12.52 13.54v22.69h-10.51v-44.88h10v5.8c3.45-4.12 8.92-6.31 15.47-6.31 10.76 0 18.75 6.19 18.75 19.67z"/><path d="m383.75 70-7.82 7.4v11.8h-10.51v-62.37h10.51v37.66l21.77-20.17h12.61l-18.75 18.83 20.51 26.05h-12.77z"/></g><g fill="#090e11"><path d="m473.93 89.2-.08-39-19.34 32.28h-4.87l-19.33-31.78v38.5h-10.43v-58.84h9l23.36 39 22.95-39h9l.08 58.84z"/><path d="m536.71 62.89v26.31h-9.92v-5.46c-2.52 3.87-7.4 6.05-14.12 6.05-10.25 0-16.73-5.63-16.73-13.45 0-7.48 5.06-13.34 18.66-13.34h11.6v-.7c0-6.13-3.7-9.75-11.18-9.75-5 0-10.25 1.68-13.61 4.46l-4.12-7.65c4.79-3.7 11.77-5.55 19-5.55 12.94 0 20.42 6.19 20.42 19.08zm-10.51 12.28v-5.17h-10.84c-7.15 0-9.08 2.69-9.08 6 0 3.78 3.2 6.22 8.58 6.22 5.14-.08 9.58-2.43 11.34-7.05z"/><path d="m577.13 86.76c-2.52 2-6.3 3-10.08 3-9.84 0-15.47-5.21-15.47-15.13v-21.57h-7.4v-8.41h7.4v-10.25h10.51v10.25h12v8.41h-12v21.35c0 4.37 2.18 6.72 6.22 6.72a9.38 9.38 0 0 0 5.88-1.85z"/><path d="m630 63.48v25.72h-10.51v-24.37c0-8-4-11.86-10.67-11.86-7.48 0-12.53 4.54-12.53 13.54v22.69h-10.5v-62.37h10.5v22.7c3.45-3.7 8.75-5.72 15-5.72 10.71 0 18.71 6.19 18.71 19.67z"/><path d="m165.97 52.31-27.36 1.23 4.82 7.55-45.63 29.16-45.25-19.01-52.55 21.89 3.64 8.75 48.89-20.37 46.18 19.4 49.82-31.84 4.83 7.55z"/></g><path d="m19.43 80.31 33.11-13.8 1.62.68v-19.61h-34.73zm75.76-80.31v84.43l2.61 1.1 32.12-20.53v-65zm-37.88 68.52 34.69 14.58v-59.31h-34.69z" fill="#636eb9"/></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<svg viewBox="0 0 462.03 462.03" xmlns="http://www.w3.org/2000/svg" width="20" class="rank-math-icon"><g fill="#fff"><path d="m462 234.84-76.17 3.43 13.43 21-127 81.18-126-52.93-146.26 60.97 10.14 24.34 136.1-56.71 128.57 54 138.69-88.61 13.43 21z"/><path d="m54.1 312.78 92.18-38.41 4.49 1.89v-54.58h-96.67zm210.9-223.57v235.05l7.26 3 89.43-57.05v-181zm-105.44 190.79 96.67 40.62v-165.19h-96.67z"/></g></svg>

After

Width:  |  Height:  |  Size: 449 B

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<svg opacity=".7" style="margin-bottom:-7px;width:24px" viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg"><path d="m17 2a1.0001 1.0001 0 0 0-0.11133 0.0058594c-2.6982 0.060284-4.8887 2.2822-4.8887 4.9941 0 2.6994 1.9427 5 4.375 5 0.60058 0 1.1422-0.094264 1.625-0.26562v26.266h-1a1.0001 1.0001 0 1 0 0 2c0.55454 0 1 0.44546 1 1s-0.44546 1-1 1h-1a1.0001 1.0001 0 0 0-1 1v4a1.0001 1.0001 0 0 0 1 1h18a1.0001 1.0001 0 0 0 1-1v-4a1.0001 1.0001 0 0 0-1-1h-1c-0.55454 0-1-0.44546-1-1s0.44546-1 1-1a1.0001 1.0001 0 0 0 0.099609-0.003906 1.0001 1.0001 0 0 0-0.099609-1.9961h-1v-26.266c0.48282 0.17136 1.0244 0.26562 1.625 0.26562 2.4323 0 4.375-2.3006 4.375-5 0-2.7153-2.1957-4.939-4.8984-4.9941a1.0001 1.0001 0 0 0-0.10156-0.0058594h-16zm0 2c2.7341 0 4.9319 2.1644 4.9941 4.8828a1.0001 1.0001 0 0 0 0.29492 0.83398 1.0001 1.0001 0 0 0 0.00586 0.0058593 1.0001 1.0001 0 0 0 0.013672 0.013672 1.0001 1.0001 0 0 0 0.84961 0.26367h3.6738a1.0001 1.0001 0 0 0 0.88867-0.29297 1.0001 1.0001 0 0 0 0.001953-0.0019531 1.0001 1.0001 0 0 0 0.00586-0.0058593 1.0001 1.0001 0 0 0 0.007812-0.0078126 1.0001 1.0001 0 0 0 0.26953-0.81641c0.066301-2.7147 2.2627-4.875 4.9941-4.875 1.6685 0 3 1.3315 3 3 0 1.7186-1.3073 3-2.375 3-0.74136 0-1.1462-0.18-1.3477-0.34961-0.20142-0.16961-0.27734-0.34314-0.27734-0.65039 0-0.51089 0.11963-0.67733 0.24805-0.79102 0.12842-0.11369 0.36929-0.20898 0.75195-0.20898a1.0001 1.0001 0 1 0 0-2c-0.72233 0-1.4828 0.18583-2.0781 0.71289s-0.92188 1.361-0.92188 2.2871v29h-10v-29c0-0.92646-0.32831-1.762-0.92383-2.2891s-1.3541-0.71094-2.0762-0.71094a1.0001 1.0001 0 1 0 0 2c0.38297 0 0.62372 0.095499 0.75195 0.20898 0.12824 0.11349 0.24805 0.27948 0.24805 0.79102 0 0.30725-0.07592 0.48078-0.27734 0.65039-0.20142 0.16961-0.6063 0.34961-1.3477 0.34961-1.0677 0-2.375-1.2814-2.375-3 0-1.6685 1.3315-3 3-3zm4.8848 0h6.2305c-1.0756 1.0512-1.8102 2.4444-2.0352 4h-2.1602c-0.22495-1.5556-0.95952-2.9488-2.0352-4zm1.0996 7.9863a1.0001 1.0001 0 0 0-0.98438 1.0137v22a1.0001 1.0001 0 1 0 2 0v-22a1.0001 1.0001 0 0 0-1.0156-1.0137zm4 0a1.0001 1.0001 0 0 0-0.98438 1.0137v22a1.0001 1.0001 0 1 0 2 0v-22a1.0001 1.0001 0 0 0-1.0156-1.0137zm-7.1719 28.014h10.375c-0.11353 0.31492-0.1875 0.64805-0.1875 1a1.0001 1.0001 0 0 0 0.29492 0.70898c0.027814 0.099682 0.066038 0.19467 0.10156 0.29102h-10.793c0.035524-0.096344 0.073748-0.19133 0.10156-0.29102a1.0001 1.0001 0 0 0 0.29492-0.70898c0-0.35195-0.07397-0.68508-0.1875-1zm-2.8125 4h16v2h-16v-2z" style="block-progression:tb;isolation:auto;mix-blend-mode:normal;text-decoration-color:#000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-transform:none"></path></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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 @@
!function(){"use strict";var t={n:function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,{a:n}),n},d:function(e,n){for(var r in n)t.o(n,r)&&!t.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:n[r]})},o:function(t,e){return Object.prototype.hasOwnProperty.call(t,e)}},e=jQuery,n=t.n(e),r=lodash;function i(t){return i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i(t)}function o(t,e){for(var n=0;n<e.length;n++){var r=e[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,u(r.key),r)}}function u(t){var e=function(t,e){if("object"!==i(t)||null===t)return t;var n=t[Symbol.toPrimitive];if(void 0!==n){var r=n.call(t,e||"default");if("object"!==i(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===e?String:Number)(t)}(t,"string");return"symbol"===i(e)?e:String(e)}var a=function(){function t(){var e,r,i;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),e=this,i=function(t){return n()(this.fields).each((function(e,r){t+=n()(r).val()})),t},(r=u(r="getContent"))in e?Object.defineProperty(e,r,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[r]=i,this.init(),this.hooks(),this.events()}var e,i,a;return e=t,(i=[{key:"init",value:function(){this.fields=this.getFields(),this.getContent=this.getContent.bind(this)}},{key:"hooks",value:function(){wp.hooks.addFilter("rank_math_content","rank-math",this.getContent,11)}},{key:"events",value:function(){n()(this.fields).each((function(t,e){n()(e).on("keyup change",(0,r.debounce)((function(){rankMathEditor.refresh("content")}),500))}))}},{key:"getFields",value:function(){var t=[];return n()("#the-list > tr:visible").each((function(e,r){var i=n()("#"+r.id+"-key").val();-1!==n().inArray(i,rankMath.analyzeFields)&&t.push("#"+r.id+"-value")})),t}}])&&o(e.prototype,i),a&&o(e,a),Object.defineProperty(e,"prototype",{writable:!1}),t}();n()((function(){setTimeout((function(){new a}),500)}))}();

View File

@@ -0,0 +1 @@
!function(){"use strict";var e={n:function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,{a:n}),n},d:function(t,n){for(var r in n)e.o(n,r)&&!e.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:n[r]})},o:function(e,t){return Object.prototype.hasOwnProperty.call(e,t)}},t=jQuery,n=e.n(t),r=wp.i18n;function o(e){return o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},o(e)}function a(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,(a=r.key,i=void 0,i=function(e,t){if("object"!==o(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!==o(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(a,"string"),"symbol"===o(i)?i:String(i)),r)}var a,i}var i=function(){function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.deactivatePlugins(),this.initializeClipBoard(),this.modeSelector(),this.dashboardWidget()}var t,o,i;return t=e,(o=[{key:"deactivatePlugins",value:function(){n()(".dashboard-deactivate-plugin").on("click",(function(e){e.preventDefault();var t=n()(this);return n().ajax({url:window.ajaxurl,type:"POST",data:{action:"rank_math_deactivate_plugins",security:rankMath.security,plugin:"all"}}).always((function(e){"1"===e&&t.parents(".rank-math-notice").remove()})),!1}))}},{key:"initializeClipBoard",value:function(){"undefined"!=typeof ClipboardJS&&(n()(".get-debug-report").on("click",(function(){return n()("#debug-report").slideDown(),n()("#debug-report textarea").trigger("focus").trigger("select"),n()(this).parent().fadeOut(),!1})),new ClipboardJS("#copy-for-support"))}},{key:"modeSelector",value:function(){n()(".rank-math-mode-selector a").on("click",(function(e){e.preventDefault();var t=n()(this).data("mode");return n().ajax({url:rankMath.api.root+"rankmath/v1/updateMode",method:"POST",beforeSend:function(e){e.setRequestHeader("X-WP-Nonce",rankMath.api.nonce)},data:{mode:t}}).done((function(e){e?window.location.reload():window.alert("Something went wrong! Please try again.")})),!1}))}},{key:"dashboardWidget",value:function(){var e=n()("#rank-math-dashboard-widget");e.length&&n().ajax({url:rankMath.api.root+"rankmath/v1/dashboardWidget",method:"GET",beforeSend:function(e){e.setRequestHeader("X-WP-Nonce",rankMath.api.nonce)}}).done((function(t){t?e.removeClass("rank-math-loading").html(t):e.removeClass("rank-math-loading").html((0,r.__)("Something went wrong! Please try again.","rank-math"))}))}}])&&a(t.prototype,o),i&&a(t,i),Object.defineProperty(t,"prototype",{writable:!1}),e}();n()((function(){new i}))}();

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
!function(){"use strict";var t={n:function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,{a:n}),n},d:function(e,n){for(var r in n)t.o(n,r)&&!t.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:n[r]})},o:function(t,e){return Object.prototype.hasOwnProperty.call(t,e)}},e=jQuery,n=t.n(e),r=lodash,i=wp.hooks;function o(t){return o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},o(t)}function a(t,e){for(var n=0;n<e.length;n++){var r=e[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,u(r.key),r)}}function u(t){var e=function(t,e){if("object"!==o(t)||null===t)return t;var n=t[Symbol.toPrimitive];if(void 0!==n){var r=n.call(t,e||"default");if("object"!==o(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===e?String:Number)(t)}(t,"string");return"symbol"===o(e)?e:String(e)}new(function(){function t(){var e,n,r;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),e=this,r=[],(n=u(n="fields"))in e?Object.defineProperty(e,n,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[n]=r,(0,i.addAction)("rank_math_loaded","rank-math",this.init.bind(this))}var e,o,l;return e=t,(o=[{key:"init",value:function(){this.getFields(),this.events()}},{key:"getFields",value:function(){var t=this;n()("#the-list > tr:visible").each((function(e,r){var i=n()("#"+r.id+"-key").val();-1!==n().inArray(i,rankMath.analyzeFields)&&t.fields.push("#"+r.id+"-value")}))}},{key:"events",value:function(){(0,i.addFilter)("rank_math_content","rank-math",this.getContent.bind(this)),n()(this.fields).each((function(t,e){n()(e).on("keyup change",(0,r.debounce)((function(){rankMathEditor.refresh("content")}),500))}))}},{key:"getContent",value:function(t){return n()(this.fields).each((function(e,r){t+=n()(r).val()})),t}}])&&a(e.prototype,o),l&&a(e,l),Object.defineProperty(e,"prototype",{writable:!1}),t}())}();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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,5 @@
/*!
* Plugin: Rank Math
* URL: https://rankmath.com/wordpress/plugin/seo-suite/
* Name: rank-math-contact-info.css
*/:root{--rankmath-wp-adminbar-height: 0}.rank-math-contact-section{clear:left;margin:1rem 0}.rank-math-contact-section label{font-weight:bold}.rank-math-contact-hours-details .rank-math-opening-hours{margin-bottom:6px}.rank-math-contact-hours-details .rank-math-opening-hours:last-child{margin-bottom:0}.rank-math-contact-hours .rank-math-opening-days,.rank-math-contact-hours .rank-math-opening-time{display:block}.rank-math-phone-number{margin:6px 0}.rank-math-contact-map iframe{width:100%;height:300px;border:0}.clear{clear:both}

View File

@@ -0,0 +1,5 @@
/*!
* Plugin: Rank Math
* URL: https://rankmath.com/wordpress/plugin/seo-suite/
* Name: rank-math-seo-score.css
*/:root{--rankmath-wp-adminbar-height: 0}.rank-math-seo-score{font-family:sans-serif;position:relative;display:inline-block;height:96px;width:96px;margin:20px 20px 30px;text-align:center;color:#fff;border:none;border-radius:50%;background:#eee;-webkit-box-shadow:1px 1px 1px #bbb;box-shadow:1px 1px 1px #bbb}.rank-math-seo-score.before-content{margin:0 0 30px 20px;float:right}.rank-math-seo-score.after-content{margin:20px 0 30px 20px}.rank-math-seo-score.as-shortcode{display:inline-block}.rank-math-seo-score .label{font-size:12px;position:absolute;top:100px;left:0;display:block;width:100%;color:#979ea5}.rank-math-seo-score .score{font-size:42px;font-weight:bold;line-height:42px;display:block}.rank-math-seo-score .outof{font-size:12px;font-weight:normal;line-height:12px;display:block;color:rgba(255,255,255,.7)}.rank-math-seo-score .backlink{font-size:12px;position:absolute;top:-94px;left:-12px;display:block;visibility:hidden;width:120px;padding:8px 10px;-webkit-transition:.25s all ease;transition:.25s all ease;-webkit-transition-delay:.25s;transition-delay:.25s;opacity:0;color:#a8a8a8;border:none;border-radius:8px;background:#fff;-webkit-box-shadow:0 4px 12px rgba(60,60,90,.15);box-shadow:0 4px 12px rgba(60,60,90,.15)}.rank-math-seo-score .backlink:after{position:absolute;bottom:-8px;left:calc(50% - 7px);width:0;height:0;content:"";border-width:8px 7.5px 0 7.5px;border-style:solid;border-color:#fff rgba(0,0,0,0) rgba(0,0,0,0) rgba(0,0,0,0)}.rank-math-seo-score:hover .backlink{top:-74px;visibility:visible;opacity:1}.rank-math-seo-score .poweredby{font-size:13px;color:#a8a8a8}.rank-math-seo-score .poweredby a{display:block;font-weight:normal;text-decoration:none;color:#6372b6;border:none}.rank-math-seo-score.unknown-seo{background:#eee;background:linear-gradient(135deg, #b9b9b9 0%, #989898 100%);-webkit-box-shadow:1px 1px 1px #bbb;box-shadow:1px 1px 1px #bbb}.rank-math-seo-score.bad-seo{background:#f8b0a2;background:linear-gradient(135deg, #f8b0a2 0%, #f1938c 100%);-webkit-box-shadow:1px 1px 1px #e48982;box-shadow:1px 1px 1px #e48982;filter:progid:DXImageTransform.Microsoft.gradient( startColorstr="#f8b0a2", endColorstr="#f1938c",GradientType=1 )}.rank-math-seo-score.good-seo{background:#fdd07a;background:linear-gradient(135deg, #fdd07a 0%, #fcbe6c 100%);-webkit-box-shadow:1px 1px 1px #efb463;box-shadow:1px 1px 1px #efb463;filter:progid:DXImageTransform.Microsoft.gradient( startColorstr="#fdd07a", endColorstr="#fcbe6c",GradientType=1 )}.rank-math-seo-score.great-seo{background:#99d484;background:linear-gradient(135deg, #99d484 0%, #83c97f 100%);-webkit-box-shadow:1px 1px 1px #5ba857;box-shadow:1px 1px 1px #5ba857;filter:progid:DXImageTransform.Microsoft.gradient( startColorstr="#99d484", endColorstr="#83c97f",GradientType=1 )}.rank-math-seo-score.template-circle .score{margin-top:22px !important}.rank-math-seo-score.template-square{height:80px;width:110px;border-radius:12px}.rank-math-seo-score.template-square .score{margin:10px 12px;text-align:left}.rank-math-seo-score.template-square .outof{display:inline-block;margin-left:-8px}.rank-math-seo-score.template-square .label{font-size:13px;top:52px;left:14px;text-align:left;color:rgba(255,255,255,.8)}.rank-math-seo-score.template-square .backlink{left:-5px}.rank-math-seo-score.template-square.before-content{margin-bottom:20px}.rank-math-seo-score.template-square.after-content{margin-bottom:0}.theme-twentytwenty .rank-math-seo-score{width:96px !important}.theme-twentytwenty .rank-math-seo-score.template-square{width:110px !important}.theme-twentytwenty .rank-math-seo-score.before-content{margin:0 auto 30px auto;display:inherit;float:none}.theme-twentytwenty .rank-math-seo-score.template-circle .score,.theme-twentytwenty .rank-math-seo-score.template-square .score{-webkit-transform:translateY(22px);transform:translateY(22px)}

View File

@@ -0,0 +1,5 @@
/*!
* Plugin: Rank Math
* URL: https://rankmath.com/wordpress/plugin/seo-suite/
* Name: rank-math.css
*/:root{--rankmath-wp-adminbar-height: 0}#wp-admin-bar-rank-math .rank-math-icon{display:inline-block;top:6px;position:relative;padding-right:10px;line-height:1}#wp-admin-bar-rank-math .rank-math-icon svg{fill-rule:evenodd;fill:#dedede;height:21px;vertical-align:inherit}#wp-admin-bar-rank-math:hover .rank-math-icon svg{fill-rule:evenodd;fill:#00b9eb}#wp-admin-bar-rank-math span.rm-mark-page-icon{font-family:dashicons;font-size:19px;line-height:28px;margin:0 3px 0 -4px}

View File

@@ -0,0 +1,5 @@
/*!
* Plugin: Rank Math
* URL: https://rankmath.com/wordpress/plugin/seo-suite/
* Name: rank-math.css
*/:root{--rankmath-wp-adminbar-height:0}#wp-admin-bar-rank-math .rank-math-icon{display:inline-block;top:6px;position:relative;padding-right:10px;line-height:1}#wp-admin-bar-rank-math .rank-math-icon svg{fill-rule:evenodd;fill:#dedede;height:21px;vertical-align:inherit}#wp-admin-bar-rank-math:hover .rank-math-icon svg{fill-rule:evenodd;fill:#00b9eb}#wp-admin-bar-rank-math span.rm-mark-page-icon{font-family:dashicons;font-size:19px;line-height:28px;margin:0 3px 0 -4px}

View File

@@ -0,0 +1 @@
!function(){"use strict";var n,t={n:function(n){var a=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(a,{a:a}),a},d:function(n,a){for(var e in a)t.o(a,e)&&!t.o(n,e)&&Object.defineProperty(n,e,{enumerable:!0,get:a[e]})},o:function(n,t){return Object.prototype.hasOwnProperty.call(n,t)}},a=jQuery;(n=t.n(a)())((function(){window.rankMathFront={init:function(){this.adminMenu()},adminMenu:function(){var t=n("#wp-admin-bar-rank-math-mark-me"),a=this;t.on("click",".mark-page-as a",(function(t){t.preventDefault(),a.ajax("mark_page_as",{objectID:rankMath.objectID,objectType:rankMath.objectType,what:n(this).attr("href").replace("#","")}),n(this).find(".dashicons").length?n(this).find(".dashicons").remove():n(this).prepend('<span class="dashicons dashicons-yes" style="font-family:dashicons;font-size:19px;line-height:28px;margin:0 3px 0 -4px;"></span>')}))},ajax:function(t,a,e){return n.ajax({url:rankMath.ajaxurl,type:e||"POST",dataType:"json",data:n.extend(!0,{action:"rank_math_"+t,security:rankMath.security},a)})}},window.rankMathFront.init()}))}();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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,60 @@
<?php
/**
* Divi admin integration.
*
* @package RankMath
* @subpackage RankMath\Core
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Divi;
use RankMath\Traits\Hooker;
defined( 'ABSPATH' ) || exit;
/**
* Divi class.
*/
class Divi_Admin {
use Hooker;
/**
* Class constructor.
*/
public function __construct() {
$this->init();
}
/**
* Intialize Divi admin.
*/
public function init() {
$screen = get_current_screen();
if ( 'toplevel_page_et_divi_options' === $screen->id ) {
$this->action( 'admin_enqueue_scripts', 'enqueue_divi_admin_scripts' );
}
}
/**
* Enqueue scripts for Divi admin options screen.
*/
public function enqueue_divi_admin_scripts() {
wp_enqueue_script(
'rank-math-divi-admin',
rank_math()->plugin_url() . 'includes/3rdparty/divi/assets/js/divi-admin.js',
[
'jquery',
'react',
'react-dom',
'wp-components',
'wp-element',
'wp-i18n',
'wp-polyfill',
],
rank_math()->version,
true
);
}
}

View File

@@ -0,0 +1,379 @@
<?php
/**
* Divi integration.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Core
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Divi;
use RankMath\KB;
use RankMath\Helper;
use RankMath\Helpers\Editor;
use RankMath\Helpers\Str;
use RankMath\Schema\DB as Schema_DB;
use RankMath\Schema\Admin as Schema_Admin;
use RankMath\Traits\Hooker;
use RankMath\Admin\Metabox\Screen;
use WP_Dependencies;
defined( 'ABSPATH' ) || exit;
/**
* Divi class.
*/
class Divi {
use Hooker;
/**
* Screen object.
*
* @var Screen
*/
private $screen;
/**
* Class constructor.
*/
public function __construct() {
$this->action( 'wp', 'init' );
}
/**
* Intialize.
*/
public function init() {
if ( ! $this->can_add_seo_tab() ) {
return;
}
$this->screen = new Screen();
$this->screen->load_screen( 'post' );
$this->action( 'template_redirect', 'set_window_lodash', 0 );
$this->action( 'wp_enqueue_scripts', 'register_rankmath_react' );
$this->action( 'wp_enqueue_scripts', 'add_json_data', 0 );
$this->action( 'wp_footer', 'footer_enqueue_scripts', 11 );
remove_action( 'wp_footer', [ rank_math()->json, 'output' ], 0 );
add_action( 'wp_footer', [ rank_math()->json, 'output' ], 11 );
$this->filter( 'script_loader_tag', 'add_et_tag', 10, 3 );
}
/**
* Set the global lodash variable.
*
* Lodash's `noConflict` would prevent UnderscoreJS from taking over the underscore (_)
* global variable. Because Underscore.js will later also be assigned to the underscore (_)
* global this function should run as early as possible.
*/
public function set_window_lodash() {
wp_register_script( 'rm-set-window-lodash', '', [ 'lodash' ], rank_math()->version, false );
wp_enqueue_script( 'rm-set-window-lodash' );
wp_add_inline_script(
'rm-set-window-lodash',
join(
"\r\n ",
[
'window.isLodash = function() {',
"if ( typeof window._ !== 'function' || typeof window._.forEach !== 'function' ) {",
'return false;',
'}',
'var isLodash = true;',
'window._.forEach(',
"[ 'cloneDeep', 'at', 'add', 'ary', 'attempt' ],",
'function( fn ) {',
"if ( isLodash && typeof window._[ fn ] !== 'function' ) {",
'isLodash = false;',
'}',
'}',
');',
'return isLodash;',
'}',
'if ( window.isLodash() ) { window.lodash = window._.noConflict(); }',
]
)
);
}
/**
* Register RankMath React and ReactDOM.
*
* Registers the native WP version of react with a custom handle for use in the
* RankMath module. Divi builder dequeues and deregisters native WP react scripts
* and replaces them with their own copy of React. Their copy might not be of the
* same version as the one RankMath requires.
*/
public function register_rankmath_react() {
$path = site_url( '/wp-includes/js/dist/vendor/' );
$suffix = wp_scripts_get_suffix();
wp_register_script( 'rm-react', "{$path}react{$suffix}.js", [ 'wp-polyfill', 'react' ], '16.13.1', true );
wp_register_script( 'rm-react-dom', "{$path}react-dom{$suffix}.js", [ 'rm-react', 'react-dom' ], '16.13.1', true );
}
/**
* Add JSON data.
*/
public function add_json_data() {
$this->maybe_load_editor_deps();
if ( Helper::has_cap( 'onpage_snippet' ) ) {
// Schema.
$schemas = $this->get_schema_data( get_the_ID() );
Helper::add_json( 'schemas', $schemas );
Helper::add_json( 'customSchemaImage', esc_url( rank_math()->plugin_url() . 'includes/modules/schema/assets/img/custom-schema-builder.jpg' ) );
// Trends.
$trends_upgrade_link = KB::get( 'pro', 'Divi General Tab Trends' );
Helper::add_json( 'trendsUpgradeLink', esc_url_raw( $trends_upgrade_link ) );
Helper::add_json( 'trendsPreviewImage', esc_url( rank_math()->plugin_url() . 'assets/admin/img/trends-preview.jpg' ) );
}
Helper::add_json(
'api',
[
'root' => esc_url_raw( get_rest_url() ),
'nonce' => ( wp_installing() && ! is_multisite() ) ? '' : wp_create_nonce( 'wp_rest' ),
]
);
Helper::add_json(
'keywordsApi',
[
'url' => 'https://api.rankmath.com/ltkw/v1/',
]
);
Helper::add_json( 'links', KB::get_links() );
Helper::add_json(
'validationl10n',
[
'regexErrorDefault' => __( 'Please use the correct format.', 'rank-math' ),
'requiredErrorDefault' => __( 'This field is required.', 'rank-math' ),
'emailErrorDefault' => __( 'Please enter a valid email address.', 'rank-math' ),
'urlErrorDefault' => __( 'Please enter a valid URL.', 'rank-math' ),
]
);
Helper::add_json( 'capitalizeTitle', Helper::get_settings( 'titles.capitalize_titles' ) );
Helper::add_json( 'blogName', get_bloginfo( 'name' ) );
if ( is_admin_bar_showing() && Helper::has_cap( 'admin_bar' ) ) {
Helper::add_json( 'objectID', get_the_ID() );
Helper::add_json( 'objectType', 'post' );
}
}
/**
* Enqueue scripts.
*/
public function footer_enqueue_scripts() {
/**
* Allow other plugins to enqueue/dequeue admin styles or scripts before plugin assets.
*/
$this->do_action( 'admin/before_editor_scripts' );
$divi_deps = [
'jquery',
'lodash',
'rm-react',
'rm-react-dom',
'rm-set-window-lodash',
'et-dynamic-asset-helpers',
'wp-api-fetch',
'wp-block-editor',
'wp-components',
'wp-compose',
'wp-core-data',
'wp-data',
'wp-element',
'wp-hooks',
'wp-media-utils',
'wp-wordcount',
'rank-math-analyzer',
'rank-math-app',
];
if ( is_admin_bar_showing() && Helper::has_cap( 'admin_bar' ) ) {
wp_enqueue_style( 'rank-math', rank_math()->assets() . 'css/rank-math.css', null, rank_math()->version );
wp_enqueue_script( 'rank-math', rank_math()->assets() . 'js/rank-math.js', [ 'jquery' ], rank_math()->version, true );
}
wp_enqueue_style( 'rank-math-common', rank_math()->plugin_url() . 'assets/admin/css/common.css', null, rank_math()->version );
wp_enqueue_style( 'wp-components' );
wp_enqueue_style( 'rank-math-editor', rank_math()->plugin_url() . 'includes/3rdparty/divi/assets/css/divi.css', [], rank_math()->version );
wp_register_script( 'rank-math-analyzer', rank_math()->plugin_url() . 'assets/admin/js/analyzer.js', null, rank_math()->version, true );
wp_enqueue_script( 'rank-math-editor', rank_math()->plugin_url() . 'includes/3rdparty/divi/assets/js/divi.js', $divi_deps, rank_math()->version, true );
wp_enqueue_script( 'rank-math-divi-iframe', rank_math()->plugin_url() . 'includes/3rdparty/divi/assets/js/divi-iframe.js', [ 'jquery', 'lodash' ], rank_math()->version, true );
wp_set_script_translations( 'rank-math-app', 'seo-by-rank-math', rank_math()->plugin_dir() . 'languages/' );
wp_set_script_translations( 'rank-math-divi-iframe', 'seo-by-rank-math', rank_math()->plugin_dir() . 'languages/' );
wp_set_script_translations( 'rank-math-editor', 'seo-by-rank-math', rank_math()->plugin_dir() . 'languages/' );
wp_set_script_translations( 'rank-math-analyzer', 'seo-by-rank-math', rank_math()->plugin_dir() . 'languages/' );
if ( Helper::is_module_active( 'rich-snippet' ) ) {
wp_enqueue_style( 'rank-math-schema', rank_math()->plugin_url() . 'includes/modules/schema/assets/css/schema.css', [ 'wp-components' ], rank_math()->version );
wp_enqueue_script( 'rank-math-schema', rank_math()->plugin_url() . 'includes/modules/schema/assets/js/schema-gutenberg.js', [ 'rank-math-editor' ], rank_math()->version, true );
wp_set_script_translations( 'rank-math-schema', 'seo-by-rank-math', rank_math()->plugin_dir() . 'languages/' );
}
rank_math()->variables->setup();
rank_math()->variables->setup_json();
$this->screen->localize();
$this->print_react_containers();
/**
* Allow other plugins to enqueue/dequeue admin styles or scripts after plugin assets.
*/
$this->do_action( 'admin/editor_scripts', $this->screen );
}
/**
* Add et attributes to script tags.
*
* @param string $tag The <script> tag for the enqueued script.
* @param string $handle The script's registered handle.
*
* @return string
*/
public function add_et_tag( $tag, $handle ) {
$script_handles = [
'rm-react',
'rm-react-dom',
'lodash',
'moment',
'rank-math',
'rank-math-analyzer',
'rank-math-schema',
'rank-math-editor',
'rank-math-content-ai',
'rank-math-app',
// Scripts required by pro version.
'wp-plugins',
'jquery-ui-autocomplete',
'rank-math-pro-editor',
'rank-math-schema-pro',
'rank-math-pro-schema-filters',
'rank-math-pro-news',
];
$exclude_handles = [
'wp-util',
'wp-backbone',
'wp-plupload',
'wp-mediaelement',
'wp-color-picker',
'wp-color-picker-alpha',
'wp-embed',
'wp-hooks',
];
if ( in_array( $handle, $exclude_handles, true ) ) {
return $tag;
}
if ( Str::starts_with( 'wp-', $handle ) || in_array( $handle, $script_handles, true ) ) {
// These tags load in parent window only, not in Divi iframe.
$tag = preg_replace(
'/<script\b(?![^>]*\bclass=)([^>]*)>/i',
'<script class="et_fb_ignore_iframe"$1>',
$tag
);
}
return $tag;
}
/**
* Print React containers onto the screen.
*/
public function print_react_containers() {
echo '<div id="rank-math-rm-app-root" class="et_fb_ignore_iframe"></div>';
echo '<div id="rank-math-rm-settings-bar-root" class="et_fb_ignore_iframe"></div>';
}
/**
* Can add SEO in Divi Page Builder.
*
* @return bool
*/
private function can_add_seo_tab() {
if (
! Helper::is_divi_frontend_editor() ||
! defined( 'ET_BUILDER_PRODUCT_VERSION' ) ||
! version_compare( '4.9.2', ET_BUILDER_PRODUCT_VERSION, 'le' )
) {
return false;
}
/**
* Filter to show/hide SEO Tab in Divi Editor.
*/
if ( ! $this->do_filter( 'divi/add_seo_tab', true ) ) {
return false;
}
$post_type = get_post_type();
if ( $post_type && ! Helper::get_settings( 'titles.pt_' . $post_type . '_add_meta_box' ) ) {
return false;
}
return Editor::can_add_editor();
}
/**
* Get Schema Data.
*
* @param int $post_id Post ID.
*
* @return array $schemas Schema Data.
*/
private function get_schema_data( $post_id ) {
$schemas = Schema_DB::get_schemas( $post_id );
if ( ! empty( $schemas ) || metadata_exists( 'post', $post_id, 'rank_math_rich_snippet' ) ) {
return $schemas;
}
$post_type = get_post_type( $post_id );
$default_type = ucfirst( Helper::get_default_schema_type( $post_id ) );
if ( ! $default_type ) {
return [];
}
$schemas['new-9999'] = [
'@type' => $default_type,
'metadata' => [
'title' => Helper::sanitize_schema_title( $default_type ),
'type' => 'template',
'shortcode' => uniqid( 's-' ),
'isPrimary' => true,
],
];
return $schemas;
}
/**
* Ensures required dependencies are loaded when toolbar is hidden.
*
* @return void
*/
private function maybe_load_editor_deps() {
if ( is_admin_bar_showing() ) {
return;
}
Helper::add_json( 'security', wp_create_nonce( 'rank-math-ajax-nonce' ) );
Helper::add_json( 'restNonce', ( wp_installing() && ! is_multisite() ) ? '' : wp_create_nonce( 'wp_rest' ) );
}
}

File diff suppressed because one or more lines are too long

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,218 @@
<?php
/**
* Elementor integration.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Core
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Elementor;
use RankMath\Helper;
use RankMath\Traits\Hooker;
use RankMath\Helpers\Editor;
defined( 'ABSPATH' ) || exit;
/**
* Elementor class.
*/
class Elementor {
use Hooker;
/**
* Class constructor.
*/
public function __construct() {
$this->action( 'init', 'init' );
$this->filter( 'rank_math/frontend/robots', 'robots' );
$this->filter( 'rank_math/frontend/disable_integration', 'disable_frontend_integration' );
}
/**
* Intialize.
*/
public function init() {
if ( ! $this->can_add_seo_tab() ) {
return;
}
$this->action( 'elementor/editor/before_enqueue_scripts', 'enqueue' );
add_action( 'elementor/editor/footer', [ rank_math()->json, 'output' ], 0 );
$this->action( 'elementor/editor/footer', 'start_capturing', 0 );
$this->action( 'elementor/editor/footer', 'end_capturing', 999 );
$this->filter( 'rank_math/sitemap/content_before_parse_html_images', 'apply_builder_in_content', 10, 2 );
}
/**
* Disable frontend integration on Elementor Maintenance page.
*
* @since 1.0.91
*
* @param boolean $value Whether to run the frontend integration.
*/
public function disable_frontend_integration( $value ) {
$mode = get_option( 'elementor_maintenance_mode_mode' );
if ( ! in_array( $mode, [ 'maintenance', 'coming_soon' ], true ) ) {
return $value;
}
if ( ! get_option( 'elementor_maintenance_mode_template_id' ) ) {
return $value;
}
$exclude_mode = get_option( 'elementor_maintenance_mode_exclude_mode', [] );
if ( 'logged_in' === $exclude_mode && is_user_logged_in() ) {
return $value;
}
if ( 'custom' !== $exclude_mode ) {
return true;
}
$exclude_roles = get_option( 'elementor_maintenance_mode_exclude_roles', [] );
$user = wp_get_current_user();
$user_roles = $user->roles;
if ( is_multisite() && is_super_admin() ) {
$user_roles[] = 'super_admin';
}
$compare_roles = array_intersect( $user_roles, $exclude_roles );
return ! empty( $compare_roles ) ? $value : true;
}
/**
* Start capturing buffer.
*/
public function start_capturing() {
ob_start();
}
/**
* End capturing buffer and add button.
*/
public function end_capturing() {
$output = \ob_get_clean();
$search = '/(<(div|button) class="elementor-component-tab elementor-panel-navigation-tab" data-tab="global">.*<\/(div|button)>)/m';
$replace = '${1}<${2} class="elementor-component-tab elementor-panel-navigation-tab" data-tab="rank-math">SEO</${2}>';
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- This comes from the output buffer, escaping it would break the output.
echo \preg_replace(
$search,
$replace,
$output
);
}
/**
* Enqueue scripts.
*/
public function enqueue() {
$deps = [
'wp-core-data',
'wp-components',
'wp-block-editor',
'wp-element',
'wp-data',
'wp-api-fetch',
'wp-media-utils',
'site-health',
'rank-math-analyzer',
'backbone-marionette',
'elementor-common-modules',
'rank-math-app',
];
if ( wp_script_is( 'elementor-v2-editor-app-bar', 'registered' ) ) {
$deps[] = 'elementor-v2-editor-app-bar';
}
$mode = \Elementor\Core\Settings\Manager::get_settings_managers( 'editorPreferences' )->get_model()->get_settings( 'ui_theme' );
wp_deregister_style( 'rank-math-editor' );
wp_enqueue_style( 'wp-components' );
wp_enqueue_style( 'site-health' );
wp_enqueue_style( 'rank-math-editor', rank_math()->plugin_url() . 'includes/3rdparty/elementor/assets/css/elementor.css', [ 'rank-math-common' ], rank_math()->version );
$media_query = '';
$dark_styles = $this->do_filter(
'elementor/dark_styles',
[
'rank-math-elementor-dark' => rank_math()->plugin_url() . 'includes/3rdparty/elementor/assets/css/elementor-dark.css',
]
);
if ( 'light' !== $mode ) {
$media_query = 'auto' === $mode ? '(prefers-color-scheme: dark)' : 'all';
foreach ( $dark_styles as $handle => $src ) {
wp_enqueue_style( $handle, $src, [], rank_math()->version, $media_query );
}
}
Helper::add_json( 'elementorDarkMode', $dark_styles );
wp_enqueue_script( 'rank-math-editor', rank_math()->plugin_url() . 'includes/3rdparty/elementor/assets/js/elementor.js', $deps, rank_math()->version, true );
rank_math()->variables->setup();
rank_math()->variables->setup_json();
}
/**
* Filters the post content before it is parsed for Sitmeap images..
* Used to apply the Elementor page editor on the post content.
*
* @since 1.0.38
*
* @param string $content The post content.
* @param int $post_id The post ID.
*
* @return string The post content.
*/
public function apply_builder_in_content( $content, $post_id ) {
if ( \Elementor\Plugin::$instance->db->is_built_with_elementor( $post_id ) ) {
return \Elementor\Plugin::$instance->frontend->get_builder_content( $post_id );
}
return $content;
}
/**
* Add SEO tab in Elementor Page Builder.
*
* @return bool
*/
private function can_add_seo_tab() {
/**
* Filter to show/hide SEO Tab in the Elementor Editor.
*/
if ( ! $this->do_filter( 'elementor/add_seo_tab', true ) ) {
return false;
}
$post_type = isset( $_GET['post'] ) ? get_post_type( absint( $_GET['post'] ) ) : '';
if ( $post_type && ! Helper::get_settings( 'titles.pt_' . $post_type . '_add_meta_box' ) ) {
return false;
}
return Editor::can_add_editor();
}
/**
* Change robots for Elementor Templates pages
*
* @param array $robots Array of robots to sanitize.
*
* @return array Modified robots.
*/
public function robots( $robots ) {
if ( is_singular( 'elementor_library' ) ) {
$robots['index'] = 'noindex';
$robots['follow'] = 'nofollow';
}
return $robots;
}
}

View File

@@ -0,0 +1,141 @@
<?php
/**
* Loco Translate inline i18n helper for injecting translations without JSON files.
*
* @since 1.0.256
* @package RankMath
* @subpackage RankMath\Core
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\ThirdParty\Loco;
use RankMath\Traits\Hooker;
use RankMath\Helper;
use RankMath\Helpers\Str;
defined( 'ABSPATH' ) || exit;
/**
* Loco_I18n_Inline class.
*/
class Loco_I18n_Inline {
use Hooker;
/**
* Class constructor.
*/
public function __construct() {
$this->action( 'rank-math/admin_enqueue_scripts', 'inject_settings_locale' );
}
/**
* Inject inline JED locale for settings screens when Loco is active.
*/
public function inject_settings_locale() {
// Load translations from all Loco locations (Customization, System, Author).
$json = $this->get_jed_json( 'rank-math', false );
if ( empty( $json ) ) {
return;
}
$inline = sprintf(
'try{if(window.wp&&wp.i18n&&wp.i18n.setLocaleData){wp.i18n.setLocaleData(%s,"rank-math");var __rm=wp.i18n.getLocaleData&&wp.i18n.getLocaleData("rank-math");if(__rm){wp.i18n.setLocaleData(__rm,"seo-by-rank-math");}}}catch(e){}',
$json
);
wp_add_inline_script( 'common', $inline, 'before' );
}
/**
* Build a JED locale JSON from the best available MO/PO for the current locale.
*
* @param string $domain Text domain (e.g. 'rank-math').
* @param bool $loco_only Whether to restrict to Loco-managed files only.
* @return string JSON string suitable for wp.i18n.setLocaleData(), or empty string.
*/
private function get_jed_json( $domain, $loco_only = true ) {
$locale = get_user_locale();
$file = $this->find_translation_file( $domain, $locale, $loco_only );
if ( ! $file ) {
return '';
}
return $this->build_jed_json( $file, $domain, $locale );
}
/**
* Build JED JSON from translation file.
*
* @param string $file Path to MO or PO file.
* @param string $domain Text domain.
* @param string $locale Locale.
* @return string JSON string or false.
*/
private function build_jed_json( $file, $domain, $locale ) {
require_once ABSPATH . WPINC . '/pomo/mo.php';
require_once ABSPATH . WPINC . '/pomo/po.php';
$translations = Str::ends_with( '.mo', $file ) ? new \MO() : new \PO();
if ( ! $translations->import_from_file( $file ) ) {
return false;
}
$data = [
'' => [
'domain' => $domain,
'lang' => $locale,
],
];
if ( ! empty( $translations->headers['plural-forms'] ) ) {
$data['']['plural-forms'] = $translations->headers['plural-forms'];
}
foreach ( $translations->entries as $entry ) {
if ( empty( $entry->translations ) ) {
continue;
}
$key = empty( $entry->context ) ? $entry->singular : $entry->context . "\004" . $entry->singular;
$data[ $key ] = $entry->translations;
}
return wp_json_encode( $data );
}
/**
* Find translation file for domain/locale.
*
* @param string $domain Text domain.
* @param string $locale Locale.
* @param bool $loco_only Restrict to Loco files only.
* @return string|false File path or false.
*/
private function find_translation_file( $domain, $locale, $loco_only ) {
$paths = [];
// 1) Loco "Customization" location.
$paths[] = WP_CONTENT_DIR . '/languages/loco/plugins/' . $domain . '-' . $locale . '.mo';
$paths[] = WP_CONTENT_DIR . '/languages/loco/plugins/' . $domain . '-' . $locale . '.po';
// 2) Loco "System" location (global WP languages dir).
if ( ! $loco_only ) {
$paths[] = WP_LANG_DIR . '/plugins/' . $domain . '-' . $locale . '.mo';
$paths[] = WP_LANG_DIR . '/plugins/' . $domain . '-' . $locale . '.po';
}
// 3) Loco "Author" location (plugin bundled languages directory).
$paths[] = RANK_MATH_PATH . 'languages/' . $domain . '-' . $locale . '.mo';
$paths[] = RANK_MATH_PATH . 'languages/' . $domain . '-' . $locale . '.po';
foreach ( $paths as $path ) {
if ( is_file( $path ) && is_readable( $path ) ) {
return $path;
}
}
return false;
}
}

View File

@@ -0,0 +1,482 @@
<?php
/**
* Admin bar menu.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Core
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath;
use RankMath\Paper\Paper;
use RankMath\Traits\Ajax;
use RankMath\Traits\Meta;
use RankMath\Traits\Hooker;
use RankMath\Helpers\Arr;
use RankMath\Helpers\Url;
use RankMath\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
* Admin_Bar_Menu class.
*/
class Admin_Bar_Menu {
use Hooker;
use Ajax;
use Meta;
/**
* The unique identifier used for the menu.
*
* @var string
*/
const MENU_IDENTIFIER = 'rank-math';
/**
* Hold menu items.
*
* @var array
*/
private $items = [];
/**
* Constructor method.
*/
public function __construct() {
$this->ajax( 'mark_page_as', 'mark_page_as' );
$this->action( 'admin_bar_menu', 'add_menu', 100 );
}
/**
* AJAX function to mark page as Pillar Content/Noindex/Nofollow.
*/
public function mark_page_as() {
check_ajax_referer( 'rank-math-ajax-nonce', 'security' );
$this->has_cap_ajax( 'onpage_general' );
$what = Param::post( 'what', '', FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH | FILTER_FLAG_STRIP_BACKTICK );
$object_id = Param::post( 'objectID', 0, FILTER_VALIDATE_INT );
$object_type = Param::post( 'objectType', '', FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH | FILTER_FLAG_STRIP_BACKTICK );
if ( ! $what || ! $object_id || ! $object_type ) {
return 0;
}
if ( 'pillar_content' === $what ) {
$current = $this->get_meta( $object_type, $object_id, 'rank_math_pillar_content' );
$updated = 'on' === $current ? 'off' : 'on';
$this->update_meta( $object_type, $object_id, 'rank_math_pillar_content', $updated );
die( '1' );
}
if ( 'noindex' === $what || 'nofollow' === $what ) {
$robots = (array) $this->get_meta( $object_type, $object_id, 'rank_math_robots' );
$robots = array_filter( $robots );
Arr::add_delete_value( $robots, $what );
$robots = $this->normalize_robots( $what, array_unique( $robots ) );
$this->update_meta( $object_type, $object_id, 'rank_math_robots', $robots );
if ( 'noindex' === $what ) {
$this->do_action( 'sitemap/invalidate_object_type', $object_type, $object_id );
}
die( '1' );
}
die();
}
/**
* Add SEO item to admin bar with context-specific submenu items.
*
* @param WP_Admin_Bar $wp_admin_bar Admin bar instance to add the menu to.
*/
public function add_menu( $wp_admin_bar ) {
if ( ! $this->can_add_menu() ) {
return;
}
$this->add_root_menu();
if ( Helper::has_cap( 'titles' ) ) {
$this->add_page_menu();
}
if ( $this->is_front() ) {
$this->add_seo_tools();
}
if ( $this->can_add_mark_menu() ) {
$this->add_mark_page_menu();
}
/**
* Add item to rank math admin bar node.
*
* @param Admin_Bar_Menu $this Class instance.
*/
$this->do_action( 'admin_bar/items', $this );
$this->add_order();
uasort( $this->items, [ $this, 'sort_by_priority' ] );
array_walk( $this->items, [ $wp_admin_bar, 'add_node' ] );
}
/**
* Normalize robots.
*
* @param string $what Current admin menu process.
* @param array $robots Array to normalize.
*
* @return array
*/
private function normalize_robots( $what, $robots ) {
if ( 'noindex' !== $what ) {
return $robots;
}
if ( ! in_array( 'noindex', $robots, true ) ) {
$robots[] = ! in_array( 'index', $robots, true ) ? 'index' : '';
return $robots;
}
if ( false !== ( $key = array_search( 'index', $robots ) ) ) { // @codingStandardsIgnoreLine
unset( $robots[ $key ] );
}
return $robots;
}
/**
* Keep original order when uasort() deals with equal "priority" values.
*/
private function add_order() {
$order = 0;
foreach ( $this->items as &$item ) {
$item['order'] = $order++;
}
}
/**
* Add root menu.
*/
private function add_root_menu() {
$first_menu = get_transient( 'rank_math_first_submenu_id' );
$first_menu = $first_menu && 'rank-math' !== $first_menu ? str_replace( 'rank-math-', '', $first_menu ) : '';
$this->items['main'] = [
'id' => self::MENU_IDENTIFIER,
'title' => '<span class="rank-math-icon">' . $this->get_icon() . '</span><span class="rank-math-text">' . esc_html__( 'Rank Math SEO', 'rank-math' ) . '</span>',
'href' => Helper::get_admin_url( $first_menu ),
'meta' => [ 'title' => esc_html__( 'Rank Math Dashboard', 'rank-math' ) ],
'priority' => 10,
];
if ( current_user_can( 'manage_options' ) ) {
$this->add_sub_menu(
'dashboard',
[
'title' => esc_html__( 'Dashboard', 'rank-math' ),
'href' => $this->items['main']['href'],
'meta' => [ 'title' => esc_html__( 'Dashboard', 'rank-math' ) ],
'priority' => 20,
]
);
}
}
/**
* Add page menu.
*/
private function add_page_menu() {
$hash = [
'add_home_menu' => is_front_page(),
'add_post_type_menu' => is_singular( Helper::get_accessible_post_types() ) || is_home(),
'add_date_menu' => is_date(),
'add_taxonomy_menu' => is_archive() && ! is_post_type_archive() && ! is_author(),
'add_search_menu' => is_search(),
];
foreach ( $hash as $func => $can_run ) {
if ( true === $can_run ) {
$this->$func();
break;
}
}
}
/**
* Add homepage menu
*/
private function add_home_menu() {
$this->add_sub_menu(
'home',
[
'title' => esc_html__( 'Homepage SEO', 'rank-math' ),
'href' => Helper::get_settings_url( 'titles', 'homepage' ),
'meta' => [ 'title' => esc_html__( 'Edit Homepage SEO Settings', 'rank-math' ) ],
'priority' => 35,
]
);
}
/**
* Add post_type menu
*/
private function add_post_type_menu() {
$post_type = get_post_type();
if ( ! $post_type ) {
return;
}
$name = get_post_type_object( $post_type )->labels->name;
if ( is_home() ) {
$post_type = 'page';
$name = esc_html__( 'Pages', 'rank-math' );
}
$this->add_sub_menu(
'posttype',
[
/* translators: Post Type Singular Name */
'title' => sprintf( esc_html__( 'SEO Settings for %s', 'rank-math' ), $name ),
'href' => Helper::get_settings_url( 'titles', 'post-type-' . $post_type ),
'meta' => [ 'title' => esc_html__( 'Edit default SEO settings for this post type', 'rank-math' ) ],
'priority' => 35,
]
);
}
/**
* Add taxonomy menu
*/
private function add_taxonomy_menu() {
$term = get_queried_object();
if ( empty( $term ) || ! ( $term instanceof \WP_Term ) ) {
return;
}
$labels = get_taxonomy_labels( get_taxonomy( $term->taxonomy ) );
$this->add_sub_menu(
'tax',
[
/* translators: Taxonomy Singular Name */
'title' => sprintf( esc_html__( 'SEO Settings for %s', 'rank-math' ), $labels->name ),
'href' => Helper::get_settings_url( 'titles', 'taxonomy-' . $term->taxonomy ),
'meta' => [ 'title' => esc_html__( 'Edit SEO settings for this archive page', 'rank-math' ) ],
'priority' => 35,
]
);
}
/**
* Add date archive menu
*/
private function add_date_menu() {
$this->add_sub_menu(
'date',
[
'title' => esc_html__( 'SEO Settings for Date Archives', 'rank-math' ),
'href' => Helper::get_settings_url( 'titles', 'global' ),
'meta' => [ 'title' => esc_html__( 'Edit SEO settings for this archive page', 'rank-math' ) ],
'priority' => 35,
]
);
}
/**
* Add search result menu
*/
private function add_search_menu() {
$this->add_sub_menu(
'search',
[
'title' => esc_html__( 'SEO Settings for Search Page', 'rank-math' ),
'href' => Helper::get_settings_url( 'titles', 'global' ),
'meta' => [ 'title' => esc_html__( 'Edit SEO settings for the search results page', 'rank-math' ) ],
'priority' => 35,
]
);
}
/**
* Add mark page menu.
*/
private function add_mark_page_menu() {
$this->add_sub_menu(
'mark-me',
[
'title' => esc_html__( 'Mark this page', 'rank-math' ),
'href' => '#',
'priority' => 100,
]
);
$is_pillar_content = '';
$dashicon_format = '<span class="dashicons dashicons-%s rm-mark-page-icon"></span>';
if ( is_singular( Helper::get_accessible_post_types() ) ) {
if ( get_post_meta( get_the_ID(), 'rank_math_pillar_content', true ) === 'on' ) {
$is_pillar_content = sprintf( $dashicon_format, 'yes' );
}
$this->add_sub_menu(
'pillar-content',
[
'title' => $is_pillar_content . esc_html__( 'As Pillar Content', 'rank-math' ),
'href' => '#pillar_content',
'meta' => [ 'class' => 'mark-page-as' ],
],
'mark-me'
);
}
if ( Paper::get() ) {
$robots = Paper::get()->get_robots();
$noindex_check = in_array( 'noindex', $robots, true ) ? sprintf( $dashicon_format, 'yes' ) : '';
$this->add_sub_menu(
'no-index',
[
'title' => $noindex_check . esc_html__( 'As NoIndex', 'rank-math' ),
'href' => '#noindex',
'meta' => [ 'class' => 'mark-page-as' ],
],
'mark-me'
);
$nofollow_check = in_array( 'nofollow', $robots, true ) ? sprintf( $dashicon_format, 'yes' ) : '';
$this->add_sub_menu(
'no-follow',
[
'title' => $nofollow_check . esc_html__( 'As NoFollow', 'rank-math' ),
'href' => '#nofollow',
'meta' => [ 'class' => 'mark-page-as' ],
],
'mark-me'
);
}
}
/**
* Third party SEO Tools, like the Google Structured Data Testing Tool.
*/
private function add_seo_tools() {
$this->add_sub_menu(
'third-party',
[
'title' => esc_html__( 'External Tools', 'rank-math' ),
'href' => '#',
'priority' => 200,
]
);
$url = rawurlencode( Url::get_current_url() );
$items = [
'google-pagespeed' => [
'title' => esc_html__( 'Google PageSpeed', 'rank-math' ),
'href' => 'https://developers.google.com/speed/pagespeed/insights/?url=' . $url,
'meta' => [ 'title' => esc_html__( 'Google PageSpeed Insights', 'rank-math' ) ],
],
'google-richresults-mobile' => [
'title' => esc_html__( 'Google Rich Results (Mobile)', 'rank-math' ),
'href' => 'https://search.google.com/test/rich-results?url=' . $url . '&user_agent=1',
'meta' => [ 'title' => esc_html__( 'Google Rich Results Test - Googlebot Smartphone', 'rank-math' ) ],
],
'google-richresults-desktop' => [
'title' => esc_html__( 'Google Rich Results (Desktop)', 'rank-math' ),
'href' => 'https://search.google.com/test/rich-results?url=' . $url . '&user_agent=2',
'meta' => [ 'title' => esc_html__( 'Google Rich Results Test - Googlebot Desktop', 'rank-math' ) ],
],
'fb-debugger' => [
'title' => esc_html__( 'Facebook Debugger', 'rank-math' ),
'href' => 'https://developers.facebook.com/tools/debug/sharing/?q=' . $url,
'meta' => [ 'title' => esc_html__( 'Facebook Sharing Debugger', 'rank-math' ) ],
],
];
foreach ( $items as $id => $args ) {
$args['meta']['target'] = '_blank';
$this->add_sub_menu( $id, $args, 'third-party' );
}
}
/**
* Add sub menu item
*
* @param string $id Unique ID for the node.
* @param array $args Arguments for adding a node.
* @param string $parent_node Node parent.
*/
public function add_sub_menu( $id, $args, $parent_node = '' ) {
$args['priority'] = isset( $args['priority'] ) ? $args['priority'] : 999;
$args['id'] = 'rank-math-' . $id;
$args['parent'] = '' !== $parent_node ? 'rank-math-' . $parent_node : self::MENU_IDENTIFIER;
$this->items[ $id ] = $args;
}
/**
* Can current user has capability for admin menu.
*
* @return bool
*/
private function can_add_menu() {
return Helper::has_cap( 'admin_bar' );
}
/**
* Can add mark me menu.
*
* @return bool
*/
private function can_add_mark_menu() {
return $this->is_front() && Helper::has_cap( 'onpage_general' );
}
/**
* Is frontend.
*
* @return bool
*/
private function is_front() {
return ! is_admin() && ! is_preview();
}
/**
* Sort admin bar items callback.
*
* @param array $item1 Item A to compare.
* @param array $item2 Item B to compare.
*
* @return integer
*/
private function sort_by_priority( $item1, $item2 ) {
if ( $item1['priority'] === $item2['priority'] ) {
return $item1['order'] < $item2['order'] ? -1 : 1;
}
return $item1['priority'] < $item2['priority'] ? -1 : 1;
}
/**
* Get Rank Math icon.
*
* @param integer $width Width of the icon.
*
* @return string
*/
private function get_icon( $width = 20 ) {
return '<svg viewBox="0 0 462.03 462.03" xmlns="http://www.w3.org/2000/svg" width="' . $width . '"><g><path d="m462 234.84-76.17 3.43 13.43 21-127 81.18-126-52.93-146.26 60.97 10.14 24.34 136.1-56.71 128.57 54 138.69-88.61 13.43 21z"/><path d="m54.1 312.78 92.18-38.41 4.49 1.89v-54.58h-96.67zm210.9-223.57v235.05l7.26 3 89.43-57.05v-181zm-105.44 190.79 96.67 40.62v-165.19h-96.67z"/></g></svg>';
}
}

View File

@@ -0,0 +1,52 @@
<?php
/**
* Breadcrumbs for the Rank Math pages.
*
* @since 1.0.44
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Helper;
use RankMath\Helpers\Param;
use RankMath\Google\Console;
defined( 'ABSPATH' ) || exit;
/**
* Admin Header class.
*
* @codeCoverageIgnore
*/
class Admin_Breadcrumbs {
/**
* Display Header.
*/
public function display() {
?>
<div class="rank-math-breadcrumbs-wrap">
<div class="rank-math-breadcrumbs">
<span><?php echo esc_html__( 'Dashboard', 'rank-math' ); ?></span>
<span class="divider">/</span>
<span class="active"><?php echo esc_html( $this->get_page_title() ); ?></span>
</div>
</div>
<?php
}
/**
* Get Current Admin Page Title.
*/
private function get_page_title() {
$base = __( 'Modules', 'rank-math' );
if ( is_network_admin() ) {
$base = __( 'Help', 'rank-math' );
}
$default = 'rank-math' === Param::get( 'page' ) ? $base : get_admin_page_title();
return str_replace( '_', ' ', Param::get( 'view', $default, FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_BACKTICK ) );
}
}

View File

@@ -0,0 +1,135 @@
<?php
/**
* The nav tabs on the Dashboard page.
*
* @since 1.0.40
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Helper;
use RankMath\Helpers\Security;
use RankMath\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
* Admin Dashboard Nav class.
*
* @codeCoverageIgnore
*/
class Admin_Dashboard_Nav {
/**
* Display dashboard tabs.
*/
public function display() {
$nav_links = $this->get_nav_links();
if ( empty( $nav_links ) ) {
return;
}
?>
<div class="rank-math-tab-nav" role="tablist" aria-orientation="horizontal">
<?php
foreach ( $nav_links as $id => $link ) {
$this->nav_link( $link );
}
?>
</div>
<?php
}
/**
* Get URL for dashboard nav links.
*
* @param array $link Link data.
* @return string Link URL.
*/
public function get_link_url( $link ) {
return is_network_admin() ?
Security::add_query_arg(
[
'page' => 'rank-math',
'view' => $link['id'],
],
network_admin_url( 'admin.php' )
) :
Helper::get_admin_url( $link['url'], $link['args'] );
}
/**
* Output dashboard nav link.
*
* @param array $link Link data.
* @return void
*/
public function nav_link( $link ) {
if ( isset( $link['cap'] ) && ! current_user_can( $link['cap'] ) ) {
return;
}
$default_tab = is_network_admin() ? 'help' : 'modules';
?>
<a
class="rank-math-tab<?php echo Param::get( 'view', $default_tab ) === sanitize_html_class( $link['id'] ) ? ' is-active' : ''; ?>"
href="<?php echo esc_url( $this->get_link_url( $link ) ); ?>"
title="<?php echo esc_attr( $link['title'] ); ?>">
<?php echo esc_html( $link['title'] ); ?>
</a>
<?php
}
/**
* Get dashbaord navigation links
*
* @return array
*/
private function get_nav_links() {
$links = [
'modules' => [
'id' => 'modules',
'url' => '',
'args' => 'view=modules',
'cap' => 'manage_options',
'title' => esc_html__( 'Modules', 'rank-math' ),
],
'help' => [
'id' => 'help',
'url' => '',
'args' => 'view=help',
'cap' => 'manage_options',
'title' => esc_html__( 'Help', 'rank-math' ),
],
'wizard' => [
'id' => 'wizard',
'url' => 'wizard',
'args' => '',
'cap' => 'manage_options',
'title' => esc_html__( 'Setup Wizard', 'rank-math' ),
],
];
if ( Helper::is_advanced_mode() ) {
$links['import-export'] = [
'id' => 'import-export',
'url' => 'status',
'args' => 'view=import_export',
'cap' => 'install_plugins',
'title' => esc_html__( 'Import &amp; Export', 'rank-math' ),
];
}
if ( Helper::is_plugin_active_for_network() ) {
unset( $links['help'] );
}
if ( is_network_admin() ) {
$links = [];
}
return apply_filters( 'rank_math/admin/dashboard_nav_links', $links );
}
}

View File

@@ -0,0 +1,157 @@
<?php
/**
* Header for the Rank Math pages
*
* @since 1.0.44
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Helper;
use RankMath\KB;
use RankMath\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
* Admin Header class.
*
* @codeCoverageIgnore
*/
class Admin_Header {
/**
* Hold current screen ID.
*
* @var Current screen ID.
*/
private $screen_id = '';
/**
* Display Header.
*
* @param bool $show_breadcrumbs Determines whether to show breadcrumbs or not.
*/
public function display( $show_breadcrumbs ) {
$logo_url = '<a href="' . esc_url( Helper::get_admin_url() ) . '"><i class="rm-icon rm-icon-rank-math"></i></a>';
$this->screen_id = $this->get_current_screen();
?>
<div class="rank-math-header">
<div class="rank-math-logo">
<?php echo $logo_url; // phpcs:ignore ?>
</div>
<h1 class="rank-math-logo-text">
Rank Math SEO
<?php do_action( 'rank_math/pro_badge' ); ?>
</h1>
<?php $this->get_search_options(); ?>
<?php $this->get_mode_selector(); ?>
<?php do_action( 'rank_math/before_help_link' ); ?>
<a href="<?php echo esc_url( $this->get_help_link() ); ?>" title="<?php esc_attr_e( 'Rank Math Knowledge Base', 'rank-math' ); ?>" target="_blank" class="button rank-math-help"><i class="dashicons dashicons-editor-help"></i></a>
</div>
<?php
// Breadcrumbs.
if ( $show_breadcrumbs ) {
rank_math()->admin->display_admin_breadcrumbs();
}
}
/**
* Get Search Options.
*/
private function get_search_options() {
if (
! in_array(
$this->screen_id,
[
'rank-math_page_rank-math-options-general',
'rank-math_page_rank-math-options-titles',
'rank-math_page_rank-math-options-sitemap',
],
true
)
) {
return;
}
?>
<div class="rank-math-search-options">
<div class="components-input-control">
<div class="components-input-control__container">
<!-- <i class="rm-icon rm-icon-search"></i> -->
<input type="search" class="components-input-control__input" value="" placeholder="<?php esc_attr_e( 'Search Options', 'rank-math' ); ?>" style="width: 100%;">
<!-- <em class="clear-search dashicons dashicons-no-alt"></em> -->
</div>
</div>
</div>
<?php
}
/**
* Get Mode Selector.
*/
private function get_mode_selector() {
if (
! in_array(
$this->screen_id,
[
'toplevel_page_rank-math',
'rank-math_page_rank-math-status',
],
true
)
) {
return;
}
$is_advanced_mode = Helper::is_advanced_mode();
?>
<div class="rank-math-mode-selector">
<a href="#" class="<?php echo ! $is_advanced_mode ? 'active' : ''; ?>" data-mode="easy"><?php esc_attr_e( 'Easy Mode', 'rank-math' ); ?></a>
<a href="#" class="<?php echo $is_advanced_mode ? 'active' : ''; ?>" data-mode="advanced"><?php esc_attr_e( 'Advanced Mode', 'rank-math' ); ?></a>
</div>
<?php
}
/**
* Get Current Screen ID.
*/
private function get_help_link() {
$links = [
'import-export-settings' => 'import_export' === Param::get( 'view' ),
'version-control' => 'version_control' === Param::get( 'view' ) || 'rank-math-status' === Param::get( 'page' ),
'general-settings' => 'rank-math-options-general' === Param::get( 'page' ),
'titles-meta' => 'rank-math-options-titles' === Param::get( 'page' ),
'sitemap-general' => 'rank-math-options-sitemap' === Param::get( 'page' ),
'role-manager' => 'rank-math-role-manager' === Param::get( 'page' ),
'seo-analysis' => 'rank-math-seo-analysis' === Param::get( 'page' ),
'content-ai-restore-credits' => 'rank-math-content-ai-page' === Param::get( 'page' ),
];
$link = KB::get( 'knowledgebase', 'RM Header KB Icon' );
foreach ( $links as $key => $value ) {
if ( $value ) {
$link = KB::get( $key, 'Admin Bar ' . ucwords( str_replace( '-', ' ', $key ) ) );
break;
}
}
return $link;
}
/**
* Get Current Screen ID.
*/
private function get_current_screen() {
$screen = get_current_screen();
if ( empty( $screen ) ) {
return '';
}
return $screen->id;
}
}

View File

@@ -0,0 +1,479 @@
<?php
/**
* Admin helper Functions.
*
* This file contains functions needed on the admin screens.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\KB;
use RankMath\Helper;
use RankMath\Data_Encryption;
use RankMath\Helpers\Security;
use RankMath\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
* Admin_Helper class.
*/
class Admin_Helper {
/**
* Get .htaccess related data.
*
* @return array
*/
public static function get_htaccess_data() {
if ( ! Helper::is_filesystem_direct() ) {
return [
'content' => '',
'writable' => false,
];
}
$wp_filesystem = Helper::get_filesystem();
if ( empty( $wp_filesystem ) ) {
return;
}
$htaccess_file = get_home_path() . '.htaccess';
return ! $wp_filesystem->exists( $htaccess_file ) ? false : [
'content' => $wp_filesystem->get_contents( $htaccess_file ),
'writable' => $wp_filesystem->is_writable( $htaccess_file ),
];
}
/**
* Get tooltip HTML.
*
* @param string $message Message to show in tooltip.
*
* @return string
*/
public static function get_tooltip( $message ) {
return '<span class="rank-math-tooltip"><em class="dashicons-before dashicons-editor-help"></em><span>' . $message . '</span></span>';
}
/**
* Get admin view file.
*
* @param string $view View filename.
*
* @return string Complete path to view
*/
public static function get_view( $view ) {
$view = sanitize_key( $view );
$view = rank_math()->admin_dir() . "views/{$view}.php";
if ( ! file_exists( $view ) ) {
Helper::redirect( Helper::get_admin_url() );
exit;
}
return $view;
}
/**
* Get taxonomies as choices.
*
* @param array $args (Optional) Arguments passed to filter list.
*
* @return array|bool
*/
public static function get_taxonomies_options( $args = [] ) {
global $wp_taxonomies;
$args = wp_parse_args( $args, [ 'public' => true ] );
$taxonomies = wp_filter_object_list( $wp_taxonomies, $args, 'and', 'label' );
return empty( $taxonomies ) ? false : [ 'off' => esc_html__( 'None', 'rank-math' ) ] + $taxonomies;
}
/**
* Registration data get/update.
*
* @param array|bool|null $data Array of data to save.
*
* @return array
*/
public static function get_registration_data( $data = null ) {
$row = 'rank_math_connect_data';
$keys = [
'username',
'email',
'api_key',
'plan',
];
// Setter.
if ( ! is_null( $data ) ) {
if ( false === $data ) {
update_option( 'rank_math_registration_skip', 1 );
return delete_option( $row );
}
foreach ( $keys as $key ) {
if ( isset( $data[ $key ] ) ) {
$data[ $key ] = Data_Encryption::encrypt( $data[ $key ] );
}
}
Helper::remove_notification( 'rank-math-site-url-mismatch' );
update_option( 'rank_math_registration_skip', 1 );
$connected = update_option( $row, $data );
do_action( 'rank_math/connect/account_connected', $data );
return $connected;
}
// Getter.
$options = Helper::is_plugin_active_for_network() ? get_blog_option( get_main_site_id(), $row, false ) : get_option( $row, false );
if ( empty( $options ) ) {
return false;
}
foreach ( $keys as $key ) {
if ( isset( $options[ $key ] ) ) {
$options[ $key ] = Data_Encryption::decrypt( $options[ $key ] );
}
}
if ( ! self::is_valid_registration( $options ) ) {
// Delete invalid registration data.
delete_option( $row );
// Ask the user to reconnect.
Helper::add_notification(
__( 'Unable to validate Rank Math SEO registration data.', 'rank-math' ) .
' <a href="' . esc_url( self::get_activate_url() ) . '">' . __( 'Please try reconnecting.', 'rank-math' ) . '</a> ' .
sprintf(
/* translators: KB Link */
__( 'If the issue persists, please try the solution described in our Knowledge Base article: %s', 'rank-math' ),
'<a href="' . KB::get( 'unable-to-encrypt', 'Registration Data' ) . '" target="_blank">' . __( '[3. Unable to Encrypt]', 'rank-math' ) . '</a>'
),
[ 'type' => 'error' ]
);
return false;
}
/**
* Filter whether we need to check for URL mismatch or not.
*/
$do_url_check = apply_filters( 'rank_math/registration/do_url_check', ! get_option( 'rank_math_siteurl_mismatch_notice_dismissed' ) );
if ( $do_url_check && isset( $options['site_url'] ) && Helper::get_home_url() !== $options['site_url'] ) {
$message = esc_html__( 'Seems like your site URL has changed since you connected to Rank Math.', 'rank-math' ) . ' <a href="' . self::get_activate_url() . '">' . esc_html__( 'Click here to reconnect.', 'rank-math' ) . '</a>';
Helper::add_notification(
$message,
[
'type' => 'warning',
'id' => 'rank-math-site-url-mismatch',
]
);
}
/**
* Ensure the site_url is returned if it is absent, as it is required for the Content AI.
*/
if ( empty( $options['site_url'] ) ) {
$options['site_url'] = Helper::get_home_url();
}
return $options;
}
/**
* Check if registration data is valid.
*
* @param array $data Registration data.
*
* @return bool
*/
public static function is_valid_registration( $data ) {
if ( empty( $data['username'] ) || empty( $data['email'] ) || empty( $data['api_key'] ) || empty( $data['plan'] ) ) {
return false;
}
if ( ! filter_var( $data['email'], FILTER_VALIDATE_EMAIL ) ) {
return false;
}
if ( strlen( $data['plan'] ) > 32 ) { // This can happen when the decryption fails for some reason.
return false;
}
return true;
}
/**
* Get user plan.
*/
public static function get_user_plan() {
$data = self::get_registration_data();
return $data['plan'];
}
/**
* Is user plan expired.
*
* @return boolean
*/
public static function is_plan_expired() {
$data = self::get_registration_data();
if ( ! isset( $data['plan'] ) ) {
return true;
}
return 'free' === $data['plan'];
}
/**
* Remove registration data and disconnect from RankMath.com.
*/
public static function deregister_user() {
$registered = self::get_registration_data();
if ( $registered && isset( $registered['username'] ) && isset( $registered['api_key'] ) ) {
Api::get()->deactivate_site( $registered['username'], $registered['api_key'] );
self::get_registration_data( false );
do_action( 'rank_math/deregister_site' );
}
}
/**
* Check if current page is media list page.
*
* @return bool
*/
public static function is_media_library() {
global $pagenow;
return 'upload.php' === $pagenow;
}
/**
* Check if current page is post list page.
*
* @return bool
*/
public static function is_post_list() {
global $pagenow;
return 'edit.php' === $pagenow;
}
/**
* Check if current page is post create/edit screen.
*
* @return bool
*/
public static function is_post_edit() {
global $pagenow;
return ! Helper::is_ux_builder() && ( 'post.php' === $pagenow || 'post-new.php' === $pagenow );
}
/**
* Check if current page is term create/edit screen.
*
* @return bool
*/
public static function is_term_edit() {
global $pagenow;
return 'term.php' === $pagenow || 'edit-tags.php' === $pagenow;
}
/**
* Check if current page is term create/term listing.
*
* @return bool
*/
public static function is_term_listing() {
global $pagenow;
return 'edit-tags.php' === $pagenow;
}
/**
* Check if current page is user create/edit screen.
*
* @return bool
*/
public static function is_user_edit() {
global $pagenow;
return 'profile.php' === $pagenow || 'user-edit.php' === $pagenow;
}
/**
* Check if current page is user or term create/edit screen.
*
* @return bool
*/
public static function is_term_profile_page() {
global $pagenow;
return self::is_term_edit() || self::is_user_edit();
}
/**
* Get Social Share buttons.
*
* @codeCoverageIgnore
*/
public static function get_social_share() {
if ( Helper::is_whitelabel() ) {
return;
}
$tw_link = KB::get( 'logo', 'Setup Wizard Tweet Button' );
$fb_link = rawurlencode( KB::get( 'logo', 'Facebook' ) );
/* translators: sitename */
$tw_message = rawurlencode( sprintf( esc_html__( 'I just installed @RankMathSEO #WordPress Plugin. It looks great! %s', 'rank-math' ), $tw_link ) );
/* translators: sitename */
$fb_message = rawurlencode( esc_html__( 'I just installed Rank Math SEO WordPress Plugin. It looks promising!', 'rank-math' ) );
$tweet_url = Security::add_query_arg(
[
'text' => $tw_message,
'hashtags' => 'SEO',
],
'https://twitter.com/intent/tweet'
);
$fb_share_url = Security::add_query_arg(
[
'u' => $fb_link,
'quote' => $fb_message,
'caption' => esc_html__( 'SEO by Rank Math', 'rank-math' ),
],
'https://www.facebook.com/sharer/sharer.php'
);
?>
<span class="wizard-share">
<a href="#" onclick="window.open('<?php echo esc_url( $tweet_url ); ?>', 'sharewindow', 'resizable,width=600,height=300'); return false;" class="share-twitter">
<span class="dashicons dashicons-twitter"></span> <?php esc_html_e( 'Tweet', 'rank-math' ); ?>
</a>
<a href="#" onclick="window.open('<?php echo esc_url( $fb_share_url ); ?>', 'sharewindow', 'resizable,width=600,height=300'); return false;" class="share-facebook">
<span class="dashicons dashicons-facebook-alt"></span> <?php esc_html_e( 'Share', 'rank-math' ); ?>
</a>
</span>
<?php
}
/**
* Get product activation URL.
*
* @param string $redirect_to Redirecto url.
*
* @return string Activate URL.
*/
public static function get_activate_url( $redirect_to = null ) {
if ( empty( $redirect_to ) ) {
$redirect_to = Security::add_query_arg_raw(
[
'page' => 'rank-math',
'view' => 'help',
'nonce' => wp_create_nonce( 'rank_math_register_product' ),
],
( is_multisite() && is_plugin_active_for_network( plugin_basename( RANK_MATH_FILE ) ) ) ? network_admin_url( 'admin.php' ) : admin_url( 'admin.php' )
);
} else {
$redirect_to = Security::add_query_arg_raw(
[
'nonce' => wp_create_nonce( 'rank_math_register_product' ),
],
$redirect_to
);
}
$args = [
'site' => rawurlencode( home_url() ),
'r' => rawurlencode( $redirect_to ),
];
return apply_filters(
'rank_math/license/activate_url',
Security::add_query_arg_raw( $args, RANK_MATH_SITE_URL . '/auth' ),
$args
);
}
/**
* Check if page is set as Homepage.
*
* @since 1.0.42
*
* @return boolean
*/
public static function is_home_page() {
$front_page = (int) get_option( 'page_on_front' );
if ( Helper::is_divi_frontend_editor() ) {
$p = get_post();
return ! empty( $p->ID ) && $p->ID === $front_page;
}
return $front_page && self::is_post_edit() && (int) Param::get( 'post' ) === $front_page;
}
/**
* Check if page is set as Posts Page.
*
* @since 1.0.43
*
* @return boolean
*/
public static function is_posts_page() {
$posts_page = (int) get_option( 'page_for_posts' );
return $posts_page && self::is_post_edit() && (int) Param::get( 'post' ) === $posts_page;
}
/**
* Get Trends icon <svg> element.
*
* @return string
*/
public static function get_trends_icon_svg() {
return '<svg viewBox="0 0 610 610"><path d="M18.85,446,174.32,290.48l58.08,58.08L76.93,504a14.54,14.54,0,0,1-20.55,0L18.83,466.48a14.54,14.54,0,0,1,0-20.55Z" style="fill:#4285f4"/><path d="M242.65,242.66,377.59,377.6l-47.75,47.75a14.54,14.54,0,0,1-20.55,0L174.37,290.43l47.75-47.75A14.52,14.52,0,0,1,242.65,242.66Z" style="fill:#ea4335"/><polygon points="319.53 319.53 479.26 159.8 537.34 217.88 377.61 377.62 319.53 319.53" style="fill:#fabb05"/><path d="M594.26,262.73V118.61h0a16.94,16.94,0,0,0-16.94-16.94H433.2a16.94,16.94,0,0,0-12,28.92L565.34,274.71h0a16.94,16.94,0,0,0,28.92-12Z" style="fill:#34a853"/><rect width="610" height="610" style="fill:none"/></svg>';
}
/**
* Check if siteurl & home options are both valid URLs.
*
* @return boolean
*/
public static function is_site_url_valid() {
return (bool) filter_var( get_option( 'siteurl' ), FILTER_VALIDATE_URL ) && (bool) filter_var( get_option( 'home' ), FILTER_VALIDATE_URL );
}
/**
* Maybe show notice about invalid siteurl.
*/
public static function maybe_show_invalid_siteurl_notice() {
if ( ! self::is_site_url_valid() ) {
?>
<p class="notice notice-warning notice-alt notice-connect-disabled">
<?php
printf(
// Translators: 1 is "WordPress Address (URL)", 2 is "Site Address (URL)", 3 is a link to the General Settings, with "WordPress General Settings" as anchor text.
esc_html__( 'Rank Math cannot be connected because your site URL doesn\'t appear to be a valid URL. If the domain name contains special characters, please make sure to use the encoded version in the %1$s &amp; %2$s fields on the %3$s page.', 'rank-math' ),
'<strong>' . esc_html__( 'WordPress Address (URL)', 'rank-math' ) . '</strong>',
'<strong>' . esc_html__( 'Site Address (URL)', 'rank-math' ) . '</strong>',
'<a href="' . esc_url( admin_url( 'options-general.php' ) ) . '">' . esc_html__( 'WordPress General Settings', 'rank-math' ) . '</a>'
);
?>
</p>
<?php
}
}
}

View File

@@ -0,0 +1,123 @@
<?php
/**
* The admin bootstrap of the plugin.
*
* @since 1.0.9
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Helper;
use RankMath\Updates;
use RankMath\Traits\Hooker;
defined( 'ABSPATH' ) || exit;
/**
* Admin_Init class.
*
* @codeCoverageIgnore
*/
class Admin_Init {
use Hooker;
/**
* The Constructor.
*/
public function __construct() {
rank_math()->admin = new Admin();
rank_math()->admin_assets = new Assets();
$this->load_review_reminders();
$this->load_pro_notice();
$this->load_setup_wizard();
$this->load_post_columns_and_filters();
$this->run(
[
rank_math()->admin,
rank_math()->admin_assets,
new Admin_Menu(),
new Option_Center(),
new Notices(),
new CMB2_Fields(),
new Metabox\Metabox(),
new Import_Export(),
new Updates(),
new Watcher(),
]
);
/**
* Fires when admin is loaded.
*/
$this->do_action( 'admin/loaded' );
}
/**
* Load out post list and edit screen class.
*/
private function load_post_columns_and_filters() {
$this->run( [ new Bulk_Actions() ] );
if ( Admin_Helper::is_post_list() || Admin_Helper::is_media_library() || Admin_Helper::is_term_listing() || wp_doing_ajax() ) {
$this->run(
[
new Post_Columns(),
new Post_Filters(),
]
);
}
}
/**
* Load review tab in metabox & footer notice.
*/
private function load_review_reminders() {
if ( get_option( 'rank_math_already_reviewed' ) ) {
return;
}
$this->run( [ new Ask_Review() ] );
}
/**
* Load Pro reminder notice.
*/
private function load_pro_notice() {
if ( ! is_main_site() ) {
return;
}
if ( defined( 'RANK_MATH_PRO_FILE' ) || get_option( 'rank_math_already_upgraded' ) ) {
return;
}
$this->run( [ new Pro_Notice() ] );
}
/**
* Run all the runners.
*
* @param array $runners Instances of runner classes.
*/
private function run( $runners ) {
foreach ( $runners as $runner ) {
$runner->hooks();
}
}
/**
* Load setup wizard.
*/
private function load_setup_wizard() {
if ( Helper::is_wizard() ) {
new Setup_Wizard();
}
}
}

View File

@@ -0,0 +1,309 @@
<?php
/**
* The admin pages of the plugin.
*
* @since 1.0.9
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\KB;
use RankMath\Helper;
use RankMath\Helpers\Param;
use RankMath\Runner;
use RankMath\Traits\Hooker;
use RankMath\Traits\Ajax;
use RankMath\Admin\Page;
defined( 'ABSPATH' ) || exit;
/**
* Admin_Menu class.
*
* @codeCoverageIgnore
*/
class Admin_Menu implements Runner {
use Hooker;
use Ajax;
/**
* Register hooks.
*/
public function hooks() {
$this->action( 'init', 'register_pages' );
$this->action( 'admin_menu', 'fix_admin_menu', 999 );
$this->action( 'admin_head', 'icon_css' );
$this->ajax( 'remove_offer_page', 'remove_offer_page' );
}
/**
* Register admin pages for plugin.
*/
public function register_pages() {
$this->maybe_deregister();
if ( Helper::is_invalid_registration() && ! is_network_admin() ) {
return;
}
$current_user = wp_get_current_user();
$capabilities = array_keys( Helper::get_roles_capabilities() );
if ( empty( array_intersect( $current_user->roles, $capabilities ) ) && ! current_user_can( 'setup_network' ) ) {
return;
}
$modules = rank_math()->manager->modules;
$data = [];
foreach ( $modules as $id => $module ) {
$data[ $id ] = array_merge(
[
'id' => $module->get_id(),
'isActive' => $module->is_active(),
'isHidden' => $module->is_hidden(),
'isPro' => $module->is_pro_module(),
],
$module->get_args()
);
}
// Dashboard / Welcome / About.
new Page(
'rank-math',
esc_html__( 'Rank Math', 'rank-math' ),
[
'position' => 50,
'menu_title' => 'Rank Math',
'capability' => 'manage_options',
'icon' => 'data:image/svg+xml;base64,' . \base64_encode( '<svg viewBox="0 0 462.03 462.03" xmlns="http://www.w3.org/2000/svg" width="20"><g fill="#fff"><path d="m462 234.84-76.17 3.43 13.43 21-127 81.18-126-52.93-146.26 60.97 10.14 24.34 136.1-56.71 128.57 54 138.69-88.61 13.43 21z"/><path d="m54.1 312.78 92.18-38.41 4.49 1.89v-54.58h-96.67zm210.9-223.57v235.05l7.26 3 89.43-57.05v-181zm-105.44 190.79 96.67 40.62v-165.19h-96.67z"/></g></svg>' ), // phpcs:ignore -- This should not cause any issue as we only pass a static svg code.
'render' => Admin_Helper::get_view( 'dashboard' ),
'classes' => [ 'rank-math-page' ],
'assets' => [
'styles' => [ 'rank-math-dashboard' => '' ],
'scripts' => [
'lodash' => '',
'rank-math-components' => '',
'rank-math-dashboard' => '',
'rank-math-modules' => rank_math()->plugin_url() . 'assets/admin/js/modules.js',
],
'json' => [
'isPro' => defined( 'RANK_MATH_PRO_FILE' ),
'isSiteConnected' => Helper::is_site_connected(),
'registerProductNonce' => wp_create_nonce( 'rank_math_register_product' ),
'activateUrl' => Admin_Helper::get_activate_url(),
'isSiteUrlValid' => Admin_Helper::is_site_url_valid(),
'isAdvancedMode' => Helper::is_advanced_mode(),
'contentAiPlan' => Helper::get_content_ai_plan(),
'data' => $data,
'isPluginActiveForNetwork' => Helper::is_plugin_active_for_network(),
'isNetworkAdmin' => is_network_admin(),
'canUser' => [
'manageOptions' => current_user_can( 'manage_options' ),
'setupNetwork' => current_user_can( 'setup_network' ),
'installPlugins' => current_user_can( 'install_plugins' ),
],
],
],
'is_network' => is_network_admin() && Helper::is_plugin_active_for_network(),
]
);
}
/**
* Fix menu names.
*/
public function fix_admin_menu() {
// Replace the main menu name "Rank Math" with "Rank Math SEO".
global $menu;
foreach ( $menu as $key => $item ) {
if ( 'Rank Math' === $item[0] ) {
$menu[ $key ][0] = esc_html__( 'Rank Math SEO', 'rank-math' ); // phpcs:ignore -- This is required to change the menu name without changing its slug `rank-math`
break;
}
}
// Replace the first submenu name "Rank Math" with "Dashboard".
global $submenu;
if ( ! isset( $submenu['rank-math'] ) ) {
return;
}
if ( 'Rank Math' === $submenu['rank-math'][0][0] ) {
if ( current_user_can( 'manage_options' ) ) {
$plan = Helper::get_content_ai_plan();
$notification = ( empty( $plan ) || 'free' === $plan ) && get_option( 'rank_math_view_modules' ) ? ' <span class="awaiting-mod count-1"><span class="pending-count" aria-hidden="true">1</span></span>' : '';
$submenu['rank-math'][0][0] = esc_html__( 'Dashboard', 'rank-math' ) . $notification; // phpcs:ignore -- This is required to change the menu name when the plugin is not configured.
} else {
unset( $submenu['rank-math'][0] );
}
}
if ( empty( $submenu['rank-math'] ) ) {
return;
}
$submenu['rank-math'][] = [ esc_html__( 'Help &amp; Support', 'rank-math' ) . '<i class="dashicons dashicons-external" style="font-size:12px;vertical-align:-2px;height:10px;"></i>', 'manage_options', KB::get( 'knowledgebase', 'Sidebar Help Link' ) ]; // phpcs:ignore -- A custom link to our KB article.
$this->add_offer_link( $submenu );
// Store ID of first_menu item so we can use it in the Admin menu item.
set_transient( 'rank_math_first_submenu_id', array_values( $submenu['rank-math'] )[0][2] );
}
/**
* Print icon CSS for admin menu bar.
*/
public function icon_css() {
?>
<script type="text/javascript">
// Open RM KB menu link in the new tab.
jQuery( document ).ready( function( $ ) {
$( "ul#adminmenu a[href$='<?php KB::the( 'knowledgebase', 'Sidebar Help Link' ); ?>']" ).attr( 'target', '_blank' );
$( "ul#adminmenu a[href$='<?php KB::the( 'offer', 'Offer Menu Item' ); ?>']" ).attr( 'target', '_blank' ).on( 'click', function() {
$( this ).remove()
$.ajax( {
url: window.ajaxurl,
type: 'POST',
data: {
action: 'rank_math_remove_offer_page',
security: rankMath.security,
},
} )
} );
} );
</script>
<style>
#wp-admin-bar-rank-math .rank-math-icon {
display: inline-block;
top: 6px;
position: relative;
padding-right: 10px;
max-width: 20px;
}
#wp-admin-bar-rank-math .rank-math-icon svg {
fill-rule: evenodd;
fill: #dedede;
}
#wp-admin-bar-rank-math:hover .rank-math-icon svg {
fill-rule: evenodd;
fill: #00b9eb;
}
#toplevel_page_rank-math:not(.wp-has-submenu) {
display: none;
}
.multisite.network-admin #toplevel_page_rank-math {
display: block;
}
#toplevel_page_rank-math a[href$='<?php KB::the( 'offer', 'Offer Menu Item' ); ?>'],
#toplevel_page_rank-math a[href$='<?php KB::the( 'offer', 'Offer Menu Item' ); ?>']:hover,
#toplevel_page_rank-math a[href$='<?php KB::the( 'offer', 'Offer Menu Item' ); ?>']:focus {
background-color: #10AC84;
color: #fff;
}
</style>
<?php
}
/**
* Check for deactivation.
*/
private function maybe_deregister() {
if ( ! Helper::has_cap( 'general' ) || 'deregister' !== Param::post( 'registration-action' ) ) {
return;
}
$nonce = Param::post( '_wpnonce' );
if ( ! $nonce || ! wp_verify_nonce( $nonce, 'rank_math_register_product' ) ) {
return;
}
Admin_Helper::deregister_user();
}
/**
* Function to add Offer link based on the date range.
*
* @param array $submenu Submenu items.
*/
private function add_offer_link( &$submenu ) {
$offer = $this->get_active_offer();
if ( ! $offer ) {
return;
}
$submenu['rank-math'][] = [ current( $offer ) . '&nbsp;', 'manage_options', KB::get( 'offer', 'Offer Menu Item' ) ];
}
/**
* Ajax handler callback to store active offer so it doesn't show up again on the site.
*/
public function remove_offer_page() {
check_ajax_referer( 'rank-math-ajax-nonce', 'security' );
$offer = $this->get_active_offer();
set_site_transient( 'rank_math_active_offer', key( $offer ) );
}
/**
* Function to get active offer
*/
private function get_active_offer() {
// Early Bail if PRO plugin is active.
if ( defined( 'RANK_MATH_PRO_FILE' ) ) {
return false;
}
$timezone = new \DateTimeZone( 'Asia/Kolkata' );
$current_date = new \DateTime( 'now', $timezone );
$dates = [
'halloween' => [
'start' => '2025-10-29',
'end' => '2025-11-05',
'text' => esc_html__( 'Halloween Sale', 'rank-math' ),
],
'anniversary' => [
'start' => '2025-11-05',
'end' => '2025-11-12',
'text' => esc_html__( 'Anniversary Sale', 'rank-math' ),
],
'black-friday' => [
'start' => '2025-11-12',
'end' => '2025-11-29',
'text' => esc_html__( 'Black Friday Sale', 'rank-math' ),
],
'cyber-monday' => [
'start' => '2025-11-29',
'end' => '2025-12-03',
'text' => esc_html__( 'Cyber Monday Sale', 'rank-math' ),
],
'christmas' => [
'start' => '2025-12-24',
'end' => '2025-12-31',
'text' => esc_html__( 'Christmas Sale', 'rank-math' ),
],
'new-year' => [
'start' => '2025-12-31',
'end' => '2026-01-07',
'text' => esc_html__( 'New Year Sale', 'rank-math' ),
],
];
$stored_offer = get_site_transient( 'rank_math_active_offer' );
$active_offer = '';
foreach ( $dates as $key => $date ) {
$start_date = new \DateTime( $date['start'] . ' 16:00:00', $timezone );
$end_date = new \DateTime( $date['end'] . ' 16:00:00', $timezone );
if ( $stored_offer !== $key && $current_date >= $start_date && $current_date <= $end_date ) {
$active_offer = [ $key => $date['text'] ];
break;
}
}
return $active_offer;
}
}

View File

@@ -0,0 +1,563 @@
<?php
/**
* The admin-specific functionality of the plugin.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Runner;
use RankMath\Helper;
use RankMath\Helpers\Str;
use RankMath\Helpers\DB as DB_Helper;
use RankMath\Helpers\Param;
use RankMath\Admin\Admin_Helper;
use RankMath\Traits\Ajax;
use RankMath\Traits\Hooker;
defined( 'ABSPATH' ) || exit;
/**
* Admin class.
*
* @codeCoverageIgnore
*/
class Admin implements Runner {
use Hooker;
use Ajax;
/**
* Register hooks.
*/
public function hooks() {
$this->action( 'init', 'flush', 999 );
$this->filter( 'user_contactmethods', 'update_user_contactmethods' );
$this->action( 'profile_update', 'profile_update', 10, 3 );
$this->action( 'admin_footer', 'convert_additional_profile_url_to_textarea' );
$this->action( 'save_post', 'canonical_check_notice' );
$this->action( 'cmb2_save_options-page_fields', 'update_is_configured_value', 10, 2 );
$this->filter( 'action_scheduler_pastdue_actions_check_pre', 'as_exclude_pastdue_actions' );
$this->filter( 'rank_math/pro_badge', 'offer_icon' );
$this->filter( 'load_script_translation_file', 'load_script_translation_file', 10, 3 );
// Use woocommerce textdomain for the Actiion scheduler strings.
$this->filter( 'gettext', 'remap_action_scheduler_translation', 10, 3 );
$this->filter( 'gettext_with_context', 'remap_action_scheduler_translation_with_context', 10, 4 );
// AJAX.
$this->ajax( 'search_pages', 'search_pages' );
$this->ajax( 'is_keyword_new', 'is_keyword_new' );
$this->ajax( 'save_checklist_layout', 'save_checklist_layout' );
$this->ajax( 'deactivate_plugins', 'deactivate_plugins' );
}
/**
* Update user profile.
*
* @param int $user_id The user ID.
* @param array $old_user_data Old user data.
* @param array $userdata User data.
*/
public function profile_update( $user_id, $old_user_data, $userdata ) {
if ( ! current_user_can( 'edit_user', $user_id ) ) {
return false;
}
$nonce = Param::post( '_wpnonce', '', FILTER_SANITIZE_SPECIAL_CHARS );
if ( ! wp_verify_nonce( $nonce, 'update-user_' . $user_id ) ) {
return false;
}
$twitter = Param::post( 'twitter', '', FILTER_SANITIZE_URL );
$facebook = Param::post( 'facebook', '', FILTER_SANITIZE_URL );
$additional_profile_urls = Param::post( 'additional_profile_urls', '' );
if ( $additional_profile_urls ) {
$additional_profile_urls = array_map( 'sanitize_url', explode( PHP_EOL, $additional_profile_urls ) );
$additional_profile_urls = implode( ' ', $additional_profile_urls );
}
update_user_meta( $user_id, 'twitter', $twitter );
update_user_meta( $user_id, 'facebook', $facebook );
update_user_meta( $user_id, 'additional_profile_urls', $additional_profile_urls );
}
/**
* Flush the rewrite rules once if the rank_math_flush_rewrite option is set.
*/
public function flush() {
if ( get_option( 'rank_math_flush_rewrite' ) ) {
flush_rewrite_rules();
delete_option( 'rank_math_flush_rewrite' );
}
if ( 'rank-math' === Param::get( 'page' ) && get_option( 'rank_math_view_modules' ) ) {
delete_option( 'rank_math_view_modules' );
}
}
/**
* Add Facebook and Twitter as user contact methods.
*
* @param array $contactmethods Current contact methods.
* @return array New contact methods with extra items.
*
* @copyright Copyright (C) 2008-2019, Yoast BV
* The following code is a derivative work of the code from the Yoast(https://github.com/Yoast/wordpress-seo/), which is licensed under GPL v3.
*/
public function update_user_contactmethods( $contactmethods ) {
$contactmethods['twitter'] = esc_html__( 'Twitter username (without @)', 'rank-math' );
$contactmethods['facebook'] = esc_html__( 'Facebook profile URL', 'rank-math' );
$contactmethods['additional_profile_urls'] = esc_html__( 'Additional profile URLs', 'rank-math' );
return $contactmethods;
}
/**
* Display admin header.
*
* @param bool $show_breadcrumbs Determines whether to show breadcrumbs or not.
*/
public function display_admin_header( $show_breadcrumbs = true ) {
$nav_tabs = new Admin_Header();
$nav_tabs->display( $show_breadcrumbs );
}
/**
* Display admin breadcrumbs.
*/
public function display_admin_breadcrumbs() {
$nav_tabs = new Admin_Breadcrumbs();
$nav_tabs->display();
}
/**
* Display dashboard tabs.
*/
public function display_dashboard_nav() {
$nav_tabs = new Admin_Dashboard_Nav();
$nav_tabs->display();
}
/**
* Show notice when canonical URL is not a valid URL.
*
* @param int $post_id The post ID.
*/
public function canonical_check_notice( $post_id ) {
$post_type = get_post_type( $post_id );
$is_allowed = in_array( $post_type, Helper::get_allowed_post_types(), true );
if ( ! $is_allowed || Helper::is_autosave() || Helper::is_ajax() || isset( $_REQUEST['bulk_edit'] ) ) { // phpcs:ignore
return $post_id;
}
if ( ! empty( $_POST['rank_math_canonical_url'] ) && false === Param::post( 'rank_math_canonical_url', false, FILTER_VALIDATE_URL ) ) { // phpcs:ignore
$message = esc_html__( 'The canonical URL you entered does not seem to be a valid URL. Please double check it in the SEO meta box &raquo; Advanced tab.', 'rank-math' );
Helper::add_notification( $message, [ 'type' => 'error' ] );
}
}
/**
* Save checklist layout.
*/
public function save_checklist_layout() {
check_ajax_referer( 'rank-math-ajax-nonce', 'security' );
$this->has_cap_ajax( 'onpage_general' );
if ( empty( $_POST['layout'] ) || ! is_array( $_POST['layout'] ) ) {
return;
}
$layout = Param::post( 'layout', [], FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
$allowed = [
'basic' => 1,
'advanced' => 1,
'title-readability' => 1,
'content-readability' => 1,
];
$layout = array_intersect_key( $layout, $allowed );
update_user_meta( get_current_user_id(), 'rank_math_metabox_checklist_layout', $layout );
exit;
}
/**
* Ajax handler to search pages based on the searched string. Used in the Local SEO Settings.
*/
public function search_pages() {
check_ajax_referer( 'rank-math-ajax-nonce', 'security' );
$this->has_cap_ajax( 'general' );
$term = Param::get( 'term' );
if ( empty( $term ) ) {
exit;
}
global $wpdb;
$pages = DB_Helper::get_results(
$wpdb->prepare(
"SELECT ID, post_title FROM {$wpdb->prefix}posts WHERE post_type = 'page' AND post_status = 'publish' AND post_title LIKE %s",
"%{$wpdb->esc_like( $term )}%"
),
ARRAY_A
);
$data = [];
foreach ( $pages as $page ) {
$data[] = [
'id' => $page['ID'],
'text' => $page['post_title'],
'url' => get_permalink( $page['ID'] ),
];
}
wp_send_json( [ 'results' => $data ] );
}
/**
* Check if the keyword has been used before for another post.
*/
public function is_keyword_new() {
global $wpdb;
check_ajax_referer( 'rank-math-ajax-nonce', 'security' );
$this->has_cap_ajax( 'onpage_general' );
$result = [ 'isNew' => true ];
if ( empty( $_GET['keyword'] ) ) {
$this->success( $result );
}
$keyword = Param::get( 'keyword', '', FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_BACKTICK );
$object_id = Param::get( 'objectID', 0, FILTER_VALIDATE_INT );
$object_type = Param::get( 'objectType', '', FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH | FILTER_FLAG_STRIP_BACKTICK );
$column_ids = [
'post' => 'ID',
'term' => 'term_id',
'user' => 'ID',
];
if ( ! in_array( $object_type, [ 'post', 'term', 'user' ], true ) ) {
$object_type = 'post';
}
$main = $wpdb->{$object_type . 's'};
$meta = $wpdb->{$object_type . 'meta'};
$query = sprintf( 'select %2$s.%1$s from %2$s inner join %3$s on %2$s.%1$s = %3$s.%4$s_id where ', $column_ids[ $object_type ], $main, $meta, $object_type );
if ( 'post' === $object_type ) {
$query .= sprintf( '%s.post_status = \'publish\' and ', $main );
}
$query .= sprintf( '%1$s.meta_key = \'rank_math_focus_keyword\' and ( %1$s.meta_value = %2$s OR %1$s.meta_value like %3$s ) and %1$s.%4$s_id != %5$d', $meta, '%s', '%s', $object_type, $object_id );
$data = DB_Helper::get_row( $wpdb->prepare( $query, $keyword, $wpdb->esc_like( $keyword ) . ',%' ) );
$result['isNew'] = empty( $data );
$this->success( $result );
}
/**
* Get link suggestions for the current post.
*
* @param int|WP_Post $post Current post.
* @return array
*/
public function get_link_suggestions( $post ) {
global $pagenow;
if ( 'post-new.php' === $pagenow ) {
return;
}
$output = [];
$post = get_post( $post );
$args = [
'post_type' => $post->post_type,
'post__not_in' => [ $post->ID ],
'posts_per_page' => 5,
'meta_key' => 'rank_math_pillar_content',
'meta_value' => 'on',
'tax_query' => [ 'relation' => 'OR' ],
];
$taxonomies = Helper::get_object_taxonomies( $post, 'names' );
$taxonomies = array_filter( $taxonomies, [ $this, 'is_taxonomy_allowed' ] );
foreach ( $taxonomies as $taxonomy ) {
$this->set_term_query( $args, $post->ID, $taxonomy );
}
$posts = get_posts( $args );
foreach ( $posts as $related_post ) {
$item = [
'title' => get_the_title( $related_post->ID ),
'url' => get_permalink( $related_post->ID ),
'post_id' => $related_post->ID,
'focus_keywords' => get_post_meta( $related_post->ID, 'rank_math_focus_keyword', true ),
];
$item['focus_keywords'] = empty( $item['focus_keywords'] ) ? [] : explode( ',', $item['focus_keywords'] );
$output[] = $item;
}
return $output;
}
/**
* Is taxonomy allowed
*
* @param string $taxonomy Taxonomy to check.
*
* @return bool
*/
public function is_taxonomy_allowed( $taxonomy ) {
$exclude_taxonomies = [ 'post_format', 'product_shipping_class' ];
if ( Str::starts_with( 'pa_', $taxonomy ) || in_array( $taxonomy, $exclude_taxonomies, true ) ) {
return false;
}
return true;
}
/**
* Remap Action Scheduler translation to use WooCommerce's text domain (no context).
*
* @param string $translated Translated text.
* @param string $text Original text.
* @param string $domain Text domain.
* @return string Modified translated text.
*/
public function remap_action_scheduler_translation( $translated, $text, $domain ) {
// phpcs:ignore -- Use WooCommerce text domain for Action Scheduler strings.
return $domain === 'action-scheduler' && Helper::is_woocommerce_active() ? __( $text, 'woocommerce' ) : $translated;
}
/**
* Remap Action Scheduler translation to use WooCommerce's text domain (with context).
*
* @param string $translated Translated text.
* @param string $text Original text.
* @param string $context Context information for translators.
* @param string $domain Text domain.
* @return string Modified translated text.
*/
public function remap_action_scheduler_translation_with_context( $translated, $text, $context, $domain ) {
// phpcs:ignore -- Use WooCommerce text domain for Action Scheduler strings.
return $domain === 'action-scheduler' && Helper::is_woocommerce_active() ? _x( $text, $context, 'woocommerce' ) : $translated;
}
/**
* Set term query.
*
* @param array $query Array of query.
* @param int $post_id Post ID to get terms from.
* @param string $taxonomy Taxonomy to get terms for.
*/
private function set_term_query( &$query, $post_id, $taxonomy ) {
$terms = wp_get_post_terms( $post_id, $taxonomy, [ 'fields' => 'ids' ] );
if ( empty( $terms ) || is_wp_error( $terms ) ) {
return;
}
$query['tax_query'][] = [
'taxonomy' => $taxonomy,
'field' => 'term_id',
'terms' => $terms,
];
}
/**
* Output link suggestions.
*
* @param array $suggestions Link items.
* @return string
*/
public function get_link_suggestions_html( $suggestions ) {
$output = '<div class="rank-math-link-suggestions-content" data-count="' . count( $suggestions ) . '">';
$is_use_fk = 'focus_keywords' === Helper::get_settings( 'titles.pt_' . get_post_type() . '_ls_use_fk' );
foreach ( $suggestions as $suggestion ) {
$label = $suggestion['title'];
if ( $is_use_fk && ! empty( $suggestion['focus_keywords'] ) ) {
$label = $suggestion['focus_keywords'][0];
}
$output .= sprintf(
'<div class="suggestion-item">
<div class="suggestion-actions">
<button class="dashicons dashicons-clipboard suggestion-copy" title="%5$s" data-clipboard-text="%2$s"></button>
<button class="dashicons dashicons-admin-links suggestion-insert" title="%6$s" data-url="%2$s" data-text="%7$s"></button>
</div>
<span class="suggestion-title" data-fk=\'%1$s\'><a target="_blank" href="%2$s" title="%3$s">%4$s</a></span>
</div>',
esc_attr( wp_json_encode( $suggestion['focus_keywords'] ) ),
$suggestion['url'],
$suggestion['title'],
$label,
esc_attr__( 'Copy Link URL to Clipboard', 'rank-math' ),
esc_attr__( 'Insert Link in Content', 'rank-math' ),
esc_attr( $label )
);
}
$output .= '</div>';
return $output;
}
/**
* Updates the is_configured value.
*
* @param int $object_id The ID of the current object.
* @param string $cmb_id The current box ID.
*/
public function update_is_configured_value( $object_id, $cmb_id ) {
if ( 0 !== strpos( $cmb_id, 'rank_math' ) && 0 !== strpos( $cmb_id, 'rank-math' ) ) {
return;
}
Helper::is_configured( true );
}
/**
* Deactivate plugin.
*/
public function deactivate_plugins() {
check_ajax_referer( 'rank-math-ajax-nonce', 'security' );
if ( ! current_user_can( 'activate_plugins' ) ) {
$this->error( esc_html__( 'You are not authorized to perform this action.', 'rank-math' ) );
}
$plugin = Param::post( 'plugin', '', FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH | FILTER_FLAG_STRIP_BACKTICK );
if ( 'all' !== $plugin ) {
deactivate_plugins( $plugin );
die( '1' );
}
Importers\Detector::deactivate_all();
die( '1' );
}
/**
* Action Scheduler: exclude our actions from the past-due checker.
* Since this is a *_pre hook, it replaces the original checker.
*
* We first do the same check as what ActionScheduler_AdminView->check_pastdue_actions() does,
* but then we also count how many of those past-due actions are ours.
*
* @param null $value Null value.
*/
public function as_exclude_pastdue_actions( $value ) {
$query_args = [
'date' => as_get_datetime_object( time() - DAY_IN_SECONDS ),
'status' => \ActionScheduler_Store::STATUS_PENDING,
'per_page' => 1,
];
$store = \ActionScheduler_Store::instance();
$num_pastdue_actions = (int) $store->query_actions( $query_args, 'count' );
if ( 0 !== $num_pastdue_actions ) {
$query_args['group'] = 'rank-math';
$num_pastdue_rm_actions = (int) $store->query_actions( $query_args, 'count' );
$num_pastdue_actions -= $num_pastdue_rm_actions;
}
$threshold_seconds = (int) apply_filters( 'action_scheduler_pastdue_actions_seconds', DAY_IN_SECONDS );
$threshhold_min = (int) apply_filters( 'action_scheduler_pastdue_actions_min', 1 );
$check = ( $num_pastdue_actions >= $threshhold_min );
return (bool) apply_filters( 'action_scheduler_pastdue_actions_check', $check, $num_pastdue_actions, $threshold_seconds, $threshhold_min );
}
/**
* Check and print the Anniversary icon in the header of Rank Math's setting pages.
*/
public static function offer_icon() {
if ( ! current_user_can( 'manage_options' ) || defined( 'RANK_MATH_PRO_FILE' ) ) {
return;
}
// Holiday Season related variables.
$time = time();
$current_year = 2025;
$anniversary_start_time = gmmktime( 17, 00, 00, 10, 29, $current_year ); // 29 Oct.
$anniversary_end_time = gmmktime( 17, 00, 00, 12, 03, $current_year ); // 30 Nov.
$holiday_start_time = gmmktime( 17, 00, 00, 12, 24, $current_year ); // 20 Dec.
$holiday_end_time = gmmktime( 17, 00, 00, 01, 07, 2026 ); // 07 Jan.
ob_start();
if (
( $time > $anniversary_start_time && $time < $anniversary_end_time ) ||
( $time > $holiday_start_time && $time < $holiday_end_time )
) { ?>
<a href="https://rankmath.com/pricing/?utm_source=Plugin&utm_medium=Header+Offer+Icon&utm_campaign=WP" target="_blank" class="rank-math-tooltip bottom" style="margin-left:5px;">
🎉
<span><?php esc_attr_e( 'Exclusive Offer!', 'rank-math' ); ?></span>
</a>
<?php
}
return ob_get_clean();
}
/**
* Code to convert Addiontal Profile URLs from input type text to textarea.
*/
public function convert_additional_profile_url_to_textarea() {
if ( ! Admin_Helper::is_user_edit() ) {
return;
}
$field_description = __( 'Additional Profiles to add in the <code>sameAs</code> Schema property.', 'rank-math' );
?>
<script type="text/javascript">
( function( $ ) {
$( function() {
const twitterWrapper = $( '.user-twitter-wrap' );
twitterWrapper.before( '<tr><th><h2 style="margin: 0;">Rank Math SEO</h2></th><td></td></tr>' );
const additionalProfileField = $( '#additional_profile_urls' );
if ( ! additionalProfileField.length ) {
return
}
var $txtarea = $( '<textarea />' );
$txtarea.attr( 'id', additionalProfileField[0].id );
$txtarea.attr( 'name', additionalProfileField[0].name );
$txtarea.attr( 'rows', 5 );
$txtarea.val( additionalProfileField[0].value.replaceAll( " ", "\n" ) );
additionalProfileField.replaceWith( $txtarea );
$( '<p class="description"><?php echo wp_kses_post( $field_description ); ?></p>' ).insertAfter( $txtarea );
} );
})(jQuery);
</script>
<?php
}
/**
* Function to replace domain with seo-by-rank-math in translation file.
*
* @param string|false $file Path to the translation file to load. False if there isn't one.
* @param string $handle Name of the script to register a translation domain to.
* @param string $domain The text domain.
*/
public function load_script_translation_file( $file, $handle, $domain ) {
if ( 'rank-math' !== $domain ) {
return $file;
}
$data = explode( '/', $file );
$data[ count( $data ) - 1 ] = preg_replace( '/rank-math/', 'seo-by-rank-math', $data[ count( $data ) - 1 ], 1 );
return implode( '/', $data );
}
}

View File

@@ -0,0 +1,278 @@
<?php
/**
* The RankMath API.
*
* @since 1.5.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use WP_Error;
/**
* Api class.
*/
class Api {
/**
* Rank Math SEO Checkup API.
*
* @var string
*/
protected $api_url = 'https://rankmath.com/wp-json/rankmath/v1/';
/**
* Was the last request successful.
*
* @var bool
*/
protected $is_success = false;
/**
* Last error.
*
* @var string
*/
protected $last_error = '';
/**
* Last response.
*
* @var array
*/
protected $last_response = [];
/**
* Last response header code.
*
* @var int
*/
protected $last_code = 0;
/**
* User agent.
*
* @var string
*/
protected $user_agent = '';
/**
* Is blocking.
*
* @var bool
*/
protected $is_blocking = true;
/**
* Main instance
*
* Ensure only one instance is loaded or can be loaded.
*
* @return Api
*/
public static function get() {
static $instance;
if ( is_null( $instance ) && ! ( $instance instanceof Api ) ) {
$instance = new Api();
$instance->is_blocking = true;
$instance->user_agent = 'RankMath/' . md5( esc_url( home_url( '/' ) ) );
}
return $instance;
}
/**
* Was the last request successful?
*
* @return bool True for success, false for failure
*/
public function is_success() {
return $this->is_success;
}
/**
* Get the last error returned by either the network transport, or by the API.
* If something didn't work, this should contain the string describing the problem.
*
* @return array|false describing the error
*/
public function get_error() {
return $this->last_error ? $this->last_error : false;
}
/**
* Get an array containing the HTTP headers and the body of the API response.
*
* @return array Assoc array with keys 'headers' and 'body'
*/
public function get_response() {
return $this->last_response;
}
/**
* Remove registration data and disconnect from RankMath.com.
*
* @param string $username Username.
* @param string $api_key Api key.
*/
public function deactivate_site( $username, $api_key ) {
$this->is_blocking = false;
$data = wp_json_encode(
[
'username' => $username,
'api_key' => $api_key,
'site_url' => esc_url( home_url() ),
]
);
$response = wp_remote_post(
RANK_MATH_SITE_URL . '/wp-json/rankmath/v1/deactivateSite',
[
'body' => $data,
'headers' => [
'Content-Type' => 'application/json',
],
],
);
}
/**
* Make an HTTP GET request - for retrieving data.
*
* @param string $url URL to do request.
* @param array $args Assoc array of arguments (usually your data).
* @param int $timeout Timeout limit for request in seconds.
*
* @return array|false Assoc array of API response, decoded from JSON.
*/
public function http_get( $url, $args = [], $timeout = 10 ) {
return $this->make_request( 'GET', $url, $args, $timeout );
}
/**
* Make an HTTP POST request - for creating and updating items.
*
* @param string $url URL to do request.
* @param array $args Assoc array of arguments (usually your data).
* @param int $timeout Timeout limit for request in seconds.
*
* @return array|false Assoc array of API response, decoded from JSON.
*/
public function http_post( $url, $args = [], $timeout = 10 ) {
return $this->make_request( 'POST', $url, $args, $timeout );
}
/**
* Make an HTTP PUT request - for creating new items.
*
* @param string $url URL to do request.
* @param array $args Assoc array of arguments (usually your data).
* @param int $timeout Timeout limit for request in seconds.
*
* @return array|false Assoc array of API response, decoded from JSON.
*/
public function http_put( $url, $args = [], $timeout = 10 ) {
return $this->make_request( 'PUT', $url, $args, $timeout );
}
/**
* Make an HTTP DELETE request - for deleting data.
*
* @param string $url URL to do request.
* @param array $args Assoc array of arguments (usually your data).
* @param int $timeout Timeout limit for request in seconds.
*
* @return array|false Assoc array of API response, decoded from JSON.
*/
public function http_delete( $url, $args = [], $timeout = 10 ) {
return $this->make_request( 'DELETE', $url, $args, $timeout );
}
/**
* Performs the underlying HTTP request. Not very exciting.
*
* @param string $http_verb The HTTP verb to use: get, post, put, patch, delete.
* @param string $url URL to do request.
* @param array $args Assoc array of parameters to be passed.
* @param int $timeout Timeout limit for request in seconds.
*
* @return array|false Assoc array of decoded result.
*/
protected function make_request( $http_verb, $url, $args = [], $timeout = 10 ) {
$params = [
'timeout' => $timeout,
'method' => $http_verb,
'user-agent' => $this->user_agent,
'blocking' => $this->is_blocking,
];
if ( ! empty( $args ) && is_array( $args ) ) {
$params['body'] = $args;
}
$this->reset();
$response = wp_remote_request( $this->api_url . $url, $params );
$this->determine_success( $response );
return $this->format_response( $response );
}
/**
* Decode the response and format any error messages for debugging
*
* @param array|WP_Error $response The response from the curl request.
*
* @return array|false The JSON decoded into an array
*/
protected function format_response( $response ) {
$this->last_response = $response;
if ( is_wp_error( $response ) ) {
return false;
}
if ( ! empty( $response['body'] ) ) {
return json_decode( $response['body'], true );
}
return false;
}
/**
* Check if the response was successful or a failure. If it failed, store the error.
*
* @param array|WP_Error $response The response from the curl request.
*/
protected function determine_success( $response ) {
if ( is_wp_error( $response ) ) {
$this->last_error = 'WP_Error: ' . $response->get_error_message();
return;
}
$this->last_code = wp_remote_retrieve_response_code( $response );
if ( in_array( $this->last_code, [ 200, 204 ], true ) ) {
$this->is_success = true;
return;
}
$this->last_error = 'Unknown error, call getLastResponse() to find out what happened.';
}
/**
* Reset request.
*/
protected function reset() {
$this->last_code = 0;
$this->last_error = '';
$this->is_success = false;
$this->is_blocking = true;
$this->last_response = [
'body' => null,
'headers' => null,
];
}
}

View File

@@ -0,0 +1,249 @@
<?php
/**
* Ask user to review Rank Math on wp.org, in the meta box after 2 weeks.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Helper;
use RankMath\Traits\Ajax;
use RankMath\Traits\Hooker;
defined( 'ABSPATH' ) || exit;
/**
* Ask_Review class.
*/
class Ask_Review {
use Hooker;
use Ajax;
/**
* Now.
*
* @var string
*/
public $current_time = '';
/**
* Date of release of version 1.0.57. Turned into a timestamp in the constructor.
*
* @var string
*/
public $record_date = '2021-02-03 13:00';
/**
* Rank Math plugin install date.
*
* @var string
*/
public $install_date = '';
/**
* Constructor method.
*/
public function __construct() {
$this->current_time = Helper::get_current_time();
$this->record_date = strtotime( $this->record_date );
$this->install_date = get_option( 'rank_math_install_date' );
if ( false === $this->install_date ) {
$this->install_date = $this->current_time;
}
}
/**
* Register hooks.
*/
public function hooks() {
$this->ajax( 'already_reviewed', 'already_reviewed' );
// Post editor tab.
if ( $this->current_time > $this->install_date + ( 10 * DAY_IN_SECONDS ) ) {
Helper::add_json( 'showReviewTab', true );
}
// Admin notice.
$review_notice_date = $this->get_review_notice_date();
if ( $this->current_time > $review_notice_date ) {
if ( get_option( 'rank_math_review_notice_added' ) === false && ! Helper::has_notification( 'rank_math_pro_notice' ) ) {
$this->add_notice();
}
// Make dismiss button work like the "Maybe later" link.
$this->action( 'wp_helpers_notification_dismissed', 'review_notice_after_dismiss' );
}
$this->action( 'admin_footer', 'review_notice_js', 15 );
}
/**
* Add inline JS related to the review notice.
*
* @return void
*/
public function review_notice_js() {
if ( ! Helper::has_notification( 'rank_math_review_plugin_notice' ) ) {
return;
}
?>
<script>
(function( $ ) {
$( function() {
$('.rank-math-dismiss-review-notice').on( 'click', function(e) {
var $this = $(this);
if ( ! $this.hasClass( 'rank-math-review-action' ) ) {
e.preventDefault();
}
if ( $this.hasClass( 'rank-math-maybe-later-action' ) ) {
$('#rank_math_review_plugin_notice').find( '.notice-dismiss' ).trigger('click');
return false;
}
jQuery.ajax( {
url: rankMath.ajaxurl,
data: { action: 'rank_math_already_reviewed', security: rankMath.security,
},
} );
$('#rank_math_review_plugin_notice').find( '.notice-dismiss' ).trigger('click');
});
});
})(jQuery);
</script>
<style>
#rank_math_review_plugin_notice .rank-math-notice.is-dismissible a,
#rank_math_pro_notice .rank-math-notice.is-dismissible a {
color: #4f52d4;
}
#rank_math_review_plugin_notice.is-dismissible,
#rank_math_pro_notice.is-dismissible {
border-width: 0 0 0 4px;
border-left-color: #6668BD;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
padding: 5px 10px 5px 65px;
}
#rank_math_review_plugin_notice.is-dismissible:before,
#rank_math_pro_notice.is-dismissible:before {
content: '';
width: 50px;
height: 100%;
background: rgba(102, 104, 189, 0.09);
position: absolute;
left: 0;
top: 0;
}
#rank_math_review_plugin_notice.is-dismissible:after,
#rank_math_pro_notice.is-dismissible:after {
content: url('data:image/svg+xml;charset=UTF-8, <svg viewBox="0 0 462.03 462.03" xmlns="http://www.w3.org/2000/svg" width="20"><g fill="white"><path d="m462 234.84-76.17 3.43 13.43 21-127 81.18-126-52.93-146.26 60.97 10.14 24.34 136.1-56.71 128.57 54 138.69-88.61 13.43 21z"></path><path d="m54.1 312.78 92.18-38.41 4.49 1.89v-54.58h-96.67zm210.9-223.57v235.05l7.26 3 89.43-57.05v-181zm-105.44 190.79 96.67 40.62v-165.19h-96.67z"></path></g></svg>' );
padding: 3px;
border-radius: 3px;
position: absolute;
left: 12px;
top: 18px;
background: linear-gradient(-135deg, #2488e1, #724bb7);
width: 23px;
height: 23px;
display: flex;
justify-content: center;
line-height: 1;
align-items: center;
}
</style>
<?php
}
/**
* Add admin notice.
*
* @return void
*/
public function add_notice() {
$review_links = [
'https://www.trustpilot.com/review/www.rankmath.com',
'https://www.trustpilot.com/evaluate/www.rankmath.com',
];
$selected_link = $review_links[ array_rand( $review_links ) ];
$message = '<p>';
// Translators: placeholder is the plugin name.
$message .= sprintf( esc_html__( 'Hey, we noticed you\'ve been using %s for more than a week now that\'s awesome!', 'rank-math' ), '<strong>' . _x( 'Rank Math SEO', 'plugin name inside the review notice', 'rank-math' ) . '</strong>' );
$message .= '<br>';
$message .= esc_html__( 'We would love to get your feedback! It\'s essential for our continued development. Please consider taking a moment to leave a review of your experience on Trustpilot.', 'rank-math' ) . '</p>
<p><strong>Bhanu Ahluwalia</strong><br>' . esc_html__( 'Co-founder of Rank Math', 'rank-math' ) . '</p>
<p>
<a href="' . esc_url( $selected_link ) . '" class="rank-math-dismiss-review-notice rank-math-review-action rank-math-review-out" target="_blank" rel="noopener noreferrer"><strong>' . esc_html__( 'Yes, you deserve it', 'rank-math' ) . '</strong></a><br>
<a href="#" class="rank-math-dismiss-review-notice rank-math-maybe-later-action">' . esc_html__( 'No, maybe later', 'rank-math' ) . '</a><br>
<a href="#" class="rank-math-dismiss-review-notice rank-math-already-reviewed-action">' . esc_html__( 'I already did', 'rank-math' ) . '</a>
</p>';
Helper::add_notification(
$message,
[
'type' => 'info',
'id' => 'rank_math_review_plugin_notice',
'capability' => 'install_plugins',
]
);
update_option( 'rank_math_review_notice_added', '1', false );
}
/**
* Set "already reviewed" flag after the user dismisses the notice.
*
* @param string $notification_id Dismissed notice ID.
* @return void
*/
public function review_notice_after_dismiss( $notification_id ) {
if ( 'rank_math_review_plugin_notice' !== $notification_id ) {
return;
}
delete_option( 'rank_math_review_notice_date' );
delete_option( 'rank_math_review_notice_added' );
update_option( 'rank_math_review_notice_delayed', true, false );
}
/**
* Get stored notice start date.
*
* @return int
*/
public function get_review_notice_date() {
$review_notice_date = get_option( 'rank_math_review_notice_date' );
if ( false !== $review_notice_date ) {
return $review_notice_date;
}
$delay_days = 14;
if ( $this->install_date < $this->record_date && ! get_option( 'rank_math_review_notice_delayed' ) ) {
$delay_days = wp_rand( 7, 30 );
}
$review_notice_date = $this->current_time + ( $delay_days * DAY_IN_SECONDS );
update_option( 'rank_math_review_notice_date', $review_notice_date, false );
return $review_notice_date;
}
/**
* Set "already reviewed" flag.
*/
public function already_reviewed() {
check_ajax_referer( 'rank-math-ajax-nonce', 'security' );
$this->has_cap_ajax( 'onpage_general' );
update_option( 'rank_math_already_reviewed', Helper::get_current_time() );
$this->success( 'success' );
}
}

View File

@@ -0,0 +1,295 @@
<?php
/**
* Register all the necessary CSS and JS.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\KB;
use RankMath\Helper;
use RankMath\Runner;
use RankMath\Traits\Hooker;
use RankMath\Google\Console;
use RankMath\Google\Analytics;
use RankMath\Analytics\Url_Inspection;
use RankMath\Admin\Admin_Helper;
use RankMath\Helpers\Str;
defined( 'ABSPATH' ) || exit;
/**
* Assets class.
*
* @codeCoverageIgnore
*/
class Assets implements Runner {
use Hooker;
/**
* Prefix for the enqueue handles.
*/
const PREFIX = 'rank-math-';
/**
* Register hooks.
*/
public function hooks() {
$this->action( 'admin_enqueue_scripts', 'register' );
$this->action( 'admin_enqueue_scripts', 'enqueue' );
$this->action( 'admin_enqueue_scripts', 'overwrite_wplink', 99 );
if ( 'elementor' === \RankMath\Helpers\Param::get( 'action' ) ) {
$this->action( 'elementor/editor/before_enqueue_scripts', 'register' );
$this->action( 'elementor/editor/before_enqueue_scripts', 'enqueue' );
$this->action( 'elementor/editor/before_enqueue_scripts', 'overwrite_wplink', 99 );
}
}
/**
* Register styles and scripts.
*/
public function register() {
$js = rank_math()->plugin_url() . 'assets/admin/js/';
$css = rank_math()->plugin_url() . 'assets/admin/css/';
$vendor = rank_math()->plugin_url() . 'assets/vendor/';
// Styles.
wp_register_style( self::PREFIX . 'common', $css . 'common.css', null, rank_math()->version );
wp_register_style( self::PREFIX . 'cmb2', $css . 'cmb2.css', null, rank_math()->version );
wp_register_style( self::PREFIX . 'dashboard', $css . 'dashboard.css', [ 'rank-math-common', 'wp-components' ], rank_math()->version );
wp_register_style( self::PREFIX . 'dashboard-widget', $css . 'dashboard-widget.css', null, rank_math()->version );
// Scripts.
wp_register_script( self::PREFIX . 'common', $js . 'common.js', [ 'jquery', 'wp-i18n', 'lodash' ], rank_math()->version, true );
wp_register_script( self::PREFIX . 'dashboard', $js . 'dashboard.js', [ 'jquery', 'clipboard', 'lodash', 'wp-components', 'wp-element', 'rank-math-components' ], rank_math()->version, true );
wp_register_script( self::PREFIX . 'components', $js . 'components.js', [ 'lodash', 'wp-components', 'wp-element', 'wp-api-fetch' ], rank_math()->version, true );
// Select2.
wp_register_style( 'select2-rm', $vendor . 'select2/select2.min.css', null, '4.0.6-rc.1' );
wp_register_script( 'select2-rm', $vendor . 'select2/select2.min.js', null, '4.0.6-rc.1', true );
// Inline script for core admin page Settings > Permalinks.
wp_register_script( self::PREFIX . 'core-permalink-settings', '' ); // phpcs:ignore
wp_add_inline_script( self::PREFIX . 'core-permalink-settings', $this->get_permalinks_inline_script() );
if ( ! wp_script_is( 'wp-hooks', 'registered' ) ) {
wp_register_script( 'wp-hooks', rank_math()->plugin_url() . 'assets/vendor/hooks.js', [], rank_math()->version, true );
}
if ( ! wp_script_is( 'wp-wordcount', 'registered' ) ) {
wp_register_script( 'wp-wordcount', rank_math()->plugin_url() . 'assets/vendor/wordcount.js', [], rank_math()->version, true );
}
if ( ! wp_script_is( 'wp-autop', 'registered' ) ) {
wp_register_script( 'wp-autop', rank_math()->plugin_url() . 'assets/vendor/autop.js', [], rank_math()->version, true );
}
if ( ! wp_script_is( 'wp-url', 'registered' ) ) {
wp_register_script( 'wp-url', rank_math()->plugin_url() . 'assets/vendor/url.js', [], rank_math()->version, true );
}
if ( ! wp_script_is( 'wp-i18n', 'registered' ) ) {
wp_register_script( 'wp-i18n', rank_math()->plugin_url() . 'assets/vendor/i18n.js', [], rank_math()->version, true );
}
if ( ! wp_script_is( 'clipboard', 'registered' ) ) {
wp_register_script( 'clipboard', rank_math()->plugin_url() . 'assets/vendor/clipboard.min.js', [], rank_math()->version, true );
}
if ( ! wp_script_is( 'lodash', 'registered' ) ) {
wp_register_script( 'lodash', rank_math()->plugin_url() . 'assets/vendor/lodash.js', [], rank_math()->version, [] );
wp_add_inline_script( 'lodash', 'window.lodash = _.noConflict();' );
}
Helper::add_json(
'api',
[
'root' => esc_url_raw( get_rest_url() ),
'nonce' => ( wp_installing() && ! is_multisite() ) ? '' : wp_create_nonce( 'wp_rest' ),
]
);
Helper::add_json(
'keywordsApi',
[
'url' => 'https://api.rankmath.com/ltkw/v1/',
]
);
Helper::add_json(
'links',
KB::get_links()
);
Helper::add_json(
'validationl10n',
[
'regexErrorDefault' => __( 'Please use the correct format.', 'rank-math' ),
'requiredErrorDefault' => __( 'This field is required.', 'rank-math' ),
'emailErrorDefault' => __( 'Please enter a valid email address.', 'rank-math' ),
'urlErrorDefault' => __( 'Please enter a valid URL.', 'rank-math' ),
]
);
Helper::add_json( 'capitalizeTitle', Helper::get_settings( 'titles.capitalize_titles' ) );
Helper::add_json( 'isConsoleConnected', Console::is_console_connected() );
Helper::add_json( 'isAnalyticsConnected', Analytics::is_analytics_connected() );
Helper::add_json( 'isUrlInspectionEnabled', Url_Inspection::is_enabled() );
/**
* Allow other plugins to register/deregister admin styles or scripts after plugin assets.
*/
$this->do_action( 'admin/register_scripts' );
}
/**
* Enqueue styles and scripts.
*/
public function enqueue() {
$screen = get_current_screen();
if ( 'dashboard' === $screen->id ) {
wp_enqueue_style( self::PREFIX . 'dashboard-widget' );
wp_enqueue_script( self::PREFIX . 'dashboard' );
}
if ( in_array( $screen->id, [ 'toplevel_page_rank-math', 'rank-math_page_rank-math-content-ai-page', 'rank-math_page_rank-math-analytics', 'rank-math_page_rank-math-role-manager', 'rank-math_page_rank-math-seo-analysis', 'rank-math_page_rank-math-status' ], true ) ||
Str::starts_with( 'rank-math_page_rank-math-options-', $screen->id )
) {
Helper::add_json(
'dashboardHeader',
[
'dashboardUrl' => esc_url( Helper::get_admin_url() ),
'proBadge' => $this->do_filter( 'pro_badge', '' ),
]
);
}
// Our screens only.
if ( ! in_array( $screen->taxonomy, Helper::get_allowed_taxonomies(), true ) && ! in_array( $screen->id, $this->get_admin_screen_ids(), true ) ) {
return;
}
// Add thank you.
$this->filter( 'admin_footer_text', 'admin_footer_text' );
/**
* Allow other plugins to enqueue/dequeue admin styles or scripts after plugin assets.
*/
$this->do_action( 'admin/enqueue_scripts' );
}
/**
* Add footer credit on admin pages.
*
* @param string $text Default text for admin footer.
* @return string
*/
public function admin_footer_text( $text ) {
/* translators: plugin url */
return Helper::is_whitelabel() ? $text : sprintf( wp_kses_post( __( 'Thank you for using <a href="%s" target="_blank">Rank Math</a>', 'rank-math' ) ), KB::get( 'seo-suite', 'Admin Footer Text' ) );
}
/**
* Overwrite wplink script file.
* Rank Math adds new options in the link popup when editing a post.
*/
public function overwrite_wplink() {
wp_deregister_script( 'wplink' );
wp_register_script( 'wplink', rank_math()->plugin_url() . 'assets/admin/js/wplink.js', [ 'jquery', 'wp-a11y' ], rank_math()->version, true );
wp_localize_script(
'wplink',
'wpLinkL10n',
[
'title' => esc_html__( 'Insert/edit link', 'rank-math' ),
'update' => esc_html__( 'Update', 'rank-math' ),
'save' => esc_html__( 'Add Link', 'rank-math' ),
'noTitle' => esc_html__( '(no title)', 'rank-math' ),
'noMatchesFound' => esc_html__( 'No matches found.', 'rank-math' ),
'linkSelected' => esc_html__( 'Link selected.', 'rank-math' ),
'linkInserted' => esc_html__( 'Link inserted.', 'rank-math' ),
'relCheckbox' => __( 'Add <code>rel="nofollow"</code>', 'rank-math' ),
'sponsoredCheckbox' => __( 'Add <code>rel="sponsored"</code>', 'rank-math' ),
'linkTitle' => esc_html__( 'Link Title', 'rank-math' ),
]
);
}
/**
* Enqueues styles.
*
* @param string $style Name of the style.
*/
public function enqueue_style( $style ) {
wp_enqueue_style( self::PREFIX . $style );
}
/**
* Enqueues scripts.
*
* @param string $script Name of the script.
*/
public function enqueue_script( $script ) {
wp_enqueue_script( self::PREFIX . $script );
}
/**
* Get admin screen ids.
*
* @return array
*/
private function get_admin_screen_ids() {
$pages = [
'toplevel_page_rank-math',
'rank-math_page_rank-math-role-manager',
'rank-math_page_rank-math-seo-analysis',
'rank-math_page_rank-math-404-monitor',
'rank-math_page_rank-math-redirections',
'rank-math_page_rank-math-link-builder',
'rank-math_page_rank-math-analytics',
'rank-math_page_rank-math-import-export',
'rank-math_page_rank-math-help',
'user-edit',
'profile',
'rank_math_schema',
];
return array_merge( $pages, Helper::get_allowed_post_types() );
}
/**
* Inline script to warn the user about the risks of changing the permalinks on a live site.
*
* @return string
*/
public function get_permalinks_inline_script() {
// Don't add the script if site is set to noindex.
if ( ! get_option( 'blog_public' ) ) {
return '';
}
return "jQuery( window ).load( function() {
var noticeShown = false;
var showNotice = function() {
if ( noticeShown ) {
return true;
}
jQuery( '.rank-math-notice-permalinks-warning' ).removeClass( 'hidden' ).insertBefore( 'p.submit' );
noticeShown = true;
return true;
}
jQuery( '.available-structure-tags button' ).on( 'click', showNotice );
jQuery( 'input[type=text], input[type=radio]' ).on( 'focus change', showNotice );
} );";
}
}

View File

@@ -0,0 +1,197 @@
<?php
/**
* The admin post columns functionality.
*
* @since 1.0.212
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Helper;
use RankMath\Helpers\Param;
use RankMath\Helpers\Url;
use RankMath\Runner;
use RankMath\Traits\Hooker;
use RankMath\Admin\Admin_Helper;
defined( 'ABSPATH' ) || exit;
/**
* Post_Columns class.
*/
class Bulk_Actions implements Runner {
use Hooker;
/**
* SEO data.
*
* @var array
*/
private $data = [];
/**
* Register hooks.
*/
public function hooks() {
$this->action( 'current_screen', 'init' );
}
/**
* Intialize.
*/
public function init() {
if ( ! Helper::has_cap( 'onpage_general' ) || ! $this->can_add() ) {
return;
}
$this->register_post_columns();
$this->action( 'admin_enqueue_scripts', 'enqueue' );
}
/**
* Register post column hooks.
*/
private function register_post_columns() {
$post_types = Helper::get_allowed_post_types();
foreach ( $post_types as $post_type ) {
$this->filter( "bulk_actions-edit-{$post_type}", 'post_bulk_actions' );
$this->filter( "handle_bulk_actions-edit-{$post_type}", 'handle_bulk_actions', 10, 3 );
}
$taxonomies = Helper::get_accessible_taxonomies();
unset( $taxonomies['post_format'] );
$taxonomies = wp_list_pluck( $taxonomies, 'label', 'name' );
foreach ( $taxonomies as $taxonomy => $label ) {
$this->filter( "bulk_actions-edit-{$taxonomy}", 'post_bulk_actions' );
}
}
/**
* Add bulk actions for applicable posts, pages, CPTs.
*
* @param array $actions Actions.
* @return array New actions.
*/
public function post_bulk_actions( $actions ) {
$new_actions = [ 'rank_math_options' => __( '&#8595; Rank Math', 'rank-math' ) ];
if ( Helper::has_cap( 'onpage_advanced' ) ) {
$new_actions['rank_math_bulk_robots_noindex'] = __( 'Set to noindex', 'rank-math' );
$new_actions['rank_math_bulk_robots_index'] = __( 'Set to index', 'rank-math' );
$new_actions['rank_math_bulk_robots_nofollow'] = __( 'Set to nofollow', 'rank-math' );
$new_actions['rank_math_bulk_robots_follow'] = __( 'Set to follow', 'rank-math' );
$new_actions['rank_math_bulk_remove_canonical'] = __( 'Remove custom canonical URL', 'rank-math' );
if ( Helper::is_module_active( 'redirections' ) && Helper::has_cap( 'redirections' ) ) {
$new_actions['rank_math_bulk_redirect'] = __( 'Redirect', 'rank-math' );
$new_actions['rank_math_bulk_stop_redirect'] = __( 'Remove redirection', 'rank-math' );
}
}
if ( Helper::is_module_active( 'rich-snippet' ) && Helper::has_cap( 'onpage_snippet' ) ) {
$new_actions['rank_math_bulk_schema_none'] = __( 'Set Schema: None', 'rank-math' );
$post_type = Param::get( 'post_type', get_post_type() );
$post_type_default = Helper::get_settings( 'titles.pt_' . $post_type . '_default_rich_snippet' );
if ( $post_type_default ) {
// Translators: placeholder is the default Schema type setting.
$new_actions['rank_math_bulk_schema_default'] = sprintf( __( 'Set Schema: Default (%s)', 'rank-math' ), $post_type_default );
}
}
if ( Helper::has_cap( 'onpage_general' ) && Helper::should_determine_search_intent() ) {
$new_actions['rank_math_bulk_determine_search_intent'] = __( 'Determine Search Intent', 'rank-math' );
}
if ( is_array( $actions ) && count( $new_actions ) > 1 ) {
return array_merge( $actions, $new_actions );
}
return $actions;
}
/**
* Handle bulk actions for applicable posts, pages, CPTs.
*
* @param string $redirect Redirect URL.
* @param string $doaction Performed action.
* @param array $object_ids Post IDs.
*
* @return string New redirect URL.
*/
public function handle_bulk_actions( $redirect, $doaction, $object_ids ) {
if (
$doaction === 'rank_math_bulk_determine_search_intent' &&
(
defined( 'RANK_MATH_PRO_VERSION' ) &&
version_compare( RANK_MATH_PRO_VERSION, '3.0.83-beta', '<' )
)
) {
Helper::add_notification(
esc_html__( 'Your current plugin version does not support this feature. Please update Rank Math PRO to version 3.0.83 or later to unlock full functionality.', 'rank-math' ),
[
'type' => 'error',
'id' => 'rank_math_search_intent_error',
'classes' => 'rank-math-notice',
]
);
}
return $redirect;
}
/**
* Enqueue styles and scripts.
*/
public function enqueue() {
$screen = get_current_screen();
wp_enqueue_style( 'rank-math-post-bulk-edit', rank_math()->plugin_url() . 'assets/admin/css/post-list.css', [ 'wp-components' ], rank_math()->version );
if ( Admin_Helper::is_term_listing() ) {
$allow_editing = Helper::get_settings( 'titles.tax_' . $screen->taxonomy . '_bulk_editing', false );
} else {
$allow_editing = Helper::get_settings( 'titles.pt_' . $screen->post_type . '_bulk_editing', true );
}
if ( ! $allow_editing || 'readonly' === $allow_editing ) {
return;
}
wp_enqueue_script( 'rank-math-post-bulk-edit', rank_math()->plugin_url() . 'assets/admin/js/post-list.js', [ 'lodash', 'wp-element', 'wp-components' ], rank_math()->version, true );
Helper::add_json(
'contentAI',
[
'isUserRegistered' => Helper::is_site_connected(),
'credits' => Helper::get_content_ai_credits(),
'plan' => Helper::get_content_ai_plan(),
]
);
Helper::add_json( 'isProActive', defined( 'RANK_MATH_PRO_FILE' ) );
Helper::add_json( 'connectSiteUrl', Admin_Helper::get_activate_url( Url::get_current_url() ) );
}
/**
* Whether to add Bulk actions on the page.
*/
private function can_add() {
global $pagenow;
if ( 'edit-tags.php' === $pagenow ) {
return Helper::get_settings( 'titles.tax_' . Param::get( 'taxonomy' ) . '_add_meta_box' );
}
if ( Admin_Helper::is_post_list() || Admin_Helper::is_media_library() ) {
$screen = get_current_screen();
$allowed_post_types = Helper::get_allowed_post_types();
$allowed_post_types[] = 'attachment';
return in_array( $screen->post_type, $allowed_post_types, true );
}
return false;
}
}

View File

@@ -0,0 +1,334 @@
<?php
/**
* The CMB2 fields for the plugin.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Runner;
use RankMath\Helpers\Str;
use RankMath\Traits\Hooker;
use RankMath\Admin\Admin_Helper;
defined( 'ABSPATH' ) || exit;
/**
* CMB2_Fields class.
*
* @codeCoverageIgnore
*/
class CMB2_Fields implements Runner {
use Hooker;
/**
* Register hooks.
*/
public function hooks() {
if ( ! has_action( 'cmb2_render_switch' ) ) {
$this->action( 'cmb2_render_switch', 'render_switch', 10, 5 );
}
if ( ! has_action( 'cmb2_render_notice' ) ) {
$this->action( 'cmb2_render_notice', 'render_notice' );
}
if ( ! has_action( 'cmb2_render_address' ) ) {
$this->action( 'cmb2_render_address', 'render_address', 10, 5 );
}
if ( ! has_action( 'cmb2_render_advanced_robots' ) ) {
$this->action( 'cmb2_render_advanced_robots', 'render_advanced_robots', 10, 5 );
}
if ( ! has_action( 'cmb2_render_toggle' ) ) {
$this->action( 'cmb2_render_toggle', 'render_toggle', 10, 5 );
}
$this->filter( 'cmb2_sanitize_toggle', 'sanitize_toggle', 10, 2 );
$this->filter( 'cmb2_field_arguments_raw', 'default_value', 10, 2 );
}
/**
* Set a default value in default_cb to prevent the callback function from executing on the site.
*
* @see https://github.com/CMB2/CMB2/issues/750
*
* @param array $args The field arguments.
* @param object $cmb2 The CMB2 object.
*/
public function default_value( $args, $cmb2 ) {
if (
! Str::starts_with( 'rank-math', trim( $cmb2->cmb_id ) ) ||
! isset( $args['default'] ) ||
! is_callable( $args['default'] )
) {
return $args;
}
$args['default_cb'] = function () use ( $args ) {
return $args['default'];
};
$args['default'] = null;
return $args;
}
/**
* Sanitize toggle field.
*
* @param string $override_value Sanitization override value to return.
* @param string $value The field value.
*/
public function sanitize_toggle( $override_value, $value ) {
return is_null( $value ) ? 'off' : $value;
}
/**
* Render toggle field.
*
* @param array $field The passed in `CMB2_Field` object.
* @param mixed $escaped_value The value of this field escaped
* It defaults to `sanitize_text_field`.
* If you need the unescaped value, you can access it
* via `$field->value()`.
* @param int $object_id The ID of the current object.
* @param string $object_type The type of object you are working with.
* Most commonly, `post` (this applies to all post-types),
* but could also be `comment`, `user` or `options-page`.
* @param object $field_type_object This `CMB2_Types` object.
*/
public function render_toggle( $field, $escaped_value, $object_id, $object_type, $field_type_object ) {
$field_name = $field->_name();
$active_value = ! empty( $field->args( 'active_value' ) ) ? $field->args( 'active_value' ) : 'on';
$escaped_value = ! empty( $field->args( 'force_enable' ) ) ? 'on' : $escaped_value;
$args = [
'type' => 'checkbox',
'id' => $field_name,
'name' => $field_name,
'desc' => '',
'value' => $active_value,
'disabled' => isset( $field->args['disabled'] ) ? $field->args['disabled'] : false,
];
if ( $escaped_value === $active_value ) {
$args['checked'] = 'checked';
}
echo '<label class="cmb2-toggle">';
echo $field_type_object->input( $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- CMB2 handles escaping.
echo '<span class="cmb2-slider">';
echo '<svg width="3" height="8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 6" class="toggle_on" role="img" aria-hidden="true" focusable="false"><path d="M0 0h2v6H0z"></path></svg>';
echo '<svg width="8" height="8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 6 6" class="toggle_off" role="img" aria-hidden="true" focusable="false"><path d="M3 1.5c.8 0 1.5.7 1.5 1.5S3.8 4.5 3 4.5 1.5 3.8 1.5 3 2.2 1.5 3 1.5M3 0C1.3 0 0 1.3 0 3s1.3 3 3 3 3-1.3 3-3-1.3-3-3-3z"></path></svg>';
echo '</span>';
echo '</label>';
$field_type_object->_desc( true, true );
}
/**
* Render switch field.
*
* @param array $field The passed in `CMB2_Field` object.
* @param mixed $escaped_value The value of this field escaped
* It defaults to `sanitize_text_field`.
* If you need the unescaped value, you can access it
* via `$field->value()`.
* @param int $object_id The ID of the current object.
* @param string $object_type The type of object you are working with.
* Most commonly, `post` (this applies to all post-types),
* but could also be `comment`, `user` or `options-page`.
* @param object $field_type_object This `CMB2_Types` object.
*/
public function render_switch( $field, $escaped_value, $object_id, $object_type, $field_type_object ) {
if ( empty( $field->args['options'] ) ) {
$field->args['options'] = [
'off' => esc_html( $field->get_string( 'off', __( 'Off', 'rank-math' ) ) ),
'on' => esc_html( $field->get_string( 'on', __( 'On', 'rank-math' ) ) ),
];
}
$field->set_options();
echo $field_type_object->radio_inline(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- CMB2 handles escaping.
}
/**
* Render notices
*
* @param object $field The passed in `CMB2_Field` object.
*/
public function render_notice( $field ) {
$hash = [
'error' => 'notice notice-alt notice-error error inline rank-math-notice',
'info' => 'notice notice-alt notice-info info inline rank-math-notice',
'warning' => 'notice notice-alt notice-warning warning inline rank-math-notice',
];
echo '<div class="' . esc_attr( $hash[ $field->args( 'what' ) ] ) . '"><p>' . $field->args( 'content' ) . '</p></div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- CMB2 handles escaping.
}
/**
* Render address field.
*
* @param object $field The passed in `CMB2_Field` object.
* @param mixed $escaped_value The value of this field escaped
* It defaults to `sanitize_text_field`.
* If you need the unescaped value, you can access it
* via `$field->value()`.
* @param int $object_id The ID of the current object.
* @param string $object_type The type of object you are working with.
* Most commonly, `post` (this applies to all post-types),
* but could also be `comment`, `user` or `options-page`.
* @param object $field_type_object This `CMB2_Types` object.
*/
public function render_address( $field, $escaped_value, $object_id, $object_type, $field_type_object ) {
// Make sure we assign each part of the value we need.
$value = wp_parse_args(
$escaped_value,
[
'streetAddress' => '',
'addressLocality' => '',
'addressRegion' => '',
'postalCode' => '',
'addressCountry' => '',
]
);
$strings = [
'streetAddress' => 'Street Address',
'addressLocality' => 'Locality',
'addressRegion' => 'Region',
'postalCode' => 'Postal Code',
'addressCountry' => '2-letter Country Code (ISO 3166-1)',
];
foreach ( array_keys( $value ) as $id ) :
$field_input = $field_type_object->input(
[
'name' => $field_type_object->_name( '[' . $id . ']' ),
'id' => $field_type_object->_id( '_' . $id ),
'value' => $value[ $id ],
'placeholder' => esc_html( $field->get_string( $id . '_text', $strings[ $id ] ) ),
]
);
echo '<div class="cmb-address-field">' . $field_input . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- CMB2 handles escaping.
endforeach;
}
/**
* Render Advanced Robots fields.
*
* @param object $field The passed in `CMB2_Field` object.
* @param mixed $escaped_value The value of this field escaped
* It defaults to `sanitize_text_field`.
* If you need the unescaped value, you can access it
* via `$field->value()`.
* @param int $object_id The ID of the current object.
* @param string $object_type The type of object you are working with.
* Most commonly, `post` (this applies to all post-types),
* but could also be `comment`, `user` or `options-page`.
* @param object $field_type_object This `CMB2_Types` object.
*/
public function render_advanced_robots( $field, $escaped_value, $object_id, $object_type, $field_type_object ) {
// Make sure we assign each part of the value we need.
$values = wp_parse_args(
$escaped_value,
[
'max-snippet' => -1,
'max-video-preview' => -1,
'max-image-preview' => 'large',
]
);
$strings = [
'max-snippet' => __( 'Snippet', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Specify a maximum text-length, in characters, of a snippet for your page.', 'rank-math' ) ),
'max-video-preview' => __( 'Video Preview', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Specify a maximum duration in seconds of an animated video preview.', 'rank-math' ) ),
'max-image-preview' => __( 'Image Preview', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Specify a maximum size of image preview to be shown for images on this page.', 'rank-math' ) ),
];
echo '<ul class="cmb-advanced-robots-list no-select-all cmb2-list cmb-rank-math-advanced-robots-field">';
foreach ( $values as $id => $value ) :
$value = isset( $escaped_value[ $id ] ) ? $escaped_value[ $id ] : $value;
echo '<li>';
echo '<label for="' . esc_attr( $field_type_object->_id( '_' . $id . '_name' ) ) . '">';
echo $this->get_advanced_robots_field( 'checkbox', $field_type_object, $id, $value, $escaped_value ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- CMB2 handles escaping.
echo wp_kses_post( $field->get_string( $id . '_text', $strings[ $id ] ) ) . '</label>';
if ( 'max-image-preview' === $id ) {
echo $this->get_advanced_robots_field( 'select', $field_type_object, $id, $value, $escaped_value ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- CMB2 handles escaping.
}
if ( 'max-image-preview' !== $id ) {
echo $this->get_advanced_robots_field( 'input', $field_type_object, $id, $value, $escaped_value ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- CMB2 handles escaping.
}
echo '</li>';
endforeach;
echo '</ul>';
}
/**
* Get the field markup for the advanced robots field.
*
* @param string $field_type The type of field.
* @param object $field_type_object The CMB2_Types object.
* @param string $id The field id.
* @param string $value The field value.
* @param string $escaped_value The escaped field value.
*
* @return string The field markup.
*/
private function get_advanced_robots_field( $field_type, $field_type_object, $id, $value, $escaped_value ) {
$props = [
'name' => $field_type_object->_name( "[{$id}][length]" ),
'id' => $field_type_object->_id( '_' . $id . '_name' ),
];
switch ( $field_type ) {
case 'checkbox':
$props['name'] = $field_type_object->_name( "[{$id}][enable]" );
$props['value'] = true;
$props['checked'] = ! empty( $escaped_value[ $id ] ) || empty( $escaped_value ) ? 'checked' : false;
break;
case 'select':
$props['options'] = $this->get_image_sizes( $value );
break;
case 'input':
$props['value'] = $value ? $value : -1;
$props['type'] = 'number';
$props['min'] = -1;
break;
}
return $field_type_object->$field_type( $props );
}
/**
* Get Image sizes.
*
* @param string $size The selected image size.
* @return string $options The image sizes.
*/
private function get_image_sizes( $size = 'large' ) {
$values = [
'large' => __( 'Large', 'rank-math' ),
'standard' => __( 'Standard', 'rank-math' ),
'none' => __( 'None', 'rank-math' ),
];
$options = '';
foreach ( $values as $data => $label ) {
$options .= '<option value="' . $data . '" ' . selected( $size, $data, false ) . ' >' . $label . '</option>';
}
return $options;
}
}

View File

@@ -0,0 +1,496 @@
<?php
/**
* The option page functionality of the plugin.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use WP_Http;
use RankMath\KB;
use RankMath\CMB2;
use RankMath\Helper;
use RankMath\Traits\Hooker;
use RankMath\Helpers\Str;
use RankMath\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
* CMB2_Options class.
*/
class CMB2_Options {
use Hooker;
/**
* Page title.
*
* @var string
*/
public $title = 'Settings';
/**
* Menu title.
*
* @var string
*/
public $menu_title = 'Settings';
/**
* Hold tabs for page.
*
* @var array
*/
public $tabs = [];
/**
* Hold folder name for tab files.
*
* @var string
*/
public $folder = '';
/**
* Menu Position.
*
* @var int
*/
public $position = 10;
/**
* The capability required for this menu to be displayed to the user.
*
* @var string
*/
public $capability = 'manage_options';
/**
* CMB2 option page id.
*
* @var string
*/
private $cmb_id = null;
/**
* Options key.
*
* @var string
*/
public $key = '';
/**
* The Constructor
*
* @param array $config Array of configuration.
*/
public function __construct( $config ) {
$this->config( $config );
$this->cmb_id = $this->key . '_options';
$this->action( 'cmb2_admin_init', 'register_option_page', $this->position );
$this->action( 'admin_post_' . $this->key, 'reset_options', 2 );
if ( true === empty( get_option( $this->key ) ) ) {
$this->action( 'cmb2_init_hookup_' . $this->cmb_id, 'set_defaults', 11 );
}
if ( ! $this->is_current_page() ) {
return;
}
$this->action( 'admin_enqueue_scripts', 'enqueue' );
$this->action( 'admin_body_class', 'body_class' );
// Check for fields and act accordingly.
$this->action( 'cmb2_save_options-page_fields_rank-math-options-general_options', 'check_updated_fields', 25, 2 );
$this->action( 'cmb2_save_options-page_fields_rank-math-options-titles_options', 'check_updated_fields', 25, 2 );
}
/**
* Create cmb2 box.
*
* @return CMB2
*/
private function create_cmb2() {
return new_cmb2_box(
[
'id' => $this->cmb_id,
'title' => $this->title,
'menu_title' => $this->menu_title,
'capability' => $this->capability,
'object_types' => [ 'options-page' ],
'option_key' => $this->key,
'parent_slug' => 'rank-math',
'cmb_styles' => false,
'display_cb' => [ $this, 'display' ],
]
);
}
/**
* Create option object and add settings.
*/
public function register_option_page() {
$cmb = $this->create_cmb2();
$tabs = $this->get_tabs();
$cmb->add_field(
[
'id' => 'setting-panel-container-' . $this->cmb_id,
'type' => 'tab_container_open',
'classes' => 'before-header',
'tabs' => $tabs,
]
);
foreach ( $tabs as $id => $tab ) {
$located = $this->locate_file( $id, $tab );
if ( false === $located ) {
continue;
}
$cmb->add_field(
[
'name' => esc_html__( 'Panel', 'rank-math' ),
'id' => 'setting-panel-' . $id,
'type' => 'tab',
'open' => true,
'classes' => isset( $tab['classes'] ) ? $tab['classes'] : '',
]
);
$cmb->add_field(
[
'id' => $id . '_section_title',
'type' => 'title',
'name' => isset( $tab['page_title'] ) ? $tab['page_title'] : ( isset( $tab['title'] ) ? $tab['title'] : '' ),
'desc' => isset( $tab['desc'] ) ? $tab['desc'] : '',
'after' => isset( $tab['after'] ) ? $tab['after'] : '',
'classes' => 'tab-header',
'after_row' => isset( $tab['after_row'] ) ? $tab['after_row'] : '',
]
);
include $located;
$this->do_action( "admin/settings/{$id}", $cmb, $tab );
$cmb->add_field(
[
'id' => 'setting-panel-' . $id . '-close',
'type' => 'tab',
]
);
}
$cmb->add_field(
[
'id' => 'setting-panel-container-close-' . $this->cmb_id,
'type' => 'tab_container_close',
]
);
CMB2::pre_init( $cmb );
}
/**
* Set the default values if not set.
*
* @param CMB2 $cmb The CMB2 object to hookup.
*/
public function set_defaults( $cmb ) {
foreach ( $cmb->prop( 'fields' ) as $id => $field_args ) {
$field = $cmb->get_field( $id );
if ( isset( $field_args['default'] ) || isset( $field_args['default_cb'] ) ) {
$defaults[ $id ] = $field->get_default();
}
}
// Save Defaults if any.
if ( ! empty( $defaults ) ) {
add_option( $this->key, $defaults );
}
}
/**
* Reset options.
*/
public function reset_options() {
if ( ! check_admin_referer( 'rank-math-reset-options' ) || ! current_user_can( 'manage_options' ) ) {
return false;
}
$url = wp_get_referer();
if ( ! $url ) {
$url = admin_url();
}
if ( filter_has_var( INPUT_POST, 'reset-cmb' ) && Param::post( 'action' ) === $this->key ) {
delete_option( $this->key );
Helper::redirect( esc_url_raw( $url ), WP_Http::SEE_OTHER );
exit;
}
}
/**
* Enqueue styles and scripts.
*/
public function enqueue() {
$screen = get_current_screen();
if ( ! Str::contains( $this->key, $screen->id ) ) {
return;
}
\CMB2_Hookup::enqueue_cmb_css();
rank_math()->variables->setup_json();
wp_enqueue_style( 'rank-math-options', rank_math()->plugin_url() . 'assets/admin/css/option-panel.css', [ 'select2-rm', 'rank-math-common', 'rank-math-cmb2' ], rank_math()->version );
wp_enqueue_script( 'rank-math-options', rank_math()->plugin_url() . 'assets/admin/js/option-panel.js', [ 'underscore', 'select2-rm', 'lodash', 'rank-math-common', 'wp-api-fetch' ], rank_math()->version, true );
// Add thank you.
Helper::add_json( 'indexUrl', rank_math()->plugin_url() . 'assets/admin/js/search-index/' );
Helper::add_json( 'optionPage', str_replace( 'rank-math-options-', '', $this->key ) );
}
/**
* Add classes to <body> of WordPress admin.
*
* @param string $classes List of CSS classes.
* @return string
*/
public function body_class( $classes = '' ) {
$mode = Helper::is_advanced_mode() ? 'advanced' : 'basic';
return $classes . ' rank-math-page rank-math-mode-' . $mode;
}
/**
* Display Setting on a page.
*
* @param CMB2_Options $machine Current CMB2 box object.
*/
public function display( $machine ) {
$cmb = $machine->cmb;
// Header.
rank_math()->admin->display_admin_header();
?>
<?php if ( ! defined( 'RANK_MATH_PRO_FILE' ) ) : ?>
<div class="rank-math-unlock-pro-notice" id="rank-math-unlock-pro-notice">
<a href="<?php KB::the( 'pro', 'Unlock PRO Options Panel Notice' ); ?>" target="_blank" class="pro-link">
<p>
<?php esc_html_e( 'Take your SEO to the Next Level!', 'rank-math' ); ?>
<strong><?php esc_html_e( 'Get Rank Math PRO!', 'rank-math' ); ?></strong>
<span><?php esc_html_e( 'Click here to see all the exciting features.', 'rank-math' ); ?></span>
</p>
<div class="close-notice">
<span class="dashicons dashicons-dismiss"></span>
</div>
</a>
</div>
<?php endif; ?>
<div class="wrap rank-math-wrap rank-math-wrap-settings">
<span class="wp-header-end"></span>
<form class="cmb-form" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="POST" id="<?php echo esc_attr( $cmb->cmb_id ); ?>" enctype="multipart/form-data" encoding="multipart/form-data">
<input type="hidden" name="action" value="<?php echo esc_attr( $machine->option_key ); ?>">
<?php $machine->options_page_metabox(); ?>
<footer class="form-footer rank-math-ui settings-footer wp-clearfix">
<?php wp_nonce_field( 'rank-math-reset-options' ); ?>
<input type="submit" name="submit-cmb" id="submit-cmb" title="<?php echo esc_html__( 'Ctrl/Cmd + Enter', 'rank-math' ); ?>" class="button button-primary save-options" value="<?php esc_attr_e( 'Save Changes', 'rank-math' ); ?>">
<input type="submit" name="reset-cmb" id="rank-math-reset-cmb" value="<?php esc_attr_e( 'Reset Options', 'rank-math' ); ?>" class="button button-secondary reset-options alignleft">
</footer>
</form>
</div>
<?php
}
/**
* Check if we are on the correct page.
*
* @return bool
*/
public function is_current_page() {
return Param::request( 'page' ) === $this->key || Param::request( 'action' ) === $this->key;
}
/**
* Check if certain fields got updated.
*
* @param int $object_id The ID of the current object.
* @param array $updated Array of field ids that were updated.
* Will only include field ids that had values change.
*/
public function check_updated_fields( $object_id, $updated ) {
/**
* Filter: Allow developers to add option fields which will flush the rewrite rules when updated.
*
* @param array $flush_fields Array of field IDs for which we need to flush.
*/
$flush_fields = $this->do_filter(
'flush_fields',
[
'strip_category_base',
'disable_author_archives',
'url_author_base',
'attachment_redirect_urls',
'attachment_redirect_default',
'nofollow_external_links',
'nofollow_image_links',
'nofollow_domains',
'nofollow_exclude_domains',
'new_window_external_links',
'redirections_header_code',
'redirections_post_redirect',
'redirections_debug',
]
);
foreach ( $flush_fields as $field_id ) {
if ( in_array( $field_id, $updated, true ) ) {
Helper::schedule_flush_rewrite();
break;
}
}
$this->maybe_update_htaccess();
}
/**
* Update .htaccess.
*/
private function maybe_update_htaccess() {
if ( empty( Param::post( 'htaccess_accept_changes' ) ) ) {
return;
}
if ( ! is_super_admin() || ! Helper::has_cap( 'general' ) || ! Helper::has_cap( 'edit_htaccess' ) ) {
Helper::add_notification(
esc_html__( 'You do not have permission to edit the .htaccess file.', 'rank-math' ),
[ 'type' => 'error' ]
);
return;
}
if ( ! Helper::is_edit_allowed() ) {
Helper::add_notification(
esc_html__( 'You do not have permission to edit the .htaccess file.', 'rank-math' ),
[ 'type' => 'error' ]
);
return;
}
// phpcs:ignore= WordPress.Security.ValidatedSanitizedInput, WordPress.Security.NonceVerification -- Writing to .htaccess file and escaping for HTML will break functionality & CMB2 package handles the nonce verification
$content = isset( $_POST['htaccess_content'] ) ? wp_unslash( $_POST['htaccess_content'] ) : '';
if ( empty( $content ) ) {
return;
}
if ( ! $this->do_htaccess_backup() ) {
Helper::add_notification(
esc_html__( 'Failed to backup .htaccess file. Please check file permissions.', 'rank-math' ),
[ 'type' => 'error' ]
);
return;
}
if ( ! $this->do_htaccess_update( $content ) ) {
Helper::add_notification(
esc_html__( 'Failed to update .htaccess file. Please check file permissions.', 'rank-math' ),
[ 'type' => 'error' ]
);
return;
}
Helper::add_notification( esc_html__( '.htaccess file updated successfully.', 'rank-math' ) );
}
/**
* Create htaccess backup.
*
* @return bool
*/
private function do_htaccess_backup() {
if ( ! Helper::is_filesystem_direct() ) {
return false;
}
$wp_filesystem = Helper::get_filesystem();
$path = get_home_path();
$file = $path . '.htaccess';
if ( ! $wp_filesystem->is_writable( $path ) || ! $wp_filesystem->exists( $file ) ) {
return false;
}
$backup = $path . uniqid( '.htaccess_back_' );
return $wp_filesystem->copy( $file, $backup, true );
}
/**
* Update htaccess file.
*
* @param string $content Htaccess content.
* @return string|bool
*/
private function do_htaccess_update( $content ) {
if ( empty( $content ) || ! Helper::is_filesystem_direct() ) {
return false;
}
$wp_filesystem = Helper::get_filesystem();
$htaccess_file = get_home_path() . '.htaccess';
return ! $wp_filesystem->is_writable( $htaccess_file ) ? false : $wp_filesystem->put_contents( $htaccess_file, $content );
}
/**
* Get setting tabs.
*
* @return array
*/
private function get_tabs() {
$filter = str_replace( '-', '_', str_replace( 'rank-math-', '', $this->key ) );
/**
* Allow developers to add new tabs into option panel.
*
* The dynamic part of hook is, page name without 'rank-math-' prefix.
*
* @param array $tabs
*/
return $this->do_filter( "admin/options/{$filter}_tabs", $this->tabs );
}
/**
* Locate tab options file.
*
* @param string $id Tab id.
* @param array $tab Tab options.
* @return string|boolean
*/
private function locate_file( $id, $tab ) {
if ( isset( $tab['type'] ) && 'seprator' === $tab['type'] ) {
return false;
}
$file = isset( $tab['file'] ) && ! empty( $tab['file'] ) ? $tab['file'] : rank_math()->includes_dir() . "settings/{$this->folder}/{$id}.php";
return file_exists( $file ) ? $file : false;
}
}

View File

@@ -0,0 +1,224 @@
<?php
/**
* The Dashboard Widget of the plugin.
*
* @since 1.0.81
* @package RankMath
* @subpackage RankMath\Core
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath;
use RankMath\KB;
use RankMath\Helper;
use RankMath\Traits\Hooker;
defined( 'ABSPATH' ) || exit;
/**
* Dashboard_Widget class.
*
* @codeCoverageIgnore
*/
class Dashboard_Widget {
use Hooker;
/**
* Constructor.
*/
public function __construct() {
$this->action( 'wp_dashboard_setup', 'add_dashboard_widgets' );
$this->action( 'rank_math/dashboard/widget', 'dashboard_widget_feed', 98 );
$this->action( 'rank_math/dashboard/widget', 'dashboard_widget_footer', 99 );
}
/**
* Register dashboard widget.
*/
public function add_dashboard_widgets() {
// Early Bail if action is not registered for the dashboard widget hook.
if (
( ! Helper::is_module_active( '404-monitor' ) || ! Helper::has_cap( '404_monitor' ) ) &&
( ! Helper::is_module_active( 'redirections' ) || ! Helper::has_cap( 'redirections' ) ) &&
( ! Helper::is_module_active( 'analytics' ) || ! Helper::has_cap( 'analytics' ) )
) {
return;
}
$icon = '<span class="rank-math-icon"><svg viewBox="0 0 462.03 462.03" xmlns="http://www.w3.org/2000/svg" width="20"><g><path d="m462 234.84-76.17 3.43 13.43 21-127 81.18-126-52.93-146.26 60.97 10.14 24.34 136.1-56.71 128.57 54 138.69-88.61 13.43 21z"></path><path d="m54.1 312.78 92.18-38.41 4.49 1.89v-54.58h-96.67zm210.9-223.57v235.05l7.26 3 89.43-57.05v-181zm-105.44 190.79 96.67 40.62v-165.19h-96.67z"></path></g></svg></span>';
wp_add_dashboard_widget(
'rank_math_dashboard_widget',
$icon . esc_html__( 'Rank Math Overview', 'rank-math' ),
[ $this, 'render_dashboard_widget' ],
null,
null,
'normal',
'high'
);
}
/**
* Render dashboard widget.
*/
public function render_dashboard_widget() {
echo '<div id="rank-math-dashboard-widget" class="rank-math-loading"></div>';
}
/**
* Add Feed data in the admin dashboard widget.
*/
public function dashboard_widget_feed() {
$posts = $this->get_feed();
?>
<h3 class="rank-math-blog-title"><?php esc_html_e( 'Latest Blog Posts from Rank Math', 'rank-math' ); ?></h3>
<?php if ( empty( $posts ) ) : ?>
<p><?php esc_html_e( 'Error: the Rank Math blog feed could not be downloaded.', 'rank-math' ); ?></p>
<?php
return;
endif;
echo '<ul class="rank-math-blog-list">';
$posts = $this->filter_posts( $posts );
$label = $this->get_item_label( $posts );
foreach ( $posts as $index => $post ) :
$link = $this->add_utm_params( $post['link'], $index );
?>
<li class="rank-math-blog-post">
<h4>
<?php if ( $label ) : ?>
<span class="rank-math-new-badge"><?php echo esc_html( $label ); ?></span>
<?php endif; ?>
<a target="_blank" href="<?php echo esc_url( $link ); ?>">
<?php echo esc_html( $post['title']['rendered'] ); ?>
</a>
</h4>
</li>
<?php
$label = '';
endforeach;
echo '</ul>';
}
/**
* Get label for first post.
*
* @param array $posts Posts.
*/
private function get_item_label( $posts ) {
$label = '';
if ( ! empty( $posts[0]['custom_label'] ) ) {
$label = $posts[0]['custom_label'];
}
$is_new = time() - strtotime( $posts[0]['date'] ) < 15 * DAY_IN_SECONDS;
if ( $is_new && empty( $label ) ) {
$label = esc_html__( 'NEW', 'rank-math' );
}
return $label;
}
/**
* Filter posts by display condition.
*
* @param array $posts Posts.
*/
private function filter_posts( $posts ) {
$posts = array_filter(
$posts,
function ( $post ) {
if ( isset( $post['condition'] ) && 'is_free' === $post['condition'] && defined( 'RANK_MATH_PRO_FILE' ) ) {
return false;
}
return true;
}
);
return array_slice( $posts, 0, 3 ); // Max 3 posts.
}
/**
* Add UTM tags to links. Only add if UTM params are not already present.
*
* @param string $link Link.
* @param int $index Array index.
*/
private function add_utm_params( $link, $index ) {
// Skip if link has any UTM tags already set.
if ( preg_match( '/[?&]utm_[a-z_]+=/', $link ) ) {
return $link;
}
$utm_params = [
'utm_source' => 'Plugin',
'utm_medium' => 'Dashboard%20Widget%20Post%20' . ( $index + 1 ),
'utm_campaign' => 'WP',
];
return add_query_arg( $utm_params, $link );
}
/**
* Add footer in the admin dashboard widget.
*/
public function dashboard_widget_footer() {
?>
<div class="rank-math-widget-footer">
<a target="_blank" href="<?php KB::the( 'blog', 'Dashboard Widget Blog' ); ?>">
<?php esc_html_e( 'Blog', 'rank-math' ); ?>
<span class="screen-reader-text"><?php esc_html_e( '(opens in a new window)', 'rank-math' ); ?></span>
<span aria-hidden="true" class="dashicons dashicons-external"></span>
</a>
<a target="_blank" href="<?php KB::the( 'knowledgebase', 'Dashboard Widget Help' ); ?>">
<?php esc_html_e( 'Help', 'rank-math' ); ?>
<span class="screen-reader-text"><?php esc_html_e( '(opens in a new window)', 'rank-math' ); ?></span>
<span aria-hidden="true" class="dashicons dashicons-external"></span>
</a>
<?php if ( ! defined( 'RANK_MATH_PRO_FILE' ) ) { ?>
<a target="_blank" href="<?php KB::the( 'pro', 'Dashboard Widget PRO' ); ?>" class="rank-math-widget-go-pro">
<?php esc_html_e( 'Go Pro', 'rank-math' ); ?>
<span class="screen-reader-text"><?php esc_html_e( '(opens in a new window)', 'rank-math' ); ?></span>
<span aria-hidden="true" class="dashicons dashicons-external"></span>
</a>
<?php } ?>
</div>
<?php
}
/**
* Get posts.
*/
private function get_feed() {
$cache_key = 'rank_math_feed_posts_v2';
$cache = get_transient( $cache_key );
if ( false !== $cache ) {
return $cache;
}
$response = wp_remote_get( 'https://rankmath.com/wp-json/wp/v2/posts?dashboard_widget_feed=1' );
if ( is_wp_error( $response ) || 200 !== (int) wp_remote_retrieve_response_code( $response ) ) {
set_transient( $cache_key, [], 2 * HOUR_IN_SECONDS );
return false;
}
$posts = json_decode( wp_remote_retrieve_body( $response ), true );
if ( empty( $posts ) || ! is_array( $posts ) ) {
set_transient( $cache_key, [], 2 * HOUR_IN_SECONDS );
return false;
}
set_transient( $cache_key, $posts, 12 * HOUR_IN_SECONDS );
return $posts;
}
}

View File

@@ -0,0 +1,102 @@
<?php
/**
* The Import Export Class
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use WP_REST_Response;
use RankMath\Helper;
use RankMath\Runner;
use RankMath\Traits\Ajax;
use RankMath\Traits\Hooker;
use RankMath\Helpers\Param;
use RankMath\Status\Backup;
use RankMath\Admin\Importers\Detector;
defined( 'ABSPATH' ) || exit;
/**
* Import_Export class.
*/
class Import_Export implements Runner {
use Hooker;
use Ajax;
/**
* Register hooks.
*/
public function hooks() {
$this->ajax( 'clean_plugin', 'clean_plugin' );
$this->ajax( 'import_plugin', 'import_plugin' );
}
/**
* Get localized JSON data to be used on the Import & Export tab of the Status & Tools page.
*/
public static function get_json_data() {
$detector = new Detector();
$importable_plugins = $detector->detect();
return [
'backups' => Backup::get_backups(),
'importablePlugins' => $importable_plugins,
];
}
/**
* Handles AJAX run plugin clean.
*/
public function clean_plugin() {
$this->verify_nonce( 'rank-math-ajax-nonce' );
$this->has_cap_ajax( 'general' );
$result = Detector::run_by_slug( Param::post( 'pluginSlug' ), 'cleanup' );
if ( $result['status'] ) {
/* translators: Plugin name */
$this->success( sprintf( esc_html__( 'Cleanup of %s data successfully done.', 'rank-math' ), $result['importer']->get_plugin_name() ) );
}
/* translators: Plugin name */
$this->error( sprintf( esc_html__( 'Cleanup of %s data failed.', 'rank-math' ), $result['importer']->get_plugin_name() ) );
}
/**
* Handles AJAX run plugin import.
*/
public function import_plugin() {
$this->verify_nonce( 'rank-math-ajax-nonce' );
$this->has_cap_ajax( 'general' );
$perform = Param::post( 'perform', '', FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH | FILTER_FLAG_STRIP_BACKTICK );
if ( ! $this->is_action_allowed( $perform ) ) {
$this->error( esc_html__( 'Action not allowed.', 'rank-math' ) );
}
try {
$result = Detector::run_by_slug( Param::post( 'pluginSlug' ), 'import', $perform );
$this->success( $result );
} catch ( \Exception $e ) {
$this->error( $e->getMessage() );
}
}
/**
* Check if given action is in the list of allowed actions.
*
* @param string $perform Action to check.
*
* @return bool
*/
private function is_action_allowed( $perform ) {
$allowed = [ 'settings', 'postmeta', 'termmeta', 'usermeta', 'redirections', 'blocks', 'deactivate', 'locations', 'news', 'video', 'recalculate' ];
return $perform && in_array( $perform, $allowed, true );
}
}

View File

@@ -0,0 +1,69 @@
<?php
/**
* The List Table Base CLass.
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMath\Admin
* @author RankMath <support@rankmath.com>
*/
namespace RankMath\Admin;
use WP_List_Table;
use RankMath\Helpers\Param;
/**
* List_Table class.
*/
class List_Table extends WP_List_Table {
/**
* Message to be displayed when there are no items.
*/
public function no_items() {
echo isset( $this->_args['no_items'] ) ? wp_kses_post( $this->_args['no_items'] ) : esc_html__( 'No items found.', 'rank-math' );
}
/**
* Get order setting.
*
* @return string
*/
protected function get_order() {
$order = Param::request( 'order', 'desc' );
return in_array( $order, [ 'desc', 'asc' ], true ) ? strtoupper( $order ) : 'DESC';
}
/**
* Get orderby setting.
*
* @param string $default_value (Optional) Extract order by from request.
*
* @return string
*/
protected function get_orderby( $default_value = 'create_date' ) {
return Param::get( 'orderby', $default_value, FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH | FILTER_FLAG_STRIP_BACKTICK );
}
/**
* Get search query variable.
*
* @return bool|string
*/
protected function get_search() {
return Param::request( 's', false, FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_BACKTICK );
}
/**
* Set column headers.
*
* @codeCoverageIgnore
*/
protected function set_column_headers() {
$this->_column_headers = [
$this->get_columns(),
[],
$this->get_sortable_columns(),
];
}
}

View File

@@ -0,0 +1,113 @@
<?php
/**
* The admin-specific functionality of the plugin.
*
* @since 1.0.223
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Helper;
use RankMath\Helpers\Editor;
use RankMath\Helpers\Param;
use RankMath\Traits\Hooker;
defined( 'ABSPATH' ) || exit;
/**
* Lock_Modified_Date class.
*
* @codeCoverageIgnore
*/
class Lock_Modified_Date {
use Hooker;
/**
* Register hooks.
*/
public function __construct() {
$this->action( 'rest_api_init', 'init_rest_api' );
$this->action( 'wp_insert_post_data', 'update_modified_date', 999, 3 );
}
/**
* Add REST filter to modify the post object.
*/
public function init_rest_api() {
$post_types = Helper::get_allowed_post_types();
foreach ( $post_types as $post_type ) {
$this->filter( "rest_pre_insert_{$post_type}", 'update_last_modified_parameter', 99, 2 );
}
}
/**
* Add last_modified parameter to a post when a post is updated from Block Editor.
*
* @param WP_POST $prepared_post Post object.
* @param WP_REST_Request $request Request object.
*/
public function update_last_modified_parameter( $prepared_post, $request ) {
$params = $request->get_params();
if ( isset( $params['meta']['rank_math_lock_modified_date'] ) ) {
$prepared_post->lock_modified_date = ! empty( $params['meta']['rank_math_lock_modified_date'] );
}
return $prepared_post;
}
/**
* Lock Modified date by overwriting the old value.
*
* @param array $data An array of slashed, sanitized, and processed post data.
* @param array $postarr An array of sanitized (and slashed) but otherwise unmodified post data.
*/
public function update_modified_date( $data, $postarr ) {
$post_id = ! empty( $postarr['ID'] ) ? $postarr['ID'] : 0;
if (
! $post_id ||
! isset( $postarr['post_modified'], $postarr['post_modified_gmt'] ) ||
! $this->lock_modified_date( $postarr, $post_id )
) {
return $data;
}
$data['post_modified'] = $postarr['post_modified'];
$data['post_modified_gmt'] = $postarr['post_modified_gmt'];
return $data;
}
/**
* Whether to lock modified date.
*
* @param array $data An array of sanitized (and slashed) but otherwise unmodified post data.
* @param int $post_id Post ID.
*/
private function lock_modified_date( $data, $post_id ) {
if ( ! Editor::can_add_lock_modified_date() ) {
return false;
}
if ( Param::request( 'action' ) === 'et_fb_ajax_save' ) {
if (
empty( $_REQUEST['et_fb_save_nonce'] ) ||
! wp_verify_nonce( Param::request( 'et_fb_save_nonce' ), 'et_fb_save_nonce' )
) {
return false;
}
$options = ! empty( $_REQUEST['options'] ) ? $_REQUEST['options'] : []; //phpcs:ignore
return ! empty( $options['conditional_tags'] ) && ! empty( $options['conditional_tags']['lock_modified_date'] );
}
if ( Param::request( 'action' ) === 'elementor_ajax' ) {
return wp_verify_nonce( Param::request( '_nonce' ), 'elementor_ajax' ) && ! empty( $_REQUEST['lock_modified_date'] );
}
return isset( $data['lock_modified_date'] ) ? $data['lock_modified_date'] : Helper::get_post_meta( 'lock_modified_date', $post_id );
}
}

View File

@@ -0,0 +1,306 @@
<?php
/**
* The admin notices.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Runner;
use RankMath\Helper;
use RankMath\Traits\Ajax;
use RankMath\Traits\Hooker;
use RankMath\Helpers\Sitepress;
use RankMath\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
* Notices class.
*/
class Notices implements Runner {
use Hooker;
use Ajax;
/**
* Register hooks.
*/
public function hooks() {
$this->action( 'admin_init', 'notices' );
$this->action( 'wp_helpers_notification_dismissed', 'notice_dismissible' );
}
/**
* Run all notices routine.
*/
public function notices() {
$this->is_plugin_configured();
$this->new_post_type();
$this->convert_wpml_settings();
$this->permalink_changes_warning();
$this->react_settings_ui_notice();
}
/**
* Show a persistent admin notice when the React Settings UI is disabled.
*
* Adds a dismissible, persistent error when the temporary option to
* disable the React-based Settings UI is turned off. The notice is removed
* when the React Settings UI is enabled again.
*
* @since 1.0.255
* @return void
*/
private function react_settings_ui_notice() {
// Only relevant for admins in the dashboard context.
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$notice_id = 'rank_math_react_settings_ui_disabled';
if ( ! Helper::is_react_enabled() ) {
$message = sprintf(
// Translators: 1: opening anchor tag, 2: closing anchor tag.
__( 'The React Settings UI is currently disabled, and the classic settings interface is active. Note: The PHP-based settings interface will be removed in an upcoming release. %1$sEnable the React Settings UI%2$s to switch back.', 'rank-math' ),
'<a href="' . esc_url( Helper::get_dashboard_url() ) . '">',
'</a>'
);
Helper::add_notification(
$message,
[
'type' => 'error',
'id' => $notice_id,
]
);
return;
}
// React UI is enabled; ensure any prior notice is removed.
Helper::remove_notification( $notice_id );
}
/**
* Set known post type after notice dismissal.
*
* @param string $notification_id Notification id.
*/
public function notice_dismissible( $notification_id ) {
if ( 'new_post_type' === $notification_id ) {
$current = get_post_types( [ 'public' => true ] );
update_option( 'rank_math_known_post_types', $current );
if ( Helper::is_module_active( 'sitemap' ) ) {
\RankMath\Sitemap\Cache::invalidate_storage();
}
return;
}
if ( 'convert_wpml_settings' === $notification_id ) {
update_option( 'rank_math_wpml_notice_dismissed', true );
}
if ( 'rank-math-site-url-mismatch' === $notification_id ) {
update_option( 'rank_math_siteurl_mismatch_notice_dismissed', true );
}
}
/**
* If plugin configuration not done.
*/
private function is_plugin_configured() {
if ( 'mts-install-plugins' === Param::get( 'page' ) ) {
return;
}
if ( rank_math()->notification->get_notification_by_id( 'plugin_not_setup' ) && ! Helper::is_configured() ) {
$message = sprintf(
'<b>Warning!</b> You didn\'t set up your Rank Math SEO plugin yet, which means you\'re missing out on essential settings and tweaks! <a href="%s">Complete your setup by clicking here.</a>',
Helper::get_admin_url( 'wizard' )
);
Helper::add_notification(
$message,
[
'type' => 'warning',
'id' => 'plugin_not_setup',
]
);
}
}
/**
* Add notification if a new post type is detected.
*/
private function new_post_type() {
$known = get_option( 'rank_math_known_post_types', [] );
$current = Helper::get_accessible_post_types();
$new = array_diff( $current, $known );
if ( empty( $new ) ) {
return;
}
$list = '<code>' . implode( '</code>, <code>', $new ) . '</code>';
/* Translators: placeholder is the post type name. */
$message = __( 'Rank Math has detected a new post type: %1$s. You may want to check the settings of the <a href="%2$s">Titles &amp; Meta page</a>.', 'rank-math' );
$count = count( $new );
if ( $count > 1 ) {
/* Translators: placeholder is the post type names separated with commas. */
$message = __( 'Rank Math has detected new post types: %1$s. You may want to check the settings of the <a href="%2$s">Titles &amp; Meta page</a>.', 'rank-math' );
}
$message = $this->do_filter( 'admin/notice/new_post_type', $message, $count );
$message = sprintf( wp_kses_post( $message ), $list, Helper::get_settings_url( 'titles', 'post-type-' . key( $new ) ), Helper::get_settings_url( 'sitemap', 'post-type-' . key( $new ) ) );
Helper::add_notification(
$message,
[
'type' => 'info',
'id' => 'new_post_type',
]
);
}
/**
* Function to show Show String Translation plugin notice and convert the settings.
*/
private function convert_wpml_settings() {
if ( ! Sitepress::get()->is_active() || get_option( 'rank_math_wpml_data_converted' ) ) {
return;
}
if ( ! function_exists( 'icl_add_string_translation' ) ) {
if ( ! get_option( 'rank_math_wpml_notice_dismissed' ) ) {
Helper::add_notification(
__( 'Please activate the WPML String Translation plugin to convert Rank Math Setting values in different languages.', 'rank-math' ),
[
'type' => 'error',
'id' => 'convert_wpml_settings',
]
);
}
return;
}
$languages = icl_get_languages(); // @phpstan-ignore-line
foreach ( $languages as $lang_code => $language ) {
foreach ( [ 'general', 'titles' ] as $option ) {
$data = get_option( "rank-math-options-{$option}_$lang_code" );
if ( empty( $data ) ) {
continue;
}
$common_data = array_intersect( array_keys( $data ), $this->get_translatable_options() );
if ( empty( $common_data ) ) {
continue;
}
foreach ( $common_data as $option_key ) {
$string_id = icl_get_string_id( Helper::get_settings( "$option.$option_key" ), "admin_texts_rank-math-options-$option" ); // @phpstan-ignore-line
icl_add_string_translation( $string_id, $lang_code, $data[ $option_key ], 10 ); // @phpstan-ignore-line
}
}
}
update_option( 'rank_math_wpml_data_converted', true );
}
/**
* Get Translatable option keys.
*
* @return array
*/
private function get_translatable_options() {
$options = [
'img_alt_format',
'img_title_format',
'breadcrumbs_separator',
'breadcrumbs_prefix',
'breadcrumbs_home_link',
'breadcrumbs_home_label',
'breadcrumbs_archive_format',
'breadcrumbs_search_format',
'breadcrumbs_404_label',
'rss_before_content',
'rss_after_content',
'title_separator',
'homepage_title',
'homepage_description',
'homepage_facebook_title',
'homepage_facebook_description',
'author_archive_title',
'author_archive_description',
'date_archive_title',
'date_archive_description',
'search_title',
'404_title',
];
$post_types = Helper::get_accessible_post_types();
foreach ( $post_types as $post_type => $data ) {
$options = array_merge(
$options,
[
"pt_{$post_type}_title",
"pt_{$post_type}_description",
"pt_{$post_type}_archive_title",
"pt_{$post_type}_archive_description",
"pt_{$post_type}_default_snippet_name",
"pt_{$post_type}_default_snippet_desc",
]
);
}
$taxonomies = Helper::get_accessible_taxonomies();
foreach ( $taxonomies as $taxonomy => $data ) {
$options = array_merge(
$options,
[
"tax_{$taxonomy}_title",
"tax_{$taxonomy}_description",
]
);
}
return $options;
}
/**
* Maybe add notice on Permalinks page about the risks of changing the permalinks on a live site.
*
* @return void
*/
public function permalink_changes_warning() {
global $pagenow;
if ( 'options-permalink.php' !== $pagenow ) {
return;
}
$this->action( 'admin_enqueue_scripts', 'add_permalink_changes_warning', 12 );
}
/**
* Add the notice for the Permalinks page.
*
* @return void
*/
public function add_permalink_changes_warning() {
wp_enqueue_script( 'rank-math-core-permalink-settings' );
$message = __( '<b>Rank Math Warning:</b> Changing the permalinks on a live, indexed site may result in serious loss of traffic if done incorrectly. Consider adding a new redirection from the old URL format to the new one.', 'rank-math' );
Helper::add_notification(
$message,
[
'type' => 'warning',
'screen' => 'options-permalink',
'classes' => 'hidden rank-math-notice-permalinks-warning is-dismissible',
]
);
}
}

View File

@@ -0,0 +1,658 @@
<?php
/**
* The option center of the plugin.
*
* @since 1.0.9
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\KB;
use RankMath\CMB2;
use RankMath\Helper;
use RankMath\Runner;
use RankMath\Traits\Hooker;
use RankMath\Helpers\Arr;
use RankMath\Helpers\Param;
use RankMath\Wizard\Search_Console;
use RankMath\Admin\Sanitize_Settings;
defined( 'ABSPATH' ) || exit;
/**
* Option_Center class.
*/
class Option_Center implements Runner {
use Hooker;
/**
* Register hooks.
*/
public function hooks() {
$this->action( 'init', 'register_general_settings', 125 );
$this->action( 'init', 'register_title_settings', 125 );
$this->filter( 'rank_math/settings/title', 'title_post_type_settings', 1 );
$this->filter( 'rank_math/settings/title', 'title_taxonomy_settings', 1 );
$this->filter( 'rank_math/settings/general', 'remove_unwanted_general_tabs', 1 );
$this->action( 'admin_enqueue_scripts', 'enqueue_settings_translations', 11 );
}
/**
* General Settings.
*/
public function register_general_settings() {
$tabs = [
'links' => [
'icon' => 'rm-icon rm-icon-link',
'title' => esc_html__( 'Links', 'rank-math' ),
/* translators: Link to kb article */
'desc' => sprintf( esc_html__( 'Change how some of the links open and operate on your website. %s.', 'rank-math' ), '<a href="' . KB::get( 'link-settings', 'Options Panel Links Tab' ) . '" target="_blank">' . esc_html__( 'Learn More', 'rank-math' ) . '</a>' ),
],
'breadcrumbs' => [
'icon' => 'rm-icon rm-icon-direction',
'title' => esc_html__( 'Breadcrumbs', 'rank-math' ),
'classes' => 'rank-math-advanced-option',
/* translators: Link to kb article */
'desc' => sprintf( esc_html__( 'Here you can set up the breadcrumbs function. %s', 'rank-math' ), '<a href="' . KB::get( 'breadcrumbs', 'Options Panel Breadcrumbs Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>. <br/>' ),
'after_row' => current_theme_supports( 'rank-math-breadcrumbs' ) ? '' : '<div class="notice notice-alt notice-warning warning inline rank-math-notice"><p>' . esc_html__( 'Use the following code in your theme template files to display breadcrumbs.', 'rank-math' ) . ' <a href="' . KB::get( 'breadcrumbs-install', 'Options Panel Breadcrumbs Tab' ) . '" target="_blank">' . esc_html__( 'Learn More', 'rank-math' ) . '</a><br /><code>&lt;?php if (function_exists(\'rank_math_the_breadcrumbs\')) rank_math_the_breadcrumbs(); ?&gt;</code> OR <code>[rank_math_breadcrumb]</code></p></div>',
],
'webmaster' => [
'icon' => 'rm-icon rm-icon-toolbox',
'title' => esc_html__( 'Webmaster Tools', 'rank-math' ),
/* translators: Link to kb article */
'desc' => sprintf( esc_html__( 'Enter verification codes for third-party webmaster tools. %s', 'rank-math' ), '<a href="' . KB::get( 'webmaster-tools', 'Options Panel Webmaster Tools Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>.<br />' ),
],
'others' => [
'icon' => 'rm-icon rm-icon-misc',
'title' => esc_html__( 'Others', 'rank-math' ),
/* translators: Link to kb article */
'desc' => sprintf( esc_html__( 'Change some uncommon but essential settings here. %s.', 'rank-math' ), '<a href="' . KB::get( 'other-settings', 'Options Panel Others Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>' ),
'classes' => 'rank-math-advanced-option',
],
];
if ( is_super_admin() && 'rank-math-options-general' === Param::get( 'page' ) ) {
Arr::insert(
$tabs,
[
'htaccess' => [
'icon' => 'rm-icon rm-icon-htaccess',
'title' => esc_html__( 'Edit .htaccess', 'rank-math' ),
/* translators: Link to kb article */
'desc' => sprintf( esc_html__( 'Edit the contents of your .htaccess file easily. %s.', 'rank-math' ), '<a href="' . KB::get( 'edit-htaccess', 'Options Panel htaccess Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>' ),
'classes' => 'rank-math-advanced-option',
'json' => [
'htaccessData' => Admin_Helper::get_htaccess_data(),
],
],
],
5
);
}
/**
* Allow developers to add new sections in the General Settings.
*
* @param array $tabs
*/
$tabs = $this->do_filter( 'settings/general', $tabs );
new Register_Options_Page(
[
'key' => 'rank-math-options-general',
'title' => esc_html__( 'SEO Settings', 'rank-math' ),
'menu_title' => esc_html__( 'General Settings', 'rank-math' ),
'capability' => 'rank_math_general',
'folder' => 'general',
'tabs' => $tabs,
]
);
}
/**
* Remove unneeded tabs from the General Settings.
*
* @param array $tabs Hold tabs for optional panel.
* @return array
*/
public function remove_unwanted_general_tabs( $tabs ) {
if ( is_multisite() ) {
unset( $tabs['robots'] );
}
if ( ! Helper::has_cap( 'edit_htaccess' ) && is_multisite() ) {
unset( $tabs['htaccess'] );
}
return $tabs;
}
/**
* Register SEO Titles & Meta Settings.
*/
public function register_title_settings() {
$homepage_notice = '';
if ( 'page' === get_option( 'show_on_front' ) ) {
$home_page_id = get_option( 'page_on_front' );
if ( ! $home_page_id ) {
$home_page_id = get_option( 'page_for_posts' );
}
$homepage_notice = '<a href="' . admin_url( 'post.php?post=' . $home_page_id . '&action=edit' ) . '">' . esc_html__( 'Edit Page: ', 'rank-math' ) . get_the_title( $home_page_id ) . '</a>';
}
$tabs = [
'global' => [
'icon' => 'rm-icon rm-icon-settings',
'title' => esc_html__( 'Global Meta', 'rank-math' ),
/* translators: Link to KB article */
'desc' => sprintf( esc_html__( 'Change Global meta settings that take effect across your website. %s.', 'rank-math' ), '<a href="' . KB::get( 'titles-meta', 'Options Panel Meta Global Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>' ),
'json' => [
'overlayImages' => array_merge( [ '' => __( 'Off', 'rank-math' ) ], Helper::choices_overlay_images( 'names' ) ),
],
],
'local' => [
'icon' => 'rm-icon rm-icon-local-seo',
'title' => esc_html__( 'Local SEO', 'rank-math' ),
/* translators: Redirection page url */
'desc' => sprintf( wp_kses_post( __( 'Optimize for local searches and Knowledge Graph using these settings. %s.', 'rank-math' ) ), '<a href="' . KB::get( 'local-seo-settings', 'Options Panel Meta Local Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>' ),
'after_row' => '<div class="notice notice-alt notice-info info inline rank-math-notice"><p>' . __( 'Use the <code>[rank_math_contact_info]</code> shortcode to display contact information in a nicely formatted way. You should also claim your business on Google if you have not already.', 'rank-math' ) . '</p></div>',
],
'social' => [
'icon' => 'rm-icon rm-icon-social',
'title' => esc_html__( 'Social Meta', 'rank-math' ),
/* translators: Link to social setting KB article */
'desc' => sprintf( esc_html__( "Add social account information to your website's Schema and Open Graph. %s.", 'rank-math' ), '<a href="' . KB::get( 'social-meta-settings', 'Options Panel Meta Social Tab' ) . '" target="_blank">' . esc_html__( 'Learn More', 'rank-math' ) . '</a>' ),
],
'homepage' => [
'icon' => 'rm-icon rm-icon-home',
'title' => esc_html__( 'Homepage', 'rank-math' ),
'desc' => sprintf(
/* translators: Link to KB article */
esc_html__( 'Add SEO meta and OpenGraph details to your homepage. %s.', 'rank-math' ),
'<a href="' . KB::get( 'homepage-settings', 'Options Panel Meta Home Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>'
),
'json' => [
'staticHomePageNotice' => $homepage_notice,
],
],
'author' => [
'icon' => 'rm-icon rm-icon-users',
'title' => esc_html__( 'Authors', 'rank-math' ),
/* translators: Link to KB article */
'desc' => sprintf( esc_html__( 'Change SEO options related to the author archives. %s.', 'rank-math' ), '<a href="' . KB::get( 'author-settings', 'Options Panel Meta Author Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>' ),
'json' => [
'disableAutorArchive' => $this->do_filter( 'settings/titles/disable_author_archives', 'off' ),
],
],
'misc' => [
'icon' => 'rm-icon rm-icon-misc',
'title' => esc_html__( 'Misc Pages', 'rank-math' ),
/* translators: Link to KB article */
'desc' => sprintf( esc_html__( 'Customize SEO meta settings of pages like search results, 404s, etc. %s.', 'rank-math' ), '<a href="' . KB::get( 'misc-settings', 'Options Panel Meta Misc Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>' ),
],
];
/**
* Allow developers to add new section in the Title Settings.
*
* @param array $tabs
*/
$tabs = $this->do_filter( 'settings/title', $tabs );
new Register_Options_Page(
[
'key' => 'rank-math-options-titles',
'title' => esc_html__( 'SEO Titles &amp; Meta', 'rank-math' ),
'menu_title' => esc_html__( 'Titles &amp; Meta', 'rank-math' ),
'capability' => 'rank_math_titles',
'folder' => 'titles',
'tabs' => $tabs,
]
);
if ( is_admin() ) {
Helper::add_json( 'postTitle', 'Post Title' );
Helper::add_json( 'postUri', home_url( '/post-title' ) );
Helper::add_json( 'blogName', get_bloginfo( 'name' ) );
}
}
/**
* Add post type tabs in the Title Settings panel.
*
* @param array $tabs Holds the tabs of the options panel.
* @return array
*/
public function title_post_type_settings( $tabs ) {
$icons = Helper::choices_post_type_icons();
$links = [
'post' => '<a href="' . KB::get( 'post-settings', 'Options Panel Meta Posts Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>.',
'page' => '<a href="' . KB::get( 'page-settings', 'Options Panel Meta Pages Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>.',
'product' => '<a href="' . KB::get( 'product-settings', 'Options Panel Meta Products Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>.',
'attachment' => '<a href="' . KB::get( 'media-settings', 'Options Panel Meta Attachments Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>.',
];
$names = [
'post' => 'single %s',
'page' => 'single %s',
'product' => 'product pages',
'attachment' => 'media %s',
];
$tabs['p_types'] = [
'title' => esc_html__( 'Post Types:', 'rank-math' ),
'type' => 'seprator',
'name' => 'p_types_separator',
];
foreach ( Helper::get_accessible_post_types() as $post_type ) {
$obj = get_post_type_object( $post_type );
$link = isset( $links[ $obj->name ] ) ? $links[ $obj->name ] : '';
$obj_name = isset( $names[ $obj->name ] ) ? sprintf( $names[ $obj->name ], $obj->name ) : $obj->name;
$is_attachment = $post_type === 'attachment';
$richsnp_default = 'off';
if ( ( class_exists( 'WooCommerce' ) && 'product' === $post_type ) || ( class_exists( 'Easy_Digital_Downloads' ) && 'download' === $post_type ) ) {
$richsnp_default = 'product';
}
if ( $post_type === 'post' ) {
$richsnp_default = 'article';
}
$primary_taxonomy_hash = [
'post' => 'category',
'product' => 'product_cat',
];
$tabs[ 'post-type-' . $obj->name ] = [
'title' => $is_attachment ? esc_html__( 'Attachments', 'rank-math' ) : $obj->label,
'icon' => isset( $icons[ $obj->name ] ) ? $icons[ $obj->name ] : $icons['default'],
/* translators: 1. post type name 2. link */
'desc' => sprintf( esc_html__( 'Change Global SEO, Schema, and other settings for %1$s. %2$s', 'rank-math' ), $obj_name, $link ),
'post_type' => $obj->name,
'file' => rank_math()->includes_dir() . 'settings/titles/post-types.php',
'classes' => 'attachment' === $post_type ? 'rank-math-advanced-option' : '',
'json' => [
'isWooCommerceActive' => class_exists( 'WooCommerce' ),
'isEddActive' => class_exists( 'Easy_Digital_Downloads' ),
'isWebStoriesActive' => defined( 'WEBSTORIES_VERSION' ),
$post_type => [
'title' => $is_attachment ? esc_html__( 'Attachments', 'rank-math' ) : $obj->label,
'name' => $is_attachment ? esc_html__( 'Media', 'rank-math' ) : $obj->labels->singular_name,
'schemaTypes' => Helper::choices_rich_snippet_types( esc_html__( 'None (Click here to set one)', 'rank-math' ), $post_type ),
'taxonomies' => Helper::get_object_taxonomies( $post_type ),
'hasArchive' => $obj->has_archive,
'customRobots' => false,
'schemaDefault' => $this->do_filter( 'settings/snippet/type', $richsnp_default, $post_type ),
'articleType' => $this->do_filter( 'settings/snippet/article_type', 'post' === $post_type ? 'BlogPosting' : 'Article', $post_type ),
'enableLinkSuggestion' => $this->do_filter( 'settings/titles/link_suggestions', true, $post_type ),
'primaryTaxonomy' => isset( $primary_taxonomy_hash[ $post_type ] ) ? $primary_taxonomy_hash[ $post_type ] : 'off',
],
],
];
}
return $tabs;
}
/**
* Add taxonomy tabs in the Title Settings panel.
*
* @param array $tabs Holds the tabs of the options panel.
* @return array
*/
public function title_taxonomy_settings( $tabs ) {
$icons = Helper::choices_taxonomy_icons();
$hash_name = [
'category' => 'category archive pages',
'product_cat' => 'Product category pages',
'product_tag' => 'Product tag pages',
];
$hash_link = [
'category' => '<a href="' . KB::get( 'category-settings', 'Options Panel Meta Categories Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>.',
'post_tag' => '<a href="' . KB::get( 'tag-settings', 'Options Panel Meta Tags Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>.',
'product_cat' => '<a href="' . KB::get( 'product-categories-settings', 'Options Panel Meta Product Categories Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>.',
'product_tag' => '<a href="' . KB::get( 'product-tags-settings', 'Options Panel Meta Product Tags Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>.',
];
$taxonomies_data = [];
foreach ( Helper::get_accessible_taxonomies() as $taxonomy ) {
$attached = implode( ' + ', $taxonomy->object_type );
$taxonomies_data[ $attached ][ $taxonomy->name ] = $taxonomy;
}
foreach ( $taxonomies_data as $attached => $taxonomies ) {
// Seprator.
$tabs[ $attached ] = [
'title' => ucwords( $attached ) . ':',
'type' => 'seprator',
'name' => 'taxonomy_separator',
];
foreach ( $taxonomies as $taxonomy ) {
$link = isset( $hash_link[ $taxonomy->name ] ) ? $hash_link[ $taxonomy->name ] : '';
$taxonomy_name = isset( $hash_name[ $taxonomy->name ] ) ? $hash_name[ $taxonomy->name ] : $taxonomy->label;
$tabs[ 'taxonomy-' . $taxonomy->name ] = [
'icon' => isset( $icons[ $taxonomy->name ] ) ? $icons[ $taxonomy->name ] : $icons['default'],
'title' => $taxonomy->label,
/* translators: 1. taxonomy name 2. link */
'desc' => sprintf( esc_html__( 'Change Global SEO, Schema, and other settings for %1$s. %2$s', 'rank-math' ), $taxonomy_name, $link ),
'taxonomy' => $taxonomy->name,
'file' => rank_math()->includes_dir() . 'settings/titles/taxonomies.php',
];
}
}
if ( isset( $tabs['taxonomy-post_format'] ) ) {
$tab = $tabs['taxonomy-post_format'];
unset( $tabs['taxonomy-post_format'] );
$tab['title'] = esc_html__( 'Post Formats', 'rank-math' );
$tab['page_title'] = esc_html__( 'Post Formats Archive', 'rank-math' );
Arr::insert( $tabs, [ 'taxonomy-post_format' => $tab ], 5 );
}
return $tabs;
}
/**
* Save Settings data. Called from the `updateSettings` endpoint.
*
* @param string $type Settings type.
* @param array $settings Settings data.
* @param array $field_types Field ids with types use to sanitize the value.
* @param array $updated Array of field ids that were updated.
* @param bool $is_reset Whether the request is to reset the data.
* @return array
*/
public static function save_settings( $type, $settings, $field_types, $updated, $is_reset ) {
$notifications = [];
$update_htaccess = self::maybe_update_htaccess( $settings );
if ( ! empty( $update_htaccess ) ) {
$notifications[] = $update_htaccess;
}
$update_analytics = self::maybe_update_analytics( $settings, $updated );
if ( ! empty( $update_analytics ) ) {
$notifications[] = $update_analytics;
}
do_action( 'rank_math/settings/before_save', $type, $settings );
foreach (
[
'htaccess_allow_editing',
'htaccess_content',
'searchConsole',
'analyticsData',
'analytics',
'usage_tracking',
] as $key
) {
if ( isset( $settings[ $key ] ) ) {
unset( $settings[ $key ] );
}
}
$settings = Sanitize_Settings::sanitize( $settings, $field_types );
self::check_updated_fields( $updated, $is_reset );
// Get current settings to compare with new settings.
$current_settings = Helper::get_settings( $type );
// Only update fields that have actually changed.
$changed_settings = self::get_changed_settings( $current_settings, $settings );
// If no settings have changed, return early.
if ( empty( $changed_settings ) ) {
return [
'notifications' => $notifications,
'settings' => $current_settings,
];
}
$map = [
'general' => [ $changed_settings, null, null ],
'titles' => [ null, $changed_settings, null ],
'sitemap' => [ null, null, $changed_settings ],
];
Helper::update_all_settings( ...$map[ $type ] );
rank_math()->settings->reset();
do_action( 'rank_math/settings/after_save', $type, $changed_settings );
return [
'notifications' => $notifications,
'settings' => apply_filters( 'rank_math/settings/saved_data', Helper::get_settings( $type ), $type ),
];
}
/**
* Update Analytics data.
*
* @param array $settings Settings data.
* @param string $updated View that was updated.
*/
public static function maybe_update_analytics( $settings, $updated ) {
if ( empty( $updated ) || ( ! in_array( 'searchConsole', $updated, true ) && ! in_array( 'analyticsData', $updated, true ) ) ) {
return;
}
Search_Console::save( $settings );
$days = $settings['console_caching_control'] ?? 90;
$search_console = $settings['searchConsole'] ?? [];
if ( in_array( 'searchConsole', $updated, true ) && ! empty( $search_console ) ) {
$search_console['days'] = $days;
$response = \RankMath\Analytics\AJAX::get()->do_save_analytic_profile( $search_console );
if ( is_wp_error( $response ) ) {
return [
'error' => $response->get_error_message(),
];
}
}
$google_analytics = $settings['analyticsData'] ?? [];
if ( in_array( 'analyticsData', $updated, true ) && ! empty( $google_analytics ) ) {
$google_analytics['days'] = $days;
$response = \RankMath\Analytics\AJAX::get()->do_save_analytic_options( $google_analytics );
if ( is_wp_error( $response ) ) {
return [
'error' => $response->get_error_message(),
];
}
}
}
/**
* Enqueue settings translations when React UI is enabled as the settings pages are loaded in chunks.
*/
public function enqueue_settings_translations() {
if ( ! Helper::is_react_enabled() ) {
return;
}
$page = str_replace( 'rank-math-options-', '', Param::get( 'page', '' ) );
$hash = [
'general' => 'generalSettings',
'titles' => 'titleSettings',
'sitemap' => 'sitemapSettings',
'instant-indexing' => 'instantIndexingSettings',
];
if ( ! isset( $hash[ $page ] ) ) {
return;
}
$chunk = $hash[ $page ];
wp_enqueue_script( 'rank-math-settings-chunk', rank_math()->plugin_url() . "assets/admin/js/$chunk.js", [ 'rank-math-options' ], rank_math()->version, true );
wp_set_script_translations( 'rank-math-settings-chunk', 'rank-math', rank_math()->plugin_dir() . 'languages/' );
wp_set_script_translations( 'rank-math-options', 'rank-math', rank_math()->plugin_dir() . 'languages/' );
wp_set_script_translations( 'rank-math-components', 'rank-math', rank_math()->plugin_dir() . 'languages/' );
$this->do_action( 'admin/after_settings_scripts' );
}
/**
* Check if certain fields got updated.
*
* @param array $updated Updated fields id.
* @param bool $is_reset Whether to reset the settings.
*/
private static function check_updated_fields( $updated, $is_reset ) {
if ( $is_reset ) {
Helper::schedule_flush_rewrite();
return;
}
/**
* Filter: Allow developers to add option fields which will flush the rewrite rules when updated.
*
* @param array $flush_fields Array of field IDs for which we need to flush.
*/
$flush_fields = apply_filters(
'rank_math/flush_fields',
[
'strip_category_base',
'disable_author_archives',
'url_author_base',
'attachment_redirect_urls',
'attachment_redirect_default',
'nofollow_external_links',
'nofollow_image_links',
'nofollow_domains',
'nofollow_exclude_domains',
'new_window_external_links',
'redirections_header_code',
'redirections_post_redirect',
'redirections_debug',
]
);
foreach ( $flush_fields as $field_id ) {
if ( in_array( $field_id, $updated, true ) ) {
Helper::schedule_flush_rewrite();
break;
}
}
}
/**
* Get only the settings that have changed.
*
* @param array $current_settings Current settings from database.
* @param array $new_settings New settings to be saved.
* @return array
*/
private static function get_changed_settings( $current_settings, $new_settings ) {
// Filter out invalid keys from both arrays.
$new_settings = array_filter( $new_settings, [ __CLASS__, 'is_valid_key' ], ARRAY_FILTER_USE_KEY );
$current_settings = array_filter( $current_settings, [ __CLASS__, 'is_valid_key' ], ARRAY_FILTER_USE_KEY );
// Merge current settings with new settings, new settings take precedence.
return array_merge( $current_settings, $new_settings );
}
/**
* Check if a key is valid for settings.
*
* @param mixed $key The key to validate.
* @return bool
*/
private static function is_valid_key( $key ) {
return is_string( $key ) && ! empty( $key );
}
/**
* Update .htaccess.
*
* @param array { $settings } Settings data.
*/
private static function maybe_update_htaccess( $settings ) {
if ( empty( $settings['htaccess_allow_editing'] ) ) {
return;
}
if ( ! is_super_admin() || ! Helper::has_cap( 'general' ) || ! Helper::has_cap( 'edit_htaccess' ) ) {
return [
'error' => esc_html__( 'You do not have permission to edit the .htaccess file.', 'rank-math' ),
];
}
if ( ! Helper::is_edit_allowed() ) {
return [
'error' => esc_html__( 'You do not have permission to edit the .htaccess file.', 'rank-math' ),
];
}
// phpcs:ignore= WordPress.Security.ValidatedSanitizedInput -- Writing to .htaccess file and escaping for HTML will break functionality.
$content = isset( $settings['htaccess_content'] ) ? $settings['htaccess_content'] : '';
if ( empty( $content ) ) {
return;
}
if ( ! self::do_htaccess_backup() ) {
return [
'error' => esc_html__( 'Failed to backup .htaccess file. Please check file permissions.', 'rank-math' ),
];
}
if ( ! self::do_htaccess_update( $content ) ) {
return [
'error' => esc_html__( 'Failed to update .htaccess file. Please check file permissions.', 'rank-math' ),
];
}
return [
'success' => esc_html__( '.htaccess file updated successfully.', 'rank-math' ),
];
}
/**
* Create htaccess backup.
*
* @return bool
*/
private static function do_htaccess_backup() {
if ( ! Helper::is_filesystem_direct() ) {
return false;
}
$wp_filesystem = Helper::get_filesystem();
$path = get_home_path();
$file = $path . '.htaccess';
if ( ! $wp_filesystem->is_writable( $path ) || ! $wp_filesystem->exists( $file ) ) {
return false;
}
$backup = $path . uniqid( '.htaccess_back_' );
return $wp_filesystem->copy( $file, $backup, true );
}
/**
* Update htaccess file.
*
* @param string $content Htaccess content.
* @return string|bool
*/
private static function do_htaccess_update( $content ) {
if ( empty( $content ) || ! Helper::is_filesystem_direct() ) {
return false;
}
$wp_filesystem = Helper::get_filesystem();
$htaccess_file = get_home_path() . '.htaccess';
return ! $wp_filesystem->is_writable( $htaccess_file ) ? false : $wp_filesystem->put_contents( $htaccess_file, $content );
}
}

View File

@@ -0,0 +1,305 @@
<?php
/**
* The option page functionality of the plugin.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use WP_Http;
use RankMath\KB;
use RankMath\CMB2;
use RankMath\Helper;
use RankMath\Traits\Hooker;
use RankMath\Helpers\Str;
use RankMath\Helpers\Param;
use RankMath\Robots_Txt;
use RankMath\Sitemap\Router;
use RankMath\Sitemap\Sitemap;
use RankMath\Admin\Page;
defined( 'ABSPATH' ) || exit;
/**
* Options class.
*/
class Options {
use Hooker;
/**
* Page title.
*
* @var string
*/
public $title = 'Settings';
/**
* Menu title.
*
* @var string
*/
public $menu_title = 'Settings';
/**
* Hold tabs for page.
*
* @var array
*/
public $tabs = [];
/**
* Hold folder name for tab files.
*
* @var string
*/
public $folder = '';
/**
* Menu Position.
*
* @var int
*/
public $position = 10;
/**
* The capability required for this menu to be displayed to the user.
*
* @var string
*/
public $capability = 'manage_options';
/**
* CMB2 option page id.
*
* @var string
*/
private $cmb_id = null;
/**
* Options key.
*
* @var string
*/
public $key = '';
/**
* The Constructor
*
* @param array $config Array of configuration.
*/
public function __construct( $config ) {
$this->config( $config );
$this->cmb_id = $this->key . '_options';
$this->action( 'admin_post_' . $this->key, 'reset_options', 2 );
}
/**
* Create option object and add settings.
*/
public function register_option_page() {
$current_page = str_replace( 'rank-math-options-', '', $this->key );
new Page(
$this->key,
$this->title,
[
'position' => $this->position,
'priority' => 9999,
'parent' => 'rank-math',
'capability' => $this->capability,
'menu_title' => $this->menu_title,
'render' => [ $this, 'display' ],
'classes' => $this->get_body_class(),
'assets' => [
'styles' => [
'select2-rm' => '',
'rank-math-common' => '',
'rank-math-cmb2' => '',
'wp-components' => '',
'rank-math-options' => rank_math()->plugin_url() . 'assets/admin/css/option-panel.css',
],
'scripts' => [
'media-editor' => '',
'underscore' => '',
'select2-rm' => '',
'lodash' => '',
'rank-math-common' => '',
'wp-api-fetch' => '',
'wp-data' => '',
'rank-math-components' => '',
'rank-math-options' => rank_math()->plugin_url() . 'assets/admin/js/settings.js',
],
'json' => $this->get_json_data( $current_page ),
],
]
);
}
/**
* Set the default values if not set.
*
* @param CMB2 $cmb The CMB2 object to hookup.
*/
public function set_defaults( $cmb ) {
foreach ( $cmb->prop( 'fields' ) as $id => $field_args ) {
$field = $cmb->get_field( $id );
if ( isset( $field_args['default'] ) || isset( $field_args['default_cb'] ) ) {
$defaults[ $id ] = $field->get_default();
}
}
// Save Defaults if any.
if ( ! empty( $defaults ) ) {
add_option( $this->key, $defaults );
}
}
/**
* Reset options.
*/
public function reset_options() {
if ( ! check_admin_referer( 'rank-math-reset-options' ) || ! current_user_can( 'manage_options' ) ) {
return false;
}
$url = wp_get_referer();
if ( ! $url ) {
$url = admin_url();
}
if ( filter_has_var( INPUT_POST, 'reset-cmb' ) && Param::post( 'action' ) === $this->key ) {
delete_option( $this->key );
Helper::redirect( esc_url_raw( $url ), WP_Http::SEE_OTHER );
exit;
}
}
/**
* Add classes to <body> of WordPress admin.
*
* @return string
*/
public function get_body_class() {
$mode = Helper::is_advanced_mode() ? 'advanced' : 'basic';
return [
'rank-math-page ',
'rank-math-mode-' . $mode,
];
}
/**
* Display Setting on a page.
*/
public function display() {
?>
<div id="rank-math-options" class="<?php echo esc_attr( $this->cmb_id ); ?>"></div>
<?php
}
/**
* Get setting tabs.
*
* @return array
*/
private function get_tabs() {
$filter = str_replace( '-', '_', str_replace( 'rank-math-', '', $this->key ) );
/**
* Allow developers to add new tabs into option panel.
*
* The dynamic part of hook is, page name without 'rank-math-' prefix.
*
* @param array $tabs
*/
return $this->do_filter( "admin/options/{$filter}_tabs", $this->tabs );
}
/**
* Get localized data for the current settings page.
*
* @param string $current_page Current Settings page.
*
* @return array
*/
private function get_json_data( $current_page ) {
if ( Param::get( 'page' ) !== $this->key ) {
return [];
}
if ( is_admin() ) {
rank_math()->variables->setup();
rank_math()->variables->setup_json();
}
$tabs = $this->get_tabs();
$data = $this->do_filter(
"admin/options/{$current_page}_data",
[
'isPro' => defined( 'RANK_MATH_PRO_FILE' ),
'tabs' => array_keys( $tabs ),
'optionPage' => $current_page,
'homeUrl' => get_home_url(),
'data' => $current_page === 'instant-indexing' ? get_option( 'rank-math-options-instant-indexing' ) : Helper::get_settings( $current_page ),
'isSiteConnected' => Helper::is_site_connected(),
'choices' => [
'postTypes' => Helper::choices_post_types(),
'accessiblePostTypes' => Helper::get_accessible_post_types(),
'accessibleTaxonomies' => Helper::get_accessible_taxonomies(),
'choicesPostTypeIcons' => Helper::choices_post_type_icons(),
'choicesTaxonomyIcons' => Helper::choices_taxonomy_icons(),
],
]
);
foreach ( $tabs as $tab ) {
if ( empty( $tab['json'] ) ) {
continue;
}
$data = array_merge( $data, $tab['json'] );
}
$method = "get_{$current_page}_data";
if ( ! method_exists( $this, $method ) ) {
return $data;
}
return array_merge( $data, $this->$method() );
}
/**
* Get General Settings page data.
*
* @return array
*/
private function get_general_data() {
return [
'activateUrl' => Admin_Helper::get_activate_url( admin_url( 'admin.php??page=rank-math-options-general&tab=content-ai' ) ),
'hasBreadcrumbSupport' => current_theme_supports( 'rank-math-breadcrumbs' ),
'showBlogPage' => 'page' === get_option( 'show_on_front' ) && get_option( 'page_for_posts' ) > 0,
'isEditAllowed' => Helper::is_edit_allowed(),
'defaultLanguage' => Helper::content_ai_default_language(),
];
}
/**
* Get General Settings page data.
*
* @return array
*/
private function get_titles_data() {
$data = [
'choicesRobots' => Helper::choices_robots(),
'supportsTitleTag' => current_theme_supports( 'title-tag' ) || wp_is_block_theme(),
'schemaTypes' => Helper::choices_rich_snippet_types( esc_html__( 'None (Click here to set one)', 'rank-math' ) ),
'isRedirectAttachments' => Helper::get_settings( 'general.attachment_redirect_urls' ),
];
return $data;
}
}

View File

@@ -0,0 +1,380 @@
<?php
/**
* The admin-page functionality.
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMath\Admin
* @author RankMath <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Helpers\Param;
use RankMath\Helper;
/**
* Page class.
*/
class Page {
/**
* Unique ID used for menu_slug.
*
* @var string
*/
public $id = null;
/**
* The text to be displayed in the title tags of the page.
*
* @var string
*/
public $title = null;
/**
* The slug name for the parent menu.
*
* @var string
*/
public $parent = null;
/**
* The The on-screen name text for the menu.
*
* @var string
*/
public $menu_title = null;
/**
* The capability required for this menu to be displayed to the user.
*
* @var string
*/
public $capability = 'manage_options';
/**
* The icon for this menu.
*
* @var string
*/
public $icon = 'dashicons-art';
/**
* The position in the menu order this menu should appear.
*
* @var int
*/
public $position = -1;
/**
* The init hook priority.
*
* @var int
*/
public $priority = 25;
/**
* The function/file that displays the page content for the menu page.
*
* @var string|callable
*/
public $render = null;
/**
* The function that run on page POST to save data.
*
* @var callable
*/
public $onsave = null;
/**
* Hold contextual help tabs.
*
* @var array
*/
public $help = null;
/**
* Hold scripts and styles.
*
* @var array
*/
public $assets = null;
/**
* Check if plugin is network active.
*
* @var array
*/
public $is_network = false;
/**
* Hold classes for body tag.
*
* @var array
*/
public $classes = null;
/**
* Hold localized data.
*
* @var array
*/
public $json = null;
/**
* The Constructor.
*
* @param string $id Admin page unique id.
* @param string $title Title of the admin page.
* @param array $config Optional. Override page settings.
*/
public function __construct( $id, $title, $config = [] ) {
// Early bail!
if ( ! $id ) {
wp_die( esc_html__( '$id variable required', 'rank-math' ), esc_html__( 'Variable Required', 'rank-math' ) );
}
if ( ! $title ) {
wp_die( esc_html__( '$title variable required', 'rank-math' ), esc_html__( 'Variable Required', 'rank-math' ) );
}
$this->id = $id;
$this->title = $title;
foreach ( $config as $key => $value ) {
$this->$key = $value;
}
if ( ! $this->menu_title ) {
$this->menu_title = $title;
}
add_action( 'init', [ $this, 'init' ], $this->priority ?? 25 );
}
/**
* Init admin page when WordPress Initialises.
*
* @codeCoverageIgnore
*/
public function init() {
$priority = $this->parent ? intval( $this->position ) : -1;
add_action( $this->is_network ? 'network_admin_menu' : 'admin_menu', [ $this, 'register_menu' ], $priority );
// If not the page is not this page stop here.
if ( ! $this->is_current_page() ) {
return;
}
$hooks = [
'admin_init' => [
'callback' => 'save',
'condition' => ! is_null( $this->onsave ) && is_callable( $this->onsave ),
],
'admin_enqueue_scripts' => [
'callback' => 'enqueue',
'condition' => ! empty( $this->assets ),
],
'admin_head' => [
'callback' => 'contextual_help',
'condition' => ! empty( $this->help ),
],
'admin_body_class' => [
'callback' => 'body_class',
'condition' => ! empty( $this->classes ),
],
];
foreach ( $hooks as $hook => $data ) {
if ( true === $data['condition'] ) {
add_action( $hook, [ $this, $data['callback'] ] );
}
}
}
/**
* Register Admin Menu.
*
* @codeCoverageIgnore
*/
public function register_menu() {
if ( ! $this->parent ) {
add_menu_page( $this->title, $this->menu_title, $this->capability, $this->id, [ $this, 'display' ], $this->icon, $this->position );
return;
}
add_submenu_page( $this->parent, $this->title, $this->menu_title, $this->capability, $this->id, [ $this, 'display' ] );
}
/**
* Enqueue styles and scripts.
*
* @codeCoverageIgnore
*/
public function enqueue() {
$this->enqueue_styles();
$this->enqueue_scripts();
$this->add_localized_data();
}
/**
* Add classes to <body> of WordPress admin.
*
* @codeCoverageIgnore
*
* @param string $classes Space-separated list of CSS classes.
*
* @return string
*/
public function body_class( $classes = '' ) {
return $classes . ' ' . join( ' ', $this->classes );
}
/**
* Save anything you want using onsave function.
*
* @codeCoverageIgnore
*/
public function save() {
call_user_func( $this->onsave, $this );
}
/**
* Contextual Help.
*
* @codeCoverageIgnore
*/
public function contextual_help() {
$screen = get_current_screen();
foreach ( $this->help as $tab_id => $tab ) {
$tab['id'] = $tab_id;
$tab['content'] = $this->get_help_content( $tab );
$screen->add_help_tab( $tab );
}
}
/**
* Render admin page content using render function you passed in config.
*
* @codeCoverageIgnore
*/
public function display() {
if ( is_null( $this->render ) ) {
return;
}
if ( 'settings' === $this->render ) {
return $this->display_settings();
}
if ( is_callable( $this->render ) ) {
call_user_func( $this->render, $this );
return;
}
if ( is_string( $this->render ) ) {
include_once $this->render;
}
}
/**
* Is the page is currrent page.
*
* @return bool
*/
public function is_current_page() {
return Param::get( 'page' ) === $this->id;
}
/**
* Enqueue styles
*
* @codeCoverageIgnore
*/
private function enqueue_styles() {
if ( ! isset( $this->assets['styles'] ) || empty( $this->assets['styles'] ) ) {
return;
}
foreach ( $this->assets['styles'] as $handle => $src ) {
wp_enqueue_style( $handle, $src, null, rank_math()->version );
}
}
/**
* Enqueue scripts.
*
* @codeCoverageIgnore
*/
private function enqueue_scripts() {
if ( ! isset( $this->assets['scripts'] ) || empty( $this->assets['scripts'] ) ) {
return;
}
foreach ( $this->assets['scripts'] as $handle => $src ) {
if ( $handle === 'media-editor' ) {
wp_enqueue_media();
}
wp_enqueue_script( $handle, $src, null, rank_math()->version, true );
}
do_action( 'rank-math/admin_enqueue_scripts' );
}
/**
* Get tab content
*
* @codeCoverageIgnore
*
* @param array $tab Tab to get content for.
*
* @return string
*/
private function get_help_content( $tab ) {
ob_start();
// If it is a function.
if ( isset( $tab['content'] ) && is_callable( $tab['content'] ) ) {
call_user_func( $tab['content'] );
}
// If it is a file.
if ( isset( $tab['view'] ) && $tab['view'] ) {
require $tab['view'];
}
return ob_get_clean();
}
/**
* Localized data.
*/
private function add_localized_data() {
if ( empty( $this->assets['json'] ) ) {
return;
}
foreach ( $this->assets['json'] as $key => $value ) {
Helper::add_json( $key, $value );
}
Helper::add_json(
'settings',
[
'general' => Helper::get_settings( 'general' ),
'titles' => Helper::get_settings( 'titles' ),
'sitemap' => Helper::get_settings( 'sitemap' ),
]
);
}
/**
* Display settings.
*/
private function display_settings() {
echo '<div id="rank-math-settings" class="' . esc_attr( $this->id ) . '"></div>';
}
}

View File

@@ -0,0 +1,571 @@
<?php
/**
* The admin post columns functionality.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Helper;
use RankMath\Helpers\Str;
use RankMath\Helpers\Param;
use RankMath\Runner;
use RankMath\Traits\Hooker;
use RankMath\Admin\Database\Database;
defined( 'ABSPATH' ) || exit;
/**
* Post_Columns class.
*/
class Post_Columns implements Runner {
use Hooker;
/**
* SEO data.
*
* @var array
*/
private $data = [];
/**
* Register hooks.
*/
public function hooks() {
$this->action( 'admin_init', 'init' );
}
/**
* Intialize.
*/
public function init() {
if ( ! Helper::has_cap( 'onpage_general' ) ) {
return;
}
$this->register_post_columns();
$this->register_media_columns();
$this->register_taxonomy_columns();
// Column Content.
$this->filter( 'rank_math_title', 'get_column_title', 5, 2 );
$this->filter( 'rank_math_description', 'get_column_description', 5, 2 );
$this->filter( 'rank_math_seo_details', 'get_column_seo_details', 5 );
}
/**
* Register post column hooks.
*/
private function register_post_columns() {
$post_types = Helper::get_allowed_post_types();
foreach ( $post_types as $post_type ) {
$this->filter( 'edd_download_columns', 'add_columns', 11 );
$this->filter( "manage_{$post_type}_posts_columns", 'add_columns', 11 );
$this->action( "manage_{$post_type}_posts_custom_column", 'columns_contents', 11, 2 );
$this->filter( "manage_edit-{$post_type}_sortable_columns", 'sortable_columns', 11 );
// Also make them hidden by default.
$user_id = get_current_user_id();
$columns_hidden = (array) get_user_meta( $user_id, "manageedit-{$post_type}columnshidden", true );
$maybe_hidden = get_user_meta( $user_id, "manageedit-{$post_type}columnshidden_default", true );
// Continue if default is already set.
if ( $maybe_hidden ) {
continue;
}
// Set it to hidden by default.
$columns_hidden = array_unique( array_merge( $columns_hidden, [ 'rank_math_title', 'rank_math_description' ] ) );
update_user_meta( $user_id, "manageedit-{$post_type}columnshidden", $columns_hidden );
update_user_meta( $user_id, "manageedit-{$post_type}columnshidden_default", '1' );
}
}
/**
* Register media column hooks.
*/
private function register_media_columns() {
if ( ! Helper::get_settings( 'titles.pt_attachment_bulk_editing' ) ) {
return;
}
$this->filter( 'manage_media_columns', 'add_media_columns', 11 );
$this->action( 'manage_media_custom_column', 'media_contents', 11, 2 );
}
/**
* Register taxonomy columns hooks.
*
* @return void
*/
private function register_taxonomy_columns() {
$taxonomies = Helper::get_allowed_taxonomies();
foreach ( $taxonomies as $taxonomy ) {
$this->filter( "manage_edit-{$taxonomy}_columns", 'add_taxonomy_columns', 9 );
$this->filter( "manage_{$taxonomy}_custom_column", 'taxonomy_columns_contents', 10, 3 );
}
}
/**
* Add new columns for SEO title, description and focus keywords.
*
* @param array $columns Array of column names.
*
* @return array
*/
public function add_columns( $columns ) {
global $post_type;
$current_pt = $post_type;
if ( ! $post_type && 'inline-save' === Param::post( 'action' ) ) {
$post_id = Param::post( 'post_ID', 0, FILTER_VALIDATE_INT );
$current_pt = get_post_type( $post_id );
}
$columns['rank_math_seo_details'] = esc_html__( 'SEO Details', 'rank-math' );
if ( Helper::get_settings( 'titles.pt_' . $current_pt . '_bulk_editing', true ) ) {
$columns['rank_math_title'] = esc_html__( 'SEO Title', 'rank-math' );
$columns['rank_math_description'] = esc_html__( 'SEO Desc', 'rank-math' );
}
return $columns;
}
/**
* Make the SEO Score column sortable.
*
* @param array $columns Array of column names.
*
* @return array
*/
public function sortable_columns( $columns ) {
$columns['rank_math_seo_details'] = 'rank_math_seo_score';
return $columns;
}
/**
* Add new columns for Media Alt & Title.
*
* @param array $columns Array of column names.
*
* @return array
*/
public function add_media_columns( $columns ) {
$columns['rank_math_image_title'] = esc_html__( 'Title', 'rank-math' );
$columns['rank_math_image_alt'] = esc_html__( 'Alternative Text', 'rank-math' );
return $columns;
}
/**
* Adds custom columns to taxonomy list view.
*
* @param array $columns Columns belonging to current taxonomy.
*
* @return array
*/
public function add_taxonomy_columns( $columns ) {
$screen = get_current_screen();
if ( Helper::get_settings( 'titles.tax_' . $screen->taxonomy . '_bulk_editing', false ) ) {
$columns['rank_math_title'] = esc_html__( 'SEO Title', 'rank-math' );
$columns['rank_math_description'] = esc_html__( 'SEO Desc', 'rank-math' );
}
return $columns;
}
/**
* Add content for custom column.
*
* @param string $column_name The name of the column to display.
* @param int $post_id The current post ID.
*/
public function columns_contents( $column_name, $post_id ) {
if ( Str::starts_with( 'rank_math', $column_name ) ) {
do_action( $column_name, $post_id );
}
}
/**
* Generate content of custom columns.
*
* @param string $content The content of the current column.
* @param string $column_name The column name.
* @param int $term_id The unique ID of the current term.
*
* @return string
*/
public function taxonomy_columns_contents( $content, $column_name, $term_id ) {
if ( Str::starts_with( 'rank_math_', $column_name ) ) {
do_action( $column_name, $term_id, 'term' );
}
return $content;
}
/**
* Add content for title column.
*
* @param int $object_id The current Object ID.
* @param string $object_type The current Object type.
*/
public function get_column_title( $object_id, $object_type = 'post' ) {
if ( empty( $this->data ) ) {
$method = "get_{$object_type}_seo_data";
$this->$method( $object_type );
}
$title = ! empty( $this->data[ $object_id ]['rank_math_title'] ) ? $this->data[ $object_id ]['rank_math_title'] : '';
if ( ! $title ) {
$title = $this->get_default_title( $object_id, $object_type );
}
?>
<span class="rank-math-column-display"><?php echo esc_html( $title ); ?></span>
<textarea class="rank-math-column-value" data-field="title" tabindex="11"><?php echo esc_attr( $title ); ?></textarea>
<div class="rank-math-column-edit">
<a href="#" class="rank-math-column-save"><?php esc_html_e( 'Save', 'rank-math' ); ?></a>
<a href="#" class="button-link-delete rank-math-column-cancel"><?php esc_html_e( 'Cancel', 'rank-math' ); ?></a>
</div>
<?php
}
/**
* Add content for description column.
*
* @param int $object_id The current Object ID.
* @param string $object_type The current Object type.
*/
public function get_column_description( $object_id, $object_type = 'post' ) {
$description = ! empty( $this->data[ $object_id ]['rank_math_description'] ) ? $this->data[ $object_id ]['rank_math_description'] : '';
if ( ! $description ) {
$description = $this->get_default_description( $object_id, $object_type );
}
?>
<span class="rank-math-column-display"><?php echo esc_html( $description ); ?></span>
<textarea class="rank-math-column-value" data-field="description" tabindex="11"><?php echo esc_attr( $description ); ?></textarea>
<div class="rank-math-column-edit">
<a href="#" class="rank-math-column-save"><?php esc_html_e( 'Save', 'rank-math' ); ?></a>
<a href="#" class="button-link-delete rank-math-column-cancel"><?php esc_html_e( 'Cancel', 'rank-math' ); ?></a>
</div>
<?php
}
/**
* Add content for title column.
*
* @param int $post_id The current post ID.
*/
public function get_column_seo_details( $post_id ) {
if ( empty( $this->data ) ) {
$this->get_post_seo_data();
}
$data = isset( $this->data[ $post_id ] ) ? $this->data[ $post_id ] : [];
if ( ! self::is_post_indexable( $post_id ) ) {
echo '<span class="rank-math-column-display seo-score no-score "><strong>N/A</strong></span>';
echo '<strong>' . esc_html__( 'No Index', 'rank-math' ) . '</strong>';
$this->do_action( 'post/column/seo_details', $post_id, $data, $this->data );
return;
}
$keyword = ! empty( $data['rank_math_focus_keyword'] ) ? $data['rank_math_focus_keyword'] : '';
$keyword = explode( ',', $keyword )[0];
$is_pillar = ! empty( $data['rank_math_pillar_content'] ) && 'on' === $data['rank_math_pillar_content'] ? true : false;
$score = empty( $keyword ) ? false : $this->get_seo_score( $data );
$class = ! $score ? 'no-score' : $this->get_seo_score_class( $score );
$score = $score ? $score . ' / 100' : 'N/A';
?>
<span class="rank-math-column-display seo-score <?php echo esc_attr( $class ); ?> <?php echo ! $score ? 'disabled' : ''; ?>">
<strong><?php echo esc_html( $score ); ?></strong>
<?php if ( $is_pillar ) { ?>
<img class="is-pillar" src="<?php echo esc_url( rank_math()->plugin_url() . 'assets/admin/img/pillar.svg' ); ?>" alt="<?php esc_html_e( 'Is Pillar', 'rank-math' ); ?>" title="<?php esc_html_e( 'Is Pillar', 'rank-math' ); ?>" width="25" />
<?php } ?>
</span>
<label><?php esc_html_e( 'Focus Keyword', 'rank-math' ); ?>:</label>
<span class="rank-math-column-display">
<strong title="Focus Keyword"><?php esc_html_e( 'Keyword', 'rank-math' ); ?>:</strong>
<span>
<?php
echo $keyword ? wp_kses_post( $this->do_filter( 'post/column/seo_details/focus_keyword', $keyword ) ) : esc_html__( 'Not Set', 'rank-math' );
?>
</span>
</span>
<input class="rank-math-column-value" data-field="focus_keyword" tabindex="11" value="<?php echo esc_attr( $keyword ); ?>" />
<?php $this->do_action( 'post/column/seo_details', $post_id, $data, $this->data ); ?>
<div class="rank-math-column-edit">
<a href="#" class="rank-math-column-save"><?php esc_html_e( 'Save', 'rank-math' ); ?></a>
<a href="#" class="button-link-delete rank-math-column-cancel"><?php esc_html_e( 'Cancel', 'rank-math' ); ?></a>
</div>
<?php
}
/**
* Add content for custom media column.
*
* @param string $column_name The name of the column to display.
* @param int $post_id The current post ID.
*/
public function media_contents( $column_name, $post_id ) {
if ( 'rank_math_image_title' === $column_name ) {
$title = get_the_title( $post_id );
?>
<span class="rank-math-column-display"><?php echo esc_html( $title ); ?></span>
<input class="rank-math-column-value" data-field="image_title" tabindex="11" value="<?php echo esc_attr( $title ); ?>" />
<div class="rank-math-column-edit">
<a href="#" class="rank-math-column-save"><?php esc_html_e( 'Save', 'rank-math' ); ?></a>
<a href="#" class="button-link-delete rank-math-column-cancel"><?php esc_html_e( 'Cancel', 'rank-math' ); ?></a>
</div>
<?php
return;
}
if ( 'rank_math_image_alt' === $column_name ) {
$alt = get_post_meta( $post_id, '_wp_attachment_image_alt', true );
?>
<span class="rank-math-column-display"><?php echo esc_html( $alt ); ?></span>
<input class="rank-math-column-value" data-field="image_alt" tabindex="11" value="<?php echo esc_attr( $alt ); ?>" />
<div class="rank-math-column-edit">
<a href="#" class="rank-math-column-save"><?php esc_html_e( 'Save', 'rank-math' ); ?></a>
<a href="#" class="button-link-delete rank-math-column-cancel"><?php esc_html_e( 'Cancel', 'rank-math' ); ?></a>
</div>
<?php
return;
}
}
/**
* Get Default title for the object type.
*
* @param int $object_id The current Object ID.
* @param string $object_type The current Object type.
*/
private function get_default_title( $object_id, $object_type ) {
if ( $object_type === 'term' ) {
$term = get_term( $object_id );
return Helper::get_settings( "titles.tax_{$term->taxonomy}_title" );
}
$post_type = get_post_type( $object_id );
return Helper::get_settings( "titles.pt_{$post_type}_title" );
}
/**
* Get Default description for the object type.
*
* @param int $object_id The current Object ID.
* @param string $object_type The current Object type.
*/
private function get_default_description( $object_id, $object_type ) {
if ( $object_type === 'term' ) {
$term = get_term( $object_id );
return Helper::get_settings( "titles.tax_{$term->taxonomy}_description" );
}
$post_type = get_post_type( $object_id );
$description = has_excerpt( $object_id ) ? '%excerpt%' : Helper::get_settings( "titles.pt_{$post_type}_description" );
}
/**
* Get Terms SEO data.
*/
private function get_term_seo_data() {
$wp_list_table = _get_list_table( 'WP_Terms_List_Table' );
$wp_list_table->prepare_items();
$items = $wp_list_table->items;
if ( empty( $items ) ) {
return false;
}
$term_ids = array_filter(
array_map(
function ( $item ) {
return isset( $item->term_id ) ? $item->term_id : '';
},
$items
)
);
$results = Database::table( 'termmeta' )->select( [ 'term_id', 'meta_key', 'meta_value' ] )->whereIn( 'term_id', $term_ids )->whereLike( 'meta_key', 'rank_math' )->get( ARRAY_A );
if ( empty( $results ) ) {
return false;
}
foreach ( $results as $result ) {
$this->data[ $result['term_id'] ][ $result['meta_key'] ] = $result['meta_value'];
}
}
/**
* Get Post SEO data.
*/
private function get_post_seo_data() {
$post_ids = [];
$post_ids = array_filter( $this->get_post_ids() );
$post_id = (int) Param::post( 'post_ID' );
if ( $post_id ) {
$post_ids[] = $post_id;
}
if ( empty( $post_ids ) ) {
return false;
}
$results = Database::table( 'postmeta' )->select( [ 'post_id', 'meta_key', 'meta_value' ] )->whereIn( 'post_id', $post_ids )->whereLike( 'meta_key', 'rank_math' )->get( ARRAY_A );
if ( empty( $results ) ) {
return false;
}
foreach ( $results as $result ) {
$this->data[ $result['post_id'] ][ $result['meta_key'] ] = $result['meta_value'];
}
}
/**
* Get Post IDs dispalyed on the Post lists page.
*/
private function get_post_ids() {
global $wp_query, $per_page;
if ( empty( $wp_query->posts ) ) {
return [];
}
$pages = $wp_query->posts;
if (
! is_post_type_hierarchical( Param::get( 'post_type' ) ) ||
'menu_order title' !== $wp_query->query['orderby']
) {
return array_map(
function ( $post ) {
return isset( $post->ID ) ? $post->ID : '';
},
$pages
);
}
$children_pages = [];
if ( empty( Param::request( 's' ) ) ) {
$top_level_pages = [];
foreach ( $pages as $page ) {
if ( $page->post_parent > 0 ) {
$children_pages[ $page->post_parent ][] = $page;
} else {
$top_level_pages[] = $page;
}
}
$pages = &$top_level_pages;
}
$pagenum = max( 1, Param::request( 'paged', 0 ) );
$count = 0;
$start = ( $pagenum - 1 ) * $per_page;
$end = $start + $per_page;
$ids = [];
foreach ( $pages as $page ) {
if ( $count >= $end ) {
break;
}
if ( $count >= $start ) {
$ids[] = $page->ID;
}
++$count;
$this->add_child_page_ids( $children_pages, $page->ID, $ids, $count );
}
return $ids;
}
/**
* Add the child page IDs to the list of IDs to be processed.
*
* @param array $children_pages Child Pages.
* @param int $id Current page ID.
* @param array $ids IDs to be processed.
* @param int $count Counter.
*/
private function add_child_page_ids( $children_pages, $id, &$ids, &$count ) {
if ( empty( $children_pages ) || empty( $children_pages[ $id ] ) ) {
return;
}
foreach ( $children_pages[ $id ] as $child_page ) {
$id = $child_page->ID;
$ids[] = $child_page->ID;
++$count;
$this->add_child_page_ids( $children_pages, $id, $ids, $count );
}
}
/**
* Get SEO score.
*
* @param array $data SEO data of current post.
*
* @return string
*/
private function get_seo_score( $data ) {
if ( ! isset( $data['rank_math_seo_score'] ) ) {
return false;
}
if ( ! Helper::is_score_enabled() ) {
return false;
}
return $data['rank_math_seo_score'] ? $data['rank_math_seo_score'] : 0;
}
/**
* Get SEO score rating string: great/good/bad.
*
* @param int $score Score.
*
* @return string
*/
private function get_seo_score_class( $score ) {
if ( $score > 80 ) {
return 'great';
}
if ( $score > 50 && $score < 81 ) {
return 'good';
}
return 'bad';
}
/**
* Check post indexable status.
*
* @param int $post_id Post ID.
*/
public static function is_post_indexable( $post_id ) {
$robots = Param::post( 'rank_math_robots', false, FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
$robots = apply_filters( 'rank_math/admin/robots', $robots, $post_id );
if ( ! empty( $robots ) ) {
return in_array( 'index', $robots, true ) ? true : false;
}
return Helper::is_post_indexable( $post_id );
}
}

View File

@@ -0,0 +1,389 @@
<?php
/**
* The admin post filters functionality.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use WP_Meta_Query;
use RankMath\Helper;
use RankMath\Runner;
use RankMath\Traits\Hooker;
use RankMath\Helpers\Security;
use RankMath\Helpers\Param;
use RankMath\Helpers\DB as DB_Helper;
defined( 'ABSPATH' ) || exit;
/**
* Post_Filters class.
*/
class Post_Filters implements Runner {
use Hooker;
/**
* Register hooks.
*/
public function hooks() {
$this->action( 'admin_init', 'init' );
}
/**
* Intialize.
*/
public function init() {
if ( ! Helper::has_cap( 'general' ) ) {
return;
}
$this->filter( 'pre_get_posts', 'posts_by_seo_filters' );
$this->filter( 'parse_query', 'posts_by_focus_keywords' );
$this->filter( 'restrict_manage_posts', 'add_seo_filters', 11 );
foreach ( Helper::get_allowed_post_types() as $post_type ) {
$this->filter( "views_edit-$post_type", 'add_pillar_content_filter_link' );
}
}
/**
* Filter posts in admin by Rank Math's Filter value.
*
* @param \WP_Query $query The wp_query instance.
*/
public function posts_by_seo_filters( $query ) {
if ( ! $this->can_seo_filters() ) {
return;
}
if ( 'rank_math_seo_score' === $query->get( 'orderby' ) ) {
$query->set( 'orderby', 'meta_value' );
$query->set( 'meta_key', 'rank_math_seo_score' );
$query->set( 'meta_type', 'numeric' );
}
if ( empty( $_GET['pillar_content'] ) && empty( $_GET['seo-filter'] ) ) {
return;
}
$meta_query = [];
// Check for Pillar Content filter.
if ( ! empty( $_GET['pillar_content'] ) ) {
$meta_query[] = [
'key' => 'rank_math_pillar_content',
'value' => 'on',
];
}
$this->set_seo_filters( $meta_query );
$query->set( 'meta_query', $meta_query );
}
/**
* Filter post in admin by Pillar Content.
*
* @param \WP_Query $query The wp_query instance.
*/
public function posts_by_focus_keywords( $query ) {
if ( ! $this->can_fk_filter() ) {
return;
}
if ( $ids = $this->posts_had_reviews() ) { // phpcs:ignore
$query->set( 'post_type', 'any' );
$query->set( 'post__in', $ids );
return;
}
$query->set( 'post_status', 'publish' );
if ( $ids = $this->has_fk_in_title() ) { // phpcs:ignore
$query->set( 'post__in', $ids );
return;
}
$focus_keyword = Param::get( 'focus_keyword', '', FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_BACKTICK );
if ( 1 === absint( $focus_keyword ) ) {
$query->set(
'meta_query',
[
'relation' => 'AND',
[
'key' => 'rank_math_focus_keyword',
'compare' => 'NOT EXISTS',
],
[
'relation' => 'OR',
[
'key' => 'rank_math_robots',
'value' => 'noindex',
'compare' => 'NOT LIKE',
],
[
'key' => 'rank_math_robots',
'compare' => 'NOT EXISTS',
],
],
]
);
return;
}
$query->set( 'post_type', 'any' );
$query->set(
'meta_query',
[
[
'relation' => 'OR',
[
'key' => 'rank_math_focus_keyword',
'value' => $focus_keyword . ',',
'compare' => 'LIKE',
],
[
'key' => 'rank_math_focus_keyword',
'value' => $focus_keyword,
'compare' => 'LIKE',
],
],
]
);
}
/**
* Add SEO filters.
*/
public function add_seo_filters() {
global $post_type;
if ( 'attachment' === $post_type || ! in_array( $post_type, Helper::get_allowed_post_types(), true ) ) {
return;
}
$options = [
'' => esc_html__( 'Rank Math', 'rank-math' ),
'great-seo' => esc_html__( 'SEO Score: Good', 'rank-math' ),
'good-seo' => esc_html__( 'SEO Score: Ok', 'rank-math' ),
'bad-seo' => esc_html__( 'SEO Score: Bad', 'rank-math' ),
'empty-fk' => esc_html__( 'Focus Keyword Not Set', 'rank-math' ),
'noindexed' => esc_html__( 'Articles noindexed', 'rank-math' ),
];
$options = $this->do_filter( 'manage_posts/seo_filter_options', $options, $post_type );
if ( empty( $options ) ) {
return;
}
$selected = Param::get( 'seo-filter' );
?>
<select name="seo-filter" id="rank-math-seo-filter">
<?php foreach ( $options as $val => $option ) : ?>
<option value="<?php echo esc_attr( $val ); ?>" <?php selected( $selected, $val, true ); ?>><?php echo esc_html( $option ); ?></option>
<?php endforeach; ?>
</select>
<?php
}
/**
* Add view to filter list for Pillar Content.
*
* @param array $views An array of available list table views.
*/
public function add_pillar_content_filter_link( $views ) {
global $typenow;
$current = empty( $_GET['pillar_content'] ) ? '' : ' class="current" aria-current="page"';
$pillars = get_posts(
[
'post_type' => $typenow,
'fields' => 'ids',
'posts_per_page' => -1,
'meta_key' => 'rank_math_pillar_content',
'meta_value' => 'on',
]
);
$views['pillar_content'] = sprintf(
'<a href="%1$s"%2$s>%3$s <span class="count">(%4$s)</span></a>',
Security::add_query_arg(
[
'post_type' => $typenow,
'pillar_content' => 1,
]
),
$current,
esc_html__( 'Pillar Content', 'rank-math' ),
number_format_i18n( count( $pillars ) )
);
return $views;
}
/**
* Can apply SEO filters.
*
* @return bool
*/
private function can_seo_filters() {
$screen = get_current_screen();
if ( is_null( $screen ) || ! in_array( $screen->post_type, Helper::get_allowed_post_types(), true ) ) {
return false;
}
return true;
}
/**
* Set SEO filters meta query.
*
* @param array $query Meta query.
*/
private function set_seo_filters( &$query ) {
$filter = Param::get( 'seo-filter' );
if ( false === $filter ) {
return;
}
$hash = [
'empty-fk' => [
'key' => 'rank_math_focus_keyword',
'compare' => 'NOT EXISTS',
],
'bad-seo' => [
'key' => 'rank_math_seo_score',
'value' => 50,
'compare' => '<=',
'type' => 'numeric',
],
'good-seo' => [
'key' => 'rank_math_seo_score',
'value' => [ 51, 80 ],
'compare' => 'BETWEEN',
'type' => 'numeric',
],
'great-seo' => [
'key' => 'rank_math_seo_score',
'value' => 80,
'compare' => '>',
'type' => 'numeric',
],
'noindexed' => [
'key' => 'rank_math_robots',
'value' => 'noindex',
'compare' => 'LIKE',
],
];
// Extra conditions for "SEO Score" filters.
$seo_score_filters = [ 'bad-seo', 'good-seo', 'great-seo' ];
if ( in_array( $filter, $seo_score_filters, true ) ) {
$query['relation'] = 'AND';
$query[] = [
'relation' => 'OR',
[
'key' => 'rank_math_robots',
'value' => 'noindex',
'compare' => 'NOT LIKE',
],
[
'key' => 'rank_math_robots',
'compare' => 'NOT EXISTS',
],
];
$query[] = [
'key' => 'rank_math_focus_keyword',
'compare' => 'EXISTS',
];
$query[] = [
'key' => 'rank_math_focus_keyword',
'value' => '',
'compare' => '!=',
];
}
if ( isset( $hash[ $filter ] ) ) {
$query[] = $hash[ $filter ];
}
}
/**
* Can apply Focus Keyword filter.
*
* @return bool
*/
private function can_fk_filter() {
$screen = get_current_screen();
if (
is_null( $screen ) ||
'edit' !== $screen->base ||
(
! isset( $_GET['focus_keyword'] ) &&
! isset( $_GET['fk_in_title'] ) &&
! isset( $_GET['review_posts'] )
)
) {
return false;
}
return true;
}
/**
* Check if Focus Keyword appears in the title.
*
* @return bool|array
*/
private function has_fk_in_title() {
global $wpdb;
if ( ! Param::get( 'fk_in_title' ) ) {
return false;
}
$screen = get_current_screen();
$meta_query = new WP_Meta_Query(
[
[
'key' => 'rank_math_focus_keyword',
'compare' => 'EXISTS',
],
[
'relation' => 'OR',
[
'key' => 'rank_math_robots',
'value' => 'noindex',
'compare' => 'NOT LIKE',
],
[
'key' => 'rank_math_robots',
'compare' => 'NOT EXISTS',
],
],
]
);
$meta_query = $meta_query->get_sql( 'post', $wpdb->posts, 'ID' );
return DB_Helper::get_col( "SELECT {$wpdb->posts}.ID FROM $wpdb->posts {$meta_query['join']} WHERE 1=1 {$meta_query['where']} AND {$wpdb->posts}.post_type = '$screen->post_type' AND ({$wpdb->posts}.post_status = 'publish') AND REPLACE({$wpdb->posts}.post_title, '&amp;', '&') NOT LIKE CONCAT( '%', SUBSTRING_INDEX( {$wpdb->postmeta}.meta_value, ',', 1 ), '%' )" );
}
/**
* Check if any posts had Review schema.
*
* @return bool|array
*/
private function posts_had_reviews() {
global $wpdb;
$review_posts = Param::get( 'review_posts' );
if ( ! $review_posts ) {
return false;
}
return ! get_option( 'rank_math_review_posts_converted', false );
}
}

View File

@@ -0,0 +1,310 @@
<?php
/**
* Inform the user about Rank Math PRO after 20 days of usage.
*
* @since 1.0.69
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\KB;
use RankMath\Helper;
use RankMath\Traits\Ajax;
use RankMath\Traits\Hooker;
defined( 'ABSPATH' ) || exit;
/**
* Pro_Notice class.
*/
class Pro_Notice {
use Hooker;
use Ajax;
/**
* Now.
*
* @var string
*/
public $current_time = '';
/**
* Rank Math plugin install date.
*
* @var string
*/
public $install_date = '';
/**
* Date of release of version 1.0.69. Turned into a timestamp in the constructor.
*
* @var string
*/
public $record_date = '2021-07-30 13:00';
/**
* Constructor method.
*/
public function __construct() {
$this->current_time = Helper::get_current_time();
$this->record_date = strtotime( $this->record_date );
$this->install_date = get_option( 'rank_math_install_date' );
if ( false === $this->install_date ) {
$this->install_date = $this->current_time;
}
}
/**
* Register hooks.
*/
public function hooks() {
$this->ajax( 'dismiss_pro_notice', 'dismiss' );
// Admin notice.
$notice_date = $this->get_notice_date();
if ( $this->current_time > $notice_date ) {
if ( get_option( 'rank_math_pro_notice_added' ) === false && ! Helper::has_notification( 'rank_math_review_plugin_notice' ) ) {
$this->add_notice( (int) get_option( 'rank_math_pro_notice_delayed' ) );
}
// Make dismiss button work like the "Maybe later" link.
$this->action( 'wp_helpers_notification_dismissed', 'pro_notice_after_dismiss' );
$this->action( 'admin_footer', 'pro_notice_js', 15 );
}
}
/**
* Add inline JS & CSS related to the Pro notice.
*
* @return void
*/
public function pro_notice_js() {
if ( ! Helper::has_notification( 'rank_math_pro_notice' ) ) {
return;
}
?>
<script>
(function( $ ) {
$( function() {
$('.rank-math-dismiss-pro-notice').on( 'click', function(e) {
var $this = $(this);
if ( ! $this.hasClass( 'rank-math-upgrade-action' ) ) {
e.preventDefault();
}
if ( $this.hasClass( 'rank-math-maybe-later-action' ) ) {
$('#rank_math_pro_notice').find( '.notice-dismiss' ).trigger('click');
return false;
}
jQuery.ajax( {
url: rankMath.ajaxurl,
data: { action: 'rank_math_already_upgraded', security: rankMath.security,
},
} );
$('#rank_math_pro_notice').find( '.notice-dismiss' ).trigger('click');
});
});
})(jQuery);
</script>
<style>
#rank_math_pro_notice.is-dismissible {
background: #253142;
color: #e4e5e7;
border-width: 3px;
border-style: solid;
border-color: #161e28;
padding: 0.25rem 1rem 1rem;
border-radius: 5px;
}
#rank_math_pro_notice.is-dismissible p {
font-size: 1.25rem;
color: #f7d070;
margin-bottom: 0;
}
#rank_math_pro_notice.is-dismissible ul {
line-height: 1;
margin-bottom: 0;
text-align: left;
opacity: 0.8;
font-size: 15px;
max-width: 530px;
}
#rank_math_pro_notice.is-dismissible li {
display: inline-block;
width: 49%;
margin-bottom: 0.5rem;
}
#rank_math_pro_notice ul li:before {
font-family: dashicons;
font-size: 20px;
width: 20px;
height: 20px;
margin-right: 5px;
content: '\f147';
text-align: center;
vertical-align: middle;
color: #161e28;
border-radius: 10px;
background: #9ce2b6;
}
#rank_math_pro_notice .button {
border-color: #f7d070;
background: #f7d070;
color: #5a4000;
font-size: 15px;
margin-right: 12px;
}
div#rank_math_pro_notice .rank-math-maybe-later-action,
div#rank_math_pro_notice .rank-math-already-upgraded-action {
color: #f7d070;
opacity: 0.7;
margin: 0 12px;
font-size: 13px;
}
.toplevel_page_rank-math #rank_math_pro_notice,
body[class*="rank-math_page_rank-math-options-"] div#rank_math_pro_notice {
display: none;
}
</style>
<?php
}
/**
* Add admin notice.
*
* @param int $variant Notice variant.
* @return void
*/
public function add_notice( $variant = 0 ) {
$message = $this->get_notice_text( $variant );
Helper::add_notification(
$message,
[
'type' => 'info',
'id' => 'rank_math_pro_notice',
'capability' => 'install_plugins',
]
);
update_option( 'rank_math_pro_notice_added', '1', false );
}
/**
* Get notice texts.
*
* @param integer $variant Message variant.
* @return string
*/
public function get_notice_text( $variant = 0 ) {
$message = '';
switch ( (int) $variant ) {
case 1:
$message = '<p><strong>';
$message .= esc_html__( 'Rank Your Content With the Power of PRO & A.I.', 'rank-math' );
$message .= '</strong></p>';
$message .= '<ul>
<li>' . esc_html__( 'Unlimited Websites', 'rank-math' ) . '</li>
<li>' . esc_html__( 'Content A.I. (Artificial Intelligence)', 'rank-math' ) . '</li>
<li>' . esc_html__( 'Keyword Rank Tracker', 'rank-math' ) . '</li>
<li>' . esc_html__( 'Powerful Schema Generator', 'rank-math' ) . '</li>
<li>' . esc_html__( '24x7 Premium Support', 'rank-math' ) . '</li>
<li>' . esc_html__( 'SEO Email Reports', 'rank-math' ) . '</li>
<li>' . esc_html__( 'and Many More…', 'rank-math' ) . '</li>
</ul>';
$message .= '<p>
<a href="' . KB::get( 'pro', 'Upgrade Notice 2 New Yes' ) . '" class="button rank-math-dismiss-pro-notice rank-math-upgrade-action" target="_blank" rel="noopener noreferrer"><strong>' . esc_html__( 'Yes, I want to learn more', 'rank-math' ) . '</strong></a><a href="#" class="rank-math-dismiss-pro-notice rank-math-already-upgraded-action">' . esc_html__( 'No, I don\'t want it', 'rank-math' ) . '</a><a href="#" class="rank-math-dismiss-pro-notice rank-math-already-upgraded-action">' . esc_html__( 'I already upgraded', 'rank-math' ) . '</a>
</p>';
break;
default:
$message = '<p><strong>';
$message .= esc_html__( 'Rank Your Content With the Power of PRO & A.I.', 'rank-math' );
$message .= '</strong></p><p>';
$message .= '<ul>
<li>' . esc_html__( 'Unlimited Websites', 'rank-math' ) . '</li>
<li>' . esc_html__( 'Content A.I. (Artificial Intelligence)', 'rank-math' ) . '</li>
<li>' . esc_html__( 'Keyword Rank Tracker', 'rank-math' ) . '</li>
<li>' . esc_html__( 'Powerful Schema Generator', 'rank-math' ) . '</li>
<li>' . esc_html__( '24x7 Premium Support', 'rank-math' ) . '</li>
<li>' . esc_html__( 'SEO Email Reports', 'rank-math' ) . '</li>
<li>' . esc_html__( 'and Many More…', 'rank-math' ) . '</li>
</ul>';
$message .= '<p>
<a href="' . KB::get( 'pro', 'Upgrade Notice 1 New Yes' ) . '" class="button rank-math-dismiss-pro-notice rank-math-upgrade-action" target="_blank" rel="noopener noreferrer"><strong>' . esc_html__( 'Yes, I want better SEO', 'rank-math' ) . '</strong></a><a href="#" class="rank-math-dismiss-pro-notice rank-math-maybe-later-action">' . esc_html__( 'No, maybe later', 'rank-math' ) . '</a><a href="#" class="rank-math-dismiss-pro-notice rank-math-already-upgraded-action">' . esc_html__( 'I already purchased', 'rank-math' ) . '</a>
</p>';
break;
}
return $message;
}
/**
* Set "delayed" flag after the user dismisses the notice.
*
* @param string $notification_id Dismissed notice ID.
* @return void
*/
public function pro_notice_after_dismiss( $notification_id ) {
if ( 'rank_math_pro_notice' !== $notification_id ) {
return;
}
// If it has already been delayed once then dismiss it forever.
if ( get_option( 'rank_math_pro_notice_delayed' ) ) {
update_option( 'rank_math_already_upgraded', Helper::get_current_time() );
return;
}
delete_option( 'rank_math_pro_notice_date' );
delete_option( 'rank_math_pro_notice_added' );
update_option( 'rank_math_pro_notice_delayed', 1, false );
}
/**
* Get stored notice start date.
*
* @return int
*/
public function get_notice_date() {
$notice_date = get_option( 'rank_math_pro_notice_date' );
if ( false !== $notice_date ) {
return $notice_date;
}
$delay_days = 10;
if ( $this->install_date < $this->record_date && ! get_option( 'rank_math_pro_notice_delayed' ) ) {
$delay_days = wp_rand( 7, 30 );
}
$notice_date = $this->current_time + ( $delay_days * DAY_IN_SECONDS );
update_option( 'rank_math_pro_notice_date', $notice_date, false );
return $notice_date;
}
/**
* Set the "already upgraded" flag.
* This also sets the "already reviewed" flag, so the review notice will not show up anymore either.
*/
public function dismiss() {
check_ajax_referer( 'rank-math-ajax-nonce', 'security' );
$this->has_cap_ajax( 'onpage_general' );
update_option( 'rank_math_already_upgraded', Helper::get_current_time() );
update_option( 'rank_math_already_reviewed', Helper::get_current_time() );
$this->success( 'success' );
}
}

View File

@@ -0,0 +1,36 @@
<?php
/**
* The option page functionality of the plugin.
*
* @since 1.0.250
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Helper;
defined( 'ABSPATH' ) || exit;
/**
* Register_Options_Page class.
*/
class Register_Options_Page {
/**
* The Constructor
*
* @param array $config Array of configuration.
*/
public function __construct( $config ) {
if ( ! Helper::is_react_enabled() ) {
new CMB2_Options( $config );
return;
}
$options_page = new Options( $config );
$options_page->register_option_page();
}
}

View File

@@ -0,0 +1,323 @@
<?php
/**
* The Setup Wizard - configure the SEO settings in just a few steps.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Helper;
use RankMath\Traits\Hooker;
use RankMath\Admin\Admin_Helper;
use RankMath\Helpers\Param;
use RankMath\Helpers\Security;
use RankMath\Google\Authentication;
defined( 'ABSPATH' ) || exit;
/**
* Registration class.
*/
class Registration {
use Hooker;
/**
* Page slug.
*
* @var string
*/
private $slug = 'rank-math-registration';
/**
* Hold current step.
*
* @var string
*/
protected $step = '';
/**
* Current step slug.
*
* @var string
*/
protected $step_slug = '';
/**
* Is registration invalid.
*
* @var bool
*/
public $invalid = false;
/**
* The Constructor.
*/
public function __construct() {
$this->step = 'register';
$this->step_slug = 'register';
$this->invalid = Helper::is_invalid_registration();
if ( $this->invalid ) {
$this->action( 'admin_menu', 'admin_menu' );
$this->action( 'admin_init', 'redirect_to_welcome' );
$this->action( 'admin_post_rank_math_save_registration', 'save_registration' );
$this->action( 'admin_post_rank_math_skip_wizard', 'skip_wizard' );
$this->action( 'admin_init', 'render_page', 30 );
}
$this->action( 'admin_init', 'handle_registration' );
$this->filter( 'allowed_redirect_hosts', 'allowed_redirect_hosts' );
}
/**
* Add allowed redirect hosts.
*
* @param array $hosts Allowed hosts.
* @return array
*/
public function allowed_redirect_hosts( $hosts ) {
$hosts[] = 'rankmath.com';
return $hosts;
}
/**
* Check for activation.
*/
public function handle_registration() {
// Bail if already connected.
if ( Helper::is_site_connected() ) {
return;
}
if ( ! Helper::has_cap( 'general' ) ) {
return;
}
$nonce = Param::get( 'nonce' );
if ( ! $nonce || ! wp_verify_nonce( $nonce, 'rank_math_register_product' ) ) {
return;
}
$status = Param::get( 'rankmath_connect' );
if ( $status && $redirect_to = $this->get_registration_url( $status ) ) { //phpcs:ignore
Helper::redirect( $redirect_to );
exit;
}
}
/**
* Handle activation.
*
* @param string $status Status parameter.
*/
private function get_registration_url( $status ) {
if ( 'cancel' === $status ) {
// User canceled activation.
Helper::add_notification( __( 'Rank Math plugin could not be connected.', 'rank-math' ), [ 'type' => 'error' ] );
return Security::remove_query_arg_raw( [ 'rankmath_connect', 'rankmath_auth' ] );
}
if ( 'banned' === $status ) {
// User or site banned.
Helper::add_notification( __( 'Unable to connect Rank Math.', 'rank-math' ), [ 'type' => 'error' ] );
return Security::remove_query_arg_raw( [ 'rankmath_connect', 'rankmath_auth' ] );
}
if ( 'ok' === $status && $auth_data = $this->get_registration_params() ) { // phpcs:ignore
Admin_Helper::get_registration_data(
[
'username' => $auth_data['username'],
'email' => $auth_data['email'],
'api_key' => $auth_data['api_key'],
'plan' => $auth_data['plan'],
'connected' => true,
'site_url' => Helper::get_home_url(),
]
);
if ( 1 === absint( Param::get( 'analytics' ) ) ) {
wp_redirect( Authentication::get_auth_url() ); //phpcs:ignore -- This is used to redirect to the external url.
exit;
}
// Redirect to the wizard is registration successful.
if ( Param::get( 'page' ) === 'rank-math-registration' ) {
return Helper::get_admin_url( 'wizard' );
}
return Security::remove_query_arg_raw( [ 'rankmath_connect', 'rankmath_auth', 'nonce' ] );
}
return false;
}
/**
* Check if 'rankmath_auth' contains all the data we need, in the
* correct format.
*
* @return bool|array Whether the input is valid.
*/
private function get_registration_params() {
$params = Param::get( 'rankmath_auth' );
if ( false === $params ) {
return false;
}
$params = json_decode( base64_decode( $params ), true ); // phpcs:ignore -- Verified as safe usage.
if (
! is_array( $params ) ||
! isset( $params['username'] ) ||
! isset( $params['email'] ) ||
! isset( $params['api_key'] )
) {
return false;
}
return $params;
}
/**
* Redirect to welcome page.
*
* Redirect the user to the welcome page after plugin activation.
*/
public function redirect_to_welcome() {
if ( ! $this->can_redirect() ) {
return;
}
$url = '';
if ( $this->invalid ) {
$url = 'registration';
} elseif ( ! get_option( 'rank_math_wizard_completed' ) ) {
$url = 'wizard';
}
Helper::redirect( Helper::get_admin_url( $url ) );
exit;
}
/**
* Add menu items.
*/
public function admin_menu() {
add_menu_page(
esc_html__( 'Rank Math', 'rank-math' ),
esc_html__( 'Rank Math SEO', 'rank-math' ),
'manage_options',
$this->slug,
[ $this, 'render_page' ]
);
}
/**
* Output the admin page.
*/
public function render_page() {
// Early bail if we're not on the right page.
if ( Param::get( 'page' ) !== $this->slug ) {
return;
}
if ( ob_get_length() ) {
ob_end_clean();
}
$assets = new Assets();
$assets->register();
wp_styles()->done = [];
wp_scripts()->done = [];
// Wizard.
wp_enqueue_media();
wp_enqueue_style( 'rank-math-wizard', rank_math()->plugin_url() . 'assets/admin/css/setup-wizard.css', [ 'wp-admin', 'buttons', 'wp-components', 'rank-math-common', 'rank-math-cmb2' ], rank_math()->version );
wp_enqueue_script( 'rank-math-registration', rank_math()->plugin_url() . 'assets/admin/js/registration.js', [ 'lodash', 'react', 'react-dom', 'wp-element', 'wp-data', 'rank-math-components' ], rank_math()->version, true );
Helper::add_json( 'logo', esc_url( rank_math()->plugin_url() . 'assets/admin/img/logo.svg' ) );
Helper::add_json( 'registerNonce', wp_create_nonce( 'rank-math-wizard' ) );
Helper::add_json( 'adminUrl', esc_url( admin_url( 'admin-post.php' ) ) );
Helper::add_json( 'isSiteUrlValid', Admin_Helper::is_site_url_valid() );
Helper::add_json( 'optionsPage', esc_url( admin_url( 'options-general.php' ) ) );
ob_start();
/**
* Start the actual page content.
*/
include_once rank_math()->admin_dir() . 'wizard/views/content.php';
exit;
}
/**
* Execute save handler for current step.
*/
public function save_registration() {
// If no form submission, bail.
$referer = Param::post( '_wp_http_referer', get_dashboard_url() );
if ( Param::post( 'step' ) !== 'register' ) {
return Helper::redirect( $referer );
}
check_admin_referer( 'rank-math-wizard', 'security' );
if ( ! Helper::has_cap( 'general' ) ) {
return Helper::redirect( $referer );
}
$this->redirect_to_connect( $_POST );
}
/**
* Skip wizard handler.
*/
public function skip_wizard() {
check_admin_referer( 'rank-math-wizard', 'security' );
if ( ! Helper::has_cap( 'general' ) ) {
exit;
}
add_option( 'rank_math_registration_skip', true );
Helper::redirect( Helper::get_admin_url( 'wizard' ) );
exit;
}
/**
* Authenticate registration.
*
* @param array $values Array of values for the step to process.
*/
private function redirect_to_connect( $values ) {
if ( ! isset( $values['rank_math_activate'] ) ) {
Admin_Helper::deregister_user();
return;
}
$url = Admin_Helper::get_activate_url( Helper::get_admin_url( 'registration' ) );
wp_safe_redirect( $url );
die();
}
/**
* Can redirect to setup/registration page after install.
*
* @return bool
*/
private function can_redirect() {
if ( ! get_transient( '_rank_math_activation_redirect' ) ) {
return false;
}
delete_transient( '_rank_math_activation_redirect' );
if ( ( ! empty( $_GET['page'] ) && in_array( $_GET['page'], [ 'rank-math-registration', 'rank-math-wizard' ], true ) ) || ! current_user_can( 'manage_options' ) ) {
return false;
}
return true;
}
}

View File

@@ -0,0 +1,362 @@
<?php
/**
* The option center of the plugin.
*
* @since 1.0.250
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Helper;
use RankMath\Helpers\Str;
/**
* Settings Sanitizer for React-based settings.
*/
class Sanitize_Settings {
/**
* Sanitize all settings data using field types.
*
* @param array $settings_data Array of setting data [field_id => value].
* @param array $field_types Array of field types [field_id => type].
*
* @return array Sanitized settings data.
*/
public static function sanitize( $settings_data, $field_types ) {
$sanitized = [];
foreach ( $settings_data as $field_id => $value ) {
$type = $field_types[ $field_id ] ?? 'text';
$sanitized[ $field_id ] = self::sanitize_field( $value, $type, $field_id );
}
return $sanitized;
}
/**
* Sanitize an individual field based on its type.
*
* @param mixed $value Field value.
* @param string $type Field type.
* @param string $field_id Field ID.
*
* @return mixed Sanitized value.
*/
public static function sanitize_field( $value, $type, $field_id ) {
// First: Check field ID-specific logic.
$field_specific = apply_filters( 'rank_math/settings/sanitize_fields', self::sanitize_by_field_id( $value, $field_id ), $value, $field_id );
if ( $field_specific !== null ) {
return $field_specific;
}
switch ( $type ) {
case 'text':
return is_array( $value ) ? array_map( [ __CLASS__, 'sanitize_textfield' ], $value ) : self::sanitize_textfield( $value );
case 'textarea':
return is_array( $value ) ? array_map( 'wp_kses_post', $value ) : wp_kses_post( $value );
case 'toggle':
return $value ? 'on' : 'off';
case 'checkbox':
case 'checkboxlist':
return is_array( $value ) ? array_map( 'sanitize_text_field', $value ) : [];
case 'select':
case 'selectSearch':
case 'selectVariable':
case 'searchPage':
case 'toggleGroup':
return is_array( $value ) ? array_map( [ __CLASS__, 'sanitize_textfield' ], $value ) : self::sanitize_textfield( $value );
case 'number':
return is_array( $value ) ? array_map( 'intval', $value ) : intval( $value );
case 'file':
return esc_url_raw( $value );
case 'group':
case 'repeatableGroup':
return self::sanitize_group_value( $value );
default:
// Fallback.
return map_deep( $value, [ __CLASS__, 'sanitize_default_value' ] );
}
}
/**
* Handles sanitization for default fields. Make sure to not change the boolean to blank text.
*
* @param string $value The unsanitized value from the form.
*
* @return string Sanitized value to be stored.
*/
public static function sanitize_default_value( $value ) {
return is_string( $value ) ? sanitize_text_field( $value ) : $value;
}
/**
* Sanitize an individual field based on its id.
*
* @param mixed $value Field value.
* @param string $field_id Field ID.
*
* @return mixed Sanitized value.
*/
private static function sanitize_by_field_id( $value, $field_id ) {
switch ( $field_id ) {
case 'robots_txt_content':
return self::sanitize_robots_text( $value );
case 'google_verify':
case 'bing_verify':
case 'baidu_verify':
case 'yandex_verify':
case 'pinterest_verify':
case 'norton_verify':
return self::sanitize_webmaster_tags( $value );
case 'custom_webmaster_tags':
return self::sanitize_custom_webmaster_tags( $value );
case 'console_caching_control':
return self::sanitize_cache_control( $value );
}
// Returning null means no special handling; fall back to type-based logic.
return null;
}
/**
* Handles sanitization for text fields.
*
* @param string $value The unsanitized value from the form.
*
* @return string Sanitized value to be stored.
*/
private static function sanitize_textfield( $value ) {
if ( is_object( $value ) || is_array( $value ) ) {
return '';
}
$value = (string) $value;
$filtered = wp_check_invalid_utf8( $value );
if ( strpos( $filtered, '<' ) !== false ) {
$filtered = wp_pre_kses_less_than( $filtered );
// Strip extra whitespace.
$filtered = wp_strip_all_tags( $filtered, false );
// Use html entities in a special case to make sure no later
// newline stripping stage could lead to a functional tag!
$filtered = str_replace( "<\n", "&lt;\n", $filtered );
}
$filtered = preg_replace( '/[\r\n\t ]+/', ' ', $filtered );
$filtered = trim( $filtered );
$found = false;
while ( preg_match( '/%[0-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 apply_filters( 'sanitize_text_field', $filtered, $value );
}
/**
* Handles sanitization of Robots text.
*
* @since 1.0.45
*
* @param mixed $value The unsanitized Robots text.
*
* @return string Sanitized Robots text to be stored.
*/
private static function sanitize_robots_text( $value ) {
if ( empty( $value ) ) {
return '';
}
return wp_strip_all_tags( $value );
}
/**
* Handles sanitization for webmaster tag and remove <meta> tag.
*
* @param mixed $value The unsanitized value from the form.
*
* @return mixed Sanitized value to be stored.
*/
private static function sanitize_webmaster_tags( $value ) {
$value = trim( $value );
if ( ! empty( $value ) && Str::starts_with( '<meta', trim( $value ) ) ) {
preg_match( '/content="([^"]+)"/i', stripslashes( $value ), $matches );
$value = $matches[1];
}
return htmlentities( wp_strip_all_tags( $value ) );
}
/**
* Handles sanitization for custom webmaster tags.
* Only <meta> tags are allowed.
*
* @param mixed $value The unsanitized value from the form.
*/
private static function sanitize_custom_webmaster_tags( $value ) {
$sanitized = wp_kses(
$value,
[
'meta' => [
'name' => [],
'content' => [],
],
]
);
return $sanitized;
}
/**
* Handles sanitization for Analytics cache control option.
*
* @param mixed $value The unsanitized value from the form.
*/
private static function sanitize_cache_control( $value ) {
$max = apply_filters( 'rank_math/analytics/max_days_allowed', 90 );
$value = absint( $value );
if ( $value > $max ) {
$value = $max;
}
return $value;
}
/**
* Do not save if name or image is empty.
*
* @param array $value Field value to save.
* @return array
*/
private function sanitize_overlays( $value ) {
if ( ! is_array( $value ) ) {
return [];
}
foreach ( $value as $key => $overlay ) {
if ( empty( $overlay['image'] ) ) {
unset( $value[ $key ] );
} elseif ( empty( $overlay['name'] ) ) {
Helper::add_notification( esc_html__( 'A Custom Watermark item could not be saved because the name field is empty.', 'rank-math' ), [ 'type' => 'error' ] );
unset( $value[ $key ] );
}
}
return $value;
}
/**
* Handles sanitization of advanced robots data.
*
* @param array $robots The unsanitized value from the form.
*
* @return array Sanitized value to be stored.
*/
private static function sanitize_advanced_robots( $robots ) {
if ( empty( $robots ) ) {
return [];
}
$advanced_robots = [];
foreach ( $robots as $key => $robot ) {
$advanced_robots[ $key ] = ! empty( $robot['enable'] ) ? $robot['length'] : false;
}
return $advanced_robots;
}
/**
* Sanitize a group or repeatable group field.
*
* - For a single group, sanitizes keys and values.
* - For repeatable groups (array of group items), recursively sanitizes each item.
* - Preserves key casing.
*
* @param array $group_value The group or repeatable group value.
* @return array Sanitized group value.
*/
private static function sanitize_group_value( $group_value ) {
if ( ! is_array( $group_value ) ) {
return [];
}
// Check if this is a repeatable group (array of associative arrays).
$is_repeatable = array_keys( $group_value ) === range( 0, count( $group_value ) - 1 );
if ( $is_repeatable ) {
$sanitized = [];
foreach ( $group_value as $item ) {
if ( is_array( $item ) ) {
$sanitized[] = self::sanitize_array_recursive( $item );
}
}
return $sanitized;
}
// Single group.
return self::sanitize_array_recursive( $group_value );
}
/**
* Recursively sanitize an array's keys (preserving casing) and values.
*
* Uses sanitize_text_field() for scalar values. Nested arrays are handled recursively.
*
* @param array $data The array to recursively sanitize.
* @return array The sanitized array.
*/
private static function sanitize_array_recursive( $data ) {
$sanitized = [];
foreach ( $data as $key => $val ) {
$clean_key = self::sanitize_key_preserve_case( $key );
if ( is_array( $val ) ) {
$sanitized[ $clean_key ] = self::sanitize_array_recursive( $val );
} else {
$sanitized[ $clean_key ] = self::sanitize_textfield( $val );
}
}
return $sanitized;
}
/**
* Sanitize a key while preserving original casing.
*
* Removes unsafe characters like spaces, HTML, and control characters,
* but keeps casing and underscores intact.
*
* @param string $key The key to sanitize.
* @return string The sanitized key.
*/
private static function sanitize_key_preserve_case( $key ) {
$key = wp_strip_all_tags( $key );
$key = preg_replace( '/[^A-Za-z0-9_\-]/', '', $key );
return $key;
}
}

View File

@@ -0,0 +1,206 @@
<?php
/**
* The Setup Wizard - configure the SEO settings in just a few steps.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Helper;
use RankMath\Traits\Hooker;
use RankMath\Traits\Wizard;
use RankMath\Admin\Importers\Detector;
use RankMath\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
* Setup_Wizard class.
*/
class Setup_Wizard {
use Hooker;
use Wizard;
/**
* Top level admin page.
*
* @var string
*/
protected $slug = 'rank-math-wizard';
/**
* Hook suffix.
*
* @var string
*/
public $hook_suffix = '';
/**
* The Constructor.
*/
public function __construct() {
$this->action( 'admin_menu', 'add_admin_menu' );
// If the page is not this page stop here.
if ( ! $this->is_current_page() ) {
return;
}
$this->action( 'admin_init', 'admin_page', 30 );
$this->filter( 'user_has_cap', 'filter_user_has_cap' );
}
/**
* Add the admin menu item, under Appearance.
*/
public function add_admin_menu() {
if ( Param::get( 'page' ) !== $this->slug ) {
return;
}
$this->hook_suffix = add_submenu_page(
'',
esc_html__( 'Setup Wizard', 'rank-math' ),
esc_html__( 'Setup Wizard', 'rank-math' ),
'manage_options',
$this->slug,
[ $this, 'admin_page' ]
);
}
/**
* Output the admin page.
*/
public function admin_page() {
// Do not proceed if we're not on the right page.
if ( Param::get( 'page' ) !== $this->slug ) {
return;
}
if ( ob_get_length() ) {
ob_end_clean();
}
// Enqueue styles.
rank_math()->admin_assets->register();
wp_enqueue_style( 'rank-math-wizard', rank_math()->plugin_url() . 'assets/admin/css/setup-wizard.css', [ 'wp-admin', 'buttons', 'select2-rm', 'rank-math-common', 'rank-math-cmb2', 'wp-components' ], rank_math()->version );
// Enqueue scripts for the SEO Score Updater tool.
\RankMath\Tools\Update_Score::get()->enqueue();
// Enqueue javascript.
wp_enqueue_media();
wp_enqueue_script( 'rank-math-wizard', rank_math()->plugin_url() . 'assets/admin/js/wizard.js', [ 'media-editor', 'select2-rm', 'lodash', 'rank-math-common', 'rank-math-components' ], rank_math()->version, true );
wp_set_script_translations( 'rank-math-wizard', 'rank-math' );
Helper::add_json( 'logo', esc_url( rank_math()->plugin_url() . 'assets/admin/img/logo.svg' ) );
ob_start();
/**
* Start the actual page content.
*/
include_once $this->get_view( 'content' );
exit;
}
/**
* Get view file to display.
*
* @param string $view View to display.
* @return string
*/
public function get_view( $view ) {
return rank_math()->admin_dir() . "wizard/views/{$view}.php";
}
/**
* Get Localized data for the given step.
*
* @param string $step Current Setup Wizard step.
*/
public static function get_localized_data( $step ) {
$steps = self::get_steps();
if ( ! isset( $steps[ $step ] ) ) {
return '';
}
$data = [
'isWhitelabel' => Helper::is_whitelabel(),
'isConfigured' => Helper::is_configured(),
'setup_mode' => Helper::get_settings( 'general.setup_mode', 'advanced' ),
'addImport' => ! self::maybe_remove_import(),
];
return apply_filters(
"rank_math/setup_wizard/$step/localized_data",
array_merge(
$data,
$steps[ $step ]::get_localized_data()
)
);
}
/**
* Get Localized data for the given step.
*
* @param string $step Current Setup Wizard step.
* @param array $values Values to update.
*/
public static function save_data( $step, $values ) {
$steps = self::get_steps();
if ( ! isset( $steps[ $step ] ) ) {
return '';
}
do_action( "rank_math/setup_wizard/$step/save_data", $values );
return $steps[ $step ]::save( $values );
}
/**
* Get Setup Wizard step class.
*/
private static function get_steps() {
return [
'compatibility' => '\\RankMath\\Wizard\\Compatibility',
'import' => '\\RankMath\\Wizard\\Import',
'yoursite' => '\\RankMath\\Wizard\\Your_Site',
'analytics' => '\\RankMath\\Wizard\\Search_Console',
'sitemaps' => '\\RankMath\\Wizard\\Sitemap',
'optimization' => '\\RankMath\\Wizard\\Optimization',
'ready' => '\\RankMath\\Wizard\\Ready',
'role' => '\\RankMath\\Wizard\\Role',
'redirection' => '\\RankMath\\Wizard\\Monitor_Redirection',
'schema-markup' => '\\RankMath\\Wizard\\Schema_Markup',
];
}
/**
* Maybe remove import step.
*
* @return bool
*/
private static function maybe_remove_import() {
$pre = apply_filters( 'rank_math/wizard/pre_remove_import_step', null );
if ( ! is_null( $pre ) ) {
return $pre;
}
if ( false === get_option( 'rank_math_is_configured' ) ) {
$detector = new Detector();
$plugins = $detector->detect();
if ( ! empty( $plugins ) ) {
return false;
}
}
return true;
}
}

View File

@@ -0,0 +1,129 @@
<?php
/**
* The clauses functions.
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMath\Admin\Database
* @author RankMath <support@rankmath.com>
*/
namespace RankMath\Admin\Database;
/**
* Clauses class.
*/
trait Clauses {
/**
* List of SQL clauses.
*
* @var array
*/
private $sql_clauses = [];
/**
* SQL clause merge filters.
*
* @var array
*/
private $sql_filters = [
'where' => [
'where',
'where_time',
],
'join' => [
'right_join',
'join',
'left_join',
],
];
/**
* Check has SQL clause.
*
* @param string $type Clause type.
*
* @return boolean True if set and not empty.
*/
public function has_sql_clause( $type ) {
return isset( $this->sql_clauses[ $type ] ) && ! empty( $this->sql_clauses[ $type ] );
}
/**
* Add a SQL clause to be included when get_data is called.
*
* @param string $type Clause type.
* @param string $clause SQL clause.
*/
public function add_sql_clause( $type, $clause ) {
if ( isset( $this->sql_clauses[ $type ] ) && ! empty( $clause ) ) {
$this->sql_clauses[ $type ][] = $clause;
}
}
/**
* Clear SQL clauses by type.
*
* @param string|array $types Clause type.
*/
protected function clear_sql_clause( $types ) {
foreach ( (array) $types as $type ) {
if ( isset( $this->sql_clauses[ $type ] ) ) {
$this->sql_clauses[ $type ] = [];
}
}
}
/**
* Get SQL clause by type.
*
* @param string $type Clause type.
* @param string $filtered Whether to filter the return value. Default unfiltered.
*
* @return string SQL clause.
*/
protected function get_sql_clause( $type, $filtered = false ) {
if ( ! isset( $this->sql_clauses[ $type ] ) ) {
return '';
}
$separator = ' ';
if ( in_array( $type, [ 'select', 'order_by', 'group_by' ], true ) ) {
$separator = ', ';
}
/**
* Default to bypassing filters for clause retrieval internal to data stores.
* The filters are applied when the full SQL statement is retrieved.
*/
if ( false === $filtered ) {
return implode( $separator, $this->sql_clauses[ $type ] );
}
if ( isset( $this->sql_filters[ $type ] ) ) {
$clauses = [];
foreach ( $this->sql_filters[ $type ] as $subset ) {
$clauses = array_merge( $clauses, $this->sql_clauses[ $subset ] );
}
} else {
$clauses = $this->sql_clauses[ $type ];
}
/**
* Filter SQL clauses by type and context.
*
* @param array $clauses The original arguments for the request.
* @param string $context The data store context.
*/
$clauses = apply_filters( "rank_math_clauses_{$type}", $clauses, $this->context );
/**
* Filter SQL clauses by type and context.
*
* @param array $clauses The original arguments for the request.
*/
$clauses = apply_filters( "rank_math_clauses_{$type}_{$this->context}", $clauses );
return implode( $separator, $clauses );
}
}

View File

@@ -0,0 +1,41 @@
<?php
/**
* The Database.
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMath\Admin\Database
* @author RankMath <support@rankmath.com>
*/
namespace RankMath\Admin\Database;
/**
* Database class.
*/
class Database {
/**
* Array of all databases objects.
*
* @var array
*/
protected static $instances = [];
/**
* Retrieve a Database instance by table name.
*
* @param string $table_name A Database instance id.
*
* @return Database Database object instance.
*/
public static function table( $table_name ) {
global $wpdb;
if ( empty( self::$instances ) || empty( self::$instances[ $table_name ] ) ) {
self::$instances[ $table_name ] = new Query_Builder( $wpdb->prefix . $table_name );
}
return self::$instances[ $table_name ];
}
}

View File

@@ -0,0 +1,65 @@
<?php
/**
* The escape functions.
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMath\Admin\Database
* @author RankMath <support@rankmath.com>
*/
namespace RankMath\Admin\Database;
/**
* Escape class.
*/
trait Escape {
/**
* Escape array values for sql
*
* @param array $arr Array to escape.
*
* @return array
*/
public function esc_array( $arr ) {
return array_map( [ $this, 'esc_value' ], $arr );
}
/**
* Escape value for sql
*
* @param mixed $value Value to escape.
*
* @return mixed
*/
public function esc_value( $value ) {
global $wpdb;
if ( is_int( $value ) ) {
return $wpdb->prepare( '%d', $value );
}
if ( is_float( $value ) ) {
return $wpdb->prepare( '%f', $value );
}
return 'NULL' === $value ? $value : $wpdb->prepare( '%s', $value );
}
/**
* Escape value for like statement
*
* @codeCoverageIgnore
*
* @param string $value Value for like statement.
* @param string $start (Optional) The start of like query.
* @param string $end (Optional) The end of like query.
*
* @return string
*/
public function esc_like( $value, $start = '%', $end = '%' ) {
global $wpdb;
return $start . $wpdb->esc_like( $value ) . $end;
}
}

View File

@@ -0,0 +1,53 @@
<?php
/**
* The groupby functions.
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMath\Admin\Database
* @author RankMath <support@rankmath.com>
*/
namespace RankMath\Admin\Database;
/**
* GroupBy class.
*/
trait GroupBy {
/**
* Add an group by statement to the current query
*
* ->groupBy('created_at')
*
* @param array|string $columns Columns.
*
* @return self The current query builder.
*/
public function groupBy( $columns ) { // @codingStandardsIgnoreLine
if ( is_string( $columns ) ) {
$columns = $this->argument_to_array( $columns );
}
foreach ( $columns as $column ) {
$this->add_sql_clause( 'group_by', $column );
}
return $this;
}
/**
* Generate Having clause
*
* @param string $column The SQL column.
* @param mixed $param1 Operator or value depending if $param2 isset.
* @param mixed $param2 The value if $param1 is an operator.
*
* @return self The current query builder.
*/
public function having( $column, $param1 = null, $param2 = null ) {
$this->add_sql_clause( 'having', $this->generateWhere( $column, $param1, $param2, 'HAVING' ) );
return $this;
}
}

View File

@@ -0,0 +1,92 @@
<?php
/**
* The joins functions.
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMath\Admin\Database
* @author RankMath <support@rankmath.com>
*/
namespace RankMath\Admin\Database;
/**
* Joins class.
*/
trait Joins {
/**
* Generate left join clause.
*
* @param string $table The SQL table.
* @param mixed $column1 The SQL Column.
* @param mixed $column2 The SQL Column.
* @param string $operator The Operator.
* @param string $alias The table alias.
*
* @return self The current query builder.
*/
public function leftJoin( $table, $column1, $column2, $operator = '=', $alias = '' ) { // @codingStandardsIgnoreLine
if ( empty( $table ) || empty( $column1 ) || empty( $column2 ) ) {
return $this;
}
if ( ! empty( $alias ) ) {
$table = "{$table} AS {$alias}";
}
$this->add_sql_clause( 'left_join', "LEFT JOIN {$table} ON {$column1} {$operator} {$column2}" );
return $this;
}
/**
* Generate right join clause.
*
* @param string $table The SQL table.
* @param mixed $column1 The SQL Column.
* @param mixed $column2 The SQL Column.
* @param string $operator The Operator.
* @param string $alias The table alias.
*
* @return self The current query builder.
*/
public function rightJoin( $table, $column1, $column2, $operator = '=', $alias = '' ) { // @codingStandardsIgnoreLine
if ( empty( $table ) || empty( $column1 ) || empty( $column2 ) ) {
return $this;
}
if ( ! empty( $alias ) ) {
$table = "{$table} AS {$alias}";
}
$this->add_sql_clause( 'right_join', "RIGHT JOIN {$table} ON {$column1} {$operator} {$column2}" );
return $this;
}
/**
* Generate left join clause.
*
* @param string $table The SQL table.
* @param mixed $column1 The SQL Column.
* @param mixed $column2 The SQL Column.
* @param string $operator The Operator.
* @param string $alias The table alias.
*
* @return self The current query builder.
*/
public function join( $table, $column1, $column2, $operator = '=', $alias = '' ) { // @codingStandardsIgnoreLine
if ( empty( $table ) || empty( $column1 ) || empty( $column2 ) ) {
return $this;
}
if ( ! empty( $alias ) ) {
$table = "{$table} AS {$alias}";
}
$this->add_sql_clause( 'join', "JOIN {$table} ON {$column1} {$operator} {$column2}" );
return $this;
}
}

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