Version Description
- Embedded Tweets
- Embedded video
- Tweet button
- Twitter Cards
- Follow button
- Advertising tracker
=
Download this release
Release Info
Developer | |
Plugin | |
Version | 1.0.0 |
Comparing to | |
See all releases |
Version 1.0.0
- LICENSE +22 -0
- autoload.php +67 -0
- composer.json +30 -0
- index.php +2 -0
- languages/twitter-ar.mo +0 -0
- languages/twitter-da_DK.mo +0 -0
- languages/twitter-de_DE.mo +0 -0
- languages/twitter-el.mo +0 -0
- languages/twitter-es_MX.mo +0 -0
- languages/twitter-fa_IR.mo +0 -0
- languages/twitter-fi.mo +0 -0
- languages/twitter-fr_FR.mo +0 -0
- languages/twitter-he_IL.mo +0 -0
- languages/twitter-hi_IN.mo +0 -0
- languages/twitter-hu_HU.mo +0 -0
- languages/twitter-id_ID.mo +0 -0
- languages/twitter-it_IT.mo +0 -0
- languages/twitter-ja.mo +0 -0
- languages/twitter-ko_KR.mo +0 -0
- languages/twitter-ms_MY.mo +0 -0
- languages/twitter-nb_NO.mo +0 -0
- languages/twitter-nl_NL.mo +0 -0
- languages/twitter-pl_PL.mo +0 -0
- languages/twitter-pt_BR.mo +0 -0
- languages/twitter-ru_RU.mo +0 -0
- languages/twitter-sv_SE.mo +0 -0
- languages/twitter-th.mo +0 -0
- languages/twitter-tl.mo +0 -0
- languages/twitter-tr_TR.mo +0 -0
- languages/twitter-zh_CN.mo +0 -0
- languages/twitter-zh_TW.mo +0 -0
- readme.txt +77 -0
- src/Twitter/Cards/Card.php +168 -0
- src/Twitter/Cards/Components/Account.php +182 -0
- src/Twitter/Cards/Components/Creator.php +59 -0
- src/Twitter/Cards/Components/Description.php +85 -0
- src/Twitter/Cards/Components/Image.php +167 -0
- src/Twitter/Cards/Components/MultipleImages.php +158 -0
- src/Twitter/Cards/Components/SingleImage.php +141 -0
- src/Twitter/Cards/Gallery.php +125 -0
- src/Twitter/Cards/Photo.php +109 -0
- src/Twitter/Cards/Product.php +187 -0
- src/Twitter/Cards/Summary.php +114 -0
- src/Twitter/Cards/SummaryLargeImage.php +63 -0
- src/Twitter/Helpers/HTMLBuilder.php +207 -0
- src/Twitter/Helpers/TwitterURL.php +108 -0
- src/Twitter/Helpers/Validators/Hashtag.php +48 -0
- src/Twitter/Helpers/Validators/ScreenName.php +106 -0
- src/Twitter/Intents/Follow.php +113 -0
- src/Twitter/Intents/Tweet.php +512 -0
- src/Twitter/Widgets/BaseWidget.php +148 -0
- src/Twitter/Widgets/FollowButton.php +288 -0
- src/Twitter/Widgets/Language.php +90 -0
- src/Twitter/Widgets/TweetButton.php +460 -0
- src/Twitter/WordPress/Admin/Post/MetaBox.php +242 -0
- src/Twitter/WordPress/Admin/Post/TweetIntent.php +296 -0
- src/Twitter/WordPress/Admin/Post/TwitterCard.php +247 -0
- src/Twitter/WordPress/Admin/Profile/User.php +120 -0
- src/Twitter/WordPress/Admin/Settings/Loader.php +78 -0
- src/Twitter/WordPress/Admin/Settings/SinglePage.php +137 -0
- src/Twitter/WordPress/Admin/Settings/SiteAttribution.php +251 -0
- src/Twitter/WordPress/Admin/Settings/Template.php +67 -0
- src/Twitter/WordPress/Admin/Settings/Theme.php +507 -0
- src/Twitter/WordPress/Admin/Settings/TweetButton.php +334 -0
- src/Twitter/WordPress/Cards/Compatibility.php +60 -0
- src/Twitter/WordPress/Cards/Generator.php +465 -0
- src/Twitter/WordPress/Cards/ImageHandler.php +356 -0
- src/Twitter/WordPress/Cards/Sanitize.php +128 -0
- src/Twitter/WordPress/Content/TweetButton.php +83 -0
- src/Twitter/WordPress/Head/AuthorshipLink.php +51 -0
- src/Twitter/WordPress/Head/CardsMetaElements.php +93 -0
- src/Twitter/WordPress/Head/MetaElement.php +64 -0
- src/Twitter/WordPress/Head/WidgetsMetaElements.php +164 -0
- src/Twitter/WordPress/Helpers/HTMLBuilder.php +104 -0
- src/Twitter/WordPress/Helpers/TwitterAPI.php +156 -0
- src/Twitter/WordPress/JavaScriptLoaders/Tracking.php +108 -0
- src/Twitter/WordPress/JavaScriptLoaders/Widgets.php +194 -0
- src/Twitter/WordPress/Language.php +91 -0
- src/Twitter/WordPress/PluginLoader.php +306 -0
- src/Twitter/WordPress/Shortcodes/EmbeddedTweet.php +451 -0
- src/Twitter/WordPress/Shortcodes/EmbeddedTweetVideo.php +206 -0
- src/Twitter/WordPress/Shortcodes/Follow.php +193 -0
- src/Twitter/WordPress/Shortcodes/Share.php +372 -0
- src/Twitter/WordPress/Shortcodes/Tracking.php +166 -0
- src/Twitter/WordPress/Site/Username.php +103 -0
- src/Twitter/WordPress/User/Meta.php +78 -0
- src/Twitter/WordPress/Widgets/Follow.php +205 -0
- static/css/admin/post/edit.min.css +1 -0
- twitter.php +70 -0
- uninstall.php +76 -0
LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
The MIT License (MIT)
|
2 |
+
|
3 |
+
Copyright (c) 2015 Twitter, Inc.
|
4 |
+
|
5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 |
+
of this software and associated documentation files (the "Software"), to deal
|
7 |
+
in the Software without restriction, including without limitation the rights
|
8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9 |
+
copies of the Software, and to permit persons to whom the Software is
|
10 |
+
furnished to do so, subject to the following conditions:
|
11 |
+
|
12 |
+
The above copyright notice and this permission notice shall be included in all
|
13 |
+
copies or substantial portions of the Software.
|
14 |
+
|
15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21 |
+
SOFTWARE.
|
22 |
+
|
autoload.php
ADDED
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Autoloader for the Twitter plugin for WordPress
|
28 |
+
*/
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Register the autoloader for the Twitter plugin classes.
|
32 |
+
*
|
33 |
+
* Based off the official PSR-4 autoloader example found here:
|
34 |
+
* https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader-examples.md
|
35 |
+
*
|
36 |
+
* @param string $class The fully-qualified class name
|
37 |
+
*
|
38 |
+
* @return void
|
39 |
+
*/
|
40 |
+
spl_autoload_register( function ( $class ) {
|
41 |
+
// project-specific namespace prefix
|
42 |
+
$prefix = 'Twitter\\';
|
43 |
+
|
44 |
+
// base directory for the namespace prefix
|
45 |
+
$base_dir = defined( 'TWITTER_PLUGIN_DIR' ) ? TWITTER_PLUGIN_DIR : __DIR__ . '/src/Twitter/';
|
46 |
+
|
47 |
+
// does the class use the namespace prefix?
|
48 |
+
$len = strlen( $prefix );
|
49 |
+
if ( 0 !== strncmp( $prefix, $class, $len ) ) {
|
50 |
+
// no, move to the next registered autoloader
|
51 |
+
return;
|
52 |
+
}
|
53 |
+
|
54 |
+
// get the relative class name
|
55 |
+
$relative_class = substr( $class, $len );
|
56 |
+
|
57 |
+
// replace the namespace prefix with the base directory, replace namespace
|
58 |
+
// separators with directory separators in the relative class name, append
|
59 |
+
// with .php
|
60 |
+
$file = $base_dir . str_replace( '\\', '/', $relative_class ) . '.php';
|
61 |
+
|
62 |
+
// if the file exists, require it
|
63 |
+
if ( file_exists( $file ) ) {
|
64 |
+
require $file;
|
65 |
+
}
|
66 |
+
});
|
67 |
+
?>
|
composer.json
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "twitter/wordpress",
|
3 |
+
"type": "wordpress-plugin",
|
4 |
+
"description": "Official Twitter plugin for WordPress",
|
5 |
+
"homepage": "https://dev.twitter.com/web/wordpress",
|
6 |
+
"license": "MIT",
|
7 |
+
"keywords": ["twitter","wordpress","plugin"],
|
8 |
+
"require": {
|
9 |
+
"php": ">=5.4.0"
|
10 |
+
},
|
11 |
+
"authors": [
|
12 |
+
{
|
13 |
+
"name": "Twitter",
|
14 |
+
"homepage": "https://github.com/twitter/wordpress/contributors"
|
15 |
+
}
|
16 |
+
],
|
17 |
+
"support": {
|
18 |
+
"forum": "https://wordpress.org/support/plugin/twitter"
|
19 |
+
},
|
20 |
+
"autoload": {
|
21 |
+
"psr-4": {
|
22 |
+
"Twitter\\": "src/Twitter/"
|
23 |
+
}
|
24 |
+
},
|
25 |
+
"autoload-dev": {
|
26 |
+
"psr-4": {
|
27 |
+
"Twitter\\Tests\\": "tests/phpunit/"
|
28 |
+
}
|
29 |
+
}
|
30 |
+
}
|
index.php
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
1 |
+
<?php
|
2 |
+
// Silence is golden.
|
languages/twitter-ar.mo
ADDED
Binary file
|
languages/twitter-da_DK.mo
ADDED
Binary file
|
languages/twitter-de_DE.mo
ADDED
Binary file
|
languages/twitter-el.mo
ADDED
Binary file
|
languages/twitter-es_MX.mo
ADDED
Binary file
|
languages/twitter-fa_IR.mo
ADDED
Binary file
|
languages/twitter-fi.mo
ADDED
Binary file
|
languages/twitter-fr_FR.mo
ADDED
Binary file
|
languages/twitter-he_IL.mo
ADDED
Binary file
|
languages/twitter-hi_IN.mo
ADDED
Binary file
|
languages/twitter-hu_HU.mo
ADDED
Binary file
|
languages/twitter-id_ID.mo
ADDED
Binary file
|
languages/twitter-it_IT.mo
ADDED
Binary file
|
languages/twitter-ja.mo
ADDED
Binary file
|
languages/twitter-ko_KR.mo
ADDED
Binary file
|
languages/twitter-ms_MY.mo
ADDED
Binary file
|
languages/twitter-nb_NO.mo
ADDED
Binary file
|
languages/twitter-nl_NL.mo
ADDED
Binary file
|
languages/twitter-pl_PL.mo
ADDED
Binary file
|
languages/twitter-pt_BR.mo
ADDED
Binary file
|
languages/twitter-ru_RU.mo
ADDED
Binary file
|
languages/twitter-sv_SE.mo
ADDED
Binary file
|
languages/twitter-th.mo
ADDED
Binary file
|
languages/twitter-tl.mo
ADDED
Binary file
|
languages/twitter-tr_TR.mo
ADDED
Binary file
|
languages/twitter-zh_CN.mo
ADDED
Binary file
|
languages/twitter-zh_TW.mo
ADDED
Binary file
|
readme.txt
ADDED
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
=== Plugin Name ===
|
2 |
+
Contributors: Twitter, niallkennedy
|
3 |
+
Tags: twitter, embedded tweet, twitter video, twitter cards, tweet button, follow button, twitter analytics, twitter ads
|
4 |
+
Requires at least: 3.9
|
5 |
+
Tested up to: 4.1
|
6 |
+
Stable tag: 1.0.0
|
7 |
+
License: MIT
|
8 |
+
License URI: http://opensource.org/licenses/MIT
|
9 |
+
|
10 |
+
Official Twitter plugin for WordPress. Embed Twitter content and grow your audience on Twitter. Requires PHP 5.4 or newer.
|
11 |
+
|
12 |
+
== Description ==
|
13 |
+
|
14 |
+
The Twitter plugin for WordPress optimizes your website for a Twitter audience through easy to use sharing buttons, embedded Tweets, auto-generated markup indexed by Twitter, and Follow buttons to help grow your Twitter audience. All features are deeply integrated with WordPress APIs to make building your webpages and administrative features as easy as possible with the extensibility you expect from WordPress.
|
15 |
+
|
16 |
+
Requires PHP 5.4 or later.
|
17 |
+
|
18 |
+
* [Embedded Tweet](https://dev.twitter.com/web/embedded-tweets) - customize backgrounds and color schemes to match your site's theme
|
19 |
+
* [Embedded Twitter video](https://dev.twitter.com/web/embedded-video) - showcase video uploaded to Twitter
|
20 |
+
* [Tweet button](https://dev.twitter.com/web/tweet-button) - simple sharing of your site's content on Twitter
|
21 |
+
* [Twitter Cards](https://dev.twitter.com/cards/overview) - highlight your site's content when shared on Twitter
|
22 |
+
* [Twitter Analytics](https://analytics.twitter.com/) - track impressions and top distributors of your site's content on Twitter
|
23 |
+
* [Follow button](https://dev.twitter.com/web/follow-button) - grow your Twitter audience
|
24 |
+
* [Twitter ads conversion tracking](https://support.twitter.com/articles/20170807-conversion-tracking-for-websites) - easily track actions on your WordPress site triggered by a Twitter ad or build a custom targeting audience
|
25 |
+
|
26 |
+
Contribute to the plugin, submit pull requests, or run test suites through the [Twitter plugin for WordPress GitHub repository](https://github.com/twitter/wordpress). View [Twitter for WordPress documentation](https://dev.twitter.com/web/wordpress) to learn more about customization through filters.
|
27 |
+
|
28 |
+
== Changelog ==
|
29 |
+
|
30 |
+
= 1.0.0 =
|
31 |
+
* Embedded Tweets
|
32 |
+
* Embedded video
|
33 |
+
* Tweet button
|
34 |
+
* Twitter Cards
|
35 |
+
* Follow button
|
36 |
+
* Advertising tracker
|
37 |
+
|
38 |
+
== Frequently Asked Questions ==
|
39 |
+
|
40 |
+
= Twitter Cards do not appear for my shared links =
|
41 |
+
|
42 |
+
Twitter Cards must be enabled for your domain before they will appear alongside a Tweet. Submit a URL to the [Twitter Cards validator](https://cards-dev.twitter.com/validator) and request Twitter add the card type for your domain.
|
43 |
+
|
44 |
+
= How can I change an embedded Tweet's background and link colors to match my site's theme? =
|
45 |
+
|
46 |
+
The Twitter plugin for WordPress includes a settings page with options to customize the background color, link color, and border color used in Twitter embedded Tweets and embedded timelines.
|
47 |
+
|
48 |
+
= How do I include an embedded timeline in my page? =
|
49 |
+
|
50 |
+
Log in to Twitter.com and visit the [Twitter widgets settings page](https://twitter.com/settings/widgets) to create and manage [embedded timeline](https://dev.twitter.com/web/embedded-timelines) widgets for your account. Widget settings are saved to a widget identifier for the logged in account; you may want to create a widget from your site's account, not your personal account, for continuity and general organization.
|
51 |
+
|
52 |
+
Copy-and-paste the HTML generated by the Twitter widgets configuration tool into a new [WordPress text widget](http://codex.wordpress.org/WordPress_Widgets#Using_Text_Widgets).
|
53 |
+
|
54 |
+
= My custom link color and border color do not appear in embedded Tweets or timelines =
|
55 |
+
|
56 |
+
Your site may have a [Content Security Policy](https://developer.mozilla.org/docs/Web/Security/CSP/Introducing_Content_Security_Policy) blocking Twitter's JavaScript from inserting your custom styling into the widget.
|
57 |
+
|
58 |
+
You may have configured an embedded timeline widget with a non-default link color. Your widget configuration overrides your page / theme configuration.
|
59 |
+
|
60 |
+
= Does the Twitter plugin add additional tracking of my site's visitors? =
|
61 |
+
|
62 |
+
The Twitter plugin for WordPress makes it easier to explicitly include Twitter features and functionality on your WordPress site. No additional tracking is added as a result of our plugin code's execution on your server(s).
|
63 |
+
|
64 |
+
Twitter widgets and buttons load Twitter's widgets.js library through the WordPress JavaScript queue. Read more about [how Twitter for Websites widgets respect user privacy](https://dev.twitter.com/web/overview/privacy).
|
65 |
+
|
66 |
+
Twitter advertising trackers are only included on the page when invoked by the site using the `twitter_tracking` shortcode. Read more about [Twitter's policies for conversion tracking and tailored audiences products](https://support.twitter.com/articles/20171365-policies-for-conversion-tracking-and-tailored-audiences).
|
67 |
+
|
68 |
+
== Screenshots ==
|
69 |
+
|
70 |
+
1. Settings screen. Customize Tweet and Timeline color schemes including background, text colors, and borders. Attribute site content to a Twitter account. Automatically include Tweet buttons alongside your post content.
|
71 |
+
2. Post editor meta box. Define custom Tweet text, hashtags, and Twitter Card data.
|
72 |
+
3. Twitter widgets and buttons in action.
|
73 |
+
|
74 |
+
== Installation ==
|
75 |
+
|
76 |
+
1. Add the Twitter plugin to your WordPress installation
|
77 |
+
1. Activate the plugin through the 'Plugins' menu in WordPress
|
src/Twitter/Cards/Card.php
ADDED
@@ -0,0 +1,168 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\Cards;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Properties common to all Twitter Cards
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class Card
|
34 |
+
{
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Twitter Card type. summary, photo, etc.
|
38 |
+
*
|
39 |
+
* @since 1.0.0
|
40 |
+
*
|
41 |
+
* @type string
|
42 |
+
*/
|
43 |
+
protected $type;
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Title of the content
|
47 |
+
*
|
48 |
+
* @since 1.0.0
|
49 |
+
*
|
50 |
+
* @type string
|
51 |
+
*/
|
52 |
+
protected $title;
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Twitter account responsible for site content
|
56 |
+
*
|
57 |
+
* @since 1.0.0
|
58 |
+
*
|
59 |
+
* @type \Twitter\Cards\Components\Account
|
60 |
+
*/
|
61 |
+
protected $site;
|
62 |
+
|
63 |
+
/**
|
64 |
+
* @since 1.0.0
|
65 |
+
*
|
66 |
+
* @param string $type card type
|
67 |
+
*/
|
68 |
+
public function __construct($type)
|
69 |
+
{
|
70 |
+
if (! ( is_string($type) && $type )) {
|
71 |
+
// summary default
|
72 |
+
$type = 'summary';
|
73 |
+
}
|
74 |
+
$this->type = $type;
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
* Prepare a passed description for the requirements of a Twitter Card description
|
79 |
+
*
|
80 |
+
* @since 1.0.0
|
81 |
+
*
|
82 |
+
* @param string $title title unique to the page
|
83 |
+
*
|
84 |
+
* @return string sanitized title, or empty string of minimum requirements not met
|
85 |
+
*/
|
86 |
+
public static function sanitizeTitle($title)
|
87 |
+
{
|
88 |
+
if (! ( is_string($title) && $title )) {
|
89 |
+
return '';
|
90 |
+
}
|
91 |
+
|
92 |
+
$title = trim($title);
|
93 |
+
if (! $title) {
|
94 |
+
return '';
|
95 |
+
}
|
96 |
+
|
97 |
+
return $title;
|
98 |
+
}
|
99 |
+
|
100 |
+
/**
|
101 |
+
* Set the title of the content
|
102 |
+
*
|
103 |
+
* @since 1.0.0
|
104 |
+
*
|
105 |
+
* @param string $title content title
|
106 |
+
*
|
107 |
+
* @return __CLASS__ support chaining
|
108 |
+
*/
|
109 |
+
public function setTitle($title)
|
110 |
+
{
|
111 |
+
$title = static::sanitizeTitle($title);
|
112 |
+
if ($title) {
|
113 |
+
$this->title = $title;
|
114 |
+
}
|
115 |
+
|
116 |
+
return $this;
|
117 |
+
}
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Set the site associated with content
|
121 |
+
*
|
122 |
+
* @param \Twitter\Cards\Components\Account $site Twitter account
|
123 |
+
*
|
124 |
+
* @since 1.0.0
|
125 |
+
*
|
126 |
+
* @return __CLASS__ support chaining
|
127 |
+
*/
|
128 |
+
public function setSite($site)
|
129 |
+
{
|
130 |
+
if ($site && is_a($site, '\Twitter\Cards\Components\Account')) {
|
131 |
+
$this->site = $site;
|
132 |
+
}
|
133 |
+
|
134 |
+
return $this;
|
135 |
+
}
|
136 |
+
|
137 |
+
/**
|
138 |
+
* Convert class properties to an array
|
139 |
+
*
|
140 |
+
* @since 1.0.0
|
141 |
+
*
|
142 |
+
* @return array class properties as an array {
|
143 |
+
* @type string property name
|
144 |
+
* @type string|int|array property value or an array for nested properties
|
145 |
+
* }
|
146 |
+
*/
|
147 |
+
public function toArray()
|
148 |
+
{
|
149 |
+
if (! ( isset( $this->type ) && $this->type )) {
|
150 |
+
return array();
|
151 |
+
}
|
152 |
+
|
153 |
+
$card = array( 'card' => $this->type );
|
154 |
+
if (isset( $this->title ) && $this->title) {
|
155 |
+
$card['title'] = $this->title;
|
156 |
+
}
|
157 |
+
|
158 |
+
if (isset( $this->site ) && $this->site) {
|
159 |
+
$site = $this->site->asCardProperties();
|
160 |
+
if ($site) {
|
161 |
+
$card['site'] = $site;
|
162 |
+
}
|
163 |
+
unset( $site );
|
164 |
+
}
|
165 |
+
|
166 |
+
return $card;
|
167 |
+
}
|
168 |
+
}
|
src/Twitter/Cards/Components/Account.php
ADDED
@@ -0,0 +1,182 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\Cards\Components;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Bundle information about a Twitter account as used in Cards markup
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class Account
|
34 |
+
{
|
35 |
+
/**
|
36 |
+
* Twitter account screen name. Example: ev
|
37 |
+
*
|
38 |
+
* @since 1.0.0
|
39 |
+
*
|
40 |
+
* @type string
|
41 |
+
*/
|
42 |
+
public $screen_name;
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Twitter account identifier. Example: '20'
|
46 |
+
*
|
47 |
+
* @since 1.0.0
|
48 |
+
*
|
49 |
+
* @type string
|
50 |
+
*/
|
51 |
+
public $id;
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Create a new account object from a Twitter screen name
|
55 |
+
*
|
56 |
+
* @since 1.0.0
|
57 |
+
*
|
58 |
+
* @return self|null
|
59 |
+
*/
|
60 |
+
public static function fromScreenName($screen_name)
|
61 |
+
{
|
62 |
+
$account = new self();
|
63 |
+
$account->setScreenName($screen_name);
|
64 |
+
|
65 |
+
if (! $account->hasScreenName()) {
|
66 |
+
return;
|
67 |
+
}
|
68 |
+
|
69 |
+
return $account;
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* Create a new account object from a Twitter id
|
74 |
+
*
|
75 |
+
* @since 1.0.0
|
76 |
+
*
|
77 |
+
* @param string $id Twitter account identifier
|
78 |
+
*
|
79 |
+
* @return self|null
|
80 |
+
*/
|
81 |
+
public static function fromID($id)
|
82 |
+
{
|
83 |
+
$account = new self();
|
84 |
+
$account->setID($id);
|
85 |
+
|
86 |
+
if (! $account->hasID()) {
|
87 |
+
return;
|
88 |
+
}
|
89 |
+
|
90 |
+
return $account;
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Set a Twitter screen_name for a Twitter account
|
95 |
+
*
|
96 |
+
* @since 1.0.0
|
97 |
+
*
|
98 |
+
* @param string $screen_name Twitter screen name
|
99 |
+
*
|
100 |
+
* @return self support chaining
|
101 |
+
*/
|
102 |
+
public function setScreenName($screen_name)
|
103 |
+
{
|
104 |
+
if (! is_string($screen_name)) {
|
105 |
+
return $this;
|
106 |
+
}
|
107 |
+
|
108 |
+
// remove any preceding @
|
109 |
+
$screen_name = \Twitter\Helpers\Validators\ScreenName::trim($screen_name);
|
110 |
+
if (! $screen_name) {
|
111 |
+
return $this;
|
112 |
+
}
|
113 |
+
|
114 |
+
$this->screen_name = $screen_name;
|
115 |
+
|
116 |
+
return $this;
|
117 |
+
}
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Test if account has screen_name set
|
121 |
+
*
|
122 |
+
* @since 1.0.0
|
123 |
+
*
|
124 |
+
* @return bool true if screen_name set and not blank
|
125 |
+
*/
|
126 |
+
public function hasScreenName()
|
127 |
+
{
|
128 |
+
return (bool) $this->screen_name;
|
129 |
+
}
|
130 |
+
|
131 |
+
/**
|
132 |
+
* Set a Twitter ID for a Twitter account
|
133 |
+
*
|
134 |
+
* @since 1.0.0
|
135 |
+
*
|
136 |
+
* @param string $id Twitter user id
|
137 |
+
*
|
138 |
+
* @return __CLASS__ support chaining
|
139 |
+
*/
|
140 |
+
public function setID($id)
|
141 |
+
{
|
142 |
+
$id = trim((string) $id);
|
143 |
+
if (! $id) {
|
144 |
+
return $this;
|
145 |
+
}
|
146 |
+
if (function_exists('ctype_digit') && ! ctype_digit($id)) {
|
147 |
+
return $this;
|
148 |
+
}
|
149 |
+
|
150 |
+
$this->id = $id;
|
151 |
+
|
152 |
+
return $this;
|
153 |
+
}
|
154 |
+
|
155 |
+
/**
|
156 |
+
* Test if account has ID set
|
157 |
+
*
|
158 |
+
* @since 1.0.0
|
159 |
+
*
|
160 |
+
* @return bool true if ID set and not blank
|
161 |
+
*/
|
162 |
+
public function hasID()
|
163 |
+
{
|
164 |
+
return (bool) $this->id;
|
165 |
+
}
|
166 |
+
|
167 |
+
/**
|
168 |
+
* Convert the account into a Twitter Card property
|
169 |
+
*
|
170 |
+
* @since 1.0.0
|
171 |
+
*
|
172 |
+
* @return string|array site username or id as structured property
|
173 |
+
*/
|
174 |
+
public function asCardProperties()
|
175 |
+
{
|
176 |
+
if ($this->hasID()) {
|
177 |
+
return array( 'id' => $this->id );
|
178 |
+
} elseif ($this->hasScreenName()) {
|
179 |
+
return '@' . $this->screen_name;
|
180 |
+
}
|
181 |
+
}
|
182 |
+
}
|
src/Twitter/Cards/Components/Creator.php
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\Cards\Components;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Twitter account of the content creator
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
trait Creator
|
34 |
+
{
|
35 |
+
/**
|
36 |
+
* Twitter account of the content creator
|
37 |
+
*
|
38 |
+
* @since 1.0.0
|
39 |
+
*
|
40 |
+
* @type \Twitter\Cards\Components\Account
|
41 |
+
*/
|
42 |
+
protected $creator;
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Set the author associated with content
|
46 |
+
*
|
47 |
+
* @param \Twitter\Cards\Components\Account $creator Twitter account
|
48 |
+
*
|
49 |
+
* @return __CLASS__ support chaining
|
50 |
+
*/
|
51 |
+
public function setCreator($creator)
|
52 |
+
{
|
53 |
+
if ($creator && is_a($creator, '\Twitter\Cards\Components\Account')) {
|
54 |
+
$this->creator = $creator;
|
55 |
+
}
|
56 |
+
|
57 |
+
return $this;
|
58 |
+
}
|
59 |
+
}
|
src/Twitter/Cards/Components/Description.php
ADDED
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\Cards\Components;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* A card with a description
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
trait Description
|
34 |
+
{
|
35 |
+
/**
|
36 |
+
* A description of the content. 200 characters max
|
37 |
+
*
|
38 |
+
* @since 1.0.0
|
39 |
+
*
|
40 |
+
* @type string
|
41 |
+
*/
|
42 |
+
protected $description;
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Prepare a passed description for the requirements of a Twitter Card description
|
46 |
+
*
|
47 |
+
* @since 1.0.0
|
48 |
+
*
|
49 |
+
* @param string $description short description of the page
|
50 |
+
*
|
51 |
+
* @return string sanitized description, or empty string of minimum requirements not met
|
52 |
+
*/
|
53 |
+
public static function sanitizeDescription($description)
|
54 |
+
{
|
55 |
+
if (! ( is_string($description) && $description )) {
|
56 |
+
return '';
|
57 |
+
}
|
58 |
+
|
59 |
+
$description = trim($description);
|
60 |
+
if (! $description) {
|
61 |
+
return '';
|
62 |
+
}
|
63 |
+
|
64 |
+
return $description;
|
65 |
+
}
|
66 |
+
|
67 |
+
/**
|
68 |
+
* Set the description of the content
|
69 |
+
*
|
70 |
+
* @since 1.0.0
|
71 |
+
*
|
72 |
+
* @param string $description content description
|
73 |
+
*
|
74 |
+
* @return __CLASS__ support chaining
|
75 |
+
*/
|
76 |
+
public function setDescription($description)
|
77 |
+
{
|
78 |
+
$description = static::sanitizeDescription($description);
|
79 |
+
if ($description) {
|
80 |
+
$this->description = $description;
|
81 |
+
}
|
82 |
+
|
83 |
+
return $this;
|
84 |
+
}
|
85 |
+
}
|
src/Twitter/Cards/Components/Image.php
ADDED
@@ -0,0 +1,167 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\Cards\Components;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Twitter Card image representation
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class Image
|
34 |
+
{
|
35 |
+
/**
|
36 |
+
* Image URL. Must be less than 1 MB in size.
|
37 |
+
*
|
38 |
+
* @since 1.0.0
|
39 |
+
*
|
40 |
+
* @type string
|
41 |
+
*/
|
42 |
+
protected $src;
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Height of the image in whole pixels
|
46 |
+
*
|
47 |
+
* @since 1.0.0
|
48 |
+
*
|
49 |
+
* @type int
|
50 |
+
*/
|
51 |
+
protected $width;
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Width of the image in whole pixels
|
55 |
+
*
|
56 |
+
* @since 1.0.0
|
57 |
+
*
|
58 |
+
* @type int
|
59 |
+
*/
|
60 |
+
protected $height;
|
61 |
+
|
62 |
+
/**
|
63 |
+
* @since 1.0.0
|
64 |
+
*
|
65 |
+
* @return void
|
66 |
+
*/
|
67 |
+
public function __construct($src)
|
68 |
+
{
|
69 |
+
if (! ( is_string($src) && $src )) {
|
70 |
+
return;
|
71 |
+
}
|
72 |
+
$this->src = $src;
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Image URL
|
77 |
+
*
|
78 |
+
* @since 1.0.0
|
79 |
+
*
|
80 |
+
* @return string absolute URL
|
81 |
+
*/
|
82 |
+
public function getURL()
|
83 |
+
{
|
84 |
+
return $this->src ?: '';
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Get the width of the image
|
89 |
+
*
|
90 |
+
* @since 1.0.0
|
91 |
+
*
|
92 |
+
* @return int width of the image in whole pixels
|
93 |
+
*/
|
94 |
+
public function getWidth()
|
95 |
+
{
|
96 |
+
return $this->width ?: 0;
|
97 |
+
}
|
98 |
+
|
99 |
+
/**
|
100 |
+
* Set the width of the image
|
101 |
+
*
|
102 |
+
* @since 1.0.0
|
103 |
+
*
|
104 |
+
* @param int $width width of the image in whole pixels
|
105 |
+
*
|
106 |
+
* @return __CLASS__ support chaining
|
107 |
+
*/
|
108 |
+
public function setWidth($width)
|
109 |
+
{
|
110 |
+
if (is_int($width) && $width >= 0) {
|
111 |
+
$this->width = $width;
|
112 |
+
}
|
113 |
+
return $this;
|
114 |
+
}
|
115 |
+
|
116 |
+
/**
|
117 |
+
* Get the height of the image
|
118 |
+
*
|
119 |
+
* @since 1.0.0
|
120 |
+
*
|
121 |
+
* @return int height of the image in whole pixels
|
122 |
+
*/
|
123 |
+
public function getHeight()
|
124 |
+
{
|
125 |
+
return $this->height ?: 0;
|
126 |
+
}
|
127 |
+
|
128 |
+
/**
|
129 |
+
* Set the height of the image
|
130 |
+
*
|
131 |
+
* @since 1.0.0
|
132 |
+
*
|
133 |
+
* @param int $height
|
134 |
+
*
|
135 |
+
* @return __CLASS__ support chaining
|
136 |
+
*/
|
137 |
+
public function setHeight($height)
|
138 |
+
{
|
139 |
+
if (is_int($height) && $height >= 0) {
|
140 |
+
$this->height = $height;
|
141 |
+
}
|
142 |
+
return $this;
|
143 |
+
}
|
144 |
+
|
145 |
+
/**
|
146 |
+
* Convert to card properties
|
147 |
+
*
|
148 |
+
* @since 1.0.0
|
149 |
+
*
|
150 |
+
* @return array|string image property as shorthand or full properties
|
151 |
+
*/
|
152 |
+
public function asCardProperties()
|
153 |
+
{
|
154 |
+
if (! ( isset( $this->src ) && $this->src )) {
|
155 |
+
return '';
|
156 |
+
}
|
157 |
+
if (isset( $this->width ) && isset( $this->height )) {
|
158 |
+
return array(
|
159 |
+
'src' => $this->src,
|
160 |
+
'width' => $this->width,
|
161 |
+
'height' => $this->height,
|
162 |
+
);
|
163 |
+
} else {
|
164 |
+
return $this->src;
|
165 |
+
}
|
166 |
+
}
|
167 |
+
}
|
src/Twitter/Cards/Components/MultipleImages.php
ADDED
@@ -0,0 +1,158 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\Cards\Components;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* A card with multiple images
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
trait MultipleImages
|
34 |
+
{
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Images representing the content of the page
|
38 |
+
*
|
39 |
+
* @since 1.0.0
|
40 |
+
*
|
41 |
+
* @type array {
|
42 |
+
* Images stored for the card
|
43 |
+
*
|
44 |
+
* @type string image uri
|
45 |
+
* @type \Twitter\Cards\Components\Image card image
|
46 |
+
* }
|
47 |
+
*/
|
48 |
+
protected $images = array();
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Keep track of the total number of images stored for the card
|
52 |
+
*
|
53 |
+
* @since 1.0.0
|
54 |
+
*
|
55 |
+
* @type int
|
56 |
+
*/
|
57 |
+
protected $image_count = 0;
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Get the images array
|
61 |
+
*
|
62 |
+
* @since 1.0.0
|
63 |
+
*
|
64 |
+
* @return array {
|
65 |
+
* Images stored for the card
|
66 |
+
*
|
67 |
+
* @type string image uri
|
68 |
+
* @type \Twitter\Cards\Components\Image card image
|
69 |
+
* }
|
70 |
+
*/
|
71 |
+
public function getImages()
|
72 |
+
{
|
73 |
+
return $this->images;
|
74 |
+
}
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Add an image representing the content of the page
|
78 |
+
*
|
79 |
+
* @since 1.0.0
|
80 |
+
*
|
81 |
+
* @param string|\Twitter\Cards\Components\Image $url absolute URL of an image file
|
82 |
+
* @param int $width width of the image in whole pixels
|
83 |
+
* @param int $height height of the image in whole pixels
|
84 |
+
*
|
85 |
+
* @return __CLASS__ support chaining
|
86 |
+
*/
|
87 |
+
public function addImage($url, $width = 0, $height = 0)
|
88 |
+
{
|
89 |
+
// URL required
|
90 |
+
if (! $url) {
|
91 |
+
return $this;
|
92 |
+
}
|
93 |
+
if (! ( is_int($width) && $width >= 0 )) {
|
94 |
+
$width = 0;
|
95 |
+
}
|
96 |
+
if (! ( is_int($height) && $height >= 0 )) {
|
97 |
+
$height = 0;
|
98 |
+
}
|
99 |
+
|
100 |
+
// have we already filled the image allotment?
|
101 |
+
if (defined(__CLASS__ . '::MAX_IMAGES') && $this->image_count === self::MAX_IMAGES) {
|
102 |
+
return $this;
|
103 |
+
}
|
104 |
+
|
105 |
+
$image = null;
|
106 |
+
$preset = false;
|
107 |
+
if (is_a($url, '\Twitter\Cards\Components\Image')) {
|
108 |
+
// support overloading the function
|
109 |
+
$image = $url;
|
110 |
+
$url = $url->getURL();
|
111 |
+
if (isset( $this->images[ $url ] )) {
|
112 |
+
return $this;
|
113 |
+
}
|
114 |
+
$preset = true;
|
115 |
+
$width = $image->getWidth();
|
116 |
+
$height = $image->getHeight();
|
117 |
+
} elseif (is_string($url)) {
|
118 |
+
if (isset( $this->images[ $url ] )) {
|
119 |
+
return $this;
|
120 |
+
}
|
121 |
+
try {
|
122 |
+
$image = new \Twitter\Cards\Components\Image($url);
|
123 |
+
} catch (Exception $e) {
|
124 |
+
return $this;
|
125 |
+
}
|
126 |
+
}
|
127 |
+
|
128 |
+
if (! $image) {
|
129 |
+
return $this;
|
130 |
+
}
|
131 |
+
|
132 |
+
// only set dimensions if both width and height exist
|
133 |
+
if (is_int($width) && $width && is_int($height) && $height) {
|
134 |
+
// test if minimum width and height requirements are met for the card type
|
135 |
+
if (defined(__CLASS__ . '::MIN_IMAGE_WIDTH') && defined(__CLASS__ . '::MIN_IMAGE_HEIGHT')) {
|
136 |
+
if ($width >= self::MIN_IMAGE_WIDTH && $height >= self::MIN_IMAGE_HEIGHT) {
|
137 |
+
if (! $preset) {
|
138 |
+
$image->setWidth($width);
|
139 |
+
$image->setHeight($height);
|
140 |
+
}
|
141 |
+
} else {
|
142 |
+
// do not store image if minimum requirements not met
|
143 |
+
return $this;
|
144 |
+
}
|
145 |
+
} else {
|
146 |
+
if (! $preset) {
|
147 |
+
$image->setWidth($width);
|
148 |
+
$image->setHeight($height);
|
149 |
+
}
|
150 |
+
}
|
151 |
+
}
|
152 |
+
|
153 |
+
$this->images[ $url ] = $image;
|
154 |
+
$this->image_count = count($this->images);
|
155 |
+
|
156 |
+
return $this;
|
157 |
+
}
|
158 |
+
}
|
src/Twitter/Cards/Components/SingleImage.php
ADDED
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\Cards\Components;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Card image store
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
trait SingleImage
|
34 |
+
{
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Image representing the content of the page
|
38 |
+
*
|
39 |
+
* @since 1.0.0
|
40 |
+
*
|
41 |
+
* @type \Twitter\Cards\Components\Image card image
|
42 |
+
*/
|
43 |
+
protected $image;
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Set an image representing the content of the page
|
47 |
+
*
|
48 |
+
* @since 1.0.0
|
49 |
+
*
|
50 |
+
* @param string|\Twitter\Cards\Components\Image $url absolute URL of an image file
|
51 |
+
* @param int $width width of the image in whole pixels
|
52 |
+
* @param int $height height of the image in whole pixels
|
53 |
+
*
|
54 |
+
* @return __CLASS__ support chaining
|
55 |
+
*/
|
56 |
+
public function setImage($url, $width = 0, $height = 0)
|
57 |
+
{
|
58 |
+
if (! $url) {
|
59 |
+
return $this;
|
60 |
+
}
|
61 |
+
if (! ( is_int($width) && $width >= 0 )) {
|
62 |
+
$width = 0;
|
63 |
+
}
|
64 |
+
if (! ( is_int($height) && $height >= 0 )) {
|
65 |
+
$height = 0;
|
66 |
+
}
|
67 |
+
|
68 |
+
$image = null;
|
69 |
+
$preset = false;
|
70 |
+
if (is_a($url, '\Twitter\Cards\Components\Image')) {
|
71 |
+
$preset = true;
|
72 |
+
$image = $url;
|
73 |
+
$width = $url->getWidth();
|
74 |
+
$height = $url->getHeight();
|
75 |
+
} elseif (is_string($url)) {
|
76 |
+
try {
|
77 |
+
$image = new \Twitter\Cards\Components\Image($url);
|
78 |
+
} catch (Exception $e) {
|
79 |
+
return $this;
|
80 |
+
}
|
81 |
+
}
|
82 |
+
|
83 |
+
if (! $image) {
|
84 |
+
return $this;
|
85 |
+
}
|
86 |
+
|
87 |
+
// only set dimensions if both width and height exist
|
88 |
+
if (is_int($width) && $width && is_int($height) && $height) {
|
89 |
+
// test if minimum width and height requirements are met for the card type
|
90 |
+
if (defined(__CLASS__ . '::MIN_IMAGE_WIDTH') && defined(__CLASS__ . '::MIN_IMAGE_HEIGHT')) {
|
91 |
+
if ($width >= self::MIN_IMAGE_WIDTH && $height >= self::MIN_IMAGE_HEIGHT) {
|
92 |
+
if (! $preset) {
|
93 |
+
$image->setWidth($width);
|
94 |
+
$image->setHeight($height);
|
95 |
+
}
|
96 |
+
} else {
|
97 |
+
// do not store image if minimum requirements not met
|
98 |
+
return $this;
|
99 |
+
}
|
100 |
+
} else {
|
101 |
+
if (! $preset) {
|
102 |
+
$image->setWidth($width);
|
103 |
+
$image->setHeight($height);
|
104 |
+
}
|
105 |
+
}
|
106 |
+
}
|
107 |
+
|
108 |
+
$this->image = $image;
|
109 |
+
|
110 |
+
return $this;
|
111 |
+
}
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Output the image properties of a Twitter card
|
115 |
+
*
|
116 |
+
* Suitable for merging with a larger Twitter Card property array
|
117 |
+
*
|
118 |
+
* @since 1.0.0
|
119 |
+
*
|
120 |
+
* @return array {
|
121 |
+
* @type string image property
|
122 |
+
* @type array Twitter Card image values {
|
123 |
+
* @type string structured property: src, width, height
|
124 |
+
* @type string|int URL and dimensions
|
125 |
+
* }
|
126 |
+
* }
|
127 |
+
*/
|
128 |
+
protected function imageCardProperties()
|
129 |
+
{
|
130 |
+
if (! isset( $this->image )) {
|
131 |
+
return '';
|
132 |
+
}
|
133 |
+
|
134 |
+
$card_properties = $this->image->asCardProperties();
|
135 |
+
if (empty( $card_properties )) {
|
136 |
+
return '';
|
137 |
+
}
|
138 |
+
|
139 |
+
return $card_properties;
|
140 |
+
}
|
141 |
+
}
|
src/Twitter/Cards/Gallery.php
ADDED
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\Cards;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Gallery card
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*
|
33 |
+
* @link https://dev.twitter.com/cards/types/gallery
|
34 |
+
*/
|
35 |
+
class Gallery extends Card
|
36 |
+
{
|
37 |
+
use \Twitter\Cards\Components\Creator;
|
38 |
+
use \Twitter\Cards\Components\Description;
|
39 |
+
use \Twitter\Cards\Components\MultipleImages;
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Twitter Card type value
|
43 |
+
*
|
44 |
+
* @since 1.0.0
|
45 |
+
*
|
46 |
+
* @type string
|
47 |
+
*/
|
48 |
+
const TYPE = 'gallery';
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Minimum width of an image in whole pixels
|
52 |
+
*
|
53 |
+
* @since 1.0.0
|
54 |
+
*
|
55 |
+
* @type int
|
56 |
+
*/
|
57 |
+
const MIN_IMAGE_WIDTH = 280;
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Minimum height of an image in whole pixels
|
61 |
+
*
|
62 |
+
* @since 1.0.0
|
63 |
+
*
|
64 |
+
* @type int
|
65 |
+
*/
|
66 |
+
const MIN_IMAGE_HEIGHT = 150;
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Maximum number of images used in a gallery card template
|
70 |
+
*
|
71 |
+
* @since 1.0.0
|
72 |
+
*
|
73 |
+
* @type int
|
74 |
+
*/
|
75 |
+
const MAX_IMAGES = 4;
|
76 |
+
|
77 |
+
/**
|
78 |
+
* Set the card type
|
79 |
+
*
|
80 |
+
* @since 1.0.0
|
81 |
+
*
|
82 |
+
* @return void
|
83 |
+
*/
|
84 |
+
public function __construct()
|
85 |
+
{
|
86 |
+
parent::__construct(static::TYPE);
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Convert to an array suitable for use as Twitter Card structured properties
|
91 |
+
*
|
92 |
+
* @since 1.0.0
|
93 |
+
*
|
94 |
+
* @return array {
|
95 |
+
* @type string Twitter card property
|
96 |
+
* @type mixed property value
|
97 |
+
* }
|
98 |
+
*/
|
99 |
+
public function toArray()
|
100 |
+
{
|
101 |
+
$card = parent::toArray();
|
102 |
+
|
103 |
+
$images = $this->getImages();
|
104 |
+
if (! empty( $images )) {
|
105 |
+
$image_count = count($images);
|
106 |
+
// flatten to just \Twitter\Cards\Components\Image
|
107 |
+
$images = array_values($images);
|
108 |
+
for ($i = 0; $i < $image_count; $i++) {
|
109 |
+
$card[ 'image' . $i ] = $images[ $i ]->asCardProperties();
|
110 |
+
}
|
111 |
+
unset( $image_count );
|
112 |
+
}
|
113 |
+
unset( $images );
|
114 |
+
|
115 |
+
if (isset( $this->creator ) && $this->creator) {
|
116 |
+
$creator = $this->creator->asCardProperties();
|
117 |
+
if ($creator) {
|
118 |
+
$card['creator'] = $creator;
|
119 |
+
}
|
120 |
+
unset( $creator );
|
121 |
+
}
|
122 |
+
|
123 |
+
return $card;
|
124 |
+
}
|
125 |
+
}
|
src/Twitter/Cards/Photo.php
ADDED
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\Cards;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Photo card
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*
|
33 |
+
* @link https://dev.twitter.com/cards/types/photo
|
34 |
+
*/
|
35 |
+
class Photo extends Card
|
36 |
+
{
|
37 |
+
use \Twitter\Cards\Components\Creator;
|
38 |
+
use \Twitter\Cards\Components\SingleImage;
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Twitter Card type value
|
42 |
+
*
|
43 |
+
* @since 1.0.0
|
44 |
+
*
|
45 |
+
* @type string
|
46 |
+
*/
|
47 |
+
const TYPE = 'photo';
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Minimum width of the image in whole pixels
|
51 |
+
*
|
52 |
+
* @since 1.0.0
|
53 |
+
*
|
54 |
+
* @type int
|
55 |
+
*/
|
56 |
+
const MIN_IMAGE_WIDTH = 280;
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Minimum height of the image in whole pixels
|
60 |
+
*
|
61 |
+
* @since 1.0.0
|
62 |
+
*
|
63 |
+
* @type int
|
64 |
+
*/
|
65 |
+
const MIN_IMAGE_HEIGHT = 150;
|
66 |
+
|
67 |
+
/**
|
68 |
+
* Set the card type
|
69 |
+
*
|
70 |
+
* @since 1.0.0
|
71 |
+
*
|
72 |
+
* @return void
|
73 |
+
*/
|
74 |
+
public function __construct()
|
75 |
+
{
|
76 |
+
parent::__construct(static::TYPE);
|
77 |
+
}
|
78 |
+
|
79 |
+
/**
|
80 |
+
* Convert to an array suitable for use as Twitter Card structured properties
|
81 |
+
*
|
82 |
+
* @since 1.0.0
|
83 |
+
*
|
84 |
+
* @return array {
|
85 |
+
* @type string Twitter card property
|
86 |
+
* @type mixed property value
|
87 |
+
* }
|
88 |
+
*/
|
89 |
+
public function toArray()
|
90 |
+
{
|
91 |
+
$card = parent::toArray();
|
92 |
+
|
93 |
+
$image_properties = $this->imageCardProperties();
|
94 |
+
if (! empty( $image_properties )) {
|
95 |
+
$card['image'] = $image_properties;
|
96 |
+
}
|
97 |
+
unset( $image_properties );
|
98 |
+
|
99 |
+
if (isset( $this->creator ) && $this->creator) {
|
100 |
+
$creator = $this->creator->asCardProperties();
|
101 |
+
if ($creator) {
|
102 |
+
$card['creator'] = $creator;
|
103 |
+
}
|
104 |
+
unset( $creator );
|
105 |
+
}
|
106 |
+
|
107 |
+
return $card;
|
108 |
+
}
|
109 |
+
}
|
src/Twitter/Cards/Product.php
ADDED
@@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\Cards;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Product card
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*
|
33 |
+
* @link https://dev.twitter.com/cards/types/product
|
34 |
+
*/
|
35 |
+
class Product extends Card
|
36 |
+
{
|
37 |
+
use \Twitter\Cards\Components\Creator;
|
38 |
+
use \Twitter\Cards\Components\Description;
|
39 |
+
use \Twitter\Cards\Components\SingleImage;
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Twitter Card type value
|
43 |
+
*
|
44 |
+
* @since 1.0.0
|
45 |
+
*
|
46 |
+
* @type string
|
47 |
+
*/
|
48 |
+
const TYPE = 'product';
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Minimum width of the image in whole pixels
|
52 |
+
*
|
53 |
+
* @since 1.0.0
|
54 |
+
*
|
55 |
+
* @type int
|
56 |
+
*/
|
57 |
+
const MIN_IMAGE_WIDTH = 160;
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Minimum height of the image in whole pixels
|
61 |
+
*
|
62 |
+
* @since 1.0.0
|
63 |
+
*
|
64 |
+
* @type int
|
65 |
+
*/
|
66 |
+
const MIN_IMAGE_HEIGHT = 160;
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Maximum number of displayed product details
|
70 |
+
*
|
71 |
+
* @since 1.0.0
|
72 |
+
*
|
73 |
+
* @type int
|
74 |
+
*/
|
75 |
+
const MAX_DETAILS = 2;
|
76 |
+
|
77 |
+
/**
|
78 |
+
* Tabular data for display in the card template
|
79 |
+
*
|
80 |
+
* @since 1.0.0
|
81 |
+
*
|
82 |
+
* @type array label value pairs {
|
83 |
+
* @type string label
|
84 |
+
* @type string data
|
85 |
+
* }
|
86 |
+
*/
|
87 |
+
protected $details = array();
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Number of stored details for the product
|
91 |
+
*
|
92 |
+
* @since 1.0.0
|
93 |
+
*
|
94 |
+
* @type int
|
95 |
+
*/
|
96 |
+
protected $details_count = 0;
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Set the card type
|
100 |
+
*
|
101 |
+
* @since 1.0.0
|
102 |
+
*
|
103 |
+
* @return void
|
104 |
+
*/
|
105 |
+
public function __construct()
|
106 |
+
{
|
107 |
+
parent::__construct(static::TYPE);
|
108 |
+
}
|
109 |
+
|
110 |
+
/**
|
111 |
+
* Add a detail
|
112 |
+
*
|
113 |
+
* @since 1.0.0
|
114 |
+
*
|
115 |
+
* @param string $label product detail label
|
116 |
+
* @param string $value product detail value
|
117 |
+
*
|
118 |
+
* @return __CLASS__ support chaining
|
119 |
+
*/
|
120 |
+
public function addDetail($label, $value)
|
121 |
+
{
|
122 |
+
// maximum allowed details already reached
|
123 |
+
if ($this->details_count === static::MAX_DETAILS) {
|
124 |
+
return $this;
|
125 |
+
}
|
126 |
+
|
127 |
+
try {
|
128 |
+
$label = trim((string) $label);
|
129 |
+
$value = trim((string) $value);
|
130 |
+
} catch (Exception $e) {
|
131 |
+
return $this;
|
132 |
+
}
|
133 |
+
|
134 |
+
if ($label && $value && ! isset( $this->details[ $label ] )) {
|
135 |
+
$this->details[ $label ] = $value;
|
136 |
+
$this->details_count = count($this->details);
|
137 |
+
}
|
138 |
+
|
139 |
+
return $this;
|
140 |
+
}
|
141 |
+
|
142 |
+
/**
|
143 |
+
* Convert to an array suitable for use as Twitter Card structured properties
|
144 |
+
*
|
145 |
+
* @since 1.0.0
|
146 |
+
*
|
147 |
+
* @return array {
|
148 |
+
* @type string Twitter card property
|
149 |
+
* @type string|array property value
|
150 |
+
* }
|
151 |
+
*/
|
152 |
+
public function toArray()
|
153 |
+
{
|
154 |
+
$card = parent::toArray();
|
155 |
+
|
156 |
+
if (isset( $this->description ) && $this->description) {
|
157 |
+
$card['description'] = $this->description;
|
158 |
+
}
|
159 |
+
|
160 |
+
$image_properties = $this->imageCardProperties();
|
161 |
+
if (! empty( $image_properties )) {
|
162 |
+
$card['image'] = $image_properties;
|
163 |
+
}
|
164 |
+
unset( $image_properties );
|
165 |
+
|
166 |
+
if (! empty( $this->details )) {
|
167 |
+
// product card table is 1-based
|
168 |
+
$details_position = 1;
|
169 |
+
foreach ($this->details as $label => $data) {
|
170 |
+
$card[ 'label' . $details_position ] = $label;
|
171 |
+
$card[ 'data' . $details_position ] = $data;
|
172 |
+
$details_position++;
|
173 |
+
}
|
174 |
+
unset( $details_position );
|
175 |
+
}
|
176 |
+
|
177 |
+
if (isset( $this->creator ) && $this->creator) {
|
178 |
+
$creator = $this->creator->asCardProperties();
|
179 |
+
if ($creator) {
|
180 |
+
$card['creator'] = $creator;
|
181 |
+
}
|
182 |
+
unset( $creator );
|
183 |
+
}
|
184 |
+
|
185 |
+
return $card;
|
186 |
+
}
|
187 |
+
}
|
src/Twitter/Cards/Summary.php
ADDED
@@ -0,0 +1,114 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\Cards;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Twitter summary card
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*
|
33 |
+
* @link https://dev.twitter.com/docs/cards/types/summary-card Twitter Summary Card
|
34 |
+
*/
|
35 |
+
class Summary extends Card
|
36 |
+
{
|
37 |
+
use \Twitter\Cards\Components\Creator;
|
38 |
+
use \Twitter\Cards\Components\Description;
|
39 |
+
use \Twitter\Cards\Components\SingleImage;
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Twitter Card type value
|
43 |
+
*
|
44 |
+
* @since 1.0.0
|
45 |
+
*
|
46 |
+
* @type string
|
47 |
+
*/
|
48 |
+
const TYPE = 'summary';
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Minimum width of the image in whole pixels
|
52 |
+
*
|
53 |
+
* @since 1.0.0
|
54 |
+
*
|
55 |
+
* @type int
|
56 |
+
*/
|
57 |
+
const MIN_IMAGE_WIDTH = 120;
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Minimum height of the image in whole pixels
|
61 |
+
*
|
62 |
+
* @since 1.0.0
|
63 |
+
*
|
64 |
+
* @type int
|
65 |
+
*/
|
66 |
+
const MIN_IMAGE_HEIGHT = 120;
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Set the card type
|
70 |
+
*
|
71 |
+
* @since 1.0.0
|
72 |
+
*
|
73 |
+
* @return void
|
74 |
+
*/
|
75 |
+
public function __construct()
|
76 |
+
{
|
77 |
+
parent::__construct(static::TYPE);
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Convert to an array suitable for use as Twitter Card structured properties
|
82 |
+
*
|
83 |
+
* @since 1.0.0
|
84 |
+
*
|
85 |
+
* @return array {
|
86 |
+
* @type string Twitter card property
|
87 |
+
* @type mixed property value
|
88 |
+
* }
|
89 |
+
*/
|
90 |
+
public function toArray()
|
91 |
+
{
|
92 |
+
$card = parent::toArray();
|
93 |
+
|
94 |
+
if (isset( $this->description ) && $this->description) {
|
95 |
+
$card['description'] = $this->description;
|
96 |
+
}
|
97 |
+
|
98 |
+
$image_properties = $this->imageCardProperties();
|
99 |
+
if (! empty( $image_properties )) {
|
100 |
+
$card['image'] = $image_properties;
|
101 |
+
}
|
102 |
+
unset( $image_properties );
|
103 |
+
|
104 |
+
if (isset( $this->creator ) && $this->creator) {
|
105 |
+
$creator = $this->creator->asCardProperties();
|
106 |
+
if ($creator) {
|
107 |
+
$card['creator'] = $creator;
|
108 |
+
}
|
109 |
+
unset( $creator );
|
110 |
+
}
|
111 |
+
|
112 |
+
return $card;
|
113 |
+
}
|
114 |
+
}
|
src/Twitter/Cards/SummaryLargeImage.php
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\Cards;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Summary large image card
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*
|
33 |
+
* @link https://dev.twitter.com/cards/types/summary-large-image
|
34 |
+
*/
|
35 |
+
class SummaryLargeImage extends Summary
|
36 |
+
{
|
37 |
+
/**
|
38 |
+
* Twitter Card type value
|
39 |
+
*
|
40 |
+
* @since 1.0.0
|
41 |
+
*
|
42 |
+
* @type string
|
43 |
+
*/
|
44 |
+
const TYPE = 'summary_large_image';
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Minimum width of the image in whole pixels
|
48 |
+
*
|
49 |
+
* @since 1.0.0
|
50 |
+
*
|
51 |
+
* @type int
|
52 |
+
*/
|
53 |
+
const MIN_IMAGE_WIDTH = 280;
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Minimum height of the image in whole pixels
|
57 |
+
*
|
58 |
+
* @since 1.0.0
|
59 |
+
*
|
60 |
+
* @type int
|
61 |
+
*/
|
62 |
+
const MIN_IMAGE_HEIGHT = 150;
|
63 |
+
}
|
src/Twitter/Helpers/HTMLBuilder.php
ADDED
@@ -0,0 +1,207 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\Helpers;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* String builder for HTML elements
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class HTMLBuilder
|
34 |
+
{
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Allow extensibility of allowed class name values
|
38 |
+
*
|
39 |
+
* @since 1.0.0
|
40 |
+
*
|
41 |
+
* @param string $class possible HTML class
|
42 |
+
*
|
43 |
+
* @return class name stripped of invalid values or empty string
|
44 |
+
*/
|
45 |
+
public static function escapeClassName($class)
|
46 |
+
{
|
47 |
+
return static::escapeAttributeValue($class);
|
48 |
+
}
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Escape an element's inner text
|
52 |
+
*
|
53 |
+
* @since 1.0.0
|
54 |
+
*
|
55 |
+
* @param string $inner_text inner text of a DOM element
|
56 |
+
*
|
57 |
+
* @return string escaped string or empty string if passed string failed to parse
|
58 |
+
*/
|
59 |
+
public static function escapeInnerText($inner_text)
|
60 |
+
{
|
61 |
+
return htmlspecialchars($inner_text, defined('ENT_HTML5') ? ENT_HTML5 : ENT_COMPAT);
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Escape an element attribute value including double quotes
|
66 |
+
*
|
67 |
+
* @since 1.0.0
|
68 |
+
*
|
69 |
+
* @param string $value element attribute value
|
70 |
+
*
|
71 |
+
* @return string escaped string or empty string if passed string failed to parse
|
72 |
+
*/
|
73 |
+
public static function escapeAttributeValue($value)
|
74 |
+
{
|
75 |
+
return htmlspecialchars($value, ENT_COMPAT);
|
76 |
+
}
|
77 |
+
|
78 |
+
/**
|
79 |
+
* Escape a URL
|
80 |
+
*
|
81 |
+
* @since 1.0.0
|
82 |
+
*
|
83 |
+
* @param string $url web URL
|
84 |
+
*
|
85 |
+
* @return string escaped string or empty string if passed string failed to parse
|
86 |
+
*/
|
87 |
+
public static function escapeURL($url)
|
88 |
+
{
|
89 |
+
return htmlspecialchars($url, ENT_QUOTES, 'UTF-8');
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Build a HTML anchor element for the given URL and data attributes
|
94 |
+
*
|
95 |
+
* @since 1.0.0
|
96 |
+
*
|
97 |
+
* @param string $href intent URL
|
98 |
+
* @param string $inner_text anchor element innerText
|
99 |
+
* @param array $attributes anchor attributes to be added. limited to a whitelist of: id, class, rel, ping, target
|
100 |
+
* @param array $data_attributes data attributes to be interpreted by Twitter's widget JS
|
101 |
+
*
|
102 |
+
* @return string HTML anchor element string or empty string if no URL passed
|
103 |
+
*/
|
104 |
+
public static function anchorElement($href, $inner_text, $attributes = array(), $data_attributes = array())
|
105 |
+
{
|
106 |
+
if (! is_string($href) && $href && is_string($inner_text) && $inner_text) {
|
107 |
+
return '';
|
108 |
+
}
|
109 |
+
|
110 |
+
$clean_attributes = array();
|
111 |
+
|
112 |
+
if (is_array($attributes) && ! empty( $attributes )) {
|
113 |
+
// string
|
114 |
+
if (isset( $attributes['id'] )) {
|
115 |
+
$id = static::escapeAttributeValue(trim($attributes['id']));
|
116 |
+
if ($id) {
|
117 |
+
$clean_attributes['id'] = $id;
|
118 |
+
}
|
119 |
+
unset( $id );
|
120 |
+
}
|
121 |
+
|
122 |
+
// accept array of values to be combined
|
123 |
+
$tokens = array( 'class', 'rel' );
|
124 |
+
foreach ($tokens as $attribute) {
|
125 |
+
if (! isset( $attributes[ $attribute ] )) {
|
126 |
+
continue;
|
127 |
+
}
|
128 |
+
|
129 |
+
$attribute_tokens = array();
|
130 |
+
if (is_array($attributes[ $attribute ])) {
|
131 |
+
if (! empty( $attributes[ $attribute ] )) {
|
132 |
+
$cleaned_tokens = array_filter(array_map('trim', $attributes[ $attribute ]));
|
133 |
+
if (! empty( $cleaned_tokens )) {
|
134 |
+
$attribute_tokens = $cleaned_tokens;
|
135 |
+
}
|
136 |
+
unset( $cleaned_tokens );
|
137 |
+
}
|
138 |
+
} elseif (is_string($attributes[ $attribute ])) {
|
139 |
+
$cleaned_token = trim($attributes[ $attribute ]);
|
140 |
+
if ($cleaned_token) {
|
141 |
+
$attribute_tokens = explode(' ', $cleaned_token);
|
142 |
+
}
|
143 |
+
unset( $cleaned_token );
|
144 |
+
}
|
145 |
+
|
146 |
+
// filter and store
|
147 |
+
if (! empty( $attribute_tokens )) {
|
148 |
+
$attribute_tokens = array_map(
|
149 |
+
__CLASS__ . '::' . ( $attribute === 'class' ? 'escapeClassName' : 'escapeAttribute' ),
|
150 |
+
$attribute_tokens
|
151 |
+
);
|
152 |
+
if (! empty( $attribute_tokens )) {
|
153 |
+
$clean_attributes[ $attribute ] = implode(' ', $attribute_tokens);
|
154 |
+
}
|
155 |
+
}
|
156 |
+
unset( $attribute_tokens );
|
157 |
+
}
|
158 |
+
unset( $tokens );
|
159 |
+
|
160 |
+
// URL
|
161 |
+
if (isset( $attributes['ping'] )) {
|
162 |
+
$ping = static::escapeURL(trim($attributes['ping']));
|
163 |
+
if ($ping) {
|
164 |
+
$clean_attributes['ping'] = $ping;
|
165 |
+
}
|
166 |
+
unset( $ping );
|
167 |
+
}
|
168 |
+
|
169 |
+
// enum
|
170 |
+
if (isset( $attributes['target'] )) {
|
171 |
+
$target = trim('target');
|
172 |
+
if ($target) {
|
173 |
+
$valid_targets = array( '_blank' => true, '_self' => true, '_parent' => true, '_top' => true );
|
174 |
+
if (isset( $valid_targets[ $target ] )) {
|
175 |
+
$clean_attributes['target'] = $target;
|
176 |
+
}
|
177 |
+
unset( $valid_targets );
|
178 |
+
}
|
179 |
+
unset( $target );
|
180 |
+
}
|
181 |
+
}
|
182 |
+
|
183 |
+
if (is_array($data_attributes) && ! empty( $data_attributes )) {
|
184 |
+
foreach ($data_attributes as $attribute => $value) {
|
185 |
+
if (! $attribute) {
|
186 |
+
continue;
|
187 |
+
}
|
188 |
+
|
189 |
+
$clean_attributes[ 'data-' . $attribute ] = static::escapeAttributeValue(trim($value));
|
190 |
+
}
|
191 |
+
}
|
192 |
+
|
193 |
+
$html = '<a href="' . static::escapeURL($href) . '"';
|
194 |
+
foreach ($clean_attributes as $attribute => $value) {
|
195 |
+
$html .= ' ' . $attribute;
|
196 |
+
|
197 |
+
// escaped during per-attribute scrub
|
198 |
+
// allow properties without a value
|
199 |
+
if ($value) {
|
200 |
+
$html .= '="' . $value . '"';
|
201 |
+
}
|
202 |
+
}
|
203 |
+
$html .= '>' . static::escapeInnerText($inner_text) . '</a>';
|
204 |
+
|
205 |
+
return $html;
|
206 |
+
}
|
207 |
+
}
|
src/Twitter/Helpers/TwitterURL.php
ADDED
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\Helpers;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Reference Twitter URLs
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class TwitterURL
|
34 |
+
{
|
35 |
+
/**
|
36 |
+
* Scheme, FQDN, and path to Twitter web
|
37 |
+
*
|
38 |
+
* @since 1.0.0
|
39 |
+
*
|
40 |
+
* @type string
|
41 |
+
*/
|
42 |
+
const BASE_URL = 'https://twitter.com/';
|
43 |
+
|
44 |
+
/**
|
45 |
+
* A Twitter user profile page
|
46 |
+
*
|
47 |
+
* @since 1.0.0
|
48 |
+
*
|
49 |
+
* @param string $screen_name Twitter screen name
|
50 |
+
*
|
51 |
+
* @return string absolute URI of a Twitter profile page
|
52 |
+
*/
|
53 |
+
public static function profile($screen_name)
|
54 |
+
{
|
55 |
+
if (! ( is_string($screen_name) && $screen_name )) {
|
56 |
+
return '';
|
57 |
+
}
|
58 |
+
return self::BASE_URL . $screen_name;
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Individual Tweet / status URI
|
63 |
+
*
|
64 |
+
* @since 1.0.0
|
65 |
+
*
|
66 |
+
* @param string $screen_name Twitter account screen name
|
67 |
+
* @param string|int $status_id status ID
|
68 |
+
*
|
69 |
+
* @return string Tweet detail page absolute URI
|
70 |
+
*/
|
71 |
+
public static function tweet($screen_name, $status_id)
|
72 |
+
{
|
73 |
+
$profile_url = static::profile($screen_name);
|
74 |
+
if (! $profile_url) {
|
75 |
+
return '';
|
76 |
+
}
|
77 |
+
$status_id = (string) $status_id;
|
78 |
+
if (! $status_id) {
|
79 |
+
return '';
|
80 |
+
}
|
81 |
+
|
82 |
+
return $profile_url . '/status/' . $status_id;
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Twitter Collection / Custom Timeline
|
87 |
+
*
|
88 |
+
* @since 1.0.0
|
89 |
+
*
|
90 |
+
* @param string $screen_name Twitter account screen name
|
91 |
+
* @param string $collection_id Twitter collection numeric identifier
|
92 |
+
*
|
93 |
+
* @return string Twitter collection absolute URI
|
94 |
+
*/
|
95 |
+
public static function collection($screen_name, $collection_id)
|
96 |
+
{
|
97 |
+
if (! ( $screen_name && $collection_id )) {
|
98 |
+
return '';
|
99 |
+
}
|
100 |
+
|
101 |
+
$profile_url = static::profile($screen_name);
|
102 |
+
if (! $profile_url) {
|
103 |
+
return '';
|
104 |
+
}
|
105 |
+
|
106 |
+
return $profile_url . '/timelines/' . $collection_id;
|
107 |
+
}
|
108 |
+
}
|
src/Twitter/Helpers/Validators/Hashtag.php
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\Helpers\Validators;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Test for Twitter hashtag validity
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class Hashtag
|
34 |
+
{
|
35 |
+
/**
|
36 |
+
* Remove possible '#' from beginning of a Twitter hashtag
|
37 |
+
*
|
38 |
+
* @since 1.0.0
|
39 |
+
*
|
40 |
+
* @param string $hashtag Twitter hashtag
|
41 |
+
*
|
42 |
+
* @return string Twitter hashtag
|
43 |
+
*/
|
44 |
+
public static function trim($hashtag)
|
45 |
+
{
|
46 |
+
return ltrim(trim($hashtag), '##');
|
47 |
+
}
|
48 |
+
}
|
src/Twitter/Helpers/Validators/ScreenName.php
ADDED
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\Helpers\Validators;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Test for Twitter screen_name validity
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class ScreenName
|
34 |
+
{
|
35 |
+
/**
|
36 |
+
* Remove possible '@' from beginning of a Twitter screen_name
|
37 |
+
*
|
38 |
+
* @since 1.0.0
|
39 |
+
*
|
40 |
+
* @param string $screen_name Twitter screen name
|
41 |
+
*
|
42 |
+
* @return string Twitter screen name
|
43 |
+
*/
|
44 |
+
public static function trim($screen_name)
|
45 |
+
{
|
46 |
+
return ltrim(trim($screen_name), '@@');
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Tests a supplied Twitter screen_name for validity
|
51 |
+
*
|
52 |
+
* @since 1.0.0
|
53 |
+
*
|
54 |
+
* @link https://github.com/twitter/twitter-text/blob/master/java/src/com/twitter/Regex.java Twitter text
|
55 |
+
*
|
56 |
+
* @param string $screen_name Twitter screen name
|
57 |
+
*
|
58 |
+
* @return bool true if valid screen name
|
59 |
+
*/
|
60 |
+
public static function isValid($screen_name)
|
61 |
+
{
|
62 |
+
return (bool) preg_match('/^[a-z0-9_]{1,20}$/i', $screen_name);
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Sanitize a user-inputted screen name value
|
67 |
+
*
|
68 |
+
* Account for a leading @, extra spaces, or a Twitter.com URL
|
69 |
+
*
|
70 |
+
* @since 1.0.0
|
71 |
+
*
|
72 |
+
* @param string $screen_name Twitter screen name
|
73 |
+
*
|
74 |
+
* @return string Twitter screen name or empty string if invalid screen name provided
|
75 |
+
*/
|
76 |
+
public static function sanitize($screen_name)
|
77 |
+
{
|
78 |
+
if (! is_string($screen_name)) {
|
79 |
+
return '';
|
80 |
+
}
|
81 |
+
|
82 |
+
$screen_name = trim($screen_name);
|
83 |
+
if (! $screen_name) {
|
84 |
+
return '';
|
85 |
+
}
|
86 |
+
$screen_name = trim(rtrim(trim($screen_name), '/'));
|
87 |
+
if (! $screen_name) {
|
88 |
+
return '';
|
89 |
+
}
|
90 |
+
|
91 |
+
$last_slash = strrpos($screen_name, '/');
|
92 |
+
if (false !== $last_slash) {
|
93 |
+
$screen_name = substr($screen_name, $last_slash + 1);
|
94 |
+
}
|
95 |
+
$screen_name = static::trim($screen_name);
|
96 |
+
if (! $screen_name) {
|
97 |
+
return '';
|
98 |
+
}
|
99 |
+
|
100 |
+
if (! static::isValid($screen_name)) {
|
101 |
+
return '';
|
102 |
+
}
|
103 |
+
|
104 |
+
return $screen_name;
|
105 |
+
}
|
106 |
+
}
|
src/Twitter/Intents/Follow.php
ADDED
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\Intents;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Link to a follow web intent page
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*
|
33 |
+
* @link https://dev.twitter.com/web/follow-button/web-intent
|
34 |
+
*/
|
35 |
+
class Follow
|
36 |
+
{
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Follow Web Intent URL
|
40 |
+
*
|
41 |
+
* @since 1.0.0
|
42 |
+
*
|
43 |
+
* @type string
|
44 |
+
*/
|
45 |
+
const INTENT_URL = 'https://twitter.com/intent/follow';
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Twitter handle
|
49 |
+
*
|
50 |
+
* @since 1.0.0
|
51 |
+
*
|
52 |
+
* @type string
|
53 |
+
*/
|
54 |
+
protected $screen_name;
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Construct a new follow intent for the given Twitter screen name
|
58 |
+
*
|
59 |
+
* @since 1.0.0
|
60 |
+
*
|
61 |
+
* @param string $screen_name Twitter screen name
|
62 |
+
* @param bool $validate validate screen name matches Twitter username allowed characters and length before saving
|
63 |
+
*/
|
64 |
+
public function __construct($screen_name, $validate = true)
|
65 |
+
{
|
66 |
+
$screen_name = \Twitter\Helpers\Validators\ScreenName::trim($screen_name);
|
67 |
+
if ($screen_name) {
|
68 |
+
if (false === $validate || \Twitter\Helpers\Validators\ScreenName::isValid($screen_name)) {
|
69 |
+
$this->screen_name = $screen_name;
|
70 |
+
}
|
71 |
+
}
|
72 |
+
}
|
73 |
+
|
74 |
+
/**
|
75 |
+
* Retrieve the stored Twitter screen name
|
76 |
+
*
|
77 |
+
* @since 1.0.0
|
78 |
+
*
|
79 |
+
* @return string Twitter screen name or empty string if none set
|
80 |
+
*/
|
81 |
+
public function getScreenName()
|
82 |
+
{
|
83 |
+
return $this->screen_name ?: '';
|
84 |
+
}
|
85 |
+
|
86 |
+
/**
|
87 |
+
* Return the follow intent URL
|
88 |
+
*
|
89 |
+
* @since 1.0.0
|
90 |
+
*
|
91 |
+
* @return string Follow intent URL or empty string if no valid screen name
|
92 |
+
*/
|
93 |
+
public function __toString()
|
94 |
+
{
|
95 |
+
return $this->getIntentURL();
|
96 |
+
}
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Follow intent URL
|
100 |
+
*
|
101 |
+
* @since 1.0.0
|
102 |
+
*
|
103 |
+
* @return string Follow intent URL or empty string if no valid screen name
|
104 |
+
*/
|
105 |
+
public function getIntentURL()
|
106 |
+
{
|
107 |
+
if (! $this->screen_name) {
|
108 |
+
return '';
|
109 |
+
}
|
110 |
+
|
111 |
+
return static::INTENT_URL . '?' . http_build_query(array( 'screen_name' => $this->screen_name ), '', '&', PHP_QUERY_RFC3986);
|
112 |
+
}
|
113 |
+
}
|
src/Twitter/Intents/Tweet.php
ADDED
@@ -0,0 +1,512 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\Intents;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Influence the Tweet creation flow
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*
|
33 |
+
* @link https://dev.twitter.com/web/tweet-button/web-intent
|
34 |
+
*/
|
35 |
+
class Tweet
|
36 |
+
{
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Tweet Web Intent URL
|
40 |
+
*
|
41 |
+
* @since 1.0.0
|
42 |
+
*
|
43 |
+
* @type string
|
44 |
+
*/
|
45 |
+
const INTENT_URL = 'https://twitter.com/intent/tweet';
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Validate passed variables before storing
|
49 |
+
*
|
50 |
+
* @since 1.0.0
|
51 |
+
*
|
52 |
+
* @type bool
|
53 |
+
*/
|
54 |
+
protected $validate_inputs = true;
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Parent Tweet identifier
|
58 |
+
*
|
59 |
+
* @since 1.0.0
|
60 |
+
*
|
61 |
+
* @type string
|
62 |
+
*/
|
63 |
+
protected $in_reply_to;
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Pre-populated Tweet text
|
67 |
+
*
|
68 |
+
* @since 1.0.0
|
69 |
+
*
|
70 |
+
* @type string
|
71 |
+
*/
|
72 |
+
protected $text;
|
73 |
+
|
74 |
+
/**
|
75 |
+
* Share a URL
|
76 |
+
*
|
77 |
+
* @since 1.0.0
|
78 |
+
*
|
79 |
+
* @type string
|
80 |
+
*/
|
81 |
+
protected $url;
|
82 |
+
|
83 |
+
/**
|
84 |
+
* Hashtags to include in the Tweet
|
85 |
+
*
|
86 |
+
* @since 1.0.0
|
87 |
+
*
|
88 |
+
* @type array {
|
89 |
+
* @type string comparison hashtag in lowercase
|
90 |
+
* @type string passed hashtag
|
91 |
+
* }
|
92 |
+
*/
|
93 |
+
protected $hashtags = array();
|
94 |
+
|
95 |
+
/**
|
96 |
+
* Associate a Tweet with an source Twitter account such as the username of your website
|
97 |
+
*
|
98 |
+
* @since 1.0.0
|
99 |
+
*
|
100 |
+
* @type string
|
101 |
+
*/
|
102 |
+
protected $via;
|
103 |
+
|
104 |
+
/**
|
105 |
+
* Related Twitter usernames
|
106 |
+
*
|
107 |
+
* May be presented as a suggested account to follow after the Tweet is published
|
108 |
+
*
|
109 |
+
* @since 1.0.0
|
110 |
+
*
|
111 |
+
* @type array {
|
112 |
+
* @type string username in lowercase
|
113 |
+
* @type string description of how the username relates to Tweet content
|
114 |
+
* }
|
115 |
+
*/
|
116 |
+
protected $related = array();
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Do not validate inputs
|
120 |
+
*
|
121 |
+
* Disabling validation may speed up Web Intent generation but may also cause user-facing issues
|
122 |
+
*
|
123 |
+
* @since 1.0.0
|
124 |
+
*
|
125 |
+
* @return __CLASS__ support chaining
|
126 |
+
*/
|
127 |
+
public function disableValidation()
|
128 |
+
{
|
129 |
+
$this->validate_inputs = false;
|
130 |
+
return $this;
|
131 |
+
}
|
132 |
+
|
133 |
+
/**
|
134 |
+
* Validate inputs
|
135 |
+
*
|
136 |
+
* @since 1.0.0
|
137 |
+
*
|
138 |
+
* @return __CLASS__ support chaining
|
139 |
+
*/
|
140 |
+
public function enableValidation()
|
141 |
+
{
|
142 |
+
$this->validate_inputs = true;
|
143 |
+
return $this;
|
144 |
+
}
|
145 |
+
|
146 |
+
/**
|
147 |
+
* Should data be validated before setting?
|
148 |
+
*
|
149 |
+
* @since 1.0.0
|
150 |
+
*
|
151 |
+
* @return bool validate inputs
|
152 |
+
*/
|
153 |
+
public function shouldValidate()
|
154 |
+
{
|
155 |
+
return $this->validate_inputs;
|
156 |
+
}
|
157 |
+
|
158 |
+
/**
|
159 |
+
* Define a parent Tweet by ID
|
160 |
+
*
|
161 |
+
* @since 1.0.0
|
162 |
+
*
|
163 |
+
* @param string $tweet_id Parent Tweet ID
|
164 |
+
*
|
165 |
+
* @return __CLASS__ support chaining
|
166 |
+
*/
|
167 |
+
public function setInReplyTo($tweet_id)
|
168 |
+
{
|
169 |
+
$tweet_id = trim($tweet_id);
|
170 |
+
if ($tweet_id) {
|
171 |
+
$this->in_reply_to = $tweet_id;
|
172 |
+
}
|
173 |
+
|
174 |
+
return $this;
|
175 |
+
}
|
176 |
+
|
177 |
+
/**
|
178 |
+
* Pre-populate Tweet text
|
179 |
+
*
|
180 |
+
* @since 1.0.0
|
181 |
+
*
|
182 |
+
* @param string $text Tweet text
|
183 |
+
*
|
184 |
+
* @return __CLASS__ support chaining
|
185 |
+
*/
|
186 |
+
public function setText($text)
|
187 |
+
{
|
188 |
+
$text = trim($text);
|
189 |
+
if ($text) {
|
190 |
+
$this->text = $text;
|
191 |
+
}
|
192 |
+
|
193 |
+
return $this;
|
194 |
+
}
|
195 |
+
|
196 |
+
/**
|
197 |
+
* Is the passed URL an absolute URL using the HTTP or HTTPS scheme?
|
198 |
+
*
|
199 |
+
* @since 1.0.0
|
200 |
+
*
|
201 |
+
* @param string $url URL to test
|
202 |
+
*
|
203 |
+
* @return bool true if URL was parsed and contains a HTTP or HTTPs scheme
|
204 |
+
*/
|
205 |
+
public static function isHTTPURL($url)
|
206 |
+
{
|
207 |
+
if (! ( is_string($url) && $url )) {
|
208 |
+
return false;
|
209 |
+
}
|
210 |
+
|
211 |
+
try {
|
212 |
+
$scheme = parse_url($url, PHP_URL_SCHEME);
|
213 |
+
} catch (Exception $e) {
|
214 |
+
return false;
|
215 |
+
}
|
216 |
+
|
217 |
+
if ('http' === $scheme || 'https' === $scheme) {
|
218 |
+
return true;
|
219 |
+
}
|
220 |
+
|
221 |
+
return false;
|
222 |
+
}
|
223 |
+
|
224 |
+
/**
|
225 |
+
* Share a URL
|
226 |
+
*
|
227 |
+
* @since 1.0.0
|
228 |
+
*
|
229 |
+
* @param string $url absolute URL
|
230 |
+
*
|
231 |
+
* @return __CLASS__ support chaining
|
232 |
+
*/
|
233 |
+
public function setURL($url)
|
234 |
+
{
|
235 |
+
$url = trim($url);
|
236 |
+
if ($url) {
|
237 |
+
if ($this->validate_inputs) {
|
238 |
+
if (static::isHTTPURL($url)) {
|
239 |
+
$this->url = $url;
|
240 |
+
}
|
241 |
+
} else {
|
242 |
+
$this->url = $url;
|
243 |
+
}
|
244 |
+
}
|
245 |
+
|
246 |
+
return $this;
|
247 |
+
}
|
248 |
+
|
249 |
+
/**
|
250 |
+
* Add a hashtag
|
251 |
+
*
|
252 |
+
* @since 1.0.0
|
253 |
+
*
|
254 |
+
* @param string $hashtag hashtag
|
255 |
+
*
|
256 |
+
* @return __CLASS__ support chaining
|
257 |
+
*/
|
258 |
+
public function addHashtag($hashtag)
|
259 |
+
{
|
260 |
+
$hashtag = \Twitter\Helpers\Validators\Hashtag::trim($hashtag);
|
261 |
+
if ($hashtag) {
|
262 |
+
$comparison_hashtag = mb_strtolower($hashtag);
|
263 |
+
if (! isset( $this->hashtags[ $comparison_hashtag ] )) {
|
264 |
+
$this->hashtags[ $comparison_hashtag ] = $hashtag;
|
265 |
+
}
|
266 |
+
}
|
267 |
+
|
268 |
+
return $this;
|
269 |
+
}
|
270 |
+
|
271 |
+
/**
|
272 |
+
* Get a list of hashtags stored for the Tweet
|
273 |
+
*
|
274 |
+
* @since 1.0.0
|
275 |
+
*
|
276 |
+
* @return array hashtags {
|
277 |
+
* @type string hashtag
|
278 |
+
* }
|
279 |
+
*/
|
280 |
+
public function getHashtags()
|
281 |
+
{
|
282 |
+
return array_values($this->hashtags);
|
283 |
+
}
|
284 |
+
|
285 |
+
/**
|
286 |
+
* Associate Tweet with a source account
|
287 |
+
*
|
288 |
+
* @since 1.0.0
|
289 |
+
*
|
290 |
+
* @param string $username Twitter username
|
291 |
+
*
|
292 |
+
* @return __CLASS__ support chaining
|
293 |
+
*/
|
294 |
+
public function setVia($username)
|
295 |
+
{
|
296 |
+
$username = \Twitter\Helpers\Validators\ScreenName::trim($username);
|
297 |
+
if ($username) {
|
298 |
+
if ($this->validate_inputs) {
|
299 |
+
if (\Twitter\Helpers\Validators\ScreenName::isValid($username)) {
|
300 |
+
$this->via = $username;
|
301 |
+
}
|
302 |
+
} else {
|
303 |
+
$this->via = $username;
|
304 |
+
}
|
305 |
+
}
|
306 |
+
|
307 |
+
return $this;
|
308 |
+
}
|
309 |
+
|
310 |
+
/**
|
311 |
+
* Add a related Twitter account
|
312 |
+
*
|
313 |
+
* @since 1.0.0
|
314 |
+
*
|
315 |
+
* @param string $username Twitter username
|
316 |
+
* @param string $label brief description of how the account relates to the Tweet content
|
317 |
+
*
|
318 |
+
* @return __CLASS__ support chaining
|
319 |
+
*/
|
320 |
+
public function addRelated($username, $label = '')
|
321 |
+
{
|
322 |
+
$username = \Twitter\Helpers\Validators\ScreenName::trim($username);
|
323 |
+
if ($username) {
|
324 |
+
// normalize passed parameter
|
325 |
+
$comparison_username = strtolower($username);
|
326 |
+
if (! isset( $this->related[ $comparison_username ] )) {
|
327 |
+
if ($this->validate_inputs) {
|
328 |
+
if (\Twitter\Helpers\Validators\ScreenName::isValid($username)) {
|
329 |
+
$this->related[ $comparison_username ] = trim($label);
|
330 |
+
}
|
331 |
+
} else {
|
332 |
+
$this->related[ $comparison_username ] = trim($label);
|
333 |
+
}
|
334 |
+
}
|
335 |
+
}
|
336 |
+
|
337 |
+
return $this;
|
338 |
+
}
|
339 |
+
|
340 |
+
/**
|
341 |
+
* Get related Twitter usernames
|
342 |
+
*
|
343 |
+
* @since 1.0.0
|
344 |
+
*
|
345 |
+
* @return array {
|
346 |
+
* @type string username in lowercase
|
347 |
+
* @type string description of how the username relates to Tweet content
|
348 |
+
* }
|
349 |
+
*/
|
350 |
+
public function getRelated()
|
351 |
+
{
|
352 |
+
return $this->related;
|
353 |
+
}
|
354 |
+
|
355 |
+
/**
|
356 |
+
* Construct a new Tweet intent object from an options array
|
357 |
+
*
|
358 |
+
* @since 1.0.0
|
359 |
+
*
|
360 |
+
* @param array $values options array {
|
361 |
+
* @type string option name
|
362 |
+
* @type string|int|bool option value
|
363 |
+
* }
|
364 |
+
*
|
365 |
+
* @return __CLASS__ object initialized based on passed array values
|
366 |
+
*/
|
367 |
+
public static function fromArray($values)
|
368 |
+
{
|
369 |
+
if (! is_array($values)) {
|
370 |
+
$values = array();
|
371 |
+
}
|
372 |
+
|
373 |
+
$class = __CLASS__;
|
374 |
+
$intent = new $class;
|
375 |
+
unset( $class );
|
376 |
+
|
377 |
+
if (isset( $values['validate'] )) {
|
378 |
+
if (false == $values['validate'] || 'false' === $values['validate'] || 0 == $values['validate']) {
|
379 |
+
$intent->disableValidation();
|
380 |
+
}
|
381 |
+
}
|
382 |
+
|
383 |
+
// remove values which evaluate to false
|
384 |
+
$values = array_filter($values);
|
385 |
+
|
386 |
+
// intent parameters
|
387 |
+
if (isset( $values['in_reply_to'] )) {
|
388 |
+
$intent->setInReplyTo($values['in_reply_to']);
|
389 |
+
}
|
390 |
+
if (isset( $values['text'] )) {
|
391 |
+
$intent->setText($values['text']);
|
392 |
+
}
|
393 |
+
if (isset( $values['url'] )) {
|
394 |
+
$intent->setURL($values['url']);
|
395 |
+
}
|
396 |
+
if (isset( $values['hashtags'] )) {
|
397 |
+
$hashtags = array();
|
398 |
+
|
399 |
+
if (is_array($values['hashtags'])) {
|
400 |
+
$hashtags = $values['hashtags'];
|
401 |
+
} else {
|
402 |
+
$hashtags = explode(',', $values['hashtags']);
|
403 |
+
}
|
404 |
+
|
405 |
+
if (! empty( $hashtags )) {
|
406 |
+
array_walk($hashtags, array( $intent, 'addHashtag' ));
|
407 |
+
}
|
408 |
+
|
409 |
+
unset( $hashtags );
|
410 |
+
}
|
411 |
+
if (isset( $values['via'] )) {
|
412 |
+
$intent->setVia($values['via']);
|
413 |
+
}
|
414 |
+
if (isset( $values['related'] )) {
|
415 |
+
$related = array();
|
416 |
+
|
417 |
+
if (is_array($values['related'])) {
|
418 |
+
$related = $values['related'];
|
419 |
+
} elseif (is_string($values['related'])) {
|
420 |
+
$related_accounts = explode(',', $values['related']);
|
421 |
+
foreach ($related_accounts as $related_account) {
|
422 |
+
// extract the label
|
423 |
+
$account_pieces = explode(':', $related_account, 2);
|
424 |
+
$related[ $account_pieces[0] ] = ( isset( $account_pieces[1] ) ? rawurldecode($account_pieces[1]) : '' );
|
425 |
+
unset( $account_pieces );
|
426 |
+
}
|
427 |
+
}
|
428 |
+
|
429 |
+
if (! empty( $related )) {
|
430 |
+
foreach ($related as $username => $label) {
|
431 |
+
if (! ( is_string($username) && $username )) {
|
432 |
+
continue;
|
433 |
+
}
|
434 |
+
|
435 |
+
$intent->addRelated($username, $label);
|
436 |
+
}
|
437 |
+
}
|
438 |
+
|
439 |
+
unset( $related );
|
440 |
+
}
|
441 |
+
|
442 |
+
return $intent;
|
443 |
+
}
|
444 |
+
|
445 |
+
/**
|
446 |
+
* Convert parameters into an array prepped for use in query parameters (underscores) or data-* attributes (dashed)
|
447 |
+
*
|
448 |
+
* @since 1.0.0
|
449 |
+
*
|
450 |
+
* @return array Tweet parameters {
|
451 |
+
* @type string Tweet parameter
|
452 |
+
* @type string parameter value
|
453 |
+
* }
|
454 |
+
*/
|
455 |
+
public function toQueryParameters()
|
456 |
+
{
|
457 |
+
$data = array();
|
458 |
+
|
459 |
+
if ($this->in_reply_to) {
|
460 |
+
$data['in_reply_to'] = $this->in_reply_to;
|
461 |
+
}
|
462 |
+
if ($this->text) {
|
463 |
+
$data['text'] = $this->text;
|
464 |
+
}
|
465 |
+
if ($this->url) {
|
466 |
+
$data['url'] = $this->url;
|
467 |
+
}
|
468 |
+
|
469 |
+
$hashtags = $this->getHashtags();
|
470 |
+
if (! empty( $hashtags )) {
|
471 |
+
$data['hashtags'] = implode(',', $hashtags);
|
472 |
+
}
|
473 |
+
unset( $hashtags );
|
474 |
+
|
475 |
+
if ($this->via) {
|
476 |
+
$data['via'] = $this->via;
|
477 |
+
}
|
478 |
+
|
479 |
+
if (! empty( $this->related )) {
|
480 |
+
$related_value = array();
|
481 |
+
foreach ($this->related as $username => $label) {
|
482 |
+
if ($label) {
|
483 |
+
$related_value[] = $username . ':' . $label;
|
484 |
+
} else {
|
485 |
+
$related_value[] = $username;
|
486 |
+
}
|
487 |
+
}
|
488 |
+
$data['related'] = implode(',', $related_value);
|
489 |
+
unset( $related_value );
|
490 |
+
}
|
491 |
+
|
492 |
+
return $data;
|
493 |
+
}
|
494 |
+
|
495 |
+
/**
|
496 |
+
* Tweet intent URL
|
497 |
+
*
|
498 |
+
* @since 1.0.0
|
499 |
+
*
|
500 |
+
* @return string Tweet intent URL with query parameters
|
501 |
+
*/
|
502 |
+
public function getIntentURL()
|
503 |
+
{
|
504 |
+
$query_parameters = $this->toQueryParameters();
|
505 |
+
|
506 |
+
if (! empty( $query_parameters )) {
|
507 |
+
return self::INTENT_URL . '?' . http_build_query($query_parameters, '', '&', PHP_QUERY_RFC3986);
|
508 |
+
}
|
509 |
+
|
510 |
+
return self::INTENT_URL;
|
511 |
+
}
|
512 |
+
}
|
src/Twitter/Widgets/BaseWidget.php
ADDED
@@ -0,0 +1,148 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\Widgets;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Base properties used across all Twitter widgets
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
abstract class BaseWidget
|
34 |
+
{
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Opt out of tailoring content and suggestions for Twitter users
|
38 |
+
*
|
39 |
+
* @since 1.0.0
|
40 |
+
*
|
41 |
+
* @link https://support.twitter.com/articles/20169421 About tailored suggestions
|
42 |
+
*
|
43 |
+
* @type bool
|
44 |
+
*/
|
45 |
+
protected $dnt = false;
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Requested language for translatable strings in the widget
|
49 |
+
*
|
50 |
+
* @since 1.0.0
|
51 |
+
*
|
52 |
+
* @type string
|
53 |
+
*/
|
54 |
+
protected $lang;
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Opt-out of tailoring content and suggestions for Twitter users
|
58 |
+
*
|
59 |
+
* @since 1.0.0
|
60 |
+
*
|
61 |
+
* @return __CLASS__ support chaining
|
62 |
+
*/
|
63 |
+
public function doNotTrack()
|
64 |
+
{
|
65 |
+
$this->dnt = true;
|
66 |
+
return $this;
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Reset the do not track preference back to its default state: false
|
71 |
+
*
|
72 |
+
* @since 1.0.0
|
73 |
+
*
|
74 |
+
* @return __CLASS__ support chaining
|
75 |
+
*/
|
76 |
+
public function allowTracking()
|
77 |
+
{
|
78 |
+
$this->dnt = false;
|
79 |
+
return $this;
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Explicitly set a Twitter-supported language code for translatable strings in a button or widget
|
84 |
+
*
|
85 |
+
* @since 1.0.0
|
86 |
+
*
|
87 |
+
* @uses \Twitter\Widgets\Language::isSupportedLanguage verify language parameter before saving
|
88 |
+
*
|
89 |
+
* @param string $lang Twitter-supported language code
|
90 |
+
*
|
91 |
+
* @return __CLASS__ support chaining
|
92 |
+
*/
|
93 |
+
public function setLanguage($lang)
|
94 |
+
{
|
95 |
+
if ($lang && \Twitter\Widgets\Language::isSupportedLanguage($lang)) {
|
96 |
+
$this->lang = $lang;
|
97 |
+
}
|
98 |
+
|
99 |
+
return $this;
|
100 |
+
}
|
101 |
+
|
102 |
+
/**
|
103 |
+
* Populate BaseWidget options from a passed associative array
|
104 |
+
*
|
105 |
+
* @since 1.0.0
|
106 |
+
*
|
107 |
+
* @param array $options associative array of options {
|
108 |
+
* @type string option name
|
109 |
+
* @type string|int|bool option value
|
110 |
+
* }
|
111 |
+
*
|
112 |
+
* @return __CLASS__ support chaining
|
113 |
+
*/
|
114 |
+
public function setBaseOptions($options)
|
115 |
+
{
|
116 |
+
if (isset( $options['dnt'] ) && ( true === $options['dnt'] || 'true' === $options['dnt'] || 'on' === $options['dnt'] || 1 == $options['dnt'] )) {
|
117 |
+
$this->doNotTrack();
|
118 |
+
}
|
119 |
+
|
120 |
+
if (isset( $options['lang'] ) && $options['lang']) {
|
121 |
+
$this->setLanguage($options['lang']);
|
122 |
+
}
|
123 |
+
|
124 |
+
return $this;
|
125 |
+
}
|
126 |
+
|
127 |
+
/**
|
128 |
+
* Convert the class object into an array, removing default field values
|
129 |
+
*
|
130 |
+
* @since 1.0.0
|
131 |
+
*
|
132 |
+
* @return array properties as associative array
|
133 |
+
*/
|
134 |
+
public function toArray()
|
135 |
+
{
|
136 |
+
$data = array();
|
137 |
+
|
138 |
+
if (true === $this->dnt) {
|
139 |
+
$data['dnt'] = 'true';
|
140 |
+
}
|
141 |
+
|
142 |
+
if ($this->lang) {
|
143 |
+
$data['lang'] = $this->lang;
|
144 |
+
}
|
145 |
+
|
146 |
+
return $data;
|
147 |
+
}
|
148 |
+
}
|
src/Twitter/Widgets/FollowButton.php
ADDED
@@ -0,0 +1,288 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\Widgets;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Follow button markup to be interpreted by Twitter's widget JavaScript
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*
|
33 |
+
* @link https://dev.twitter.com/web/follow-button Follow button documentation
|
34 |
+
*/
|
35 |
+
class FollowButton extends BaseWidget
|
36 |
+
{
|
37 |
+
|
38 |
+
/**
|
39 |
+
* HTML class expected by the Twitter widget JS
|
40 |
+
*
|
41 |
+
* @since 1.0.0
|
42 |
+
*
|
43 |
+
* @type string
|
44 |
+
*/
|
45 |
+
const HTML_CLASS = 'twitter-follow-button';
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Allowed values for the size property
|
49 |
+
*
|
50 |
+
* @since 1.0.0
|
51 |
+
*
|
52 |
+
* @type array allowed sizes {
|
53 |
+
* @type string size
|
54 |
+
* @type bool exists
|
55 |
+
* }
|
56 |
+
*/
|
57 |
+
public static $ALLOWED_SIZES = array( 'medium' => true, 'large' => true );
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Show the current number of followers alongside the button
|
61 |
+
*
|
62 |
+
* @since 1.0.0
|
63 |
+
*
|
64 |
+
* @type bool
|
65 |
+
*/
|
66 |
+
protected $show_count = true;
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Follow Web Intent
|
70 |
+
*
|
71 |
+
* @since 1.0.0
|
72 |
+
*
|
73 |
+
* @type \Twitter\Intents\Follow
|
74 |
+
*/
|
75 |
+
protected $intent;
|
76 |
+
|
77 |
+
/**
|
78 |
+
* Show or hide the screen name of the account
|
79 |
+
*
|
80 |
+
* @since 1.0.0
|
81 |
+
*
|
82 |
+
* @type bool
|
83 |
+
*/
|
84 |
+
protected $show_screen_name = true;
|
85 |
+
|
86 |
+
/**
|
87 |
+
* Size of the button
|
88 |
+
*
|
89 |
+
* @since 1.0.0
|
90 |
+
*
|
91 |
+
* @type string
|
92 |
+
*/
|
93 |
+
protected $size;
|
94 |
+
|
95 |
+
/**
|
96 |
+
* Require screen name. Initialize Follow Web Intent
|
97 |
+
*
|
98 |
+
* @since 1.0.0
|
99 |
+
*
|
100 |
+
* @param string $screen_name Twitter account name
|
101 |
+
* @param bool $validate validate screen name matches Twitter username allowed characters and length before saving
|
102 |
+
*/
|
103 |
+
public function __construct($screen_name, $validate = true)
|
104 |
+
{
|
105 |
+
$this->intent = new \Twitter\Intents\Follow($screen_name, $validate);
|
106 |
+
}
|
107 |
+
|
108 |
+
/**
|
109 |
+
* Show the number of followers alongside the Follow button
|
110 |
+
*
|
111 |
+
* @since 1.0.0
|
112 |
+
*
|
113 |
+
* @return __CLASS__ support chaining
|
114 |
+
*/
|
115 |
+
public function showCount()
|
116 |
+
{
|
117 |
+
$this->show_count = true;
|
118 |
+
return $this;
|
119 |
+
}
|
120 |
+
|
121 |
+
/**
|
122 |
+
* Show only the Follow button, without a follower count
|
123 |
+
*
|
124 |
+
* @since 1.0.0
|
125 |
+
*
|
126 |
+
* @return __CLASS__ support chaining
|
127 |
+
*/
|
128 |
+
public function hideCount()
|
129 |
+
{
|
130 |
+
$this->show_count = false;
|
131 |
+
return $this;
|
132 |
+
}
|
133 |
+
|
134 |
+
/**
|
135 |
+
* Return the screen name of the Twitter user
|
136 |
+
*
|
137 |
+
* @since 1.0.0
|
138 |
+
*
|
139 |
+
* @return string Twitter screen name, or blank string if no screen name stored
|
140 |
+
*/
|
141 |
+
public function getScreenName()
|
142 |
+
{
|
143 |
+
return $this->intent->getScreenName();
|
144 |
+
}
|
145 |
+
|
146 |
+
/**
|
147 |
+
* Show the screen name to follow inside the Follow button
|
148 |
+
*
|
149 |
+
* @since 1.0.0
|
150 |
+
*
|
151 |
+
* @return __CLASS__ support chaining
|
152 |
+
*/
|
153 |
+
public function showScreenName()
|
154 |
+
{
|
155 |
+
$this->show_screen_name = true;
|
156 |
+
return $this;
|
157 |
+
}
|
158 |
+
|
159 |
+
/**
|
160 |
+
* Hide the screen name from display inside the Follow button
|
161 |
+
*
|
162 |
+
* @since 1.0.0
|
163 |
+
*
|
164 |
+
* @return __CLASS__ support chaining
|
165 |
+
*/
|
166 |
+
public function hideScreenName()
|
167 |
+
{
|
168 |
+
$this->show_screen_name = false;
|
169 |
+
return $this;
|
170 |
+
}
|
171 |
+
|
172 |
+
/**
|
173 |
+
* Set the desired size of the Follow button
|
174 |
+
*
|
175 |
+
* @since 1.0.0
|
176 |
+
*
|
177 |
+
* @param string $size button size
|
178 |
+
*
|
179 |
+
* @return __CLASS__ support chaining
|
180 |
+
*/
|
181 |
+
public function setSize($size)
|
182 |
+
{
|
183 |
+
if ($size && isset(static::$ALLOWED_SIZES[$size])) {
|
184 |
+
$this->size = $size;
|
185 |
+
}
|
186 |
+
return $this;
|
187 |
+
}
|
188 |
+
|
189 |
+
|
190 |
+
/**
|
191 |
+
* Build a Follow button object from an associative array
|
192 |
+
*
|
193 |
+
* @since 1.0.0
|
194 |
+
*
|
195 |
+
* @param array $options associative array of options {
|
196 |
+
* @type string option name
|
197 |
+
* @type string|int|bool option value
|
198 |
+
* }
|
199 |
+
*
|
200 |
+
* @return __CLASS__ support chaining
|
201 |
+
*/
|
202 |
+
public static function fromArray($options)
|
203 |
+
{
|
204 |
+
if (! isset( $options['screen_name'] ) && $options['screen_name']) {
|
205 |
+
return;
|
206 |
+
}
|
207 |
+
|
208 |
+
$class = __CLASS__;
|
209 |
+
$follow = new $class( $options['screen_name'] );
|
210 |
+
unset( $class );
|
211 |
+
|
212 |
+
$follow->setBaseOptions($options);
|
213 |
+
|
214 |
+
if (isset( $options['show_count'] ) && ( false === $options['show_count'] || 'false' === $options['show_count'] || 0 == $options['show_count'] )) {
|
215 |
+
$follow->hideCount();
|
216 |
+
}
|
217 |
+
if (isset( $options['show_screen_name'] ) && ( false === $options['show_screen_name'] || 'false' === $options['show_screen_name'] || 0 == $options['show_screen_name'] )) {
|
218 |
+
$follow->hideScreenName();
|
219 |
+
}
|
220 |
+
|
221 |
+
if (isset( $options['size'] ) && 'medium' !== $options['size']) {
|
222 |
+
$follow->setSize($options['size']);
|
223 |
+
}
|
224 |
+
|
225 |
+
return $follow;
|
226 |
+
}
|
227 |
+
|
228 |
+
/**
|
229 |
+
* Convert the class object into an array, removing default field values
|
230 |
+
*
|
231 |
+
* @since 1.0.0
|
232 |
+
*
|
233 |
+
* @return array properties as associative array
|
234 |
+
*/
|
235 |
+
public function toArray()
|
236 |
+
{
|
237 |
+
$data = parent::toArray();
|
238 |
+
|
239 |
+
if (false === $this->show_screen_name) {
|
240 |
+
$data['show-screen-name'] = 'false';
|
241 |
+
}
|
242 |
+
if (false === $this->show_count) {
|
243 |
+
$data['show-count'] = 'false';
|
244 |
+
}
|
245 |
+
if ($this->size && 'medium' !== $this->size) {
|
246 |
+
$data['size'] = $this->size;
|
247 |
+
}
|
248 |
+
|
249 |
+
return $data;
|
250 |
+
}
|
251 |
+
|
252 |
+
/**
|
253 |
+
* Generate HTML to encourage follow behavior and expose data to the Twitter for Websites JavaScript
|
254 |
+
*
|
255 |
+
* @since 1.0.0
|
256 |
+
*
|
257 |
+
* @param string $anchor_text inner text of the generated anchor element. Supports a single '%s' screen name passed through sprintf. Default: Follow %s
|
258 |
+
* @param string $html_builder_class callable HTML builder with a static anchorElement class
|
259 |
+
*
|
260 |
+
* @return string HTML markup or empty string if minimum requirements not met
|
261 |
+
*/
|
262 |
+
public function toHTML($anchor_text = 'Follow %s', $html_builder_class = '\Twitter\Helpers\HTMLBuilder')
|
263 |
+
{
|
264 |
+
if (! ( is_string($anchor_text) && $anchor_text )) {
|
265 |
+
return '';
|
266 |
+
}
|
267 |
+
|
268 |
+
// test for invalid passed class
|
269 |
+
if (! ( class_exists($html_builder_class) && method_exists($html_builder_class, 'anchorElement') )) {
|
270 |
+
return '';
|
271 |
+
}
|
272 |
+
|
273 |
+
$intent_url = $this->intent->getIntentURL();
|
274 |
+
// no screen name stored
|
275 |
+
if (! $intent_url) {
|
276 |
+
return '';
|
277 |
+
}
|
278 |
+
|
279 |
+
return $html_builder_class::anchorElement(
|
280 |
+
$intent_url,
|
281 |
+
sprintf($anchor_text, '@' . $this->getScreenName()),
|
282 |
+
array(
|
283 |
+
'class' => static::HTML_CLASS,
|
284 |
+
),
|
285 |
+
$this->toArray()
|
286 |
+
);
|
287 |
+
}
|
288 |
+
}
|
src/Twitter/Widgets/Language.php
ADDED
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\Widgets;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Languages supported by Twitter for Websites widgets
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*
|
33 |
+
* @link https://dev.twitter.com/rest/reference/get/help/languages list of supported languages
|
34 |
+
*/
|
35 |
+
class Language
|
36 |
+
{
|
37 |
+
/**
|
38 |
+
* A list of languages supported by Twitter in production
|
39 |
+
*
|
40 |
+
* @since 1.0.0
|
41 |
+
*
|
42 |
+
* @type array language code => english name
|
43 |
+
*/
|
44 |
+
public static $SUPPORTED_LANGUAGES = array(
|
45 |
+
'ar' => 'Arabic',
|
46 |
+
'bn' => 'Bengali',
|
47 |
+
'cs' => 'Czech',
|
48 |
+
'da' => 'Danish',
|
49 |
+
'de' => 'German',
|
50 |
+
'en' => 'English',
|
51 |
+
'es' => 'Spanish',
|
52 |
+
'fa' => 'Farsi',
|
53 |
+
'fi' => 'Finnish',
|
54 |
+
'fil' => 'Filipino',
|
55 |
+
'fr' => 'French',
|
56 |
+
'he' => 'Hebrew',
|
57 |
+
'hi' => 'Hindi',
|
58 |
+
'hu' => 'Hungarian',
|
59 |
+
'id' => 'Indonesian',
|
60 |
+
'it' => 'Italian',
|
61 |
+
'ja' => 'Japanese',
|
62 |
+
'ko' => 'Korean',
|
63 |
+
'msa' => 'Malay',
|
64 |
+
'nl' => 'Dutch',
|
65 |
+
'no' => 'Norwegian',
|
66 |
+
'pl' => 'Polish',
|
67 |
+
'pt' => 'Portuguese',
|
68 |
+
'ro' => 'Romanian',
|
69 |
+
'ru' => 'Russian',
|
70 |
+
'sv' => 'Swedish',
|
71 |
+
'th' => 'Thai',
|
72 |
+
'tr' => 'Turkish',
|
73 |
+
'ur' => 'Urdu',
|
74 |
+
'vi' => 'Vietnamese',
|
75 |
+
'zh-cn' => 'Simplified Chinese',
|
76 |
+
'zh-tw' => 'Traditional Chinese',
|
77 |
+
);
|
78 |
+
|
79 |
+
/**
|
80 |
+
* Is the passed language a valid Twitter production language code?
|
81 |
+
*
|
82 |
+
* @since 1.0.0
|
83 |
+
*
|
84 |
+
* @return bool true if passed language exists in list of Twitter production language codes
|
85 |
+
*/
|
86 |
+
public static function isSupportedLanguage($lang)
|
87 |
+
{
|
88 |
+
return ( is_string($lang) && $lang && isset(static::$SUPPORTED_LANGUAGES[$lang]) );
|
89 |
+
}
|
90 |
+
}
|
src/Twitter/Widgets/TweetButton.php
ADDED
@@ -0,0 +1,460 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\Widgets;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Tweet button markup to be interpreted by Twitter's widget JavaScript
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*
|
33 |
+
* @link https://dev.twitter.com/web/tweet-button Tweet button documentation
|
34 |
+
*/
|
35 |
+
class TweetButton extends BaseWidget
|
36 |
+
{
|
37 |
+
|
38 |
+
/**
|
39 |
+
* HTML class expected by the Twitter widget JS
|
40 |
+
*
|
41 |
+
* @since 1.0.0
|
42 |
+
*
|
43 |
+
* @type string
|
44 |
+
*/
|
45 |
+
const HTML_CLASS = 'twitter-share-button';
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Class name of the stored web intent
|
49 |
+
*
|
50 |
+
* @since 1.0.0
|
51 |
+
*
|
52 |
+
* @type string
|
53 |
+
*/
|
54 |
+
const INTENT_CLASS = '\Twitter\Intents\Tweet';
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Allowed values for the count variable
|
58 |
+
*
|
59 |
+
* @since 1.0.0
|
60 |
+
*
|
61 |
+
* @type array allowed values {
|
62 |
+
* @type string count value
|
63 |
+
* @type bool exists
|
64 |
+
* }
|
65 |
+
*/
|
66 |
+
public static $ALLOWED_COUNT_VALUES = array(
|
67 |
+
'' => true, // reset to default (horizontal)
|
68 |
+
'none' => true, // hide Tweet count
|
69 |
+
'vertical' => true, // display above Tweet button
|
70 |
+
);
|
71 |
+
|
72 |
+
/**
|
73 |
+
* Allowed values for the align variable
|
74 |
+
*
|
75 |
+
* @since 1.0.0
|
76 |
+
*
|
77 |
+
* @type array allowed values {
|
78 |
+
* @type string align value
|
79 |
+
* @type bool exists
|
80 |
+
* }
|
81 |
+
*/
|
82 |
+
public static $ALLOWED_ALIGN_VALUES = array(
|
83 |
+
'left' => true,
|
84 |
+
'right' => true,
|
85 |
+
);
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Tweet Web Intent
|
89 |
+
*
|
90 |
+
* @since 1.0.0
|
91 |
+
*
|
92 |
+
* @type \Twitter\Intents\Tweet
|
93 |
+
*/
|
94 |
+
protected $intent;
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Size of the Tweet button
|
98 |
+
*
|
99 |
+
* Large is currently the only supported size.
|
100 |
+
*
|
101 |
+
* @since 1.0.0
|
102 |
+
*
|
103 |
+
* @type string
|
104 |
+
*/
|
105 |
+
protected $size;
|
106 |
+
|
107 |
+
/**
|
108 |
+
* Show the number of Tweets mentioning this URL
|
109 |
+
*
|
110 |
+
* @since 1.0.0
|
111 |
+
*
|
112 |
+
* @type string
|
113 |
+
*/
|
114 |
+
protected $count = '';
|
115 |
+
|
116 |
+
/**
|
117 |
+
* URL to use for Tweet count purposes
|
118 |
+
*
|
119 |
+
* Count should also be true for the URL used for the count to affect the button
|
120 |
+
*
|
121 |
+
* @since 1.0.0
|
122 |
+
*
|
123 |
+
* @type string
|
124 |
+
*/
|
125 |
+
protected $counturl;
|
126 |
+
|
127 |
+
/**
|
128 |
+
* Force align the button to the left or right of the generated iframe
|
129 |
+
*
|
130 |
+
* @since 1.0.0
|
131 |
+
*
|
132 |
+
* @type string
|
133 |
+
*/
|
134 |
+
protected $align;
|
135 |
+
|
136 |
+
/**
|
137 |
+
* Create a new button. Initialize the web intent.
|
138 |
+
*
|
139 |
+
* @since 1.0.0
|
140 |
+
*
|
141 |
+
* @param bool $validate Validate inputs such as screen
|
142 |
+
*/
|
143 |
+
public function __construct($validate = true)
|
144 |
+
{
|
145 |
+
$intent_class = static::INTENT_CLASS;
|
146 |
+
$this->intent = new $intent_class();
|
147 |
+
if (! $validate) {
|
148 |
+
$this->intent->disableValidation();
|
149 |
+
}
|
150 |
+
}
|
151 |
+
|
152 |
+
/**
|
153 |
+
* Set a new intent
|
154 |
+
*
|
155 |
+
* @since 1.0.0
|
156 |
+
*
|
157 |
+
* @param \Twitter\Intents\Tweet $intent Tweet Intent
|
158 |
+
*
|
159 |
+
* @return __CLASS__ support chaining
|
160 |
+
*/
|
161 |
+
public function setIntent($intent)
|
162 |
+
{
|
163 |
+
if (is_a($intent, self::INTENT_CLASS)) {
|
164 |
+
$this->intent = $intent;
|
165 |
+
}
|
166 |
+
|
167 |
+
return $this;
|
168 |
+
}
|
169 |
+
|
170 |
+
/**
|
171 |
+
* Set the size of the Tweet button
|
172 |
+
*
|
173 |
+
* @since 1.0.0
|
174 |
+
*
|
175 |
+
* @param string $size button size
|
176 |
+
*
|
177 |
+
* @return __CLASS__ support chaining
|
178 |
+
*/
|
179 |
+
public function setSize($size)
|
180 |
+
{
|
181 |
+
// only one size override supported
|
182 |
+
if ('large' === $size) {
|
183 |
+
$this->size = $size;
|
184 |
+
}
|
185 |
+
return $this;
|
186 |
+
}
|
187 |
+
|
188 |
+
/**
|
189 |
+
* Show the Tweet count next to the Tweet button
|
190 |
+
*
|
191 |
+
* @since 1.0.0
|
192 |
+
*
|
193 |
+
* @param string $count a valid count value
|
194 |
+
*
|
195 |
+
* @return __CLASS__ support chaining
|
196 |
+
*/
|
197 |
+
public function setCount($count)
|
198 |
+
{
|
199 |
+
if (is_string($count) && isset(static::$ALLOWED_COUNT_VALUES[$count])) {
|
200 |
+
$this->count = $count;
|
201 |
+
}
|
202 |
+
|
203 |
+
return $this;
|
204 |
+
}
|
205 |
+
|
206 |
+
/**
|
207 |
+
* Set the URL used for Tweet counts
|
208 |
+
*
|
209 |
+
* @since 1.0.0
|
210 |
+
*
|
211 |
+
* @param string $url absolute URL to be used for Tweet count
|
212 |
+
*
|
213 |
+
* @return __CLASS__ support chaining
|
214 |
+
*/
|
215 |
+
public function setCountURL($url)
|
216 |
+
{
|
217 |
+
$url = trim($url);
|
218 |
+
if ($url) {
|
219 |
+
if ($this->intent->shouldValidate()) {
|
220 |
+
if ($this->intent->isHTTPURL($url)) {
|
221 |
+
$this->counturl = $url;
|
222 |
+
}
|
223 |
+
} else {
|
224 |
+
$this->counturl = $url;
|
225 |
+
}
|
226 |
+
}
|
227 |
+
|
228 |
+
return $this;
|
229 |
+
}
|
230 |
+
|
231 |
+
/**
|
232 |
+
* Force the alignment of the button inside the iframe
|
233 |
+
*
|
234 |
+
* @since 1.0.0
|
235 |
+
*
|
236 |
+
* @param string $align left|right
|
237 |
+
*
|
238 |
+
* @return __CLASS__ support chaining
|
239 |
+
*/
|
240 |
+
public function setAlign($align)
|
241 |
+
{
|
242 |
+
if (isset(static::$ALLOWED_ALIGN_VALUES[$align])) {
|
243 |
+
$this->align = $align;
|
244 |
+
}
|
245 |
+
|
246 |
+
return $this;
|
247 |
+
}
|
248 |
+
|
249 |
+
/**
|
250 |
+
* Define a parent Tweet by ID
|
251 |
+
*
|
252 |
+
* @since 1.0.0
|
253 |
+
*
|
254 |
+
* @param string $tweet_id Parent Tweet ID
|
255 |
+
*
|
256 |
+
* @return __CLASS__ support chaining
|
257 |
+
*/
|
258 |
+
public function setInReplyTo($tweet_id)
|
259 |
+
{
|
260 |
+
$this->intent->setInReplyTo($tweet_id);
|
261 |
+
|
262 |
+
return $this;
|
263 |
+
}
|
264 |
+
|
265 |
+
/**
|
266 |
+
* Pre-populate Tweet text
|
267 |
+
*
|
268 |
+
* @since 1.0.0
|
269 |
+
*
|
270 |
+
* @param string $text Tweet text
|
271 |
+
*
|
272 |
+
* @return __CLASS__ support chaining
|
273 |
+
*/
|
274 |
+
public function setText($text)
|
275 |
+
{
|
276 |
+
$this->intent->setText($text);
|
277 |
+
|
278 |
+
return $this;
|
279 |
+
}
|
280 |
+
|
281 |
+
/**
|
282 |
+
* Share a URL
|
283 |
+
*
|
284 |
+
* @since 1.0.0
|
285 |
+
*
|
286 |
+
* @param string $url absolute URL
|
287 |
+
*
|
288 |
+
* @return __CLASS__ support chaining
|
289 |
+
*/
|
290 |
+
public function setURL($url)
|
291 |
+
{
|
292 |
+
$this->intent->setURL($url);
|
293 |
+
|
294 |
+
return $this;
|
295 |
+
}
|
296 |
+
|
297 |
+
/**
|
298 |
+
* Add a hashtag
|
299 |
+
*
|
300 |
+
* @since 1.0.0
|
301 |
+
*
|
302 |
+
* @param string $hashtag hashtag
|
303 |
+
*
|
304 |
+
* @return __CLASS__ support chaining
|
305 |
+
*/
|
306 |
+
public function addHashtag($hashtag)
|
307 |
+
{
|
308 |
+
$this->intent->addHashtag($hashtag);
|
309 |
+
|
310 |
+
return $this;
|
311 |
+
}
|
312 |
+
|
313 |
+
/**
|
314 |
+
* Associate Tweet with a source account
|
315 |
+
*
|
316 |
+
* @since 1.0.0
|
317 |
+
*
|
318 |
+
* @param string $username Twitter username
|
319 |
+
*
|
320 |
+
* @return __CLASS__ support chaining
|
321 |
+
*/
|
322 |
+
public function setVia($username)
|
323 |
+
{
|
324 |
+
$this->intent->setVia($username);
|
325 |
+
}
|
326 |
+
|
327 |
+
/**
|
328 |
+
* Add a related Twitter account
|
329 |
+
*
|
330 |
+
* @since 1.0.0
|
331 |
+
*
|
332 |
+
* @param string $username Twitter username
|
333 |
+
* @param string $label brief description of how the account relates to the Tweet content
|
334 |
+
*
|
335 |
+
* @return __CLASS__ support chaining
|
336 |
+
*/
|
337 |
+
public function addRelated($username, $label = '')
|
338 |
+
{
|
339 |
+
$this->intent->addRelated($username, $label);
|
340 |
+
|
341 |
+
return $this;
|
342 |
+
}
|
343 |
+
|
344 |
+
/**
|
345 |
+
* Create a Tweet button from an associative array
|
346 |
+
*
|
347 |
+
* @param array $options {
|
348 |
+
* @type string parameter name
|
349 |
+
* @type string|int|bool parameter value
|
350 |
+
* }
|
351 |
+
*
|
352 |
+
* @return __CLASS__ new button with configured parameters
|
353 |
+
*/
|
354 |
+
public static function fromArray($options)
|
355 |
+
{
|
356 |
+
if (! is_array($options)) {
|
357 |
+
// initialize a Tweet button with default parameters
|
358 |
+
$options = array();
|
359 |
+
}
|
360 |
+
|
361 |
+
$class = __CLASS__;
|
362 |
+
$button = new $class();
|
363 |
+
unset( $class );
|
364 |
+
|
365 |
+
// remove values which evaluate to false
|
366 |
+
$options = array_filter($options);
|
367 |
+
$button->setBaseOptions($options);
|
368 |
+
|
369 |
+
// intent parameters
|
370 |
+
$intent_class = static::INTENT_CLASS;
|
371 |
+
$button->setIntent($intent_class::fromArray($options));
|
372 |
+
unset( $intent_class );
|
373 |
+
|
374 |
+
// button parameters
|
375 |
+
if (isset( $options['size'] )) {
|
376 |
+
$button->setSize($options['size']);
|
377 |
+
}
|
378 |
+
if (isset( $options['count'] )) {
|
379 |
+
$button->setCount($options['count']);
|
380 |
+
}
|
381 |
+
if (isset( $options['counturl'] )) {
|
382 |
+
$button->setCountURL($options['counturl']);
|
383 |
+
}
|
384 |
+
if (isset( $options['align'] )) {
|
385 |
+
$button->setAlign($options['align']);
|
386 |
+
}
|
387 |
+
|
388 |
+
return $button;
|
389 |
+
}
|
390 |
+
|
391 |
+
/**
|
392 |
+
* Return Tweet button parameters suitable
|
393 |
+
*
|
394 |
+
* @since 1.0.0
|
395 |
+
*
|
396 |
+
* @return array Tweet button parameter array {
|
397 |
+
* @type string dashed parameter name
|
398 |
+
* @type string parameter value
|
399 |
+
* }
|
400 |
+
*/
|
401 |
+
public function toArray()
|
402 |
+
{
|
403 |
+
$data = parent::toArray();
|
404 |
+
|
405 |
+
if ($this->size) {
|
406 |
+
$data['size'] = $this->size;
|
407 |
+
}
|
408 |
+
|
409 |
+
// empty string is default value
|
410 |
+
if ($this->count) {
|
411 |
+
$data['count'] = $this->count;
|
412 |
+
}
|
413 |
+
// only include counturl if a count will be shown
|
414 |
+
if ('none' !== $this->count && $this->counturl) {
|
415 |
+
$data['counturl'] = $this->counturl;
|
416 |
+
}
|
417 |
+
if ($this->align) {
|
418 |
+
$data['align'] = $this->align;
|
419 |
+
}
|
420 |
+
|
421 |
+
return $data;
|
422 |
+
}
|
423 |
+
|
424 |
+
/**
|
425 |
+
* Tweet button HTML
|
426 |
+
*
|
427 |
+
* @since 1.0.0
|
428 |
+
*
|
429 |
+
* @param string $anchor_text inner text of the generated anchor element. Default: Tweet
|
430 |
+
* @param string $html_builder_class callable HTML builder with a static anchorElement class
|
431 |
+
*
|
432 |
+
* @return string HTML markup
|
433 |
+
*/
|
434 |
+
public function toHTML($anchor_text = 'Tweet', $html_builder_class = '\Twitter\Helpers\HTMLBuilder')
|
435 |
+
{
|
436 |
+
if (! ( is_string($anchor_text) && $anchor_text )) {
|
437 |
+
return '';
|
438 |
+
}
|
439 |
+
|
440 |
+
// test for invalid passed class
|
441 |
+
if (! ( class_exists($html_builder_class) && method_exists($html_builder_class, 'anchorElement') )) {
|
442 |
+
return '';
|
443 |
+
}
|
444 |
+
|
445 |
+
$intent_url = $this->intent->getIntentURL();
|
446 |
+
// no screen name stored
|
447 |
+
if (! $intent_url) {
|
448 |
+
return '';
|
449 |
+
}
|
450 |
+
|
451 |
+
return $html_builder_class::anchorElement(
|
452 |
+
$intent_url,
|
453 |
+
$anchor_text,
|
454 |
+
array(
|
455 |
+
'class' => static::HTML_CLASS,
|
456 |
+
),
|
457 |
+
$this->toArray()
|
458 |
+
);
|
459 |
+
}
|
460 |
+
}
|
src/Twitter/WordPress/Admin/Post/MetaBox.php
ADDED
@@ -0,0 +1,242 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Admin\Post;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Post meta box for setting Twitter Card and Tweet text custom values
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class MetaBox
|
34 |
+
{
|
35 |
+
/**
|
36 |
+
* Check page origin before saving
|
37 |
+
*
|
38 |
+
* @since 1.0.0
|
39 |
+
*
|
40 |
+
* @var string
|
41 |
+
*/
|
42 |
+
const NONCE_NAME = 'twitter_custom';
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Attach hooks when the post edit screen loads
|
46 |
+
*
|
47 |
+
* @since 1.0.0
|
48 |
+
*
|
49 |
+
* @return void
|
50 |
+
*/
|
51 |
+
public static function init()
|
52 |
+
{
|
53 |
+
// load meta box hooks on post creation screens
|
54 |
+
foreach ( array( 'post', 'post-new' ) as $hook ) {
|
55 |
+
add_action( 'load-' . $hook . '.php', array( __CLASS__, 'load' ), 1, 0 );
|
56 |
+
}
|
57 |
+
add_action( 'save_post', array( __CLASS__, 'save' ) );
|
58 |
+
}
|
59 |
+
|
60 |
+
/**
|
61 |
+
* Attach meta boxes and save actions to the post edit screen
|
62 |
+
*
|
63 |
+
* @since 1.0.0
|
64 |
+
*
|
65 |
+
* @return void
|
66 |
+
*/
|
67 |
+
public static function load()
|
68 |
+
{
|
69 |
+
add_action( 'wp', array( '\Twitter\WordPress\Admin\Post\TweetIntent', 'registerPostMeta' ), 10, 0 );
|
70 |
+
add_action( 'add_meta_boxes', array( __CLASS__, 'addMetaBox' ), 1, 0 );
|
71 |
+
add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueueScripts' ) );
|
72 |
+
}
|
73 |
+
|
74 |
+
/**
|
75 |
+
* Is the current post type meant for display on the public Web?
|
76 |
+
*
|
77 |
+
* @since 1.0.0
|
78 |
+
*
|
79 |
+
* @param string $post_type WordPress post type
|
80 |
+
*
|
81 |
+
* @return bool true if meant for public viewing and sharing
|
82 |
+
*/
|
83 |
+
public static function isPostTypePublic( $post_type )
|
84 |
+
{
|
85 |
+
if ( ! $post_type ) {
|
86 |
+
return false;
|
87 |
+
}
|
88 |
+
|
89 |
+
$post_type_object = get_post_type_object( $post_type );
|
90 |
+
if ( isset( $post_type_object->public ) && $post_type_object->public ) {
|
91 |
+
return true;
|
92 |
+
}
|
93 |
+
|
94 |
+
return false;
|
95 |
+
}
|
96 |
+
|
97 |
+
/**
|
98 |
+
* Add a post meta box to the post editor page to set custom Twitter values for the post
|
99 |
+
*
|
100 |
+
* @since 1.0.0
|
101 |
+
*
|
102 |
+
* @uses add_meta_box
|
103 |
+
*
|
104 |
+
* @return void
|
105 |
+
*/
|
106 |
+
public static function addMetaBox()
|
107 |
+
{
|
108 |
+
$post = get_post();
|
109 |
+
|
110 |
+
if ( ! ( $post && is_a( $post, 'WP_Post' ) ) ) {
|
111 |
+
return;
|
112 |
+
}
|
113 |
+
|
114 |
+
// is the post type meant to be public?
|
115 |
+
$post_type = get_post_type( $post );
|
116 |
+
if ( ! $post_type ) {
|
117 |
+
return;
|
118 |
+
}
|
119 |
+
$post_type_object = get_post_type_object( $post_type );
|
120 |
+
if ( ! ( isset( $post_type_object->public ) && $post_type_object->public ) ) {
|
121 |
+
return;
|
122 |
+
}
|
123 |
+
|
124 |
+
add_meta_box(
|
125 |
+
'twitter-custom',
|
126 |
+
_x( 'Twitter Custom Text', 'Text displayed for a Twitter audience', 'twitter' ),
|
127 |
+
array( __CLASS__, 'content' ),
|
128 |
+
$post_type
|
129 |
+
);
|
130 |
+
}
|
131 |
+
|
132 |
+
/**
|
133 |
+
* Queue JS and CSS resources for use on the page
|
134 |
+
*
|
135 |
+
* @since 1.0.0
|
136 |
+
*
|
137 |
+
* @return void
|
138 |
+
*/
|
139 |
+
public static function enqueueScripts()
|
140 |
+
{
|
141 |
+
wp_enqueue_style(
|
142 |
+
'twitter-admin-edit-post', // handle
|
143 |
+
plugins_url(
|
144 |
+
'static/css/admin/post/edit.min.css',
|
145 |
+
\Twitter\WordPress\PluginLoader::getPluginMainFile()
|
146 |
+
), // absolute URI
|
147 |
+
array(), // no dependencies
|
148 |
+
'1.0.0' // last chance. used for caching
|
149 |
+
);
|
150 |
+
}
|
151 |
+
|
152 |
+
/**
|
153 |
+
* Display meta box content
|
154 |
+
*
|
155 |
+
* @since 1.0.0
|
156 |
+
*
|
157 |
+
* @param WP_Post $post WordPress post object
|
158 |
+
*
|
159 |
+
* @return void
|
160 |
+
*/
|
161 |
+
public static function content( $post )
|
162 |
+
{
|
163 |
+
// Use nonce for verification
|
164 |
+
wp_nonce_field( plugin_basename( __FILE__ ), self::NONCE_NAME );
|
165 |
+
|
166 |
+
\Twitter\WordPress\Admin\Post\TweetIntent::metaBoxContent();
|
167 |
+
\Twitter\WordPress\Admin\Post\TwitterCard::metaBoxContent();
|
168 |
+
}
|
169 |
+
|
170 |
+
/**
|
171 |
+
* Get post capability singular base to be used when gating access.
|
172 |
+
*
|
173 |
+
* @since 1.0.0
|
174 |
+
*
|
175 |
+
* @param string $post_type post type
|
176 |
+
*
|
177 |
+
* @return string post type object capability type or empty string
|
178 |
+
*/
|
179 |
+
public static function postTypeCapabilityBase( $post_type )
|
180 |
+
{
|
181 |
+
$post_type_object = get_post_type_object( $post_type );
|
182 |
+
|
183 |
+
if ( ! isset( $post_type_object->capability_type ) ) {
|
184 |
+
return '';
|
185 |
+
}
|
186 |
+
|
187 |
+
$capability_singular_base = '';
|
188 |
+
if ( is_string( $post_type_object->capability_type ) ) {
|
189 |
+
$capability_singular_base = $post_type_object->capability_type;
|
190 |
+
} else if ( is_array( $post_type_object->capability_type ) ) {
|
191 |
+
if ( isset( $post_type_object->capability_type[0] ) ) {
|
192 |
+
$capability_singular_base = $post_type_object->capability_type[0];
|
193 |
+
}
|
194 |
+
}
|
195 |
+
return $capability_singular_base;
|
196 |
+
}
|
197 |
+
|
198 |
+
/**
|
199 |
+
* Save custom values entered in the post edit screen
|
200 |
+
*
|
201 |
+
* @since 1.0.0
|
202 |
+
*
|
203 |
+
* @param int $post_id WordPress post identifier
|
204 |
+
*
|
205 |
+
* @return void
|
206 |
+
*/
|
207 |
+
public static function save( $post_id )
|
208 |
+
{
|
209 |
+
// verify if this is an auto save routine
|
210 |
+
// do not take action until the form is submitted
|
211 |
+
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
|
212 |
+
return;
|
213 |
+
}
|
214 |
+
|
215 |
+
// verify nonce
|
216 |
+
if ( empty( $_POST[ self::NONCE_NAME ] ) || ! wp_verify_nonce( $_POST[ self::NONCE_NAME ], plugin_basename( __FILE__ ) ) ) {
|
217 |
+
return;
|
218 |
+
}
|
219 |
+
|
220 |
+
if ( ! $post_id ) {
|
221 |
+
return;
|
222 |
+
}
|
223 |
+
// does post exist?
|
224 |
+
$post = get_post( $post_id );
|
225 |
+
if ( ! $post ) {
|
226 |
+
return;
|
227 |
+
}
|
228 |
+
|
229 |
+
// check permissions
|
230 |
+
$post_type = get_post_type( $post );
|
231 |
+
if ( ! $post_type ) {
|
232 |
+
return;
|
233 |
+
}
|
234 |
+
$capability_singular_base = static::postTypeCapabilityBase( $post_type );
|
235 |
+
if ( ! ( $capability_singular_base && current_user_can( 'edit_' . $capability_singular_base, $post_id ) ) ) {
|
236 |
+
return;
|
237 |
+
}
|
238 |
+
|
239 |
+
\Twitter\WordPress\Admin\Post\TweetIntent::save( $post );
|
240 |
+
\Twitter\WordPress\Admin\Post\TwitterCard::save( $post );
|
241 |
+
}
|
242 |
+
}
|
src/Twitter/WordPress/Admin/Post/TweetIntent.php
ADDED
@@ -0,0 +1,296 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Admin\Post;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Store custom Tweet Intent data for a WordPress post
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class TweetIntent
|
34 |
+
{
|
35 |
+
/**
|
36 |
+
* Meta field key used to store custom Tweet Intent data
|
37 |
+
*
|
38 |
+
* @since 1.0.0
|
39 |
+
*
|
40 |
+
* @type string
|
41 |
+
*/
|
42 |
+
const META_KEY = 'twitter_share';
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Associative array key representing the hashtags CSV value inside the META_KEY array
|
46 |
+
*
|
47 |
+
* @since 1.0.0
|
48 |
+
*
|
49 |
+
* @type string
|
50 |
+
*/
|
51 |
+
const HASHTAGS_KEY = 'hashtags';
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Associative array key representing the Tweet text string inside META_KEY array
|
55 |
+
*
|
56 |
+
* @since 1.0.0
|
57 |
+
*
|
58 |
+
* @type string
|
59 |
+
*/
|
60 |
+
const TEXT_KEY = 'text';
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Register the post meta key and its sanizitzer
|
64 |
+
*
|
65 |
+
* Used by WordPress JSON API to expose programmatic editor beyond the post meta box display used in the HTML-based admin interface
|
66 |
+
*
|
67 |
+
* @since 1.0.0
|
68 |
+
* @uses register_meta
|
69 |
+
*
|
70 |
+
* @return void
|
71 |
+
*/
|
72 |
+
public static function registerPostMeta()
|
73 |
+
{
|
74 |
+
register_meta(
|
75 |
+
'post',
|
76 |
+
static::META_KEY,
|
77 |
+
array( __CLASS__, 'sanitizeFields' )
|
78 |
+
);
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Get a Twitter configuration object for up-to-date character counts for a wrapped URL
|
83 |
+
*
|
84 |
+
* Hard coded in this plugin to avoid requiring Twitter application credentials
|
85 |
+
* Implementing sites may want to override this function with a cached value from Twitter's help/configuration API response
|
86 |
+
*
|
87 |
+
* @since 1.0.0
|
88 |
+
*
|
89 |
+
* @return object object with short_url_length and optional short_url_length_https properties
|
90 |
+
*/
|
91 |
+
public static function getTwitterConfiguration()
|
92 |
+
{
|
93 |
+
$config = new \stdClass();
|
94 |
+
$config->short_url_length = 22;
|
95 |
+
$config->short_url_length_https = $config->short_url_length + 1;
|
96 |
+
|
97 |
+
return $config;
|
98 |
+
}
|
99 |
+
|
100 |
+
/**
|
101 |
+
* Get the length of a wrapped post URL shared on Twitter
|
102 |
+
*
|
103 |
+
* @since 1.0.0
|
104 |
+
*
|
105 |
+
* @return int wrapped URL length or 0 if no length info found
|
106 |
+
*/
|
107 |
+
public static function getShortURLLength()
|
108 |
+
{
|
109 |
+
$config = static::getTwitterConfiguration();
|
110 |
+
|
111 |
+
if ( ! ( is_object( $config ) && isset( $config->short_url_length ) ) ) {
|
112 |
+
return 0;
|
113 |
+
}
|
114 |
+
$url_length = absint( $config->short_url_length );
|
115 |
+
|
116 |
+
// check if the post URL to be wrapped uses the HTTPS scheme
|
117 |
+
if ( isset( $config->short_url_length_https ) ) {
|
118 |
+
$post_url = get_permalink();
|
119 |
+
if ( $post_url ) {
|
120 |
+
$is_https = false;
|
121 |
+
try {
|
122 |
+
if ( 'https' === strtolower( parse_url( $post_url, PHP_URL_SCHEME ) ) ) {
|
123 |
+
$is_https = true;
|
124 |
+
}
|
125 |
+
} catch(Exception $e) {}
|
126 |
+
if ( $is_https ) {
|
127 |
+
$url_length = absint( $config->short_url_length_https );
|
128 |
+
}
|
129 |
+
}
|
130 |
+
}
|
131 |
+
|
132 |
+
return $url_length;
|
133 |
+
}
|
134 |
+
|
135 |
+
/**
|
136 |
+
* Display Tweet Web Intent customizations
|
137 |
+
*
|
138 |
+
* @since 1.0.0
|
139 |
+
*
|
140 |
+
* @return void
|
141 |
+
*/
|
142 |
+
public static function metaBoxContent()
|
143 |
+
{
|
144 |
+
$post = get_post();
|
145 |
+
|
146 |
+
$stored_values = array();
|
147 |
+
if ( $post && is_a( $post, 'WP_Post' ) && isset( $post->ID ) ) {
|
148 |
+
$stored_values = get_post_meta( $post->ID, static::META_KEY, true );
|
149 |
+
if ( ! is_array( $stored_values ) ) {
|
150 |
+
$stored_values = array();
|
151 |
+
}
|
152 |
+
}
|
153 |
+
|
154 |
+
echo '<h4>' . esc_html( _x( 'Tweet', 'Tweet verb. Sharing.', 'twitter' ) ) . '</h4>';
|
155 |
+
echo '<table id="tweet-intent">';
|
156 |
+
echo '<thead><tr><th scope="col">' . esc_html( _x( 'Parameter', 'Customization or variable', 'twitter' ) ) . '</th><th scope="col">' . esc_html( __( 'Value' ) ) . '</th></tr></thead><tbody>';
|
157 |
+
|
158 |
+
$available_characters = 140;
|
159 |
+
// t.co wrapped URL length
|
160 |
+
$short_url_length = static::getShortURLLength();
|
161 |
+
if ( $short_url_length ) {
|
162 |
+
// tweet length after accounting for the shared URL with a space separator
|
163 |
+
$available_characters = $available_characters - $short_url_length - 1;
|
164 |
+
}
|
165 |
+
|
166 |
+
echo '<tr>';
|
167 |
+
echo '<td scope="row" class="left"><label for="tweet-text">' . esc_html( _x( 'Text', 'Share / Tweet text', 'twitter' ) ) . '</label></th>';
|
168 |
+
echo '<td><input id="tweet-text" name="' . esc_attr( static::META_KEY . '[' . static::TEXT_KEY . ']' ) . '" type="text" maxlength="' . $available_characters . '" autocomplete="off"';
|
169 |
+
if ( isset( $stored_values[ static::TEXT_KEY ] ) ) {
|
170 |
+
echo ' value="' . esc_attr( $stored_values[ static::TEXT_KEY ] ) . '"';
|
171 |
+
} else {
|
172 |
+
echo ' placeholder="' . esc_attr( get_the_title( $post ) ) . '"';
|
173 |
+
}
|
174 |
+
echo \Twitter\WordPress\Helpers\HTMLBuilder::closeVoidHTMLElement() . '></td>';
|
175 |
+
echo '</tr>';
|
176 |
+
echo '<tr>';
|
177 |
+
echo '<td scope="row" class="left"><label for"tweet-hashtags">' . esc_html( __( 'Hashtags', 'twitter' ) ) . '</label></th>';
|
178 |
+
echo '<td><input id="tweet-hashtags" name="' . esc_attr( static::META_KEY . '[' . static::HASHTAGS_KEY . ']' ) . '" type="text" maxlength="' . ($available_characters - 2) . '" autocomplete="off"';
|
179 |
+
if ( isset( $stored_values[ static::HASHTAGS_KEY ] ) && is_array( $stored_values[ static::HASHTAGS_KEY ] ) ) {
|
180 |
+
echo ' value="' . esc_attr( implode( ',', $stored_values[ static::HASHTAGS_KEY ] ) ) . '"';
|
181 |
+
}
|
182 |
+
echo \Twitter\WordPress\Helpers\HTMLBuilder::closeVoidHTMLElement() . '></td>';
|
183 |
+
echo '</tr>';
|
184 |
+
|
185 |
+
echo '</tbody></table>';
|
186 |
+
echo '<p class="description">' . esc_html( __( 'Pre-populate Tweet text', 'twitter' ) ) . '</p>';
|
187 |
+
}
|
188 |
+
|
189 |
+
/**
|
190 |
+
* Sanitize user inputs for Tweet Intent data before saving as a post meta value
|
191 |
+
*
|
192 |
+
* @since 1.0.0
|
193 |
+
*
|
194 |
+
* @param array $fields POST fields for META_KEY
|
195 |
+
*
|
196 |
+
* @return array|bool sanizited array or false if none set
|
197 |
+
*/
|
198 |
+
public static function sanitizeFields( $fields )
|
199 |
+
{
|
200 |
+
if ( ! is_array( $fields ) ) {
|
201 |
+
// store nothing
|
202 |
+
return false;
|
203 |
+
}
|
204 |
+
|
205 |
+
// overwrite everything
|
206 |
+
if ( empty( $fields ) ) {
|
207 |
+
return array();
|
208 |
+
}
|
209 |
+
|
210 |
+
$cleaned_fields = array();
|
211 |
+
|
212 |
+
if ( isset( $fields[ static::HASHTAGS_KEY ] ) ) {
|
213 |
+
$hashtags = static::sanitizeCommaSeparatedHashtags( $fields[ static::HASHTAGS_KEY ] );
|
214 |
+
if ( ! empty( $hashtags ) ) {
|
215 |
+
$cleaned_fields[ static::HASHTAGS_KEY ] = $hashtags;
|
216 |
+
}
|
217 |
+
unset( $hashtags );
|
218 |
+
}
|
219 |
+
|
220 |
+
if ( isset( $fields[ static::TEXT_KEY ] ) ) {
|
221 |
+
// allow Tweet text length overruns
|
222 |
+
// the text will appear pre-populated in the Tweet composer but require editing before posting a Tweet
|
223 |
+
$text = trim( $fields[ static::TEXT_KEY ] );
|
224 |
+
if ( $text ) {
|
225 |
+
$cleaned_fields[ static::TEXT_KEY ] = $text;
|
226 |
+
}
|
227 |
+
unset( $text );
|
228 |
+
}
|
229 |
+
|
230 |
+
return $cleaned_fields;
|
231 |
+
}
|
232 |
+
|
233 |
+
/**
|
234 |
+
* Sanitize an expected comma-separated list of hashtags into an array
|
235 |
+
*
|
236 |
+
* @since 1.0.0
|
237 |
+
*
|
238 |
+
* @param string $hashtag_string comma-separated list of hashtags
|
239 |
+
*
|
240 |
+
* @return array list of hashtags
|
241 |
+
*/
|
242 |
+
public static function sanitizeCommaSeparatedHashtags( $hashtag_string )
|
243 |
+
{
|
244 |
+
if ( ! is_string( $hashtag_string ) ) {
|
245 |
+
return array();
|
246 |
+
}
|
247 |
+
|
248 |
+
$hashtag_string = trim( $hashtag_string );
|
249 |
+
if ( ! $hashtag_string ) {
|
250 |
+
return array();
|
251 |
+
}
|
252 |
+
|
253 |
+
$intent = \Twitter\Intents\Tweet::fromArray( array( 'hashtags' => $hashtag_string ) );
|
254 |
+
if ( ! $intent ) {
|
255 |
+
return array();
|
256 |
+
}
|
257 |
+
|
258 |
+
return $intent->getHashtags();
|
259 |
+
|
260 |
+
}
|
261 |
+
|
262 |
+
/**
|
263 |
+
* Save post meta values
|
264 |
+
*
|
265 |
+
* Basic capability tests should already be applied by \Twitter\WordPress\Admin\Post\MetaBox::save before calling this method
|
266 |
+
*
|
267 |
+
* @since 1.0.0
|
268 |
+
*
|
269 |
+
* @param WP_Post $post WordPress post object
|
270 |
+
*
|
271 |
+
* @return void
|
272 |
+
*/
|
273 |
+
public static function save( $post )
|
274 |
+
{
|
275 |
+
// test if post ID exists on object
|
276 |
+
if ( ! is_a( $post, 'WP_Post' ) ) {
|
277 |
+
return;
|
278 |
+
}
|
279 |
+
|
280 |
+
if ( ! isset( $_POST[ static::META_KEY ] ) ) {
|
281 |
+
return;
|
282 |
+
}
|
283 |
+
|
284 |
+
$fields = $_POST[ static::META_KEY ];
|
285 |
+
if ( ! is_array( $fields ) ) {
|
286 |
+
return;
|
287 |
+
}
|
288 |
+
|
289 |
+
$fields = static::sanitizeFields( $fields );
|
290 |
+
if ( empty( $fields ) ) {
|
291 |
+
delete_post_meta_by_key( static::META_KEY );
|
292 |
+
} else {
|
293 |
+
update_post_meta( $post->ID, static::META_KEY, $fields );
|
294 |
+
}
|
295 |
+
}
|
296 |
+
}
|
src/Twitter/WordPress/Admin/Post/TwitterCard.php
ADDED
@@ -0,0 +1,247 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Admin\Post;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Store Twitter Card data for a WordPress post
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class TwitterCard
|
34 |
+
{
|
35 |
+
/**
|
36 |
+
* Meta field key used to store custom Twitter Card data
|
37 |
+
*
|
38 |
+
* @since 1.0.0
|
39 |
+
*
|
40 |
+
* @type string
|
41 |
+
*/
|
42 |
+
const META_KEY = 'twitter_card';
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Associative array key representing the title value inside the META_KEY array
|
46 |
+
*
|
47 |
+
* @since 1.0.0
|
48 |
+
*
|
49 |
+
* @type string
|
50 |
+
*/
|
51 |
+
const TITLE_KEY = 'title';
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Associative array key representing the description value inside the META_KEY array
|
55 |
+
*
|
56 |
+
* @since 1.0.0
|
57 |
+
*
|
58 |
+
* @type string
|
59 |
+
*/
|
60 |
+
const DESCRIPTION_KEY = 'description';
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Register the post meta key and its sanizitzer
|
64 |
+
*
|
65 |
+
* Used by WordPress JSON API to expose programmatic editor beyond the post meta box display used in the HTML-based admin interface
|
66 |
+
*
|
67 |
+
* @since 1.0.0
|
68 |
+
* @uses register_meta
|
69 |
+
*
|
70 |
+
* @return void
|
71 |
+
*/
|
72 |
+
public static function registerPostMeta()
|
73 |
+
{
|
74 |
+
register_meta(
|
75 |
+
'post',
|
76 |
+
static::META_KEY,
|
77 |
+
array( __CLASS__, 'sanitizeFields' )
|
78 |
+
);
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Limit displayed card fields to fields supported by the post type
|
83 |
+
*
|
84 |
+
* @since 1.0.0
|
85 |
+
*
|
86 |
+
* @param string $post_type post type
|
87 |
+
*
|
88 |
+
* @return array associative array of supported fields {
|
89 |
+
* @type string field name (examples: title, description)
|
90 |
+
* @type bool exists boolean for easy key reference
|
91 |
+
* }
|
92 |
+
*/
|
93 |
+
public static function supportedCardFieldsByPostType( $post_type )
|
94 |
+
{
|
95 |
+
if ( ! is_string( $post_type ) && $post_type ) {
|
96 |
+
return array();
|
97 |
+
}
|
98 |
+
|
99 |
+
$features = array();
|
100 |
+
if ( post_type_supports( $post_type, 'title' ) ) {
|
101 |
+
$features[ static::TITLE_KEY ] = true;
|
102 |
+
}
|
103 |
+
if ( post_type_supports( $post_type, 'excerpt' ) ) {
|
104 |
+
$features[ static::DESCRIPTION_KEY ] = true;
|
105 |
+
}
|
106 |
+
return $features;
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Display Twitter Card customizations
|
111 |
+
*
|
112 |
+
* @since 1.0.0
|
113 |
+
*
|
114 |
+
* @return void
|
115 |
+
*/
|
116 |
+
public static function metaBoxContent()
|
117 |
+
{
|
118 |
+
$post = get_post();
|
119 |
+
$cards_fields_supported_by_post_type = array();
|
120 |
+
|
121 |
+
$stored_values = array();
|
122 |
+
if ( $post && is_a( $post, 'WP_Post' ) && isset( $post->ID ) ) {
|
123 |
+
$stored_values = get_post_meta( $post->ID, static::META_KEY, true );
|
124 |
+
if ( ! is_array( $stored_values ) ) {
|
125 |
+
$stored_values = array();
|
126 |
+
}
|
127 |
+
$cards_fields_supported_by_post_type = static::supportedCardFieldsByPostType( get_post_type( $post ) );
|
128 |
+
}
|
129 |
+
|
130 |
+
// no supported Twitter Cards fields
|
131 |
+
if ( empty( $cards_fields_supported_by_post_type ) ) {
|
132 |
+
return;
|
133 |
+
}
|
134 |
+
|
135 |
+
// separate Twitter Cards content from Intent content above
|
136 |
+
echo '<hr' . \Twitter\WordPress\Helpers\HTMLBuilder::closeVoidHTMLElement() . '>';
|
137 |
+
|
138 |
+
echo '<h4>' . esc_html( __( 'Twitter Card', 'twitter' ) ) . '</h4>';
|
139 |
+
|
140 |
+
if ( isset( $cards_fields_supported_by_post_type[ static::TITLE_KEY ] ) ) {
|
141 |
+
echo '<table id="twitter-card">';
|
142 |
+
echo '<thead><tr><th scope="col">' . esc_html( _x( 'Property', 'Object component, such as a title and description of an article', 'twitter' ) ) . '</th><th scope="col">' . esc_html( __( 'Value' ) ) . '</th></tr></thead><tbody>';
|
143 |
+
|
144 |
+
echo '<tr>';
|
145 |
+
echo '<td scope="row" class="left"><label for="twitter-card-title">' . esc_html( __( 'Title' ) ) . '</label></th>';
|
146 |
+
echo '<td><input type="text" id="twitter-card-title" name="' . esc_attr( static::META_KEY . '[' . static::TITLE_KEY . ']' ) . '" maxlength="70" autocomplete="off"';
|
147 |
+
if ( isset( $stored_values[ static::TITLE_KEY ] ) ) {
|
148 |
+
echo ' value="' . esc_attr( $stored_values[ static::TITLE_KEY ] ) . '"';
|
149 |
+
} else {
|
150 |
+
echo ' placeholder="' . esc_attr( get_the_title( $post ) ) . '"';
|
151 |
+
}
|
152 |
+
|
153 |
+
echo \Twitter\WordPress\Helpers\HTMLBuilder::closeVoidHTMLElement() . '></td>';
|
154 |
+
echo '</tr>';
|
155 |
+
}
|
156 |
+
|
157 |
+
if ( isset( $cards_fields_supported_by_post_type[ static::DESCRIPTION_KEY ] ) ) {
|
158 |
+
echo '<tr>';
|
159 |
+
echo '<td scope="row" class="left"><label for="twitter-card-description">' . esc_html( __( 'Description' ) ) . '</label></th>';
|
160 |
+
echo '<td><input type="text" id="twitter-card-description" name="' . esc_attr( static::META_KEY . '[' . static::DESCRIPTION_KEY . ']' ) . '" maxlength="200" autocomplete="off"';
|
161 |
+
if ( isset( $stored_values[ static::DESCRIPTION_KEY ] ) ) {
|
162 |
+
echo ' value="' . esc_attr( $stored_values[ static::DESCRIPTION_KEY ] ) . '"';
|
163 |
+
}
|
164 |
+
echo \Twitter\WordPress\Helpers\HTMLBuilder::closeVoidHTMLElement() . '></td>';
|
165 |
+
echo '</tr>';
|
166 |
+
|
167 |
+
echo '</tbody></table>';
|
168 |
+
echo '<p class="description">' . esc_html( __( 'Customize Twitter link previews', 'twitter' ) ) . '</p>';
|
169 |
+
}
|
170 |
+
}
|
171 |
+
|
172 |
+
/**
|
173 |
+
* Sanitize user inputs for Twitter Card data before saving as a post meta value
|
174 |
+
*
|
175 |
+
* @since 1.0.0
|
176 |
+
*
|
177 |
+
* @param array $fields POST fields for META_KEY
|
178 |
+
*
|
179 |
+
* @return array|bool sanizited array or false if none set
|
180 |
+
*/
|
181 |
+
public static function sanitizeFields( $fields )
|
182 |
+
{
|
183 |
+
if ( ! is_array( $fields ) ) {
|
184 |
+
// store nothing
|
185 |
+
return false;
|
186 |
+
}
|
187 |
+
|
188 |
+
// overwrite everything
|
189 |
+
if ( empty( $fields ) ) {
|
190 |
+
return array();
|
191 |
+
}
|
192 |
+
|
193 |
+
$cleaned_fields = array();
|
194 |
+
|
195 |
+
if ( isset( $fields[ static::TITLE_KEY ] ) ) {
|
196 |
+
$title = \Twitter\WordPress\Cards\Sanitize::sanitizePlainTextString( $fields[ static::TITLE_KEY ], /* remove breaks */ true );
|
197 |
+
if ( $title ) {
|
198 |
+
$cleaned_fields[ static::TITLE_KEY ] = $title;
|
199 |
+
}
|
200 |
+
unset($title);
|
201 |
+
}
|
202 |
+
if ( isset( $fields[ static::DESCRIPTION_KEY ] ) ) {
|
203 |
+
$description = \Twitter\WordPress\Cards\Sanitize::sanitizePlainTextString( $fields[ static::DESCRIPTION_KEY ], /* remove breaks */ true );
|
204 |
+
if ( $description ) {
|
205 |
+
$cleaned_fields[ static::DESCRIPTION_KEY ] = $description;
|
206 |
+
}
|
207 |
+
unset($description);
|
208 |
+
}
|
209 |
+
|
210 |
+
return $cleaned_fields;
|
211 |
+
}
|
212 |
+
|
213 |
+
/**
|
214 |
+
* Save post meta values
|
215 |
+
*
|
216 |
+
* Basic capability tests should already be applied by \Twitter\WordPress\Admin\Post\MetaBox::save before calling this method
|
217 |
+
*
|
218 |
+
* @since 1.0.0
|
219 |
+
*
|
220 |
+
* @param WP_Post $post WordPress post object
|
221 |
+
*
|
222 |
+
* @return void
|
223 |
+
*/
|
224 |
+
public static function save( $post )
|
225 |
+
{
|
226 |
+
// test if post ID exists on object
|
227 |
+
if ( ! is_a( $post, 'WP_Post' ) ) {
|
228 |
+
return;
|
229 |
+
}
|
230 |
+
|
231 |
+
if ( ! isset( $_POST[ static::META_KEY ] ) ) {
|
232 |
+
return;
|
233 |
+
}
|
234 |
+
|
235 |
+
$fields = $_POST[ static::META_KEY ];
|
236 |
+
if ( ! is_array( $fields ) ) {
|
237 |
+
return;
|
238 |
+
}
|
239 |
+
|
240 |
+
$fields = static::sanitizeFields( $fields );
|
241 |
+
if ( empty( $fields ) ) {
|
242 |
+
delete_post_meta_by_key( static::META_KEY );
|
243 |
+
} else {
|
244 |
+
update_post_meta( $post->ID, static::META_KEY, $fields );
|
245 |
+
}
|
246 |
+
}
|
247 |
+
}
|
src/Twitter/WordPress/Admin/Profile/User.php
ADDED
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Admin\Profile;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Associate a WordPress account with a Twitter account
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class User
|
34 |
+
{
|
35 |
+
/**
|
36 |
+
* Conditionally load features on the edit profile page.
|
37 |
+
*
|
38 |
+
* @since 1.0.0
|
39 |
+
*
|
40 |
+
* @return void
|
41 |
+
*/
|
42 |
+
public static function init()
|
43 |
+
{
|
44 |
+
// only show to authors
|
45 |
+
if ( ! current_user_can( 'edit_posts' ) ) {
|
46 |
+
return;
|
47 |
+
}
|
48 |
+
|
49 |
+
// add Twitter after website
|
50 |
+
add_filter( 'user_contactmethods', array( __CLASS__, 'addContactMethod' ), 1, 2 );
|
51 |
+
// provide additional hints in label text
|
52 |
+
add_filter( 'user_twitter_label', array( __CLASS__, 'contactMethodLabel' ), 10, 1 );
|
53 |
+
// clean up user input
|
54 |
+
add_filter( 'sanitize_user_meta_twitter', array( __CLASS__, 'sanitize' ), 10, 1 );
|
55 |
+
}
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Add Twitter as a contact method in the Contact Info profile section
|
59 |
+
*
|
60 |
+
* @since 1.0.0
|
61 |
+
*
|
62 |
+
* @see wp_get_user_contact_methods()
|
63 |
+
*
|
64 |
+
* @param array $methods contact methods and their labels {
|
65 |
+
* @type string contact method
|
66 |
+
* @type string label
|
67 |
+
* }
|
68 |
+
* @param WP_User $user WP_User object.
|
69 |
+
*
|
70 |
+
* @return array contact methods and their labels {
|
71 |
+
* @type string contact method
|
72 |
+
* @type string label
|
73 |
+
* }
|
74 |
+
*/
|
75 |
+
public static function addContactMethod( $methods, $user )
|
76 |
+
{
|
77 |
+
$methods['twitter'] = 'Twitter';
|
78 |
+
return $methods;
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Customize HTML display label for contact method
|
83 |
+
*
|
84 |
+
* @since 1.0.0
|
85 |
+
*
|
86 |
+
* @param string $label HTML label
|
87 |
+
*
|
88 |
+
* @return string HTML label
|
89 |
+
*/
|
90 |
+
public static function contactMethodLabel( $label = '' )
|
91 |
+
{
|
92 |
+
return _x( 'Twitter @username', 'Prompt requesting entry of a Twitter username', 'twitter' );
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* Clean up user inputted Twitter username value before saving the option
|
97 |
+
*
|
98 |
+
* @since 1.0.0
|
99 |
+
*
|
100 |
+
* @param string $screen_name inputted Twitter username value
|
101 |
+
*
|
102 |
+
* @return string sanitized Twitter username value
|
103 |
+
*/
|
104 |
+
public static function sanitize( $screen_name )
|
105 |
+
{
|
106 |
+
if ( ! is_string( $screen_name ) ) {
|
107 |
+
return '';
|
108 |
+
}
|
109 |
+
$screen_name = trim( $screen_name );
|
110 |
+
if ( ! $screen_name ) {
|
111 |
+
return '';
|
112 |
+
}
|
113 |
+
$screen_name = sanitize_text_field( $screen_name );
|
114 |
+
if ( ! $screen_name ) {
|
115 |
+
return '';
|
116 |
+
}
|
117 |
+
|
118 |
+
return \Twitter\Helpers\Validators\ScreenName::sanitize( $screen_name );
|
119 |
+
}
|
120 |
+
}
|
src/Twitter/WordPress/Admin/Settings/Loader.php
ADDED
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Admin\Settings;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Initialize hooks related to WordPress admin interface settings
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class Loader
|
34 |
+
{
|
35 |
+
/**
|
36 |
+
* Add hooks
|
37 |
+
*
|
38 |
+
* @since 1.0.0
|
39 |
+
*
|
40 |
+
* @return void
|
41 |
+
*/
|
42 |
+
public static function init()
|
43 |
+
{
|
44 |
+
add_action( 'admin_menu', array( __CLASS__, 'settingsMenuItems' ) );
|
45 |
+
add_filter( 'plugin_action_links', array( __CLASS__, 'pluginActionLinks' ), 10, 2 );
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Add Twitter settings to the WordPress administration menu.
|
50 |
+
*
|
51 |
+
* @since 1.0.0
|
52 |
+
*
|
53 |
+
* @return void
|
54 |
+
*/
|
55 |
+
public static function settingsMenuItems()
|
56 |
+
{
|
57 |
+
\Twitter\WordPress\Admin\Settings\SinglePage::menuItem();
|
58 |
+
}
|
59 |
+
|
60 |
+
/**
|
61 |
+
* Link to settings from the plugin listing page
|
62 |
+
*
|
63 |
+
* @since 1.0.0
|
64 |
+
*
|
65 |
+
* @param array $links links displayed under the plugin
|
66 |
+
* @param string $file plugin main file path relative to plugin dir
|
67 |
+
*
|
68 |
+
* @return array links array passed in, possibly with our settings link added
|
69 |
+
*/
|
70 |
+
public static function pluginActionLinks( $links, $file )
|
71 |
+
{
|
72 |
+
if ( $file === plugin_basename( \Twitter\WordPress\PluginLoader::getPluginMainFile() ) ) {
|
73 |
+
array_unshift( $links, '<a href="' . esc_url( admin_url( 'admin.php' ) . '?' . http_build_query( array( 'page' => \Twitter\WordPress\Admin\Settings\SinglePage::PAGE_SLUG ) ) ) . '">' . __( 'Settings' ) . '</a>' );
|
74 |
+
}
|
75 |
+
|
76 |
+
return $links;
|
77 |
+
}
|
78 |
+
}
|
src/Twitter/WordPress/Admin/Settings/SinglePage.php
ADDED
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Admin\Settings;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Combine Twitter settings into a single settings page
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class SinglePage
|
34 |
+
{
|
35 |
+
use Template;
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Settings page identifier.
|
39 |
+
*
|
40 |
+
* @since 1.0.0
|
41 |
+
*
|
42 |
+
* @type string
|
43 |
+
*/
|
44 |
+
const PAGE_SLUG = 'twitter';
|
45 |
+
|
46 |
+
/**
|
47 |
+
* The hook suffix assigned by add_utility_page()
|
48 |
+
*
|
49 |
+
* @since 1.0.0
|
50 |
+
*
|
51 |
+
* @type string
|
52 |
+
*/
|
53 |
+
protected $hook_suffix;
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Class names containing single page settings components
|
57 |
+
*
|
58 |
+
* The addToSettingsPage method is called on each class to initialize its components
|
59 |
+
*
|
60 |
+
* @since 1.0.0
|
61 |
+
*
|
62 |
+
* @type array settings component fully qualified class names {
|
63 |
+
* @type string fully qualified class name
|
64 |
+
* }
|
65 |
+
*/
|
66 |
+
protected static $SETTINGS_COMPONENTS = array( '\Twitter\WordPress\Admin\Settings\Theme', '\Twitter\WordPress\Admin\Settings\SiteAttribution', '\Twitter\WordPress\Admin\Settings\TweetButton' );
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Reference the feature by name
|
70 |
+
*
|
71 |
+
* @since 1.0.0
|
72 |
+
*
|
73 |
+
* @return string translated feature name
|
74 |
+
*/
|
75 |
+
public static function featureName()
|
76 |
+
{
|
77 |
+
return __( 'Twitter settings', 'twitter' );
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Add a submenu item to WordPress admin.
|
82 |
+
*
|
83 |
+
* @since 1.0.0
|
84 |
+
*
|
85 |
+
* @return string|null page hook or null if page capability requirements not met
|
86 |
+
*/
|
87 |
+
public static function menuItem()
|
88 |
+
{
|
89 |
+
$settings = new static();
|
90 |
+
|
91 |
+
$hook_suffix = add_utility_page(
|
92 |
+
static::featureName(), // page <title>
|
93 |
+
'Twitter', // brand name. not translated
|
94 |
+
'manage_options', // capability needed
|
95 |
+
static::PAGE_SLUG, // unique menu slug
|
96 |
+
array( &$settings, 'settingsPage' ), // pageload callback
|
97 |
+
'dashicons-twitter' // to be replaced by dashicon
|
98 |
+
);
|
99 |
+
|
100 |
+
// hook_suffix may be false if current viewer does not have the manage_options capability
|
101 |
+
if ( ! $hook_suffix ) {
|
102 |
+
return;
|
103 |
+
}
|
104 |
+
$settings->hook_suffix = $hook_suffix;
|
105 |
+
|
106 |
+
// add each settings component to the single page settings page
|
107 |
+
foreach ( static::$SETTINGS_COMPONENTS as $settings_component ) {
|
108 |
+
$settings_component::addToSettingsPage( $hook_suffix );
|
109 |
+
}
|
110 |
+
|
111 |
+
add_action(
|
112 |
+
'load-' . $hook_suffix,
|
113 |
+
array( &$settings, 'addContextualHelp' ),
|
114 |
+
99,
|
115 |
+
0
|
116 |
+
);
|
117 |
+
|
118 |
+
return $hook_suffix;
|
119 |
+
}
|
120 |
+
|
121 |
+
/**
|
122 |
+
* Add contextual help content to the settings screen
|
123 |
+
*
|
124 |
+
* @since 1.0.0
|
125 |
+
*
|
126 |
+
* @return void
|
127 |
+
*/
|
128 |
+
public function addContextualHelp()
|
129 |
+
{
|
130 |
+
$screen = get_current_screen();
|
131 |
+
if ( ! $screen ) { // null if global not set
|
132 |
+
return;
|
133 |
+
}
|
134 |
+
|
135 |
+
do_action( 'add-' . $this->hook_suffix . '-help-tab', $screen );
|
136 |
+
}
|
137 |
+
}
|
src/Twitter/WordPress/Admin/Settings/SiteAttribution.php
ADDED
@@ -0,0 +1,251 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Admin\Settings;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Store a Twitter username for attribution of site content
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class SiteAttribution
|
34 |
+
{
|
35 |
+
/**
|
36 |
+
* Define our option name
|
37 |
+
*
|
38 |
+
* @since 1.0.0
|
39 |
+
*
|
40 |
+
* @type string
|
41 |
+
*/
|
42 |
+
const OPTION_NAME = 'twitter_site_attribution';
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Priority of the section affecting insertion order on the single settings page
|
46 |
+
*
|
47 |
+
* Display after theme section
|
48 |
+
*
|
49 |
+
* @since 1.0.0
|
50 |
+
*
|
51 |
+
* @type int
|
52 |
+
*/
|
53 |
+
const SECTION_PRIORITY = 5;
|
54 |
+
|
55 |
+
/**
|
56 |
+
* The hook suffix of the parent settings page
|
57 |
+
*
|
58 |
+
* @since 1.0.0
|
59 |
+
*
|
60 |
+
* @type string
|
61 |
+
*/
|
62 |
+
protected $hook_suffix;
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Reference the feature by name
|
66 |
+
*
|
67 |
+
* @since 1.0.0
|
68 |
+
*
|
69 |
+
* @return string translated feature name
|
70 |
+
*/
|
71 |
+
public static function featureName()
|
72 |
+
{
|
73 |
+
return _x( 'Site attribution', 'Attribute content on a website to a Twitter account', 'twitter' );
|
74 |
+
}
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Add site attribution option and settings section to an existing settings page
|
78 |
+
*
|
79 |
+
* @since 1.0.0
|
80 |
+
*
|
81 |
+
* @param string $hook_suffix hook suffix of an existing settings page
|
82 |
+
*
|
83 |
+
* @return bool site attribution settings loaded
|
84 |
+
*/
|
85 |
+
public static function addToSettingsPage( $hook_suffix )
|
86 |
+
{
|
87 |
+
if ( ! ( is_string( $hook_suffix ) && $hook_suffix ) ) {
|
88 |
+
return false;
|
89 |
+
}
|
90 |
+
|
91 |
+
$settings = new static();
|
92 |
+
$settings->hook_suffix = $hook_suffix;
|
93 |
+
|
94 |
+
register_setting( $hook_suffix, self::OPTION_NAME, array( __CLASS__, 'sanitize' ) );
|
95 |
+
add_action(
|
96 |
+
'load-' . $hook_suffix,
|
97 |
+
array( &$settings, 'onload' ),
|
98 |
+
5, // after theme settings
|
99 |
+
0
|
100 |
+
);
|
101 |
+
|
102 |
+
return true;
|
103 |
+
}
|
104 |
+
|
105 |
+
/**
|
106 |
+
* Set up settings section
|
107 |
+
*
|
108 |
+
* @since 1.0.0
|
109 |
+
*
|
110 |
+
* @return void
|
111 |
+
*/
|
112 |
+
public function onload()
|
113 |
+
{
|
114 |
+
if ( ! isset( $this->hook_suffix ) ) {
|
115 |
+
return;
|
116 |
+
}
|
117 |
+
|
118 |
+
add_action(
|
119 |
+
'add-' . $this->hook_suffix . '-section',
|
120 |
+
array( &$this, 'defineSection' ),
|
121 |
+
static::SECTION_PRIORITY,
|
122 |
+
0 // no parameters
|
123 |
+
);
|
124 |
+
|
125 |
+
// contextual help
|
126 |
+
add_action(
|
127 |
+
'add-' . $this->hook_suffix . '-help-tab',
|
128 |
+
array( __CLASS__, 'addHelpTab' ),
|
129 |
+
static::SECTION_PRIORITY,
|
130 |
+
1 // accept current screen as a parameter
|
131 |
+
);
|
132 |
+
}
|
133 |
+
|
134 |
+
/**
|
135 |
+
* Define site attribution section and the fields within
|
136 |
+
*
|
137 |
+
* @since 1.0.0
|
138 |
+
*
|
139 |
+
* @return void
|
140 |
+
*/
|
141 |
+
public function defineSection()
|
142 |
+
{
|
143 |
+
if ( ! isset( $this->hook_suffix ) ) {
|
144 |
+
return;
|
145 |
+
}
|
146 |
+
|
147 |
+
$section = 'site-attribution';
|
148 |
+
add_settings_section(
|
149 |
+
$section,
|
150 |
+
static::featureName(),
|
151 |
+
array( __CLASS__, 'sectionHeader' ),
|
152 |
+
$this->hook_suffix
|
153 |
+
);
|
154 |
+
|
155 |
+
add_settings_field(
|
156 |
+
'site-attribution-username',
|
157 |
+
\Twitter\WordPress\Admin\Profile\User::contactMethodLabel(),
|
158 |
+
array( &$this, 'displaySiteAttributionUsername' ),
|
159 |
+
$this->hook_suffix,
|
160 |
+
$section,
|
161 |
+
array( 'label_for' => self::OPTION_NAME )
|
162 |
+
);
|
163 |
+
}
|
164 |
+
|
165 |
+
/**
|
166 |
+
* Introduce the settings section
|
167 |
+
*
|
168 |
+
* @since 1.0.0
|
169 |
+
*
|
170 |
+
* @return void
|
171 |
+
*/
|
172 |
+
public static function sectionHeader()
|
173 |
+
{
|
174 |
+
echo '<p>';
|
175 |
+
echo esc_html( __( "Attribute shared content to your site's Twitter account", 'twitter' ) );
|
176 |
+
echo '</p>';
|
177 |
+
}
|
178 |
+
|
179 |
+
/**
|
180 |
+
* Input a Twitter screen_name to attribute to site content
|
181 |
+
*
|
182 |
+
* @since 1.0.0
|
183 |
+
*
|
184 |
+
* @return void
|
185 |
+
*/
|
186 |
+
public function displaySiteAttributionUsername()
|
187 |
+
{
|
188 |
+
$html = '<input type="text" id="' . esc_attr( self::OPTION_NAME ) . '" name="' . esc_attr( self::OPTION_NAME ) . '" size="20"';
|
189 |
+
$site_username = get_option( self::OPTION_NAME );
|
190 |
+
if ( $site_username ) {
|
191 |
+
$html .= ' value="' . esc_attr( $site_username ) . '"';
|
192 |
+
}
|
193 |
+
$html .= \Twitter\WordPress\Helpers\HTMLBuilder::closeVoidHTMLElement() . '>';
|
194 |
+
|
195 |
+
// escaped in markup builder
|
196 |
+
// @codingStandardsIgnoreStart WordPress.XSS.EscapeOutput
|
197 |
+
echo $html;
|
198 |
+
// @codingStandardsIgnoreEnd WordPress.XSS.EscapeOutput
|
199 |
+
}
|
200 |
+
|
201 |
+
/**
|
202 |
+
* Display inline help content
|
203 |
+
*
|
204 |
+
* @since 1.0.0
|
205 |
+
*
|
206 |
+
* @param WP_Screen $screen current screen
|
207 |
+
*
|
208 |
+
* @return void
|
209 |
+
*/
|
210 |
+
public static function addHelpTab( $screen )
|
211 |
+
{
|
212 |
+
if ( ! $screen ) {
|
213 |
+
return;
|
214 |
+
}
|
215 |
+
|
216 |
+
$content = '<p>' . sprintf( esc_html( __( 'Site attribution is used to attribute site content to a Twitter account in %1$s and %2$s.', 'twitter' ) ), '<a href="' . esc_url( 'https://dev.twitter.com/cards/overview', array( 'https', 'http' ) ) . '">' . esc_html( __( 'Twitter Cards', 'twitter' ) ) . '</a>', '<a href="' . esc_url( 'https://support.twitter.com/articles/20170934-twitter-card-analytics-dashboard', array( 'https', 'http' ) ) . '">' . esc_html( __( 'Twitter Analytics', 'twitter' ) ) . '</a>' ) . '</p>';
|
217 |
+
$content .= '<p>' . esc_html( __( 'The account may also be used to note a Tweet originated from a Tweet Button on your site.', 'twitter' ) ) . '</p>';
|
218 |
+
|
219 |
+
$screen->add_help_tab( array(
|
220 |
+
'id' => 'twitter-site-attribution-help',
|
221 |
+
'title' => static::featureName(),
|
222 |
+
'content' => $content,
|
223 |
+
) );
|
224 |
+
}
|
225 |
+
|
226 |
+
/**
|
227 |
+
* Clean up user inputted Twitter username value before saving the option
|
228 |
+
*
|
229 |
+
* @since 1.0.0
|
230 |
+
*
|
231 |
+
* @param string $screen_name inputted Twitter username value
|
232 |
+
*
|
233 |
+
* @return string sanitized Twitter username value
|
234 |
+
*/
|
235 |
+
public static function sanitize( $screen_name )
|
236 |
+
{
|
237 |
+
if ( ! is_string( $screen_name ) ) {
|
238 |
+
return '';
|
239 |
+
}
|
240 |
+
$screen_name = trim( $screen_name );
|
241 |
+
if ( ! $screen_name ) {
|
242 |
+
return '';
|
243 |
+
}
|
244 |
+
$screen_name = sanitize_text_field( $screen_name );
|
245 |
+
if ( ! $screen_name ) {
|
246 |
+
return '';
|
247 |
+
}
|
248 |
+
|
249 |
+
return \Twitter\Helpers\Validators\ScreenName::sanitize( $screen_name );
|
250 |
+
}
|
251 |
+
}
|
src/Twitter/WordPress/Admin/Settings/Template.php
ADDED
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Admin\Settings;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Share common template functionality across Twitter setting pages
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
trait Template
|
34 |
+
{
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Load the settings page
|
38 |
+
*
|
39 |
+
* @since 1.0.0
|
40 |
+
*
|
41 |
+
* @return void
|
42 |
+
*/
|
43 |
+
public function settingsPage()
|
44 |
+
{
|
45 |
+
if ( ! isset( $this->hook_suffix ) ) {
|
46 |
+
return;
|
47 |
+
}
|
48 |
+
|
49 |
+
do_action( 'add-' . $this->hook_suffix . '-section' );
|
50 |
+
|
51 |
+
echo '<div class="wrap">';
|
52 |
+
|
53 |
+
echo '<header><h2>' . esc_html( static::featureName() ) . '</h2></header>';
|
54 |
+
// handle general messages such as settings updated up top
|
55 |
+
// place individual settings errors alongside their fields
|
56 |
+
settings_errors( 'general' );
|
57 |
+
|
58 |
+
echo '<form method="post" action="' . esc_url( admin_url( 'options.php' ), array( 'https', 'http' ) ) . '">';
|
59 |
+
settings_fields( $this->hook_suffix );
|
60 |
+
do_settings_sections( $this->hook_suffix );
|
61 |
+
submit_button();
|
62 |
+
echo '</form>';
|
63 |
+
|
64 |
+
echo '</div>';
|
65 |
+
}
|
66 |
+
|
67 |
+
}
|
src/Twitter/WordPress/Admin/Settings/Theme.php
ADDED
@@ -0,0 +1,507 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Admin\Settings;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Site-level settings for Twitter widget themes
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class Theme
|
34 |
+
{
|
35 |
+
/**
|
36 |
+
* Define our option array value.
|
37 |
+
*
|
38 |
+
* @since 1.0.0
|
39 |
+
*
|
40 |
+
* @type string
|
41 |
+
*/
|
42 |
+
const OPTION_NAME = 'twitter_widgets';
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Priority of the section affecting insertion order on the single settings page
|
46 |
+
*
|
47 |
+
* First section
|
48 |
+
*
|
49 |
+
* @since 1.0.0
|
50 |
+
*
|
51 |
+
* @type int
|
52 |
+
*/
|
53 |
+
const SECTION_PRIORITY = 1;
|
54 |
+
|
55 |
+
/**
|
56 |
+
* The hook suffix of the parent settings page
|
57 |
+
*
|
58 |
+
* @since 1.0.0
|
59 |
+
*
|
60 |
+
* @type string
|
61 |
+
*/
|
62 |
+
protected $hook_suffix;
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Reference the feature by name
|
66 |
+
*
|
67 |
+
* @since 1.0.0
|
68 |
+
*
|
69 |
+
* @return string translated feature name
|
70 |
+
*/
|
71 |
+
public static function featureName()
|
72 |
+
{
|
73 |
+
return _x( 'Theme', 'Visual and color theme', 'twitter' );
|
74 |
+
}
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Theme options and labels
|
78 |
+
*
|
79 |
+
* @since 1.0.0
|
80 |
+
*
|
81 |
+
* @return array associative array of accepted values and the value's translated label
|
82 |
+
*/
|
83 |
+
public static function themeChoices()
|
84 |
+
{
|
85 |
+
return array(
|
86 |
+
'light' => _x( 'light', 'Option for content to appear with a light background and dark text', 'twitter' ),
|
87 |
+
'dark' => _x( 'dark', 'Option for content to appear with a dark background and light text', 'twitter' )
|
88 |
+
);
|
89 |
+
}
|
90 |
+
|
91 |
+
/**
|
92 |
+
* Default options if no options exist
|
93 |
+
*
|
94 |
+
* @since 1.0.0
|
95 |
+
*
|
96 |
+
* @return array associative array of option values
|
97 |
+
*/
|
98 |
+
public static function defaultOptions()
|
99 |
+
{
|
100 |
+
return array(
|
101 |
+
'theme' => 'light',
|
102 |
+
);
|
103 |
+
}
|
104 |
+
|
105 |
+
/**
|
106 |
+
* Add site attribution option and settings section to an existing settings page
|
107 |
+
*
|
108 |
+
* @since 1.0.0
|
109 |
+
*
|
110 |
+
* @param string $hook_suffix hook suffix of an existing settings page
|
111 |
+
*
|
112 |
+
* @return bool site attribution settings loaded
|
113 |
+
*/
|
114 |
+
public static function addToSettingsPage( $hook_suffix )
|
115 |
+
{
|
116 |
+
if ( ! ( is_string( $hook_suffix ) && $hook_suffix ) ) {
|
117 |
+
return false;
|
118 |
+
}
|
119 |
+
|
120 |
+
$settings = new static();
|
121 |
+
$settings->hook_suffix = $hook_suffix;
|
122 |
+
|
123 |
+
register_setting(
|
124 |
+
$hook_suffix,
|
125 |
+
self::OPTION_NAME,
|
126 |
+
array( __CLASS__, 'sanitizeOptions' )
|
127 |
+
);
|
128 |
+
add_action(
|
129 |
+
'load-' . $hook_suffix,
|
130 |
+
array( &$settings, 'onload' ),
|
131 |
+
1, // first section
|
132 |
+
0
|
133 |
+
);
|
134 |
+
|
135 |
+
return true;
|
136 |
+
}
|
137 |
+
|
138 |
+
/**
|
139 |
+
* Store existing options. Set up page sections
|
140 |
+
*
|
141 |
+
* @since 1.0.0
|
142 |
+
*
|
143 |
+
* @return void
|
144 |
+
*/
|
145 |
+
public function onload()
|
146 |
+
{
|
147 |
+
if ( ! isset( $this->hook_suffix ) ) {
|
148 |
+
return;
|
149 |
+
}
|
150 |
+
|
151 |
+
$options = get_option( self::OPTION_NAME );
|
152 |
+
if ( ! is_array( $options ) ) {
|
153 |
+
$options = static::defaultOptions();
|
154 |
+
}
|
155 |
+
$this->existing_options = $options;
|
156 |
+
|
157 |
+
// theme
|
158 |
+
add_action(
|
159 |
+
'add-' . $this->hook_suffix . '-section',
|
160 |
+
array( &$this, 'defineThemeSection' ),
|
161 |
+
static::SECTION_PRIORITY, // top of screen
|
162 |
+
0 // no parameters
|
163 |
+
);
|
164 |
+
// contextual help
|
165 |
+
add_action(
|
166 |
+
'add-' . $this->hook_suffix . '-help-tab',
|
167 |
+
array( __CLASS__, 'addHelpTab' ),
|
168 |
+
static::SECTION_PRIORITY,
|
169 |
+
1
|
170 |
+
);
|
171 |
+
|
172 |
+
$late_priority = 10;
|
173 |
+
|
174 |
+
// warnings
|
175 |
+
add_action(
|
176 |
+
'add-' . $this->hook_suffix . '-section',
|
177 |
+
array( &$this, 'defineWarningsSection' ),
|
178 |
+
$late_priority, // default priority
|
179 |
+
0 // no parameters
|
180 |
+
);
|
181 |
+
}
|
182 |
+
|
183 |
+
/**
|
184 |
+
* Add theme settings section and fields
|
185 |
+
*
|
186 |
+
* @since 1.0.0
|
187 |
+
*
|
188 |
+
* @return void
|
189 |
+
*/
|
190 |
+
public function defineThemeSection()
|
191 |
+
{
|
192 |
+
$section = 'twitter-colorscheme';
|
193 |
+
add_settings_section(
|
194 |
+
$section,
|
195 |
+
static::featureName(),
|
196 |
+
array( __CLASS__, 'sectionHeader' ),
|
197 |
+
$this->hook_suffix
|
198 |
+
);
|
199 |
+
|
200 |
+
add_settings_field(
|
201 |
+
'twitter-theme',
|
202 |
+
_x( 'Theme', 'A choice of color options grouped as a theme', 'twitter' ),
|
203 |
+
array( &$this, 'displayTheme' ),
|
204 |
+
$this->hook_suffix,
|
205 |
+
$section,
|
206 |
+
array( 'label_for' => 'twitter-theme' )
|
207 |
+
);
|
208 |
+
|
209 |
+
add_settings_field(
|
210 |
+
'twitter-link-color',
|
211 |
+
_x( 'Link color', 'CSS color styling of a link text', 'twitter' ),
|
212 |
+
array( &$this, 'displayLinkColor' ),
|
213 |
+
$this->hook_suffix,
|
214 |
+
$section,
|
215 |
+
array( 'label_for' => 'twitter-link-color' )
|
216 |
+
);
|
217 |
+
|
218 |
+
add_settings_field(
|
219 |
+
'twitter-border-color',
|
220 |
+
_x( 'Border color', 'CSS color styling of a box border', 'twitter' ),
|
221 |
+
array( &$this, 'displayBorderColor' ),
|
222 |
+
$this->hook_suffix,
|
223 |
+
$section,
|
224 |
+
array( 'label_for' => 'twitter-border-color' )
|
225 |
+
);
|
226 |
+
}
|
227 |
+
|
228 |
+
/**
|
229 |
+
* Add warnings settings section and fields
|
230 |
+
*
|
231 |
+
* @since 1.0.0
|
232 |
+
*
|
233 |
+
* @return void
|
234 |
+
*/
|
235 |
+
public function defineWarningsSection()
|
236 |
+
{
|
237 |
+
$section = 'warnings';
|
238 |
+
add_settings_section(
|
239 |
+
$section,
|
240 |
+
__( 'Warnings', 'twitter' ),
|
241 |
+
array( __CLASS__, 'warningsSectionHeader' ),
|
242 |
+
$this->hook_suffix
|
243 |
+
);
|
244 |
+
|
245 |
+
add_settings_field(
|
246 |
+
'twitter-csp',
|
247 |
+
__( 'Content Security Policy', 'twitter' ),
|
248 |
+
array( &$this, 'displayContentSecurityPolicy' ),
|
249 |
+
$this->hook_suffix,
|
250 |
+
$section
|
251 |
+
);
|
252 |
+
}
|
253 |
+
|
254 |
+
/**
|
255 |
+
* Add warnings settings section and fields
|
256 |
+
*
|
257 |
+
* @since 1.0.0
|
258 |
+
*
|
259 |
+
* @return void
|
260 |
+
*/
|
261 |
+
public function defineRestrictionsSection()
|
262 |
+
{
|
263 |
+
$section = 'twitter-restrictions';
|
264 |
+
add_settings_section(
|
265 |
+
$section,
|
266 |
+
__( 'Restrictions', 'twitter' ),
|
267 |
+
array( __CLASS__, 'restrictionsSectionHeader' ),
|
268 |
+
$this->hook_suffix
|
269 |
+
);
|
270 |
+
|
271 |
+
// do not track
|
272 |
+
add_settings_field(
|
273 |
+
'twitter-dnt',
|
274 |
+
_x( 'Personalization', 'Personalize Twitter content based on website visits', 'twitter' ),
|
275 |
+
array( &$this, 'displayDoNotTrack' ),
|
276 |
+
$this->hook_suffix,
|
277 |
+
$section
|
278 |
+
);
|
279 |
+
}
|
280 |
+
|
281 |
+
/**
|
282 |
+
* Introduce the settings page
|
283 |
+
*
|
284 |
+
* @since 1.0.0
|
285 |
+
*
|
286 |
+
* @return void
|
287 |
+
*/
|
288 |
+
public static function sectionHeader()
|
289 |
+
{
|
290 |
+
echo '<p>';
|
291 |
+
echo esc_html( __( 'Customize colors used in Twitter widgets to match your site\'s theme', 'twitter' ) );
|
292 |
+
echo '</p>';
|
293 |
+
}
|
294 |
+
|
295 |
+
/**
|
296 |
+
* Choose a theme
|
297 |
+
*
|
298 |
+
* @since 1.0.0
|
299 |
+
*
|
300 |
+
* @return void
|
301 |
+
*/
|
302 |
+
public function displayTheme()
|
303 |
+
{
|
304 |
+
$key = 'theme';
|
305 |
+
|
306 |
+
$existing_value = 'light';
|
307 |
+
if ( isset( $this->existing_options[ $key ] ) ) {
|
308 |
+
$existing_value = $this->existing_options[ $key ];
|
309 |
+
}
|
310 |
+
|
311 |
+
$name_attribute = esc_attr( esc_attr( self::OPTION_NAME . '[' . $key . ']' ) );
|
312 |
+
$close_void_element = \Twitter\WordPress\Helpers\HTMLBuilder::closeVoidHTMLElement() . '>';
|
313 |
+
$choices = static::themeChoices();
|
314 |
+
|
315 |
+
echo '<fieldset id="' . esc_attr( 'twitter-' . $key ) . '">';
|
316 |
+
foreach ( $choices as $value => $label ) {
|
317 |
+
echo '<div><label><input type="radio" name="' . $name_attribute . '" value="' . esc_attr( $value ) . '"' . checked( $existing_value, $value, false ) . $close_void_element;
|
318 |
+
echo ' ' . esc_html( $label );
|
319 |
+
echo '</label></div>';
|
320 |
+
}
|
321 |
+
echo '</fieldset>';
|
322 |
+
}
|
323 |
+
|
324 |
+
/**
|
325 |
+
* Choose a hex color value as the link color
|
326 |
+
*
|
327 |
+
* @since 1.0.0
|
328 |
+
*
|
329 |
+
* @return void
|
330 |
+
*/
|
331 |
+
public function displayLinkColor()
|
332 |
+
{
|
333 |
+
$key = 'link-color';
|
334 |
+
|
335 |
+
echo '<input type="color" name="' . esc_attr( self::OPTION_NAME . '[' . $key . ']' ) . '" id="twitter-link-color"';
|
336 |
+
if ( isset( $this->existing_options[ $key ] ) ) {
|
337 |
+
echo ' value="' . esc_attr( '#' . $this->existing_options[ $key ] ) . '"';
|
338 |
+
}
|
339 |
+
echo \Twitter\WordPress\Helpers\HTMLBuilder::closeVoidHTMLElement() . '>';
|
340 |
+
|
341 |
+
echo '<p class="description">';
|
342 |
+
echo esc_html( __( 'Color of link text inside a Twitter widget.', 'twitter' ) );
|
343 |
+
echo '</p>';
|
344 |
+
}
|
345 |
+
|
346 |
+
/**
|
347 |
+
* Choose a hex color value as the border color
|
348 |
+
*
|
349 |
+
* @since 1.0.0
|
350 |
+
*
|
351 |
+
* @return void
|
352 |
+
*/
|
353 |
+
public function displayBorderColor()
|
354 |
+
{
|
355 |
+
$key = 'border-color';
|
356 |
+
|
357 |
+
echo '<input type="color" name="' . esc_attr( self::OPTION_NAME . '[' . $key . ']' ) . '" id="twitter-border-color"';
|
358 |
+
if ( isset( $this->existing_options[ $key ] ) ) {
|
359 |
+
echo ' value="' . esc_attr( '#' . $this->existing_options[ $key ] ) . '"';
|
360 |
+
}
|
361 |
+
echo \Twitter\WordPress\Helpers\HTMLBuilder::closeVoidHTMLElement() . '>';
|
362 |
+
|
363 |
+
echo '<p class="description">';
|
364 |
+
echo esc_html( __( 'Color of border surrounding a Twitter widget.', 'twitter' ) );
|
365 |
+
echo '</p>';
|
366 |
+
}
|
367 |
+
|
368 |
+
/**
|
369 |
+
* Display inline help content
|
370 |
+
*
|
371 |
+
* @since 1.0.0
|
372 |
+
*
|
373 |
+
* @param WP_Screen $screen current screen
|
374 |
+
*
|
375 |
+
* @return void
|
376 |
+
*/
|
377 |
+
public static function addHelpTab( $screen )
|
378 |
+
{
|
379 |
+
if ( ! $screen ) {
|
380 |
+
return;
|
381 |
+
}
|
382 |
+
|
383 |
+
$content = '<p>' . esc_html( __( 'Twitter Embedded Tweet and Timeline widgets support customization of color theme, link color, and border color inside a rendered widget.', 'twitter' ) ) . '</p>';
|
384 |
+
$content .= '<p>' . esc_html( __( 'Choose a light or dark theme to best match the background color and text color of surrounding content.', 'twitter' ) ) . '</p>';
|
385 |
+
$content .= '<p>' . esc_html( __( 'Link color is applied to linked text including URLs, #hashtags, and @mentions.', 'twitter' ) ) . '</p>';
|
386 |
+
$content .= '<p>' . esc_html( __( 'Border color applies to borders separating Tweet sections or individual Tweets.', 'twitter' ) ) . '</p>';
|
387 |
+
|
388 |
+
$screen->add_help_tab( array(
|
389 |
+
'id' => 'twitter-theme-help',
|
390 |
+
'title' => static::featureName(),
|
391 |
+
'content' => $content,
|
392 |
+
) );
|
393 |
+
}
|
394 |
+
|
395 |
+
/**
|
396 |
+
* Introduction to the Twitter restrictions section
|
397 |
+
*
|
398 |
+
* @since 1.0.0
|
399 |
+
*
|
400 |
+
* @return void
|
401 |
+
*/
|
402 |
+
public static function restrictionsSectionHeader()
|
403 |
+
{
|
404 |
+
echo '<p>';
|
405 |
+
echo esc_html( __( 'Limit Twitter functionality', 'twitter' ) );
|
406 |
+
echo '</p>';
|
407 |
+
}
|
408 |
+
|
409 |
+
/**
|
410 |
+
* Do not track visitors for use in Twitter advertisers and site suggestions
|
411 |
+
*
|
412 |
+
* @since 1.0.0
|
413 |
+
*
|
414 |
+
* @return void
|
415 |
+
*/
|
416 |
+
public function displayDoNotTrack()
|
417 |
+
{
|
418 |
+
$key = 'dnt';
|
419 |
+
|
420 |
+
echo '<label>';
|
421 |
+
echo '<input type="checkbox" name="' . esc_attr( self::OPTION_NAME . '[' . $key . ']' ) . '" id="twitter-dnt" value="1"';
|
422 |
+
checked( isset( $this->existing_options[ $key ] ) );
|
423 |
+
echo \Twitter\WordPress\Helpers\HTMLBuilder::closeVoidHTMLElement() . '>';
|
424 |
+
echo esc_html( __( 'Do not use my website to tailor content and suggestions for Twitter users', 'twitter' ) );
|
425 |
+
echo '</label>';
|
426 |
+
|
427 |
+
echo '<p class="description">';
|
428 |
+
echo esc_html( __( 'Twitter may track website visitors for advertising targeting, suggested Twitter accounts, and other purposes.', 'twitter' ) );
|
429 |
+
echo ' ' . '<a href="https://dev.twitter.com/web/overview/privacy" target="_blank">' . esc_html( _x( 'Read more', 'learn more about this topic', 'twitter' ) ) . '</a>';
|
430 |
+
echo '</p><p class="description">';
|
431 |
+
echo esc_html( __( 'Select this option if you wish to opt-out of Twitter tracking visitors when a Twitter button or widget appears on a webpage.', 'twitter' ) );
|
432 |
+
echo '</p>';
|
433 |
+
}
|
434 |
+
|
435 |
+
/**
|
436 |
+
* Introduce the warnings section
|
437 |
+
*
|
438 |
+
* @since 1.0.0
|
439 |
+
*
|
440 |
+
* @return void
|
441 |
+
*/
|
442 |
+
public static function warningsSectionHeader()
|
443 |
+
{
|
444 |
+
echo '<p>';
|
445 |
+
echo esc_html( __( 'Warnings and error display', 'twitter' ) );
|
446 |
+
echo '</p>';
|
447 |
+
}
|
448 |
+
|
449 |
+
/**
|
450 |
+
* Suppress a Content Security Policy warning
|
451 |
+
*
|
452 |
+
* @since 1.0.0
|
453 |
+
*
|
454 |
+
* @return void
|
455 |
+
*/
|
456 |
+
public function displayContentSecurityPolicy()
|
457 |
+
{
|
458 |
+
$key = 'csp';
|
459 |
+
|
460 |
+
echo '<label><input type="checkbox" name="' . esc_attr( self::OPTION_NAME . '[' . $key . ']' ) . '" value="1"';
|
461 |
+
checked( isset( $this->existing_options[ $key ] ) );
|
462 |
+
echo \Twitter\WordPress\Helpers\HTMLBuilder::closeVoidHTMLElement() . '>';
|
463 |
+
echo esc_html( __( 'Suppress Content Security Policy warnings', 'twitter' ) );
|
464 |
+
echo '</label>';
|
465 |
+
|
466 |
+
echo '<p class="description">';
|
467 |
+
echo sprintf( esc_html( __( 'Please note: Not all widget functionality is supported when a %s is applied', 'twitter' ) ), '<a href="' . esc_url( 'https://developer.mozilla.org/docs/Web/Security/CSP/Introducing_Content_Security_Policy', array( 'https', 'http' ) ) . '">' . esc_html( __( 'Content Security Policy', 'twitter' ) ) . '</a>' );
|
468 |
+
echo '</p>';
|
469 |
+
}
|
470 |
+
|
471 |
+
/**
|
472 |
+
* Sanitize theme options
|
473 |
+
*
|
474 |
+
* @since 1.0.0
|
475 |
+
*
|
476 |
+
* @param array $options submitted options
|
477 |
+
*
|
478 |
+
* @return array associative array of clean options
|
479 |
+
*/
|
480 |
+
public static function sanitizeOptions( $options )
|
481 |
+
{
|
482 |
+
if ( ! is_array( $options ) || empty( $options ) ) {
|
483 |
+
return array();
|
484 |
+
}
|
485 |
+
$clean_options = array();
|
486 |
+
|
487 |
+
if ( isset( $options['theme'] ) && 'dark' === $options['theme'] ) {
|
488 |
+
$clean_options['theme'] = 'dark';
|
489 |
+
}
|
490 |
+
foreach ( array( 'link-color', 'border-color' ) as $color_option ) {
|
491 |
+
if ( ! ( isset( $options[ $color_option ] ) && is_string( $options[ $color_option ] ) ) ) {
|
492 |
+
continue;
|
493 |
+
}
|
494 |
+
$color_hex = ltrim( trim( $options[ $color_option ] ), '#' );
|
495 |
+
if ( strlen( $color_hex ) <= 6 && ctype_xdigit( $color_hex ) ) {
|
496 |
+
$clean_options[ $color_option ] = strtolower( $color_hex );
|
497 |
+
}
|
498 |
+
}
|
499 |
+
foreach ( array( 'dnt', 'csp' ) as $bool_option ) {
|
500 |
+
if ( isset( $options[ $bool_option ] ) && $options[ $bool_option ] ) {
|
501 |
+
$clean_options[ $bool_option ] = true;
|
502 |
+
}
|
503 |
+
}
|
504 |
+
|
505 |
+
return $clean_options;
|
506 |
+
}
|
507 |
+
}
|
src/Twitter/WordPress/Admin/Settings/TweetButton.php
ADDED
@@ -0,0 +1,334 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Admin\Settings;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Store a Twitter username for attribution of site content
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class TweetButton
|
34 |
+
{
|
35 |
+
/**
|
36 |
+
* Define our option name
|
37 |
+
*
|
38 |
+
* @since 1.0.0
|
39 |
+
*
|
40 |
+
* @type string
|
41 |
+
*/
|
42 |
+
const OPTION_NAME = 'twitter_share';
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Priority of the section affecting insertion order on the single settings page
|
46 |
+
*
|
47 |
+
* Display after site attribution section
|
48 |
+
*
|
49 |
+
* @since 1.0.0
|
50 |
+
*
|
51 |
+
* @type int
|
52 |
+
*/
|
53 |
+
const SECTION_PRIORITY = 6;
|
54 |
+
|
55 |
+
/**
|
56 |
+
* The hook suffix of the parent settings page
|
57 |
+
*
|
58 |
+
* @since 1.0.0
|
59 |
+
*
|
60 |
+
* @type string
|
61 |
+
*/
|
62 |
+
protected $hook_suffix;
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Reference the feature by name
|
66 |
+
*
|
67 |
+
* @since 1.0.0
|
68 |
+
*
|
69 |
+
* @return string translated feature name
|
70 |
+
*/
|
71 |
+
public static function featureName()
|
72 |
+
{
|
73 |
+
return __( 'Tweet Button', 'twitter' );
|
74 |
+
}
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Add Tweet button content wrapper option and settings section to an existing settings page
|
78 |
+
*
|
79 |
+
* @since 1.0.0
|
80 |
+
*
|
81 |
+
* @param string $hook_suffix hook suffix of an existing settings page
|
82 |
+
*
|
83 |
+
* @return bool site attribution settings loaded
|
84 |
+
*/
|
85 |
+
public static function addToSettingsPage( $hook_suffix )
|
86 |
+
{
|
87 |
+
if ( ! ( is_string( $hook_suffix ) && $hook_suffix ) ) {
|
88 |
+
return false;
|
89 |
+
}
|
90 |
+
|
91 |
+
$settings = new static();
|
92 |
+
$settings->hook_suffix = $hook_suffix;
|
93 |
+
|
94 |
+
register_setting( $hook_suffix, self::OPTION_NAME, array( __CLASS__, 'sanitizeOption' ) );
|
95 |
+
add_action(
|
96 |
+
'load-' . $hook_suffix,
|
97 |
+
array( &$settings, 'onload' ),
|
98 |
+
5, // after theme settings
|
99 |
+
0
|
100 |
+
);
|
101 |
+
|
102 |
+
return true;
|
103 |
+
}
|
104 |
+
|
105 |
+
/**
|
106 |
+
* Set up settings section
|
107 |
+
*
|
108 |
+
* @since 1.0.0
|
109 |
+
*
|
110 |
+
* @return void
|
111 |
+
*/
|
112 |
+
public function onload()
|
113 |
+
{
|
114 |
+
if ( ! isset( $this->hook_suffix ) ) {
|
115 |
+
return;
|
116 |
+
}
|
117 |
+
|
118 |
+
$options = get_option( self::OPTION_NAME );
|
119 |
+
if ( ! is_array( $options ) ) {
|
120 |
+
$options = array();
|
121 |
+
}
|
122 |
+
$this->existing_options = $options;
|
123 |
+
|
124 |
+
add_action(
|
125 |
+
'add-' . $this->hook_suffix . '-section',
|
126 |
+
array( &$this, 'defineSection' ),
|
127 |
+
static::SECTION_PRIORITY,
|
128 |
+
0 // no parameters
|
129 |
+
);
|
130 |
+
}
|
131 |
+
|
132 |
+
/**
|
133 |
+
* Define Tweet button section and the fields within
|
134 |
+
*
|
135 |
+
* @since 1.0.0
|
136 |
+
*
|
137 |
+
* @return void
|
138 |
+
*/
|
139 |
+
public function defineSection()
|
140 |
+
{
|
141 |
+
if ( ! isset( $this->hook_suffix ) ) {
|
142 |
+
return;
|
143 |
+
}
|
144 |
+
|
145 |
+
$section = 'tweet-button';
|
146 |
+
add_settings_section(
|
147 |
+
$section,
|
148 |
+
static::featureName(),
|
149 |
+
array( __CLASS__, 'sectionHeader' ),
|
150 |
+
$this->hook_suffix
|
151 |
+
);
|
152 |
+
|
153 |
+
add_settings_field(
|
154 |
+
'tweet-button-position',
|
155 |
+
_x( 'Position', 'Display of content relative to other content. above, below, left, right', 'twitter' ),
|
156 |
+
array( &$this, 'displayPosition' ),
|
157 |
+
$this->hook_suffix,
|
158 |
+
$section
|
159 |
+
);
|
160 |
+
add_settings_field(
|
161 |
+
'tweet-button-count',
|
162 |
+
_x( 'Count', 'Numeric sum: number of Tweets referencing this URL', 'twitter' ),
|
163 |
+
array( &$this, 'displayCount' ),
|
164 |
+
$this->hook_suffix,
|
165 |
+
$section
|
166 |
+
);
|
167 |
+
add_settings_field(
|
168 |
+
'tweet-button-size',
|
169 |
+
__( 'Size' ),
|
170 |
+
array( &$this, 'displaySize' ),
|
171 |
+
$this->hook_suffix,
|
172 |
+
$section
|
173 |
+
);
|
174 |
+
}
|
175 |
+
|
176 |
+
/**
|
177 |
+
* Introduce the settings section
|
178 |
+
*
|
179 |
+
* @since 1.0.0
|
180 |
+
*
|
181 |
+
* @return void
|
182 |
+
*/
|
183 |
+
public static function sectionHeader()
|
184 |
+
{
|
185 |
+
echo '<p>';
|
186 |
+
echo esc_html( __( 'Add a Tweet Button to every public post.', 'twitter' ) );
|
187 |
+
echo '</p>';
|
188 |
+
}
|
189 |
+
|
190 |
+
/**
|
191 |
+
* Get option values and labels for dropdown display
|
192 |
+
*
|
193 |
+
* @since 1.0.0
|
194 |
+
*
|
195 |
+
* @return array option values and labels {
|
196 |
+
* @type string option value
|
197 |
+
* @type string translated option label
|
198 |
+
* }
|
199 |
+
*/
|
200 |
+
public static function getPositionOptions()
|
201 |
+
{
|
202 |
+
return array(
|
203 |
+
'' => ' ',
|
204 |
+
'before' => _x( 'before', 'before another piece of content', 'twitter' ),
|
205 |
+
'after' => _x( 'after', 'after another piece of content', 'twitter' ),
|
206 |
+
'both' => _x( 'before & after', 'before and after another piece of content', 'twitter' )
|
207 |
+
);
|
208 |
+
}
|
209 |
+
|
210 |
+
/**
|
211 |
+
* Choose to display a Tweet button before, after, or before & after every public post
|
212 |
+
*
|
213 |
+
* @since 1.0.0
|
214 |
+
*
|
215 |
+
* @return void
|
216 |
+
*/
|
217 |
+
public function displayPosition()
|
218 |
+
{
|
219 |
+
$key = 'position';
|
220 |
+
|
221 |
+
$position_options = static::getPositionOptions();
|
222 |
+
$existing_value = '';
|
223 |
+
if ( isset( $this->existing_options ) && isset( $this->existing_options[ $key ] ) && $this->existing_options[ $key ] && isset( $position_options[ $this->existing_options[ $key ] ] ) ) {
|
224 |
+
$existing_value = $this->existing_options[ $key ];
|
225 |
+
}
|
226 |
+
|
227 |
+
$select = '<select name="' . esc_attr( static::OPTION_NAME . '[' . $key . ']' ) . '">';
|
228 |
+
foreach ( $position_options as $option => $label ) {
|
229 |
+
$select .= '<option';
|
230 |
+
if ( $option ) {
|
231 |
+
$select .= ' value="' . esc_attr( $option ) . '"';
|
232 |
+
}
|
233 |
+
if ( $option === $existing_value ) {
|
234 |
+
$select .= ' selected';
|
235 |
+
if ( ! current_theme_supports( 'html5' ) ) {
|
236 |
+
$select .= '="selected"';
|
237 |
+
}
|
238 |
+
}
|
239 |
+
$select .= '>' . esc_html( $label ) . '</option>';
|
240 |
+
}
|
241 |
+
$select .= '</select>';
|
242 |
+
|
243 |
+
echo sprintf( esc_html( _x( 'Display Tweet Button %s post content', 'display Tweet Button relative to the content of an article', 'twitter' ) ), $select );
|
244 |
+
}
|
245 |
+
|
246 |
+
/**
|
247 |
+
* Choose a large button size, overriding the default
|
248 |
+
*
|
249 |
+
* @since 1.0.0
|
250 |
+
*
|
251 |
+
* @return void
|
252 |
+
*/
|
253 |
+
public function displaySize()
|
254 |
+
{
|
255 |
+
$key = 'size';
|
256 |
+
|
257 |
+
echo '<label><input type="checkbox" name="' . esc_attr( static::OPTION_NAME . '[' . $key . ']' ) . '" value="large"';
|
258 |
+
|
259 |
+
if ( isset( $this->existing_options ) && isset( $this->existing_options[ $key ] ) && 'large' === $this->existing_options[ $key ] ) {
|
260 |
+
echo ' checked';
|
261 |
+
if ( ! current_theme_supports( 'html5' ) ) {
|
262 |
+
echo '="checked"';
|
263 |
+
}
|
264 |
+
}
|
265 |
+
echo \Twitter\WordPress\Helpers\HTMLBuilder::closeVoidHTMLElement() . '> ' . esc_html( __( 'Large button', 'twitter' ) ) . '</label>';
|
266 |
+
}
|
267 |
+
|
268 |
+
/**
|
269 |
+
* Control display of the total number of Tweets citing the Tweet URL
|
270 |
+
*
|
271 |
+
* @since 1.0.0
|
272 |
+
*
|
273 |
+
* @return void
|
274 |
+
*/
|
275 |
+
public function displayCount()
|
276 |
+
{
|
277 |
+
$key = 'count';
|
278 |
+
|
279 |
+
echo '<label><input type="checkbox" name="' . esc_attr( static::OPTION_NAME . '[' . $key . ']' ) . '" value="1"';
|
280 |
+
if ( ! ( isset( $this->existing_options ) && isset( $this->existing_options[ $key ] ) && 'none' === $this->existing_options[ $key ] ) ) {
|
281 |
+
echo ' checked';
|
282 |
+
if ( ! current_theme_supports( 'html5' ) ) {
|
283 |
+
echo '="checked"';
|
284 |
+
}
|
285 |
+
}
|
286 |
+
echo \Twitter\WordPress\Helpers\HTMLBuilder::closeVoidHTMLElement() . '> ' . esc_html( __( 'Show the number of Tweets citing the post URL', 'twitter' ) ) . '</label>';
|
287 |
+
}
|
288 |
+
|
289 |
+
/**
|
290 |
+
* Sanitize posted option before saving
|
291 |
+
*
|
292 |
+
* @since 1.0.0
|
293 |
+
*
|
294 |
+
* @param array $options submitted option {
|
295 |
+
* @type string option name
|
296 |
+
* @type mixed option value
|
297 |
+
* }
|
298 |
+
*
|
299 |
+
* @return array $options cleaned option {
|
300 |
+
* @type string option name
|
301 |
+
* @type string option value
|
302 |
+
* }
|
303 |
+
*/
|
304 |
+
public static function sanitizeOption( $options )
|
305 |
+
{
|
306 |
+
if ( ! is_array( $options ) ) {
|
307 |
+
return array();
|
308 |
+
}
|
309 |
+
|
310 |
+
$clean_options = array();
|
311 |
+
|
312 |
+
$key = 'position';
|
313 |
+
if ( isset( $options[ $key ] ) && $options[ $key ] ) {
|
314 |
+
$position_options = static::getPositionOptions();
|
315 |
+
if ( isset( $position_options[ $options[ $key ] ] ) ) {
|
316 |
+
$clean_options[ $key ] = $options[ $key ];
|
317 |
+
}
|
318 |
+
unset( $position_options );
|
319 |
+
}
|
320 |
+
unset($key);
|
321 |
+
|
322 |
+
if ( isset( $options['size'] ) && 'large' === $options['size'] ) {
|
323 |
+
$clean_options['size'] = 'large';
|
324 |
+
}
|
325 |
+
|
326 |
+
$key = 'count';
|
327 |
+
if ( ! ( isset( $options[ $key ] ) && 1 == $options[ $key ] ) ) {
|
328 |
+
$clean_options[ $key ] = 'none';
|
329 |
+
}
|
330 |
+
unset( $key );
|
331 |
+
|
332 |
+
return $clean_options;
|
333 |
+
}
|
334 |
+
}
|
src/Twitter/WordPress/Cards/Compatibility.php
ADDED
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Cards;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Compatability wrappers for popular WordPress plugins with existing Twitter Cards functionality
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class Compatibility
|
34 |
+
{
|
35 |
+
/**
|
36 |
+
* Disable Twitter Cards markup output in Jetpack
|
37 |
+
*
|
38 |
+
* Filter should be hooked before plugins_loaded priority 99
|
39 |
+
*
|
40 |
+
* @since 1.0.0
|
41 |
+
*
|
42 |
+
* @return void
|
43 |
+
*/
|
44 |
+
public static function disableJetpack()
|
45 |
+
{
|
46 |
+
add_filter( 'jetpack_disable_twitter_cards', '__return_true' );
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Add compatability wrappers for known, popular Twitter Cards plugins which may conflict with our plugin
|
51 |
+
*
|
52 |
+
* @since 1.0.0
|
53 |
+
*
|
54 |
+
* @return void
|
55 |
+
*/
|
56 |
+
public static function init()
|
57 |
+
{
|
58 |
+
static::disableJetpack();
|
59 |
+
}
|
60 |
+
}
|
src/Twitter/WordPress/Cards/Generator.php
ADDED
@@ -0,0 +1,465 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Cards;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Generate Twitter Card data based on the current WordPress context
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class Generator
|
34 |
+
{
|
35 |
+
/**
|
36 |
+
* Card types supported by the Twitter plugin for WordPress
|
37 |
+
*
|
38 |
+
* Maps short names to Twitter Card builder class names
|
39 |
+
*
|
40 |
+
* @since 1.0.0
|
41 |
+
*
|
42 |
+
* @type array Twitter Card options {
|
43 |
+
* @type string Twitter Card type
|
44 |
+
* @type string Twitter Card class name
|
45 |
+
* }
|
46 |
+
*/
|
47 |
+
public static $SUPPORTED_CARDS = array(
|
48 |
+
'summary' => '\Twitter\Cards\Summary',
|
49 |
+
'summary_large_image' => '\Twitter\Cards\SummaryLargeImage',
|
50 |
+
'photo' => '\Twitter\Cards\Photo',
|
51 |
+
'gallery' => '\Twitter\Cards\Gallery',
|
52 |
+
'product' => '\Twitter\Cards\Product',
|
53 |
+
);
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Is the passed card type a Twitter Card type supported by the plugin
|
57 |
+
*
|
58 |
+
* @since 1.0.0
|
59 |
+
*
|
60 |
+
* @param string $card_type Twitter Card type
|
61 |
+
*
|
62 |
+
* @return bool true if card type supported by plugin
|
63 |
+
*/
|
64 |
+
public static function isSupportedCardType( $card_type )
|
65 |
+
{
|
66 |
+
return ( is_string( $card_type ) && $card_type && isset( static::$SUPPORTED_CARDS[ $card_type ] ) );
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Initialize a Twitter Card object for a given card type string
|
71 |
+
*
|
72 |
+
* @since 1.0.0
|
73 |
+
*
|
74 |
+
* @param string $card_type Twitter Card global type
|
75 |
+
*
|
76 |
+
* @return \Twitter\Cards\Card|null Twitter Card object
|
77 |
+
*/
|
78 |
+
public static function getCardForType( $card_type )
|
79 |
+
{
|
80 |
+
if ( static::isSupportedCardType( $card_type ) ) {
|
81 |
+
return (new static::$SUPPORTED_CARDS[ $card_type ]);
|
82 |
+
}
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Set up a card object for the query type
|
87 |
+
*
|
88 |
+
* Allows sites to override the Twitter Card type for multiple query types through a filter
|
89 |
+
* Set up card attributes common to all queries
|
90 |
+
*
|
91 |
+
* @param string|null $query_type short name for current query type, similar to WP_Query flags
|
92 |
+
* @param int|string|null $object_id current object identifier: post ID, author ID, etc. depending on query type
|
93 |
+
* @param string $card_type default Twitter Card type for the query
|
94 |
+
*
|
95 |
+
* @return \Twitter\Cards\Card|null Twitter Card object or null if minimum requirements not met
|
96 |
+
*/
|
97 |
+
public static function getCardObject( $query_type = null, $object_id = null, $card_type = 'summary' )
|
98 |
+
{
|
99 |
+
if ( ! static::isSupportedCardType( $card_type ) ) {
|
100 |
+
return;
|
101 |
+
}
|
102 |
+
if ( ! ( is_string( $query_type ) && $query_type ) ) {
|
103 |
+
$query_type = null;
|
104 |
+
}
|
105 |
+
|
106 |
+
/**
|
107 |
+
* Filter the Twitter Card template to be applied for the given query type and object
|
108 |
+
*
|
109 |
+
* @since 1.0.0
|
110 |
+
*
|
111 |
+
* @link https://dev.twitter.com/cards/types Twitter Card types
|
112 |
+
*
|
113 |
+
* @param string $card_type Twitter Card type
|
114 |
+
* @param string|null $query_type current rendering context. similar to WP_Query flags (home, archive, author, post)
|
115 |
+
* @param int|string|null $object_id current object identifier: post ID, author ID, etc. depending on query type
|
116 |
+
*/
|
117 |
+
$card_type = apply_filters( 'twitter_card_type', $card_type, $query_type, $object_id );
|
118 |
+
|
119 |
+
$card = static::getCardForType( $card_type );
|
120 |
+
if ( ! ( $card && is_a( $card, '\Twitter\Cards\Card' ) ) ) {
|
121 |
+
return;
|
122 |
+
}
|
123 |
+
|
124 |
+
return static::addSiteAttribution( $card, ( $query_type === 'post' ? $object_id : null ) );
|
125 |
+
}
|
126 |
+
|
127 |
+
/**
|
128 |
+
* Add site attibution to the passed card if a Twitter username is stored for the current site
|
129 |
+
*
|
130 |
+
* @since 1.0.0
|
131 |
+
*
|
132 |
+
* @param \Twitter\Cards\Card $card Twitter Card object
|
133 |
+
* @param int|string $post_id WP_Post->ID or proprietary post identifier
|
134 |
+
*
|
135 |
+
* @return \Twitter\Cards\Card Twitter Card object
|
136 |
+
*/
|
137 |
+
public static function addSiteAttribution( $card, $post_id = null )
|
138 |
+
{
|
139 |
+
if ( ! is_a( $card, '\Twitter\Cards\Card' ) ) {
|
140 |
+
return;
|
141 |
+
}
|
142 |
+
if ( ! method_exists( $card, 'setSite' ) ) {
|
143 |
+
return $card;
|
144 |
+
}
|
145 |
+
|
146 |
+
$site_username = \Twitter\WordPress\Site\Username::getSiteAttribution( $post_id );
|
147 |
+
if ( $site_username ) {
|
148 |
+
$card->setSite( \Twitter\Cards\Components\Account::fromScreenName( $site_username ) );
|
149 |
+
}
|
150 |
+
|
151 |
+
return $card;
|
152 |
+
}
|
153 |
+
|
154 |
+
/**
|
155 |
+
* Output Twitter Card markup for the current display context
|
156 |
+
*
|
157 |
+
* @since 1.0.0
|
158 |
+
*
|
159 |
+
* @return \Twitter\Cards\Card|null Twitter Card object or null if no card available or condition not met for query type
|
160 |
+
*/
|
161 |
+
public static function get()
|
162 |
+
{
|
163 |
+
if ( is_home() || is_front_page() ) {
|
164 |
+
return static::buildHomepageCard();
|
165 |
+
} else if ( is_singular() ) {
|
166 |
+
return static::buildPostCard();
|
167 |
+
} else if ( is_author() ) {
|
168 |
+
return static::buildAuthorCard();
|
169 |
+
} else if ( is_archive() ) {
|
170 |
+
return static::buildArchiveCard();
|
171 |
+
}
|
172 |
+
}
|
173 |
+
|
174 |
+
/**
|
175 |
+
* Twitter Card markup for the site homepage
|
176 |
+
*
|
177 |
+
* @since 1.0.0
|
178 |
+
*
|
179 |
+
* @return \Twitter\Cards\Card|null Twitter Card or null if minimum requirements not met
|
180 |
+
*/
|
181 |
+
public static function buildHomepageCard()
|
182 |
+
{
|
183 |
+
$query_type = 'home';
|
184 |
+
$card = static::getCardObject( $query_type );
|
185 |
+
if ( ! $card ) {
|
186 |
+
return;
|
187 |
+
}
|
188 |
+
|
189 |
+
/**
|
190 |
+
* Filter the title displayed in a Twitter Card template
|
191 |
+
*
|
192 |
+
* A title is only passed through this filter when not explicitly provided by the website for display in a Twitter Card template.
|
193 |
+
* This distinction is meant to simplify possible overrides by other plugins.
|
194 |
+
* Act on the `twitter_card` filter to always override this value late in the card builder process.
|
195 |
+
*
|
196 |
+
* @since 1.0.0
|
197 |
+
*
|
198 |
+
* @param string $title default title
|
199 |
+
* @param string $query_type current context, similar to a WP_Query
|
200 |
+
* @param string $object_id object identifier for the query type, if applicable (post ID, author ID)
|
201 |
+
*/
|
202 |
+
$title = apply_filters( 'twitter_card_title', get_bloginfo( 'name' ) ?: '', $query_type, null );
|
203 |
+
if ( $title ) {
|
204 |
+
$card->setTitle( \Twitter\WordPress\Cards\Sanitize::sanitizePlainTextString( $title ) );
|
205 |
+
}
|
206 |
+
unset( $title );
|
207 |
+
|
208 |
+
if ( method_exists( $card, 'setDescription' ) ) {
|
209 |
+
/**
|
210 |
+
* Filter the description displayed in a Twitter Card template
|
211 |
+
*
|
212 |
+
* A title is only passed through this filter when not explicitly provided by the website for display in a Twitter Card template.
|
213 |
+
* This distinction is meant to simplify possible overrides by other plugins.
|
214 |
+
* Act on the `twitter_card` filter to always override this value late in the card builder process.
|
215 |
+
*
|
216 |
+
* @since 1.0.0
|
217 |
+
*
|
218 |
+
* @param string $description default description
|
219 |
+
* @param string $query_type current context, similar to a WP_Query
|
220 |
+
* @param string $object_id object identifier for the query type, if applicable (post ID, author ID)
|
221 |
+
*/
|
222 |
+
$description = apply_filters( 'twitter_card_description', get_bloginfo( 'description' ) ?: '', $query_type, null );
|
223 |
+
if ( $description ) {
|
224 |
+
$card->setDescription( \Twitter\WordPress\Cards\Sanitize::sanitizeDescription( $description ) );
|
225 |
+
}
|
226 |
+
unset( $description );
|
227 |
+
}
|
228 |
+
|
229 |
+
return $card;
|
230 |
+
}
|
231 |
+
|
232 |
+
/**
|
233 |
+
* Build a card for an author view
|
234 |
+
*
|
235 |
+
* @since 1.0.0
|
236 |
+
*
|
237 |
+
* @return \Twitter\Cards\Card|null Twitter Card object or null if minimum requirements not met
|
238 |
+
*/
|
239 |
+
public static function buildAuthorCard()
|
240 |
+
{
|
241 |
+
$author = get_queried_object();
|
242 |
+
if ( ! ( $author && isset( $author->ID ) ) ) {
|
243 |
+
return;
|
244 |
+
}
|
245 |
+
|
246 |
+
$query_type = 'author';
|
247 |
+
$card = static::getCardObject( $query_type, $author->ID );
|
248 |
+
if ( ! $card ) {
|
249 |
+
return;
|
250 |
+
}
|
251 |
+
|
252 |
+
/** This filter is documented in ::buildHomepageCard */
|
253 |
+
$title = apply_filters( 'twitter_card_title', get_the_author_meta( 'display_name', $author->ID ) ?: '', $query_type, $author->ID );
|
254 |
+
if ( $title ) {
|
255 |
+
$card->setTitle( \Twitter\WordPress\Cards\Sanitize::sanitizePlainTextString( $title ) );
|
256 |
+
}
|
257 |
+
unset( $title );
|
258 |
+
|
259 |
+
if ( method_exists( $card, 'setDescription' ) ) {
|
260 |
+
/** This filter is documented in ::buildHomepageCard */
|
261 |
+
$description = apply_filters( 'twitter_card_description', get_the_author_meta( 'description', $author->ID ) ?: '', $query_type, $author->ID );
|
262 |
+
if ( $description ) {
|
263 |
+
$card->setDescription( \Twitter\WordPress\Cards\Sanitize::sanitizeDescription( $description ) );
|
264 |
+
}
|
265 |
+
unset( $description );
|
266 |
+
}
|
267 |
+
if ( method_exists( $card, 'setCreator' ) ) {
|
268 |
+
$author_twitter_username = \Twitter\WordPress\User\Meta::getTwitterUsername( $author->ID );
|
269 |
+
if ( $author_twitter_username ) {
|
270 |
+
$card->setCreator( \Twitter\Cards\Components\Account::fromScreenName( $author_twitter_username ) );
|
271 |
+
}
|
272 |
+
unset( $author_twitter_username );
|
273 |
+
}
|
274 |
+
|
275 |
+
return $card;
|
276 |
+
}
|
277 |
+
|
278 |
+
/**
|
279 |
+
* Build a card for an archive view
|
280 |
+
*
|
281 |
+
* @since 1.0.0
|
282 |
+
*
|
283 |
+
* @return \Twitter\Cards\Card|null Twitter Card object or null if minimum requirements not met
|
284 |
+
*/
|
285 |
+
public static function buildArchiveCard()
|
286 |
+
{
|
287 |
+
$query_type = 'archive';
|
288 |
+
$card = static::getCardObject( $query_type );
|
289 |
+
if ( ! $card ) {
|
290 |
+
return;
|
291 |
+
}
|
292 |
+
|
293 |
+
// WP 4.1+ functions
|
294 |
+
if ( function_exists( 'get_the_archive_title' ) ) {
|
295 |
+
/** This filter is documented in ::buildHomepageCard */
|
296 |
+
$title = apply_filters( 'twitter_card_title', get_the_archive_title(), $query_type, null );
|
297 |
+
if ( $title ) {
|
298 |
+
$card->setTitle( \Twitter\WordPress\Cards\Sanitize::sanitizePlainTextString( $title ) );
|
299 |
+
}
|
300 |
+
unset( $title );
|
301 |
+
}
|
302 |
+
if ( method_exists( $card, 'setDescription' ) && function_exists( 'get_the_archive_description' ) ) {
|
303 |
+
/** This filter is documented in ::buildHomepageCard */
|
304 |
+
$description = apply_filters( 'twitter_card_description', get_the_archive_description(), $query_type, null );
|
305 |
+
if ( $description ) {
|
306 |
+
$card->setDescription( \Twitter\WordPress\Cards\Sanitize::sanitizeDescription( $description ) );
|
307 |
+
}
|
308 |
+
unset( $description );
|
309 |
+
}
|
310 |
+
|
311 |
+
return $card;
|
312 |
+
}
|
313 |
+
|
314 |
+
/**
|
315 |
+
* Build a card for a single-post view
|
316 |
+
*
|
317 |
+
* @since 1.0.0
|
318 |
+
*
|
319 |
+
* @return \Twitter\Cards\Card|null Twitter Card object or null
|
320 |
+
*/
|
321 |
+
public static function buildPostCard()
|
322 |
+
{
|
323 |
+
$post = get_post();
|
324 |
+
|
325 |
+
if ( ! $post || ! isset( $post->ID ) ) {
|
326 |
+
return;
|
327 |
+
}
|
328 |
+
setup_postdata( $post );
|
329 |
+
|
330 |
+
// do not publish card markup for password-protected posts
|
331 |
+
if ( ! empty( $post->post_password ) ) {
|
332 |
+
return;
|
333 |
+
}
|
334 |
+
|
335 |
+
// only publish card markup for public posts
|
336 |
+
$post_status_object = get_post_status_object( get_post_status( $post->ID ) );
|
337 |
+
if ( ! ( $post_status_object && isset( $post_status_object->public ) && $post_status_object->public ) ) {
|
338 |
+
return;
|
339 |
+
}
|
340 |
+
|
341 |
+
// only output Twitter Card markup for public post types
|
342 |
+
// don't waste page generation time if the page is not meant to be consumed by TwitterBot
|
343 |
+
$post_type = get_post_type( $post );
|
344 |
+
if ( ! $post_type ) {
|
345 |
+
return;
|
346 |
+
}
|
347 |
+
$post_type_object = get_post_type_object( $post_type );
|
348 |
+
if ( ! ( $post_type_object && isset( $post_type_object->public ) && $post_status_object->public ) ) {
|
349 |
+
return;
|
350 |
+
}
|
351 |
+
|
352 |
+
$card_type = 'summary';
|
353 |
+
if ( has_post_format( 'image', $post->ID ) ) {
|
354 |
+
$card_type = 'photo';
|
355 |
+
} else if ( has_post_format( 'gallery', $post->ID ) ) {
|
356 |
+
$card_type = 'gallery';
|
357 |
+
}
|
358 |
+
|
359 |
+
$query_type = 'post';
|
360 |
+
$card = static::getCardObject( $query_type, $post->ID, $card_type );
|
361 |
+
if ( ! $card ) {
|
362 |
+
return;
|
363 |
+
}
|
364 |
+
|
365 |
+
$card_class = get_class( $card );
|
366 |
+
if ( ! $card_class ) {
|
367 |
+
return;
|
368 |
+
}
|
369 |
+
|
370 |
+
// get post-specific overrides
|
371 |
+
$cards_post_meta = get_post_meta(
|
372 |
+
$post->ID,
|
373 |
+
\Twitter\WordPress\Admin\Post\TwitterCard::META_KEY,
|
374 |
+
true // single
|
375 |
+
);
|
376 |
+
|
377 |
+
// all cards support title
|
378 |
+
if ( post_type_supports( $post_type, 'title' ) ) {
|
379 |
+
$title = '';
|
380 |
+
if ( isset( $cards_post_meta['title'] ) && $cards_post_meta['title'] ) {
|
381 |
+
// do not pass an explicitly defined Twitter Card title through the title filter
|
382 |
+
$title = $cards_post_meta['title'];
|
383 |
+
} else {
|
384 |
+
/** This filter is documented in ::buildHomepageCard */
|
385 |
+
$title = apply_filters( 'twitter_card_title', get_the_title( $post->ID ), $query_type, $post->ID );
|
386 |
+
}
|
387 |
+
if ( $title ) {
|
388 |
+
$card->setTitle( \Twitter\WordPress\Cards\Sanitize::sanitizePlainTextString( $title ) );
|
389 |
+
}
|
390 |
+
unset( $title );
|
391 |
+
}
|
392 |
+
|
393 |
+
// add description if card supports
|
394 |
+
if ( method_exists( $card, 'setDescription' ) && post_type_supports( $post_type, 'excerpt' ) ) {
|
395 |
+
$description = '';
|
396 |
+
if ( isset( $cards_post_meta['description'] ) ) {
|
397 |
+
// do not pass an explicitly defined Twitter Card description through the description filter
|
398 |
+
$description = $cards_post_meta['description'];
|
399 |
+
} else if ( ! empty( $post->post_excerpt ) ) {
|
400 |
+
/** This filter is documented in wp-includes/post-template.php */
|
401 |
+
$description = apply_filters( 'get_the_excerpt', $post->post_excerpt );
|
402 |
+
/** This filter is documented in ::buildHomepageCard */
|
403 |
+
$description = apply_filters( 'twitter_card_description', $description, $query_type, $post->ID );
|
404 |
+
} else {
|
405 |
+
/** This filter is documented in ::buildHomepageCard */
|
406 |
+
$description = apply_filters( 'twitter_card_description', $post->post_content, $query_type, $post->ID );
|
407 |
+
}
|
408 |
+
|
409 |
+
$description = \Twitter\WordPress\Cards\Sanitize::sanitizeDescription( $description );
|
410 |
+
if ( $description ) {
|
411 |
+
$card->setDescription( $description );
|
412 |
+
}
|
413 |
+
unset( $description );
|
414 |
+
}
|
415 |
+
|
416 |
+
if ( defined( $card_class . '::MIN_IMAGE_WIDTH' ) && defined( $card_class . '::MIN_IMAGE_HEIGHT' ) ) {
|
417 |
+
if ( method_exists( $card, 'setImage' ) ) {
|
418 |
+
// single image card type
|
419 |
+
|
420 |
+
$cards_image_handler = new \Twitter\WordPress\Cards\ImageHandler();
|
421 |
+
$cards_image_handler->setLimit( 1 );
|
422 |
+
$cards_image_handler->setMinWidth( $card::MIN_IMAGE_WIDTH );
|
423 |
+
$cards_image_handler->setMinHeight( $card::MIN_IMAGE_HEIGHT );
|
424 |
+
|
425 |
+
// discover images associated with the post
|
426 |
+
$cards_image_handler->addPostImages( $post );
|
427 |
+
|
428 |
+
$images = $cards_image_handler->getTwitterCardImages();
|
429 |
+
if ( ! empty( $images ) ) {
|
430 |
+
$card->setImage( array_shift( $images ) );
|
431 |
+
}
|
432 |
+
unset( $images );
|
433 |
+
|
434 |
+
unset( $cards_image_handler );
|
435 |
+
} else if ( defined( $card_class . '::MAX_IMAGES' ) && method_exists( $card, 'addImage' ) ) {
|
436 |
+
// multiple image card type
|
437 |
+
|
438 |
+
$cards_image_handler = new \Twitter\WordPress\Cards\ImageHandler();
|
439 |
+
$cards_image_handler->setLimit( $card::MAX_IMAGES );
|
440 |
+
$cards_image_handler->setMinWidth( $card::MIN_IMAGE_WIDTH );
|
441 |
+
$cards_image_handler->setMinHeight( $card::MIN_IMAGE_HEIGHT );
|
442 |
+
|
443 |
+
// discover images associated with the post
|
444 |
+
$cards_image_handler->addPostImages( $post );
|
445 |
+
$images = $cards_image_handler->getTwitterCardImages();
|
446 |
+
if ( ! empty( $images ) ) {
|
447 |
+
array_walk( $images, array( $card, 'addImage' ) );
|
448 |
+
}
|
449 |
+
unset( $images );
|
450 |
+
|
451 |
+
unset( $cards_image_handler );
|
452 |
+
}
|
453 |
+
}
|
454 |
+
|
455 |
+
if ( post_type_supports( $post_type, 'author' ) && isset( $post->post_author ) && method_exists( $card, 'setCreator' ) ) {
|
456 |
+
$author_twitter_username = \Twitter\WordPress\User\Meta::getTwitterUsername( $post->post_author );
|
457 |
+
if ( $author_twitter_username ) {
|
458 |
+
$card->setCreator( \Twitter\Cards\Components\Account::fromScreenName( $author_twitter_username ) );
|
459 |
+
}
|
460 |
+
unset( $author_twitter_username );
|
461 |
+
}
|
462 |
+
|
463 |
+
return $card;
|
464 |
+
}
|
465 |
+
}
|
src/Twitter/WordPress/Cards/ImageHandler.php
ADDED
@@ -0,0 +1,356 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Cards;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Discover images in a WordPress post eligible for inclusion as a Twitter Card image
|
30 |
+
*
|
31 |
+
* Rejects images under the minimum dimensions specified for the card type. Rejection allows the search for a suitable image to continue, up to the total number of images used in the card template.
|
32 |
+
*
|
33 |
+
* @since 1.0.0
|
34 |
+
*/
|
35 |
+
class ImageHandler
|
36 |
+
{
|
37 |
+
|
38 |
+
/**
|
39 |
+
* 1 MB in decimal units
|
40 |
+
*
|
41 |
+
* @since 1.0.0
|
42 |
+
*
|
43 |
+
* @var int
|
44 |
+
*/
|
45 |
+
const MAX_FILESIZE = 1000000;
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Maximum number of images supported by the Twitter Cards template
|
49 |
+
*
|
50 |
+
* @since 1.0.0
|
51 |
+
*
|
52 |
+
* @var int
|
53 |
+
*/
|
54 |
+
protected $limit = 1;
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Minimum required width of a Twitter Card image
|
58 |
+
*
|
59 |
+
* @since 1.0.0
|
60 |
+
*
|
61 |
+
* @var int
|
62 |
+
*/
|
63 |
+
protected $min_width = 120;
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Minimum required height of a Twitter Card image
|
67 |
+
*
|
68 |
+
* @since 1.0.0
|
69 |
+
*
|
70 |
+
* @var int
|
71 |
+
*/
|
72 |
+
protected $min_height = 120;
|
73 |
+
|
74 |
+
/**
|
75 |
+
* Store discovered images for the post
|
76 |
+
*
|
77 |
+
* @since 1.0.0
|
78 |
+
*
|
79 |
+
* @var array images {
|
80 |
+
* @type string image URL
|
81 |
+
* @type \Twitter\Cards\Components\Image
|
82 |
+
* }
|
83 |
+
*/
|
84 |
+
protected $images = array();
|
85 |
+
|
86 |
+
/**
|
87 |
+
* Number of images currently stored in $images
|
88 |
+
*
|
89 |
+
* @since 1.0.0
|
90 |
+
*
|
91 |
+
* @var int number of stored images
|
92 |
+
*/
|
93 |
+
protected $images_count = 0;
|
94 |
+
|
95 |
+
/**
|
96 |
+
* Maximum number of images displayed in the Twitter Card template
|
97 |
+
*
|
98 |
+
* @since 1.0.0
|
99 |
+
*
|
100 |
+
* @param int $limit maximum number of images displayed in the Twitter Card template
|
101 |
+
*
|
102 |
+
* @return \Twitter\WordPress\Cards\ImageHandler support chaining
|
103 |
+
*/
|
104 |
+
public function setLimit( $limit )
|
105 |
+
{
|
106 |
+
if ( is_int( $limit ) && $limit > 0 ) {
|
107 |
+
// set max range to extended entities limit
|
108 |
+
if ( $limit > 25 ) {
|
109 |
+
$limit = 25;
|
110 |
+
}
|
111 |
+
|
112 |
+
$this->limit = $limit;
|
113 |
+
}
|
114 |
+
|
115 |
+
return $this;
|
116 |
+
}
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Have we stored the maximum number of images displayed in the Twitter Card template?
|
120 |
+
*
|
121 |
+
* @since 1.0.0
|
122 |
+
*
|
123 |
+
* @return bool True if no more images needed, else False
|
124 |
+
*/
|
125 |
+
public function isFull()
|
126 |
+
{
|
127 |
+
return ( $this->images_count === $this->limit );
|
128 |
+
}
|
129 |
+
|
130 |
+
/**
|
131 |
+
* Set the minimum image width of the current card
|
132 |
+
*
|
133 |
+
* @since 1.0.0
|
134 |
+
*
|
135 |
+
* @param int $width minimum width of the Twitter Cards image in whole pixels
|
136 |
+
*
|
137 |
+
* @return \Twitter\WordPress\Cards\ImageHandler support chaining
|
138 |
+
*/
|
139 |
+
public function setMinWidth( $width )
|
140 |
+
{
|
141 |
+
if ( is_int( $width ) && $width >= 120 ) {
|
142 |
+
$this->min_width = $width;
|
143 |
+
}
|
144 |
+
return $this;
|
145 |
+
}
|
146 |
+
|
147 |
+
/**
|
148 |
+
* Set the minimum image height of hte current card
|
149 |
+
*
|
150 |
+
* @since 1.0.0
|
151 |
+
*
|
152 |
+
* @param int $height minimum height of the Twitter Cards image in whole pixels
|
153 |
+
*
|
154 |
+
* @return \Twitter\WordPress\Cards\ImageHandler support chaining
|
155 |
+
*/
|
156 |
+
public function setMinHeight( $height )
|
157 |
+
{
|
158 |
+
if ( is_int( $height ) && $height >= 120 ) {
|
159 |
+
$this->min_height = $height;
|
160 |
+
}
|
161 |
+
return $this;
|
162 |
+
}
|
163 |
+
|
164 |
+
/**
|
165 |
+
* Get a flattened array of Twitter Card images
|
166 |
+
*
|
167 |
+
* @since 1.0.0
|
168 |
+
*
|
169 |
+
* @return array Twitter Card images {
|
170 |
+
* @type \Twitter\Cards\Components\Image Twitter Card image
|
171 |
+
* }
|
172 |
+
*/
|
173 |
+
public function getTwitterCardImages()
|
174 |
+
{
|
175 |
+
if ( empty( $this->images ) ) {
|
176 |
+
return array();
|
177 |
+
}
|
178 |
+
|
179 |
+
return array_values( $this->images );
|
180 |
+
}
|
181 |
+
|
182 |
+
/**
|
183 |
+
* Possibly add a new image for a given WordPress attachment ID
|
184 |
+
*
|
185 |
+
* @since 1.0.0
|
186 |
+
*
|
187 |
+
* @param int $attachment_id WordPress attachment ID
|
188 |
+
*
|
189 |
+
* @return bool was an image added to the array?
|
190 |
+
*/
|
191 |
+
public function addImageByAttachmentID( $attachment_id )
|
192 |
+
{
|
193 |
+
if ( ! $attachment_id ) {
|
194 |
+
return false;
|
195 |
+
}
|
196 |
+
|
197 |
+
$image = $this->attachmentToTwitterImage( $attachment_id );
|
198 |
+
if ( ! $image ) {
|
199 |
+
return false;
|
200 |
+
}
|
201 |
+
|
202 |
+
$image_url = $image->getURL();
|
203 |
+
if ( ! $image_url || isset( $this->images[ $image_url ] ) ) {
|
204 |
+
return false;
|
205 |
+
}
|
206 |
+
|
207 |
+
$this->images[ $image_url ] = $image;
|
208 |
+
$this->images_count++;
|
209 |
+
|
210 |
+
return true;
|
211 |
+
}
|
212 |
+
|
213 |
+
/**
|
214 |
+
* Add images associated with a WP_Post up to limit.
|
215 |
+
*
|
216 |
+
* @since 1.0.0
|
217 |
+
*
|
218 |
+
* @param WP_Post $post post of interest
|
219 |
+
*
|
220 |
+
* @return void
|
221 |
+
*/
|
222 |
+
public function addPostImages( $post )
|
223 |
+
{
|
224 |
+
// bad parameter
|
225 |
+
if ( ! $post || ! isset( $post->ID ) ) {
|
226 |
+
return;
|
227 |
+
}
|
228 |
+
|
229 |
+
// does current post type and the current theme support post thumbnails?
|
230 |
+
if ( post_type_supports( get_post_type( $post ), 'thumbnail' ) && function_exists( 'has_post_thumbnail' ) && has_post_thumbnail() ) {
|
231 |
+
if ( $this->addImageByAttachmentID( get_post_thumbnail_id( $post->ID ) ) ) {
|
232 |
+
if ( $this->isFull() ) {
|
233 |
+
return;
|
234 |
+
}
|
235 |
+
}
|
236 |
+
}
|
237 |
+
|
238 |
+
// image attachments
|
239 |
+
$attached_images = get_attached_media( 'image', $post );
|
240 |
+
if ( ! empty( $attached_images ) ) {
|
241 |
+
foreach ( $attached_images as $attached_image ) {
|
242 |
+
if ( ! isset( $attached_image->ID ) ) {
|
243 |
+
continue;
|
244 |
+
}
|
245 |
+
|
246 |
+
if ( ! $this->addImageByAttachmentID( $attached_image->ID ) ) {
|
247 |
+
continue;
|
248 |
+
}
|
249 |
+
|
250 |
+
// hit the limit. end the search
|
251 |
+
if ( $this->isFull() ) {
|
252 |
+
return;
|
253 |
+
}
|
254 |
+
}
|
255 |
+
}
|
256 |
+
unset( $attached_images );
|
257 |
+
|
258 |
+
// post galleries
|
259 |
+
$galleries = get_post_galleries( $post, /* html */ false );
|
260 |
+
foreach ( $galleries as $gallery ) {
|
261 |
+
if ( ! ( isset( $gallery['ids'] ) && $gallery['ids'] ) ) {
|
262 |
+
continue;
|
263 |
+
}
|
264 |
+
|
265 |
+
$gallery_ids = explode( ',', $gallery['ids'] );
|
266 |
+
foreach ( $gallery_ids as $attachment_id ) {
|
267 |
+
if ( ! $this->addImageByAttachmentID( $attachment_id ) ) {
|
268 |
+
continue;
|
269 |
+
}
|
270 |
+
|
271 |
+
// hit the limit. end the search
|
272 |
+
if ( $this->isFull() ) {
|
273 |
+
return;
|
274 |
+
}
|
275 |
+
}
|
276 |
+
unset( $gallery_ids );
|
277 |
+
}
|
278 |
+
unset( $galleries );
|
279 |
+
}
|
280 |
+
|
281 |
+
/**
|
282 |
+
* Convert a WordPress image attachment to a Twitter Card image object
|
283 |
+
*
|
284 |
+
* @since 1.0.0
|
285 |
+
*
|
286 |
+
* @param int $attachment_id WordPress attachment ID
|
287 |
+
* @param string $size desired size
|
288 |
+
*
|
289 |
+
* @return \Twitter\Cards\Components\Image|null Twitter Card image
|
290 |
+
*/
|
291 |
+
public function attachmentToTwitterImage( $attachment_id, $size = 'full' )
|
292 |
+
{
|
293 |
+
if ( ! ( is_string( $size ) && $size ) ) {
|
294 |
+
$size = 'full';
|
295 |
+
}
|
296 |
+
|
297 |
+
// request large version of image if full version exceeds filesize limit
|
298 |
+
if ( 'full' === $size ) {
|
299 |
+
$attached_file = get_attached_file( $attachment_id );
|
300 |
+
if ( $attached_file && file_exists( $attached_file ) ) {
|
301 |
+
$bytes = filesize( $attached_file );
|
302 |
+
if ( $bytes && $bytes > self::MAX_FILESIZE ) {
|
303 |
+
/**
|
304 |
+
* Filter the intermediate image size to be provided for Twitter thumbnail when a full-size image exceeds Twitter's filesize limit
|
305 |
+
*
|
306 |
+
* Twitter will consume the largest available image under the filesize limit and generate thumbnails appropriate for Twitter Card display in various dimension and DPI contexts
|
307 |
+
*
|
308 |
+
* @since 1.0.0
|
309 |
+
*
|
310 |
+
* @param string $size The intermediate size. Default: large
|
311 |
+
* @param int $attachment_id Attachment identifier
|
312 |
+
*/
|
313 |
+
$intermediate_size = apply_filters( 'twitter_card_intermediate_image_size', 'large', $attachment_id );
|
314 |
+
// check filtered intermediate size to avoid possible infinite loop
|
315 |
+
if ( ! $intermediate_size || 'full' === $intermediate_size || ! has_image_size( $intermediate_size ) ) {
|
316 |
+
return;
|
317 |
+
}
|
318 |
+
return $handler->attachmentToTwitterImage( $attachment_id, $intermediate_size );
|
319 |
+
}
|
320 |
+
unset( $bytes );
|
321 |
+
}
|
322 |
+
unset( $attached_file );
|
323 |
+
}
|
324 |
+
|
325 |
+
list( $url, $width, $height ) = wp_get_attachment_image_src( $attachment_id, $size );
|
326 |
+
|
327 |
+
if ( empty( $url ) ) {
|
328 |
+
return;
|
329 |
+
}
|
330 |
+
$image = new \Twitter\Cards\Components\Image( $url );
|
331 |
+
|
332 |
+
if ( ! empty( $width ) ) {
|
333 |
+
$width = absint( $width );
|
334 |
+
if ( $width ) {
|
335 |
+
if ( $width < $this->min_width ) {
|
336 |
+
// reject if image width below required width
|
337 |
+
return;
|
338 |
+
}
|
339 |
+
$image->setWidth( $width );
|
340 |
+
}
|
341 |
+
// width and height are a resizing hint. must exist as a pair
|
342 |
+
if ( ! empty( $height ) ) {
|
343 |
+
$height = absint( $height );
|
344 |
+
if ( $height ) {
|
345 |
+
if ( $height < $this->min_height ) {
|
346 |
+
// reject if image height below required height
|
347 |
+
return;
|
348 |
+
}
|
349 |
+
$image->setHeight( $height );
|
350 |
+
}
|
351 |
+
}
|
352 |
+
}
|
353 |
+
|
354 |
+
return $image;
|
355 |
+
}
|
356 |
+
}
|
src/Twitter/WordPress/Cards/Sanitize.php
ADDED
@@ -0,0 +1,128 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Cards;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Clean up data from WordPress to prepare for a Twitter Card
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class Sanitize
|
34 |
+
{
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Remove HTML, leading and trailing whitespaces, and other unexpected qualities of a plain text string
|
38 |
+
*
|
39 |
+
* @since 1.0.0
|
40 |
+
*
|
41 |
+
* @param string $s string to sanitize
|
42 |
+
*
|
43 |
+
* @return string sanitized string
|
44 |
+
*/
|
45 |
+
public static function sanitizePlainTextString( $s )
|
46 |
+
{
|
47 |
+
if ( ! ( is_string( $s ) && $s ) ) {
|
48 |
+
return '';
|
49 |
+
}
|
50 |
+
|
51 |
+
$s = trim( $s );
|
52 |
+
if ( $s ) {
|
53 |
+
// strip HTML
|
54 |
+
$s = wp_kses( $s, array() );
|
55 |
+
}
|
56 |
+
|
57 |
+
return $s;
|
58 |
+
}
|
59 |
+
|
60 |
+
/**
|
61 |
+
* Clean up a string before including as a Twitter Card description
|
62 |
+
*
|
63 |
+
* @since 1.0.0
|
64 |
+
*
|
65 |
+
* @param string $description short description of the page
|
66 |
+
*
|
67 |
+
* @return string sanitized short description of the page
|
68 |
+
*/
|
69 |
+
public static function sanitizeDescription( $description )
|
70 |
+
{
|
71 |
+
// strip HTML
|
72 |
+
$description = static::sanitizePlainTextString( $description );
|
73 |
+
if ( ! $description ) {
|
74 |
+
return '';
|
75 |
+
}
|
76 |
+
|
77 |
+
// strip shortcodes
|
78 |
+
$description = strip_shortcodes( $description );
|
79 |
+
if ( ! $description ) {
|
80 |
+
return '';
|
81 |
+
}
|
82 |
+
|
83 |
+
// strip URLs on their own line (possible oEmbeds)
|
84 |
+
// @see \WP_Embed::autoembed
|
85 |
+
$description = preg_replace( '|^(\s*)(https?://[^\s"]+)(\s*)$|im', '', $description );
|
86 |
+
if ( ! $description ) {
|
87 |
+
return '';
|
88 |
+
}
|
89 |
+
|
90 |
+
$description = wp_trim_words(
|
91 |
+
$description,
|
92 |
+
/**
|
93 |
+
* Filter excerpt length, measured in number of words, used by a Twitter Card description
|
94 |
+
*
|
95 |
+
* Override the default excerpt length used by the site for a Twitter-specific context
|
96 |
+
* Twitter will truncate text at 200 characters
|
97 |
+
*
|
98 |
+
* @since 1.0.0
|
99 |
+
*
|
100 |
+
* @see wp_trim_excerpt()
|
101 |
+
*
|
102 |
+
* @param int $num_words The number of words in an excerpt
|
103 |
+
*/
|
104 |
+
apply_filters(
|
105 |
+
'twitter_excerpt_length',
|
106 |
+
/** This filter is documented in wp-includes/formatting.php */
|
107 |
+
apply_filters( 'excerpt_length', 55 )
|
108 |
+
),
|
109 |
+
/**
|
110 |
+
* Filter the string used after a trimmed excerpt for Twitter Card description text if text is longer than the specified word count
|
111 |
+
*
|
112 |
+
* @since 1.0.0
|
113 |
+
*
|
114 |
+
* @see wp_trim_words()
|
115 |
+
*
|
116 |
+
* @param string $more_string the string shown at the end of generated excerpt text
|
117 |
+
*/
|
118 |
+
apply_filters(
|
119 |
+
'twitter_excerpt_more',
|
120 |
+
__( '…' )
|
121 |
+
)
|
122 |
+
);
|
123 |
+
if ( ! $description ) {
|
124 |
+
return '';
|
125 |
+
}
|
126 |
+
return $description;
|
127 |
+
}
|
128 |
+
}
|
src/Twitter/WordPress/Content/TweetButton.php
ADDED
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Content;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Add a Tweet button to post content
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class TweetButton
|
34 |
+
{
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Get the stored site option for Tweet button content
|
38 |
+
*
|
39 |
+
* @since 1.0.0
|
40 |
+
*
|
41 |
+
* @return array stored options {
|
42 |
+
* @type string option name
|
43 |
+
* @type string option value
|
44 |
+
* }
|
45 |
+
*/
|
46 |
+
protected static function getOption()
|
47 |
+
{
|
48 |
+
return get_option( \Twitter\WordPress\Admin\Settings\TweetButton::OPTION_NAME, array() );
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Filter the_content, possibly adding Tweet button(s)
|
53 |
+
*
|
54 |
+
* @since 1.0.0
|
55 |
+
*
|
56 |
+
* @param string $content content of the current post
|
57 |
+
*
|
58 |
+
* @return string $content content of the current post, possibly with Tweet button markup added
|
59 |
+
*/
|
60 |
+
public static function contentFilter( $content )
|
61 |
+
{
|
62 |
+
$options = static::getOption();
|
63 |
+
if ( isset( $options['position'] ) ) {
|
64 |
+
$position = $options['position'];
|
65 |
+
unset( $options['position'] );
|
66 |
+
|
67 |
+
$tweet_button = \Twitter\WordPress\Shortcodes\Share::shortcodeHandler( $options );
|
68 |
+
if ( $tweet_button ) {
|
69 |
+
// wrap in newlines to preserve content scanners looking for adjacent content on its own line
|
70 |
+
$tweet_button = "\n" . $tweet_button . "\n";
|
71 |
+
if ( 'before' === $position ) {
|
72 |
+
return $tweet_button . $content;
|
73 |
+
} else if ( 'after' === $position ) {
|
74 |
+
return $content . $tweet_button;
|
75 |
+
} else if ( 'both' === $position ) {
|
76 |
+
return $tweet_button . $content . $tweet_button;
|
77 |
+
}
|
78 |
+
}
|
79 |
+
}
|
80 |
+
|
81 |
+
return $content;
|
82 |
+
}
|
83 |
+
}
|
src/Twitter/WordPress/Head/AuthorshipLink.php
ADDED
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Head;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Identify the Twitter profile of a site using XFN relationship tokens
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class AuthorshipLink
|
34 |
+
{
|
35 |
+
/**
|
36 |
+
* Link to a site's Twitter profile using rel me
|
37 |
+
*
|
38 |
+
* Adds via attribution to Twitter widgets on the page
|
39 |
+
*
|
40 |
+
* @link http://microformats.org/wiki/rel-me XFN rel me
|
41 |
+
*
|
42 |
+
* @return void
|
43 |
+
*/
|
44 |
+
public static function relMe()
|
45 |
+
{
|
46 |
+
$site_username = \Twitter\WordPress\Site\Username::getViaAttribution( ( in_the_loop() ? get_the_ID() : null ) );
|
47 |
+
if ( $site_username ) {
|
48 |
+
echo '<link rel="me" href="' . esc_url( \Twitter\Helpers\TwitterURL::profile( $site_username ), array( 'https', 'http' ) ) . '"' . \Twitter\WordPress\Helpers\HTMLBuilder::closeVoidHTMLElement() . '>';
|
49 |
+
}
|
50 |
+
}
|
51 |
+
}
|
src/Twitter/WordPress/Head/CardsMetaElements.php
ADDED
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Head;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Generate and output Twitter Cards meta elements
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class CardsMetaElements
|
34 |
+
{
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Convert a Twitter card into <meta name="" content=""> pairs
|
38 |
+
*
|
39 |
+
* @since 1.0.0
|
40 |
+
*
|
41 |
+
* @return string HTML <meta> elements
|
42 |
+
*/
|
43 |
+
public static function buildMetaElements()
|
44 |
+
{
|
45 |
+
$card = \Twitter\WordPress\Cards\Generator::get();
|
46 |
+
if ( ! $card ) {
|
47 |
+
return '';
|
48 |
+
}
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Filter associative array of Twitter Card values
|
52 |
+
*
|
53 |
+
* Resulting array will be output to the page as <meta> elements
|
54 |
+
* All keys receive the "twitter:" prefix inside a name attribute before output
|
55 |
+
* Structured values are passed as an array. example: 'image' => array( 'src' => 'http://example.com/i.jpg', 'width' => 640 )
|
56 |
+
*
|
57 |
+
* @since 1.0.0
|
58 |
+
*
|
59 |
+
* @param array $card_properties associative array of Twitter Card values {
|
60 |
+
* @type string card property name
|
61 |
+
* @type string|int|array property value
|
62 |
+
* }
|
63 |
+
*/
|
64 |
+
$card_properties = apply_filters( 'twitter_card', $card->toArray() );
|
65 |
+
if ( ! is_array( $card_properties ) || empty( $card_properties ) ) {
|
66 |
+
return '';
|
67 |
+
}
|
68 |
+
|
69 |
+
$html = '';
|
70 |
+
foreach ( $card_properties as $name => $content ) {
|
71 |
+
if ( is_array( $content ) && $name ) {
|
72 |
+
foreach ( $content as $structured_name => $structured_value ) {
|
73 |
+
$html .= \Twitter\WordPress\Head\MetaElement::fromNameContentPair( $name . ':' . $structured_name, $structured_value );
|
74 |
+
}
|
75 |
+
} else {
|
76 |
+
$html .= \Twitter\WordPress\Head\MetaElement::fromNameContentPair( $name, $content );
|
77 |
+
}
|
78 |
+
}
|
79 |
+
return $html;
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Output a HTML containing all card elements for the current context
|
84 |
+
*
|
85 |
+
* @since 1.0.0
|
86 |
+
*
|
87 |
+
* @return void
|
88 |
+
*/
|
89 |
+
public static function outputMetaElements()
|
90 |
+
{
|
91 |
+
echo "\n" . static::buildMetaElements() . "\n";
|
92 |
+
}
|
93 |
+
}
|
src/Twitter/WordPress/Head/MetaElement.php
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Head;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Build a HTML meta element
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*
|
33 |
+
* @link http://www.whatwg.org/specs/web-apps/current-work/multipage/semantics.html#the-meta-element meta element
|
34 |
+
*/
|
35 |
+
class MetaElement
|
36 |
+
{
|
37 |
+
/**
|
38 |
+
* Meta element name prefix
|
39 |
+
*
|
40 |
+
* @since 1.0.0
|
41 |
+
*
|
42 |
+
* @type string
|
43 |
+
*/
|
44 |
+
const PREFIX = 'twitter:';
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Build a HTML meta element from name and content values
|
48 |
+
*
|
49 |
+
* @since 1.0.0
|
50 |
+
*
|
51 |
+
* @param string $name name attribute value
|
52 |
+
* @param mixed $content content attribute value. will be converted to string for output
|
53 |
+
*
|
54 |
+
* @return string HTML meta element or empty string if name and content attribute values not provided
|
55 |
+
*/
|
56 |
+
public static function fromNameContentPair( $name, $content )
|
57 |
+
{
|
58 |
+
if ( ! ( $name && $content ) ) {
|
59 |
+
return '';
|
60 |
+
}
|
61 |
+
|
62 |
+
return '<meta name="' . esc_attr( self::PREFIX . $name ) . '" content="' . esc_attr( (string) $content ) . '"' . \Twitter\WordPress\Helpers\HTMLBuilder::closeVoidHTMLElement() . '>';
|
63 |
+
}
|
64 |
+
}
|
src/Twitter/WordPress/Head/WidgetsMetaElements.php
ADDED
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Head;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Output Twitter for Websites <meta> elements
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class WidgetsMetaElements
|
34 |
+
{
|
35 |
+
/**
|
36 |
+
* Get any stored widget theme options
|
37 |
+
*
|
38 |
+
* @since 1.0.0
|
39 |
+
*
|
40 |
+
* @return array|bool array of set options or false if no option exists
|
41 |
+
*/
|
42 |
+
public static function getWidgetOptions()
|
43 |
+
{
|
44 |
+
return get_option( \Twitter\WordPress\Admin\Settings\Theme::OPTION_NAME );
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Opt-out of using visits to this website to influence Twitter tailored content and other suggestions for Twitter users
|
49 |
+
*
|
50 |
+
* Applies when Twitter's widgets.js appears on the page to enhance a button or widget
|
51 |
+
*
|
52 |
+
* @since 1.0.0
|
53 |
+
*
|
54 |
+
* @link https://dev.twitter.com/web/overview/privacy Twitter for Websites privacy
|
55 |
+
*
|
56 |
+
* @return bool opt out of Twitter tailored audiences
|
57 |
+
*/
|
58 |
+
public static function optOutOfTwitterTailoredAudiences()
|
59 |
+
{
|
60 |
+
/**
|
61 |
+
* Do not use website visits to tailor content and suggestions for the Twitter audience
|
62 |
+
*
|
63 |
+
* This setting does not apply to Twitter's advertising tracker, opt.js, which you may choose to include on the page to build a target audience or track conversions.
|
64 |
+
*
|
65 |
+
* @since 1.0.0
|
66 |
+
*
|
67 |
+
* @link https://dev.twitter.com/web/overview/privacy Twitter for Websites privacy
|
68 |
+
*
|
69 |
+
* @param bool $override opt out of Twitter tailoring
|
70 |
+
*/
|
71 |
+
return apply_filters( 'twitter_dnt', false );
|
72 |
+
}
|
73 |
+
|
74 |
+
/**
|
75 |
+
* Convert stored option associative array into a new associative array of meta element name-content pairs for consumption by Twitter's widget JS
|
76 |
+
*
|
77 |
+
* @since 1.0.0
|
78 |
+
*
|
79 |
+
* @param array $options widget options stored by the site
|
80 |
+
*
|
81 |
+
* @return array associative array
|
82 |
+
*/
|
83 |
+
public static function widgetOptionsToMetaElementPairs( array $options )
|
84 |
+
{
|
85 |
+
if ( empty( $options ) ) {
|
86 |
+
return array();
|
87 |
+
}
|
88 |
+
|
89 |
+
$widgets_prefix = 'widgets:';
|
90 |
+
|
91 |
+
$meta = array();
|
92 |
+
|
93 |
+
// Suppress Content Security Policy warning
|
94 |
+
if ( isset( $options['csp'] ) ) {
|
95 |
+
$meta[ $widgets_prefix . 'csp' ] = 'on';
|
96 |
+
}
|
97 |
+
|
98 |
+
// dark theme
|
99 |
+
if ( isset( $options['theme'] ) && 'dark' === $options['theme'] ) {
|
100 |
+
$meta[ $widgets_prefix . 'theme' ] = 'dark';
|
101 |
+
}
|
102 |
+
|
103 |
+
// colors
|
104 |
+
foreach ( array( 'link-color', 'border-color' ) as $color_option ) {
|
105 |
+
if ( isset( $options[ $color_option ] ) && $options[ $color_option ] ) {
|
106 |
+
$meta[ $widgets_prefix . $color_option ] = '#' . $options[ $color_option ];
|
107 |
+
}
|
108 |
+
}
|
109 |
+
|
110 |
+
return $meta;
|
111 |
+
}
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Build HTML meta elements to be included as children of <head>
|
115 |
+
*
|
116 |
+
* @since 1.0.0
|
117 |
+
*
|
118 |
+
* @return string HTML meta elements
|
119 |
+
*/
|
120 |
+
public static function buildMetaElements()
|
121 |
+
{
|
122 |
+
$meta = array();
|
123 |
+
|
124 |
+
$widget_options = static::getWidgetOptions();
|
125 |
+
if ( ! empty( $widget_options ) ) {
|
126 |
+
$meta = static::widgetOptionsToMetaElementPairs( $widget_options );
|
127 |
+
}
|
128 |
+
unset( $widget_options );
|
129 |
+
|
130 |
+
// opt out of tailored audiences
|
131 |
+
if ( static::optOutOfTwitterTailoredAudiences() ) {
|
132 |
+
$meta['dnt'] = 'on';
|
133 |
+
}
|
134 |
+
|
135 |
+
// powered by Twitter plugin for WordPress
|
136 |
+
// please leave for stats
|
137 |
+
$meta['partner'] = 'tfwp';
|
138 |
+
|
139 |
+
if ( empty( $meta ) ) {
|
140 |
+
return '';
|
141 |
+
}
|
142 |
+
|
143 |
+
$html = '';
|
144 |
+
foreach ( $meta as $name => $content ) {
|
145 |
+
$html .= \Twitter\WordPress\Head\MetaElement::fromNameContentPair( $name, $content );
|
146 |
+
}
|
147 |
+
return $html;
|
148 |
+
}
|
149 |
+
|
150 |
+
/**
|
151 |
+
* Output a HTML string if wiidget theme or other preferences exist
|
152 |
+
*
|
153 |
+
* @since 1.0.0
|
154 |
+
*
|
155 |
+
* @return void
|
156 |
+
*/
|
157 |
+
public static function outputMetaElements()
|
158 |
+
{
|
159 |
+
// escaped in markup builder
|
160 |
+
// @codingStandardsIgnoreStart WordPress.XSS.EscapeOutput
|
161 |
+
echo static::buildMetaElements();
|
162 |
+
// @codingStandardsIgnoreEnd WordPress.XSS.EscapeOutput
|
163 |
+
}
|
164 |
+
}
|
src/Twitter/WordPress/Helpers/HTMLBuilder.php
ADDED
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Helpers;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Help build HTML strings
|
30 |
+
*
|
31 |
+
* Extensible class meant to be extended for use in a framework's HTML builders
|
32 |
+
*
|
33 |
+
* @since 1.0.0
|
34 |
+
*/
|
35 |
+
class HTMLBuilder extends \Twitter\Helpers\HTMLBuilder
|
36 |
+
{
|
37 |
+
/**
|
38 |
+
* Escape HTML class names in the WordPress way
|
39 |
+
*
|
40 |
+
* @since 1.0.0
|
41 |
+
*
|
42 |
+
* @param string $class possible HTML class
|
43 |
+
*
|
44 |
+
* @return class name stripped of invalid values or empty string
|
45 |
+
*/
|
46 |
+
public static function escapeClassName( $class )
|
47 |
+
{
|
48 |
+
return sanitize_html_class( $class );
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Escape an element's inner text
|
53 |
+
*
|
54 |
+
* @since 1.0.0
|
55 |
+
*
|
56 |
+
* @param string $inner_text inner text of a DOM element
|
57 |
+
*
|
58 |
+
* @return string escaped string or empty string if passed string failed to parse
|
59 |
+
*/
|
60 |
+
public static function escapeInnerText( $inner_text )
|
61 |
+
{
|
62 |
+
return esc_html( $inner_text );
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Escape an element attribute value
|
67 |
+
*
|
68 |
+
* @since 1.0.0
|
69 |
+
*
|
70 |
+
* @param string $value element attribute value
|
71 |
+
*
|
72 |
+
* @return string escaped string or empty string if passed string failed to parse
|
73 |
+
*/
|
74 |
+
public static function escapeAttributeValue( $value )
|
75 |
+
{
|
76 |
+
return esc_attr( $value );
|
77 |
+
}
|
78 |
+
|
79 |
+
/**
|
80 |
+
* Escape an element attribute value
|
81 |
+
*
|
82 |
+
* @since 1.0.0
|
83 |
+
*
|
84 |
+
* @param string $url web URL
|
85 |
+
*
|
86 |
+
* @return string escaped string or empty string if passed string failed to parse
|
87 |
+
*/
|
88 |
+
public static function escapeURL( $url )
|
89 |
+
{
|
90 |
+
return esc_url( $url, array( 'http', 'https' ) );
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Close a void HTML element in a HTML or xHTML (default)
|
95 |
+
*
|
96 |
+
* @since 1.0.0
|
97 |
+
*
|
98 |
+
* @return string empty string if known HTML, else space and slash
|
99 |
+
*/
|
100 |
+
public static function closeVoidHTMLElement()
|
101 |
+
{
|
102 |
+
return (current_theme_supports( 'html5' ) ? '' : ' /');
|
103 |
+
}
|
104 |
+
}
|
src/Twitter/WordPress/Helpers/TwitterAPI.php
ADDED
@@ -0,0 +1,156 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Helpers;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Request information from the Twitter API using OAuth
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class TwitterAPI
|
34 |
+
{
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Twitter API FQDN
|
38 |
+
*
|
39 |
+
* @since 1.0.0
|
40 |
+
*
|
41 |
+
* @type string
|
42 |
+
*/
|
43 |
+
const HOST = 'api.twitter.com';
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Response formats supported by the Twitter API
|
47 |
+
*
|
48 |
+
* @since 1.0.0
|
49 |
+
*
|
50 |
+
* @type array supported formats {
|
51 |
+
* @type string filename extension
|
52 |
+
* @type string media type
|
53 |
+
* }
|
54 |
+
*/
|
55 |
+
public static $RESPONSE_FORMATS = array( 'json' => 'application/json', 'xml' => 'application/xml' );
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Build a Twitter REST API URL
|
59 |
+
*
|
60 |
+
* @since 1.0.0
|
61 |
+
*
|
62 |
+
* @param string $relative_path API path
|
63 |
+
* @param array $query_parameters query parameters to append to the URL
|
64 |
+
* @param string $response_format requested response format
|
65 |
+
*
|
66 |
+
* @return string absolute API URL or empty string if invalid relative_path passed
|
67 |
+
*/
|
68 |
+
public static function getAPIURL( $relative_path, $query_parameters = null, $response_format = 'json' )
|
69 |
+
{
|
70 |
+
if ( ! is_string( $relative_path ) ) {
|
71 |
+
return '';
|
72 |
+
}
|
73 |
+
$relative_path = trim( trim( $relative_path, '/' ) );
|
74 |
+
if ( ! $relative_path ) {
|
75 |
+
return '';
|
76 |
+
}
|
77 |
+
|
78 |
+
if ( ! ( is_string( $response_format ) && $response_format && isset( static::$RESPONSE_FORMATS[ $response_format ] ) ) ) {
|
79 |
+
$response_format = '';
|
80 |
+
}
|
81 |
+
|
82 |
+
$api_version = '1.1';
|
83 |
+
if ( 'statuses/oembed' === $relative_path ) {
|
84 |
+
$api_version = '1';
|
85 |
+
}
|
86 |
+
|
87 |
+
$url = 'https://' . implode( '/', array( static::HOST, $api_version, $relative_path ) );
|
88 |
+
if ( $response_format ) {
|
89 |
+
$url .= '.' . $response_format;
|
90 |
+
}
|
91 |
+
if ( is_array( $query_parameters ) && ! empty( $query_parameters ) ) {
|
92 |
+
$url .= '?' . http_build_query( $query_parameters, '', '&' );
|
93 |
+
}
|
94 |
+
|
95 |
+
return $url;
|
96 |
+
}
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Build a User-Agent string for use in a HTTP request to Twitter REST API servers
|
100 |
+
*
|
101 |
+
* @since 1.0.0
|
102 |
+
*
|
103 |
+
* @return string User-Agent
|
104 |
+
*/
|
105 |
+
public static function getUserAgent()
|
106 |
+
{
|
107 |
+
global $wp_version;
|
108 |
+
|
109 |
+
return apply_filters( 'http_headers_useragent', 'WordPress/' . $wp_version . '; TfWP/' . \Twitter\WordPress\PluginLoader::VERSION . '; ' . get_bloginfo( 'url' ) );
|
110 |
+
}
|
111 |
+
|
112 |
+
/**
|
113 |
+
* Request JSON data from the Twitter API. JSON decode the results
|
114 |
+
*
|
115 |
+
* @since 1.0.0
|
116 |
+
*
|
117 |
+
* @param string $relative_path API path without the response type. e.g. statuses/show
|
118 |
+
* @param array $parameters query parameters
|
119 |
+
*
|
120 |
+
* @return stdClass|null json decoded result or null if no JSON returned or issues with parameters
|
121 |
+
*/
|
122 |
+
public static function getJSON( $relative_path, $parameters = null )
|
123 |
+
{
|
124 |
+
if ( ! $relative_path ) {
|
125 |
+
return;
|
126 |
+
}
|
127 |
+
|
128 |
+
$request_url = static::getAPIURL( $relative_path, $parameters );
|
129 |
+
if ( ! $request_url ) {
|
130 |
+
return;
|
131 |
+
}
|
132 |
+
|
133 |
+
$response = wp_safe_remote_get(
|
134 |
+
$request_url,
|
135 |
+
array(
|
136 |
+
'redirection' => 0,
|
137 |
+
'httpversion' => '1.1',
|
138 |
+
'user-agent' => static::getUserAgent()
|
139 |
+
)
|
140 |
+
);
|
141 |
+
if ( is_wp_error( $response ) ) {
|
142 |
+
return;
|
143 |
+
}
|
144 |
+
$response_body = wp_remote_retrieve_body( $response );
|
145 |
+
if ( ! $response_body ) {
|
146 |
+
return;
|
147 |
+
}
|
148 |
+
|
149 |
+
$json_response = json_decode( $response_body );
|
150 |
+
|
151 |
+
// account for parse failures
|
152 |
+
if ( $json_response ) {
|
153 |
+
return $json_response;
|
154 |
+
}
|
155 |
+
}
|
156 |
+
}
|
src/Twitter/WordPress/JavaScriptLoaders/Tracking.php
ADDED
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\JavaScriptLoaders;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Load the remotely hosted Twitter advertising tracking JavaScript
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class Tracking
|
34 |
+
{
|
35 |
+
/**
|
36 |
+
* Twitter tracking JavaScript handle
|
37 |
+
*
|
38 |
+
* Used in WordPress JavaScript queue
|
39 |
+
*
|
40 |
+
* @since 1.0.0
|
41 |
+
*
|
42 |
+
* @type string
|
43 |
+
*/
|
44 |
+
const QUEUE_HANDLE = 'twitter-tracking';
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Proactively resolve Twitter advertising JS FQDN asynchronously before later use
|
48 |
+
*
|
49 |
+
* @since 1.0.0
|
50 |
+
*
|
51 |
+
* @link http://dev.chromium.org/developers/design-documents/dns-prefetching Chromium prefetch behavior
|
52 |
+
* @link https://developer.mozilla.org/en-US/docs/Controlling_DNS_prefetching Firefox prefetch behavior
|
53 |
+
*
|
54 |
+
* @return void
|
55 |
+
*/
|
56 |
+
public static function dnsPrefetch()
|
57 |
+
{
|
58 |
+
echo '<link rel="dns-prefetch" href="//platform.twitter.com"';
|
59 |
+
echo \Twitter\WordPress\Helpers\HTMLBuilder::closeVoidHTMLElement();
|
60 |
+
echo '>' . "\n";
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Register Twitter advertising JavaScript
|
65 |
+
*
|
66 |
+
* @since 1.0.0
|
67 |
+
*
|
68 |
+
* @return void
|
69 |
+
*/
|
70 |
+
public static function register()
|
71 |
+
{
|
72 |
+
wp_register_script(
|
73 |
+
self::QUEUE_HANDLE,
|
74 |
+
static::getAbsoluteURI(),
|
75 |
+
array(), // no dependencies
|
76 |
+
null, // no not add extra query parameters for cache busting
|
77 |
+
true // in footer
|
78 |
+
);
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Enqueue the advertising JavaScript
|
83 |
+
*
|
84 |
+
* @since 1.0.0
|
85 |
+
*
|
86 |
+
* @uses wp_enqueue_script()
|
87 |
+
*
|
88 |
+
* @return void
|
89 |
+
*/
|
90 |
+
public static function enqueue()
|
91 |
+
{
|
92 |
+
wp_enqueue_script( self::QUEUE_HANDLE );
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* The absolute URI of the Twitter advertising tracker JavaScript file
|
97 |
+
*
|
98 |
+
* Prefer absolute URI over scheme-relative URI
|
99 |
+
*
|
100 |
+
* @since 1.0.0
|
101 |
+
*
|
102 |
+
* @return string absolute URI for the Twitter advertising tracker JavaScript file
|
103 |
+
*/
|
104 |
+
public static function getAbsoluteURI()
|
105 |
+
{
|
106 |
+
return 'http' . ( is_ssl() ? 's' : '' ) . '://platform.twitter.com/oct.js';
|
107 |
+
}
|
108 |
+
}
|
src/Twitter/WordPress/JavaScriptLoaders/Widgets.php
ADDED
@@ -0,0 +1,194 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\JavaScriptLoaders;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Load the remotely hosted Twitter widget JavaScript
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class Widgets
|
34 |
+
{
|
35 |
+
/**
|
36 |
+
* Twitter widget JavaScript handle
|
37 |
+
* Used in WordPress JavaScript queue
|
38 |
+
*
|
39 |
+
* @since 1.0.0
|
40 |
+
*
|
41 |
+
* @type string
|
42 |
+
*/
|
43 |
+
const QUEUE_HANDLE = 'twitter-wjs';
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Proactively resolve Twitter widget JS FQDN asynchronously before later use
|
47 |
+
*
|
48 |
+
* @since 1.0.0
|
49 |
+
*
|
50 |
+
* @link http://dev.chromium.org/developers/design-documents/dns-prefetching Chromium prefetch behavior
|
51 |
+
* @link https://developer.mozilla.org/en-US/docs/Controlling_DNS_prefetching Firefox prefetch behavior
|
52 |
+
*
|
53 |
+
* @return void
|
54 |
+
*/
|
55 |
+
public static function dnsPrefetch()
|
56 |
+
{
|
57 |
+
echo '<link rel="dns-prefetch" href="//platform.twitter.com"';
|
58 |
+
echo \Twitter\WordPress\Helpers\HTMLBuilder::closeVoidHTMLElement();
|
59 |
+
echo '>' . "\n";
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Register Twitter widget JavaScript
|
64 |
+
*
|
65 |
+
* @since 1.0.0
|
66 |
+
*
|
67 |
+
* @return void
|
68 |
+
*/
|
69 |
+
public static function register()
|
70 |
+
{
|
71 |
+
global $wp_scripts;
|
72 |
+
|
73 |
+
wp_register_script(
|
74 |
+
self::QUEUE_HANDLE,
|
75 |
+
static::getAbsoluteURI(), // should be overridden during queue output by asyncScriptLoaderSrc
|
76 |
+
array(), // no dependencies
|
77 |
+
null, // no not add extra query parameters for cache busting
|
78 |
+
true // in footer
|
79 |
+
);
|
80 |
+
|
81 |
+
// initialize the twttr variable to attach ready events before JS loaded
|
82 |
+
$script = 'window.twttr=(function(w){t=w.twttr||{};t._e=[];t.ready=function(f){t._e.push(f);};return t;}(window));';
|
83 |
+
$data = $wp_scripts->get_data( self::QUEUE_HANDLE, 'data' );
|
84 |
+
if ( $data ) {
|
85 |
+
$script = $data . "\n" . $script;
|
86 |
+
}
|
87 |
+
$wp_scripts->add_data( self::QUEUE_HANDLE, 'data', $script );
|
88 |
+
|
89 |
+
// replace standard script element with async script element
|
90 |
+
add_filter( 'script_loader_src', array( __CLASS__, 'asyncScriptLoaderSrc' ), 1, 2 );
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Enqueue the widgets JavaScript
|
95 |
+
*
|
96 |
+
* @since 1.0.0
|
97 |
+
*
|
98 |
+
* @uses wp_enqueue_script()
|
99 |
+
*
|
100 |
+
* @return void
|
101 |
+
*/
|
102 |
+
public static function enqueue()
|
103 |
+
{
|
104 |
+
if ( ! wp_script_is( self::QUEUE_HANDLE, 'registered' ) ) {
|
105 |
+
static::register();
|
106 |
+
}
|
107 |
+
|
108 |
+
wp_enqueue_script( self::QUEUE_HANDLE );
|
109 |
+
}
|
110 |
+
|
111 |
+
/**
|
112 |
+
* The absolute URI of the Twitter widgets JavaScript file
|
113 |
+
*
|
114 |
+
* Prefer absolute URI over scheme-relative URI
|
115 |
+
*
|
116 |
+
* @since 1.0.0
|
117 |
+
*
|
118 |
+
* @return string absolute URI for the Twitter widgets JavaScript file
|
119 |
+
*/
|
120 |
+
public static function getAbsoluteURI()
|
121 |
+
{
|
122 |
+
return 'http' . ( is_ssl() ? 's' : '' ) . '://platform.twitter.com/widgets.js';
|
123 |
+
}
|
124 |
+
|
125 |
+
/**
|
126 |
+
* Get the script element HTML markup used to load widgets.js in a browser
|
127 |
+
*
|
128 |
+
* @since 1.0.0
|
129 |
+
*
|
130 |
+
* @return string HTML <script> element
|
131 |
+
*/
|
132 |
+
public static function getScriptElement()
|
133 |
+
{
|
134 |
+
// type = text/javascript to match default WP_Scripts output
|
135 |
+
// async property to unlock page load, preload scanner discoverable in modern browsers
|
136 |
+
// defer property for IE 9 and older
|
137 |
+
return '<script type="text/javascript" id="' . esc_attr( self::QUEUE_HANDLE ) . '" async defer src="' . esc_url( static::getAbsoluteURI(), array( 'http', 'https' ) ) . '" charset="utf-8"></script>' . "\n";
|
138 |
+
}
|
139 |
+
|
140 |
+
/**
|
141 |
+
* Create our own script element markup, replacing WordPress default with async loading
|
142 |
+
*
|
143 |
+
* Can be used with `script_loader_tag` filter in WordPress 4.1+
|
144 |
+
*
|
145 |
+
* @since 1.0.0
|
146 |
+
*
|
147 |
+
* @param string $tag The `<script>` tag for the enqueued script.
|
148 |
+
* @param string $handle The script's registered handle.
|
149 |
+
* @param string $src The script's source URL.
|
150 |
+
*
|
151 |
+
* @return string The `<script>` tag for the enqueued script
|
152 |
+
*/
|
153 |
+
public static function scriptLoaderTag( $tag, $handle, $src = '' )
|
154 |
+
{
|
155 |
+
if ( ! ( is_string( $handle ) && $handle === static::QUEUE_HANDLE ) ) {
|
156 |
+
return $tag;
|
157 |
+
}
|
158 |
+
|
159 |
+
return static::getScriptElement();
|
160 |
+
}
|
161 |
+
|
162 |
+
/**
|
163 |
+
* Load Twitter widget JS using async deferred JavaScript properties
|
164 |
+
*
|
165 |
+
* Called from `script_loader_src` filter.
|
166 |
+
*
|
167 |
+
* @since 1.0.0
|
168 |
+
*
|
169 |
+
* @param string $src script URL
|
170 |
+
* @param string $handle WordPress registered script handle
|
171 |
+
* @global WP_Scripts $wp_scripts match concatenation preferences
|
172 |
+
*
|
173 |
+
* @return string empty string if Twitter widget JS, else give back the src variable
|
174 |
+
*/
|
175 |
+
public static function asyncScriptLoaderSrc( $src, $handle )
|
176 |
+
{
|
177 |
+
global $wp_scripts;
|
178 |
+
|
179 |
+
if ( ! ( is_string( $handle ) && $handle === self::QUEUE_HANDLE ) ) {
|
180 |
+
return $src;
|
181 |
+
}
|
182 |
+
|
183 |
+
$html = static::getScriptElement();
|
184 |
+
|
185 |
+
if ( isset( $wp_scripts ) && $wp_scripts->do_concat ) {
|
186 |
+
$wp_scripts->print_html .= $html;
|
187 |
+
} else {
|
188 |
+
echo $html;
|
189 |
+
}
|
190 |
+
|
191 |
+
// empty out the src response to avoid extra <script>
|
192 |
+
return '';
|
193 |
+
}
|
194 |
+
}
|
src/Twitter/WordPress/Language.php
ADDED
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Match WordPress locale to a Twitter language
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class Language extends \Twitter\Widgets\Language
|
34 |
+
{
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Convert a WordPress locale into a Twitter-supported language code
|
38 |
+
*
|
39 |
+
* @since 1.0.0
|
40 |
+
*
|
41 |
+
* @return string Twitter language code or empty string if no suitable match found
|
42 |
+
*/
|
43 |
+
public static function localeToTwitterLang()
|
44 |
+
{
|
45 |
+
/**
|
46 |
+
* Filter the locale used to display translated text inside Twitter widgets
|
47 |
+
*
|
48 |
+
* @since 1.0.0
|
49 |
+
*
|
50 |
+
* @link https://dev.twitter.com/web/overview/languages supported languages
|
51 |
+
* @see \Twitter\Widgets\Language::$SUPPORTED_LANGUAGES
|
52 |
+
*
|
53 |
+
* @param string $locale locale returned by get_locale()
|
54 |
+
*/
|
55 |
+
$locale = apply_filters( 'twitter_locale', get_locale() );
|
56 |
+
|
57 |
+
if ( ! ( is_string( $locale ) && $locale ) ) {
|
58 |
+
return '';
|
59 |
+
}
|
60 |
+
$locale = strtolower( $locale );
|
61 |
+
|
62 |
+
if ( 'tl' === $locale ) {
|
63 |
+
return 'fil';
|
64 |
+
} else if ( 'ms' === $locale ) {
|
65 |
+
return 'msa';
|
66 |
+
}
|
67 |
+
|
68 |
+
// handle regional
|
69 |
+
if ( 'zh_cn' === $locale ) {
|
70 |
+
return 'zh-cn';
|
71 |
+
} else if ( 'zh_tw' === $locale ) {
|
72 |
+
return 'zh-tw';
|
73 |
+
}
|
74 |
+
|
75 |
+
if ( isset( static::$SUPPORTED_LANGUAGES[ $locale ] ) ) {
|
76 |
+
return $locale;
|
77 |
+
}
|
78 |
+
|
79 |
+
if ( strlen( $locale ) > 2 ) {
|
80 |
+
$locale = substr( $locale, 0, 2 );
|
81 |
+
if ( isset( static::$SUPPORTED_LANGUAGES[ $locale ] ) ) {
|
82 |
+
return $locale;
|
83 |
+
}
|
84 |
+
if ( 'ms' === $locale ) {
|
85 |
+
return 'msa';
|
86 |
+
}
|
87 |
+
}
|
88 |
+
|
89 |
+
return '';
|
90 |
+
}
|
91 |
+
}
|
src/Twitter/WordPress/PluginLoader.php
ADDED
@@ -0,0 +1,306 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Hook the WordPress plugin into the appropriate WordPress actions and filters
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class PluginLoader
|
34 |
+
{
|
35 |
+
/**
|
36 |
+
* Uniquely identify plugin version
|
37 |
+
*
|
38 |
+
* Bust caches based on this value
|
39 |
+
*
|
40 |
+
* @since 1.0.0
|
41 |
+
*
|
42 |
+
* @type string
|
43 |
+
*/
|
44 |
+
const VERSION = '1.0.0';
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Unique domain of the plugin's translated text
|
48 |
+
*
|
49 |
+
* @since 1.0.0
|
50 |
+
*
|
51 |
+
* @type string
|
52 |
+
*/
|
53 |
+
const TEXT_DOMAIN = 'twitter';
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Bind to hooks and filters
|
57 |
+
*
|
58 |
+
* @since 1.0.0
|
59 |
+
*
|
60 |
+
* @return void
|
61 |
+
*/
|
62 |
+
public static function init()
|
63 |
+
{
|
64 |
+
// load translated text
|
65 |
+
add_action( 'init', array( __CLASS__, 'loadTranslatedText' ) );
|
66 |
+
|
67 |
+
// compatibility wrappers to coexist with other popular plugins
|
68 |
+
add_action( 'plugins_loaded', array( __CLASS__, 'compatibility' ) );
|
69 |
+
|
70 |
+
// make widgets available on front and back end
|
71 |
+
add_action( 'widgets_init', array( __CLASS__, 'widgetsInit' ) );
|
72 |
+
|
73 |
+
// register Twitter JavaScript to eligible for later enqueueing
|
74 |
+
add_action( 'wp_enqueue_scripts', array( __CLASS__, 'registerScripts' ), 1, 0 );
|
75 |
+
|
76 |
+
if ( is_admin() ) {
|
77 |
+
// admin-specific functionality
|
78 |
+
add_action( 'init', array( __CLASS__, 'adminInit' ) );
|
79 |
+
} else {
|
80 |
+
// hooks to be executed on general execution of WordPress such as public pageviews
|
81 |
+
static::registerShortcodeHandlers();
|
82 |
+
add_action( 'init', array( __CLASS__, 'publicInit' ) );
|
83 |
+
add_action( 'wp_head', array( __CLASS__, 'wpHead' ), 1, 0 );
|
84 |
+
}
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Full path to the directory containing the Twitter for WordPress plugin files
|
89 |
+
*
|
90 |
+
* @since 1.0.0
|
91 |
+
*
|
92 |
+
* @return string full directory path
|
93 |
+
*/
|
94 |
+
public static function getPluginDirectory()
|
95 |
+
{
|
96 |
+
return dirname( dirname( dirname( dirname( __FILE__ ) ) ) ) . '/';
|
97 |
+
}
|
98 |
+
|
99 |
+
/**
|
100 |
+
* Full path to the main file of the Twitter for WordPress plugin
|
101 |
+
*
|
102 |
+
* @since 1.0.0
|
103 |
+
*
|
104 |
+
* @return string full path to file
|
105 |
+
*/
|
106 |
+
public static function getPluginMainFile()
|
107 |
+
{
|
108 |
+
return static::getPluginDirectory() . 'twitter.php';
|
109 |
+
}
|
110 |
+
|
111 |
+
/**
|
112 |
+
* Load translated strings for the current locale, if a translation exists
|
113 |
+
*
|
114 |
+
* @since 1.0.0
|
115 |
+
*
|
116 |
+
* @return void
|
117 |
+
*/
|
118 |
+
public static function loadTranslatedText()
|
119 |
+
{
|
120 |
+
load_plugin_textdomain(
|
121 |
+
static::TEXT_DOMAIN,
|
122 |
+
false, // deprecated parameter as of WP 2.7
|
123 |
+
dirname( plugin_basename( static::getPluginMainFile() ) ) . '/languages/' // directory location of MO files
|
124 |
+
);
|
125 |
+
}
|
126 |
+
|
127 |
+
/**
|
128 |
+
* Register widgets
|
129 |
+
*
|
130 |
+
* @since 1.0.0
|
131 |
+
*
|
132 |
+
* @return void
|
133 |
+
*/
|
134 |
+
public static function widgetsInit()
|
135 |
+
{
|
136 |
+
register_widget( '\Twitter\WordPress\Widgets\Follow' );
|
137 |
+
}
|
138 |
+
|
139 |
+
/**
|
140 |
+
* Hook into actions and filters specific to a WordPress administrative view
|
141 |
+
*
|
142 |
+
* @since 1.0.0
|
143 |
+
*
|
144 |
+
* @return void
|
145 |
+
*/
|
146 |
+
public static function adminInit()
|
147 |
+
{
|
148 |
+
// Twitter settings menu
|
149 |
+
\Twitter\WordPress\Admin\Settings\Loader::init();
|
150 |
+
|
151 |
+
// Edit post meta box
|
152 |
+
add_action( 'admin_init', array( '\Twitter\WordPress\Admin\Post\MetaBox', 'init' ) );
|
153 |
+
|
154 |
+
// User profile fields
|
155 |
+
add_action( 'admin_init', array( '\Twitter\WordPress\Admin\Profile\User', 'init' ) );
|
156 |
+
}
|
157 |
+
|
158 |
+
/**
|
159 |
+
* Register actions and filters shown in a non-admin context
|
160 |
+
*
|
161 |
+
* @since 1.0.0
|
162 |
+
*
|
163 |
+
* @return void
|
164 |
+
*/
|
165 |
+
public static function publicInit()
|
166 |
+
{
|
167 |
+
// enhance web browser view only
|
168 |
+
if ( is_feed() ) {
|
169 |
+
return;
|
170 |
+
}
|
171 |
+
|
172 |
+
// load widgets JS if a Twitter widget is active
|
173 |
+
if ( is_active_widget( false, false, \Twitter\WordPress\Widgets\Follow::BASE_ID, true ) ) {
|
174 |
+
// enqueue after the script is registered in wp_enqueue_scripts action priority 1
|
175 |
+
add_action( 'wp_enqueue_scripts', array( '\Twitter\WordPress\JavaScriptLoaders\Widgets', 'enqueue' ) );
|
176 |
+
}
|
177 |
+
|
178 |
+
// do not add content filters to HTTP 404 response
|
179 |
+
if ( is_404() ) {
|
180 |
+
return;
|
181 |
+
}
|
182 |
+
|
183 |
+
$twitter_content_priority = apply_filters( 'twitter_content_filter_priority', 10 );
|
184 |
+
add_filter(
|
185 |
+
'the_content',
|
186 |
+
array( '\Twitter\WordPress\Content\TweetButton', 'contentFilter' ),
|
187 |
+
$twitter_content_priority
|
188 |
+
);
|
189 |
+
}
|
190 |
+
|
191 |
+
/**
|
192 |
+
* Register shortcodes handlers and callbacks
|
193 |
+
*
|
194 |
+
* @since 1.0.0
|
195 |
+
*
|
196 |
+
* @return void
|
197 |
+
*/
|
198 |
+
public static function registerShortcodeHandlers()
|
199 |
+
{
|
200 |
+
// features requiring HTTPS remote requests
|
201 |
+
if ( wp_http_supports( array( 'ssl' => true ) ) ) {
|
202 |
+
// Embedded Tweet
|
203 |
+
add_action(
|
204 |
+
'plugins_loaded',
|
205 |
+
array( '\Twitter\WordPress\Shortcodes\EmbeddedTweet', 'init' ),
|
206 |
+
5,
|
207 |
+
0
|
208 |
+
);
|
209 |
+
// Twitter embedded videos
|
210 |
+
add_action(
|
211 |
+
'plugins_loaded',
|
212 |
+
array( '\Twitter\WordPress\Shortcodes\EmbeddedTweetVideo', 'init' ),
|
213 |
+
5,
|
214 |
+
0
|
215 |
+
);
|
216 |
+
}
|
217 |
+
|
218 |
+
// Follow button
|
219 |
+
add_action(
|
220 |
+
'plugins_loaded',
|
221 |
+
array( '\Twitter\WordPress\Shortcodes\Follow', 'init' ),
|
222 |
+
5,
|
223 |
+
0
|
224 |
+
);
|
225 |
+
|
226 |
+
// Tweet button
|
227 |
+
add_action(
|
228 |
+
'plugins_loaded',
|
229 |
+
array( '\Twitter\WordPress\Shortcodes\Share', 'init' ),
|
230 |
+
5,
|
231 |
+
0
|
232 |
+
);
|
233 |
+
|
234 |
+
// Ad conversion and audience tracking
|
235 |
+
add_action(
|
236 |
+
'plugins_loaded',
|
237 |
+
array( '\Twitter\WordPress\Shortcodes\Tracking', 'init' ),
|
238 |
+
5,
|
239 |
+
0
|
240 |
+
);
|
241 |
+
}
|
242 |
+
|
243 |
+
/**
|
244 |
+
* Attach actions to the wp_head action
|
245 |
+
*
|
246 |
+
* @since 1.0.0
|
247 |
+
*
|
248 |
+
* @return void
|
249 |
+
*/
|
250 |
+
public static function wpHead()
|
251 |
+
{
|
252 |
+
// Twitter Cards markup
|
253 |
+
add_action(
|
254 |
+
'wp_head',
|
255 |
+
array( '\Twitter\WordPress\Head\CardsMetaElements', 'outputMetaElements' ),
|
256 |
+
99, // late priority to override if multiple values provided
|
257 |
+
0 // expects no arguments
|
258 |
+
);
|
259 |
+
|
260 |
+
// page-level customizations referenced by Twitter JavaScript
|
261 |
+
add_action(
|
262 |
+
'wp_head',
|
263 |
+
array( '\Twitter\WordPress\Head\WidgetsMetaElements', 'outputMetaElements' ),
|
264 |
+
11, // priority
|
265 |
+
0 // expects no arguments
|
266 |
+
);
|
267 |
+
|
268 |
+
if ( ! is_singular() && ! is_author() ) {
|
269 |
+
// attribute authorship to site or site section when a post author does not exist
|
270 |
+
add_action(
|
271 |
+
'wp_head',
|
272 |
+
array( '\Twitter\WordPress\Head\AuthorshipLink', 'relMe' ),
|
273 |
+
10, // default priority
|
274 |
+
0 // no parameters
|
275 |
+
);
|
276 |
+
}
|
277 |
+
}
|
278 |
+
|
279 |
+
/**
|
280 |
+
* Register JavaScript during the enqueue scripts action
|
281 |
+
*
|
282 |
+
* @since 1.0.0
|
283 |
+
*
|
284 |
+
* @return void
|
285 |
+
*/
|
286 |
+
public static function registerScripts()
|
287 |
+
{
|
288 |
+
// widgets.js
|
289 |
+
\Twitter\WordPress\JavaScriptLoaders\Widgets::register();
|
290 |
+
|
291 |
+
// ad tracker
|
292 |
+
\Twitter\WordPress\JavaScriptLoaders\Tracking::register();
|
293 |
+
}
|
294 |
+
|
295 |
+
/**
|
296 |
+
* Compatibility wrappers for popular plugins
|
297 |
+
*
|
298 |
+
* @since 1.0.0
|
299 |
+
*
|
300 |
+
* @return void
|
301 |
+
*/
|
302 |
+
public static function compatibility()
|
303 |
+
{
|
304 |
+
\Twitter\WordPress\Cards\Compatibility::init();
|
305 |
+
}
|
306 |
+
}
|
src/Twitter/WordPress/Shortcodes/EmbeddedTweet.php
ADDED
@@ -0,0 +1,451 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Shortcodes;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Display a Tweet
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class EmbeddedTweet
|
34 |
+
{
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Shortcode tag to be matched
|
38 |
+
*
|
39 |
+
* @since 1.0.0
|
40 |
+
*
|
41 |
+
* @type string
|
42 |
+
*/
|
43 |
+
const SHORTCODE_TAG = 'tweet';
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Relative path for the oEmbed API relative to Twitter API base path
|
47 |
+
*
|
48 |
+
* @since 1.0.0
|
49 |
+
*
|
50 |
+
* @type string
|
51 |
+
*/
|
52 |
+
const OEMBED_API_ENDPOINT = 'statuses/oembed';
|
53 |
+
|
54 |
+
/**
|
55 |
+
* oEmbed regex registered by WordPress Core
|
56 |
+
*
|
57 |
+
* @since 1.0.0
|
58 |
+
*
|
59 |
+
* @type string
|
60 |
+
*/
|
61 |
+
const OEMBED_CORE_REGEX = '#https?://(www\.)?twitter\.com/.+?/status(es)?/.*#i';
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Regex used to match a Tweet in text
|
65 |
+
*
|
66 |
+
* More specific than WordPress Core regex
|
67 |
+
*
|
68 |
+
* @since 1.0.0
|
69 |
+
*
|
70 |
+
* @type string
|
71 |
+
*/
|
72 |
+
const TWEET_URL_REGEX = '#^https?://(www\.)?twitter\.com/.+?/status(es)?/([0-9]+)#i';
|
73 |
+
|
74 |
+
/**
|
75 |
+
* Accepted values for the align parameter
|
76 |
+
*
|
77 |
+
* @since 1.0.0
|
78 |
+
*
|
79 |
+
* @type array
|
80 |
+
*/
|
81 |
+
public static $ALIGN_OPTIONS = array( 'left' => true, 'center' => true, 'right' => true );
|
82 |
+
|
83 |
+
/**
|
84 |
+
* Accepted shortcode attributes and their default values
|
85 |
+
*
|
86 |
+
* @since 1.0.0
|
87 |
+
*
|
88 |
+
* @type array
|
89 |
+
*/
|
90 |
+
public static $SHORTCODE_DEFAULTS = array( 'id' => '', 'conversation' => true, 'cards' => true, 'align' => '' );
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Attach handlers for embedded Tweets
|
94 |
+
*
|
95 |
+
* @since 1.0.0
|
96 |
+
*
|
97 |
+
* @return void
|
98 |
+
*/
|
99 |
+
public static function init()
|
100 |
+
{
|
101 |
+
// register our shortcode and its handler
|
102 |
+
add_shortcode( self::SHORTCODE_TAG, array( __CLASS__, 'shortcodeHandler' ) );
|
103 |
+
|
104 |
+
// unhook the WordPress Core oEmbed handler
|
105 |
+
wp_oembed_remove_provider( static::OEMBED_CORE_REGEX );
|
106 |
+
// pass a Tweet detail URL through the Tweet shortcode handler
|
107 |
+
wp_embed_register_handler(
|
108 |
+
self::SHORTCODE_TAG,
|
109 |
+
static::TWEET_URL_REGEX,
|
110 |
+
array( __CLASS__, 'linkHandler' ),
|
111 |
+
1
|
112 |
+
);
|
113 |
+
}
|
114 |
+
|
115 |
+
/**
|
116 |
+
* Handle a URL matched by an embed handler
|
117 |
+
*
|
118 |
+
* @since 1.0.0
|
119 |
+
*
|
120 |
+
* @param array $matches The regex matches from the provided regex when calling {@link wp_embed_register_handler()}.
|
121 |
+
* @param array $attr Embed attributes. Not used.
|
122 |
+
* @param string $url The original URL that was matched by the regex. Not used.
|
123 |
+
* @param array $rawattr The original unmodified attributes. Not used.
|
124 |
+
*
|
125 |
+
* @return string HTML markup for the Tweet or an empty string if requirements not met
|
126 |
+
*/
|
127 |
+
public static function linkHandler( $matches, $attr, $url, $rawattr )
|
128 |
+
{
|
129 |
+
if ( ! ( is_array( $matches ) && isset( $matches[3] ) && $matches[3] ) ) {
|
130 |
+
return '';
|
131 |
+
}
|
132 |
+
|
133 |
+
return static::shortcodeHandler( array( 'id' => $matches[3] ) );
|
134 |
+
}
|
135 |
+
|
136 |
+
/**
|
137 |
+
* Convert a Tweet ID in ID or URL form into a trimmed ID
|
138 |
+
*
|
139 |
+
* @since 1.0.0
|
140 |
+
*
|
141 |
+
* @param string $tweet_id Tweet identifier
|
142 |
+
*
|
143 |
+
* @return string $tweet_id Tweet identifier or empty string if minimum requirements not met
|
144 |
+
*/
|
145 |
+
public static function sanitizeTweetID( $tweet_id )
|
146 |
+
{
|
147 |
+
if ( ! is_string( $tweet_id ) ) {
|
148 |
+
return '';
|
149 |
+
}
|
150 |
+
|
151 |
+
$tweet_id = trim( $tweet_id );
|
152 |
+
if ( ! $tweet_id ) {
|
153 |
+
return '';
|
154 |
+
}
|
155 |
+
$tweet_id = trim( rtrim( trim( $tweet_id ), '/' ) );
|
156 |
+
if ( ! $tweet_id ) {
|
157 |
+
return '';
|
158 |
+
}
|
159 |
+
|
160 |
+
$last_slash = strrpos( $tweet_id, '/' );
|
161 |
+
if ( false !== $last_slash ) {
|
162 |
+
$tweet_id = substr( $tweet_id, $last_slash + 1 );
|
163 |
+
}
|
164 |
+
|
165 |
+
return $tweet_id;
|
166 |
+
}
|
167 |
+
|
168 |
+
/**
|
169 |
+
* Convert shortcode parameters, attributes, and defaults into a clean set of Tweet parameters
|
170 |
+
*
|
171 |
+
* @since 1.0.0
|
172 |
+
*
|
173 |
+
* @param array $attributes set of shortcode attribute-value pairs or positional content matching the WordPress shortcode regex {
|
174 |
+
* @type string|int attribute name or positional int
|
175 |
+
* @type mixed shortcode value
|
176 |
+
* }
|
177 |
+
*
|
178 |
+
* @return array cleaned up options ready for comparison {
|
179 |
+
* @type string option name
|
180 |
+
* @type string|bool option value
|
181 |
+
* }
|
182 |
+
*/
|
183 |
+
public static function sanitizeShortcodeParameters( $attributes = array() )
|
184 |
+
{
|
185 |
+
if ( ! is_array( $attributes ) ) {
|
186 |
+
return array();
|
187 |
+
}
|
188 |
+
|
189 |
+
$options = array();
|
190 |
+
|
191 |
+
if ( isset( $attributes['id'] ) ) {
|
192 |
+
$tweet_id = static::sanitizeTweetID( (string) $attributes['id'] );
|
193 |
+
if ( $tweet_id ) {
|
194 |
+
$options['id'] = $tweet_id;
|
195 |
+
}
|
196 |
+
unset( $tweet_id );
|
197 |
+
} else if ( isset( $attributes[0] ) ) {
|
198 |
+
// compatibility with WordPress.com positional shortcode
|
199 |
+
$tweet_id = static::sanitizeTweetID( (string) $attributes[0] );
|
200 |
+
if ( $tweet_id ) {
|
201 |
+
$options['id'] = $tweet_id;
|
202 |
+
}
|
203 |
+
unset( $tweet_id );
|
204 |
+
}
|
205 |
+
|
206 |
+
foreach ( array( 'cards' => 'hide_media', 'conversation' => 'hide_thread' ) as $falsey_option => $alternate_naming ) {
|
207 |
+
// check for falsey values passed to shortcode
|
208 |
+
if ( isset( $attributes[ $falsey_option ] ) ) {
|
209 |
+
if ( false === $attributes[ $falsey_option ] || '0' == $attributes[ $falsey_option ] || ( is_string( $attributes[ $falsey_option ] ) && in_array( strtolower( $attributes[ $falsey_option ] ), array( 'false', 'no', 'off' ) ) ) ) {
|
210 |
+
$options[ $falsey_option ] = false;
|
211 |
+
}
|
212 |
+
} else if ( isset( $attributes[ $alternate_naming ] ) ) {
|
213 |
+
// test for an oEmbed-style parameter provided in the shortcode if the equivalent parameter was not defined
|
214 |
+
if ( true === $attributes[ $alternate_naming ] || '1' == $attributes[ $alternate_naming ] || ( is_string( $attributes[ $alternate_naming ] ) && in_array( strtolower( $attributes[ $alternate_naming ] ), array( 'true', 'yes', 'on' ) ) ) ) {
|
215 |
+
// test alternate attribute used by other shortcodes
|
216 |
+
$options[ $falsey_option ] = false;
|
217 |
+
}
|
218 |
+
}
|
219 |
+
}
|
220 |
+
|
221 |
+
if ( isset( $attributes['align'] ) && $attributes['align'] ) {
|
222 |
+
$attributes['align'] = trim( strtolower( $attributes['align'] ) );
|
223 |
+
if ( array_key_exists( $attributes['align'], static::$ALIGN_OPTIONS ) ) {
|
224 |
+
$options['align'] = $attributes['align'];
|
225 |
+
}
|
226 |
+
}
|
227 |
+
|
228 |
+
return $options;
|
229 |
+
}
|
230 |
+
|
231 |
+
/**
|
232 |
+
* Handle shortcode macro
|
233 |
+
*
|
234 |
+
* @since 1.0.0
|
235 |
+
*
|
236 |
+
* @param array $attributes set of shortcode attribute-value pairs or positional content matching the WordPress shortcode regex {
|
237 |
+
* @type string|int attribute name or positional int
|
238 |
+
* @type mixed shortcode value
|
239 |
+
* }
|
240 |
+
* @param string $content content inside a shortcode macro. no effect on this shortcode
|
241 |
+
*
|
242 |
+
* @return string HTML markup. empty string if parameter requirement not met or no Tweet info found
|
243 |
+
*/
|
244 |
+
public static function shortcodeHandler( $attributes, $content = '' )
|
245 |
+
{
|
246 |
+
// clean up attribute to shortcode option mappings before passing to filter
|
247 |
+
// apply the same filter as shortcode_atts
|
248 |
+
/** This filter is documented in wp-includes/shortcodes.php */
|
249 |
+
$options = apply_filters(
|
250 |
+
'shortcode_atts_' . self::SHORTCODE_TAG,
|
251 |
+
array_merge(
|
252 |
+
static::$SHORTCODE_DEFAULTS,
|
253 |
+
static::sanitizeShortcodeParameters( (array) $attributes )
|
254 |
+
),
|
255 |
+
static::$SHORTCODE_DEFAULTS,
|
256 |
+
$attributes
|
257 |
+
);
|
258 |
+
|
259 |
+
if ( ! $options['id'] ) {
|
260 |
+
return '';
|
261 |
+
}
|
262 |
+
$tweet_id = $options['id'];
|
263 |
+
unset( $options['id'] );
|
264 |
+
|
265 |
+
$oembed_params = static::shortcodeParamsToOEmbedParams( $tweet_id, $options );
|
266 |
+
if ( empty( $oembed_params ) ) {
|
267 |
+
return '';
|
268 |
+
}
|
269 |
+
|
270 |
+
// fetch HTML markup from Twitter oEmbed endpoint for the given parameters
|
271 |
+
$html = trim( static::getOEmbedMarkup( $oembed_params ) );
|
272 |
+
if ( ! $html ) {
|
273 |
+
return '';
|
274 |
+
}
|
275 |
+
|
276 |
+
\Twitter\WordPress\JavaScriptLoaders\Widgets::enqueue();
|
277 |
+
return '<div class="twitter-tweet">' . $html . '</div>';
|
278 |
+
}
|
279 |
+
|
280 |
+
/**
|
281 |
+
* Get the base set of oEmbed params before applying shortcode customizations
|
282 |
+
*
|
283 |
+
* @since 1.0.0
|
284 |
+
*
|
285 |
+
* @param string $tweet_id Tweet identifier
|
286 |
+
*
|
287 |
+
* @return array associative array of query parameters ready for http_build_query {
|
288 |
+
* @type string query parameter name
|
289 |
+
* @type string|bool query parameter value
|
290 |
+
* }
|
291 |
+
*/
|
292 |
+
public static function getBaseOEmbedParams( $tweet_id )
|
293 |
+
{
|
294 |
+
$tweet_id = trim( $tweet_id );
|
295 |
+
if ( ! $tweet_id ) {
|
296 |
+
return array();
|
297 |
+
}
|
298 |
+
|
299 |
+
// omit JavaScript. enqueue separately
|
300 |
+
$query_parameters = array(
|
301 |
+
'id' => $tweet_id,
|
302 |
+
'omit_script' => true,
|
303 |
+
);
|
304 |
+
|
305 |
+
// attempt to customize text for site language
|
306 |
+
$lang = \Twitter\WordPress\Language::localeToTwitterLang();
|
307 |
+
if ( $lang ) {
|
308 |
+
$query_parameters['lang'] = $lang;
|
309 |
+
}
|
310 |
+
|
311 |
+
return $query_parameters;
|
312 |
+
}
|
313 |
+
|
314 |
+
/**
|
315 |
+
* Convert shortcode parameters into query parameters supported by the Twitter oEmbed endpoint
|
316 |
+
*
|
317 |
+
* @since 1.0.0
|
318 |
+
*
|
319 |
+
* @param string $tweet_id Tweet identifier
|
320 |
+
* @param array $shortcode_options customizations specified in the shortcode
|
321 |
+
*
|
322 |
+
* @return array associative array of query parameters ready for http_build_query {
|
323 |
+
* @type string query parameter name
|
324 |
+
* @type string|bool query parameter value
|
325 |
+
* }
|
326 |
+
*/
|
327 |
+
public static function shortcodeParamsToOEmbedParams( $tweet_id, $shortcode_options = array() )
|
328 |
+
{
|
329 |
+
$query_parameters = static::getBaseOEmbedParams( $tweet_id );
|
330 |
+
if ( empty( $query_parameters ) ) {
|
331 |
+
return array();
|
332 |
+
}
|
333 |
+
|
334 |
+
// test for valid align value
|
335 |
+
if ( isset( $shortcode_options['align'] ) && $shortcode_options['align'] && array_key_exists( $shortcode_options['align'], static::$ALIGN_OPTIONS ) ) {
|
336 |
+
$query_parameters['align'] = $shortcode_options['align'];
|
337 |
+
}
|
338 |
+
|
339 |
+
// oembed parameters are the opposite of widget parameters
|
340 |
+
// hide_* in oEmbed API
|
341 |
+
foreach ( array( 'cards' => 'hide_media', 'conversation' => 'hide_thread' ) as $bool_option => $oembed_parameter ) {
|
342 |
+
if ( isset( $shortcode_options[ $bool_option ] ) && false === $shortcode_options[ $bool_option ] ) {
|
343 |
+
$query_parameters[ $oembed_parameter ] = true;
|
344 |
+
}
|
345 |
+
}
|
346 |
+
|
347 |
+
return $query_parameters;
|
348 |
+
}
|
349 |
+
|
350 |
+
/**
|
351 |
+
* Generate a unique string representing oEmbed result customizations set by shortcode parameters
|
352 |
+
*
|
353 |
+
* @since 1.0.0
|
354 |
+
*
|
355 |
+
* @param array $query_parameters associative array of query parameters sent to the oEmbed endpoint {
|
356 |
+
* @type string query parameter name
|
357 |
+
* @type string|bool query parameter value
|
358 |
+
* }
|
359 |
+
*
|
360 |
+
* @return string cache key component
|
361 |
+
*/
|
362 |
+
public static function getOEmbedCacheKeyCustomParameters( array $query_parameters )
|
363 |
+
{
|
364 |
+
$customizations = '';
|
365 |
+
|
366 |
+
if ( isset( $query_parameters['hide_media'] ) && $query_parameters['hide_media'] ) {
|
367 |
+
$customizations .= 'm';
|
368 |
+
}
|
369 |
+
if ( isset( $query_parameters['hide_thread'] ) && $query_parameters['hide_thread'] ) {
|
370 |
+
$customizations .= 't';
|
371 |
+
}
|
372 |
+
// left, right, center
|
373 |
+
if ( isset( $query_parameters['align'] ) && $query_parameters['align'] && array_key_exists( $query_parameters['align'], static::$ALIGN_OPTIONS ) ) {
|
374 |
+
$customizations .= substr( $query_parameters['align'], 0, 1 );
|
375 |
+
}
|
376 |
+
|
377 |
+
return $customizations;
|
378 |
+
}
|
379 |
+
|
380 |
+
/**
|
381 |
+
* Construct a cache key for the oEmbed response. Account for query parameters needing to bust cache
|
382 |
+
*
|
383 |
+
* @since 1.0.0
|
384 |
+
*
|
385 |
+
* @link https://dev.twitter.com/rest/reference/get/statuses/oembed oEmbed doc
|
386 |
+
* @param array $query_parameters oEmbed API query parameters
|
387 |
+
*
|
388 |
+
* @return string cache key
|
389 |
+
*/
|
390 |
+
public static function oEmbedCacheKey( array $query_parameters )
|
391 |
+
{
|
392 |
+
if ( ! ( isset( $query_parameters['id'] ) && $query_parameters['id'] ) ) {
|
393 |
+
return '';
|
394 |
+
}
|
395 |
+
|
396 |
+
$key_pieces = array( self::SHORTCODE_TAG, $query_parameters['id'] );
|
397 |
+
|
398 |
+
// separate cache for each explicitly-defined display language
|
399 |
+
if ( isset( $query_parameters['lang'] ) && $query_parameters['lang'] ) {
|
400 |
+
$key_pieces[] = $query_parameters['lang'];
|
401 |
+
}
|
402 |
+
|
403 |
+
$customizations = static::getOEmbedCacheKeyCustomParameters( $query_parameters );
|
404 |
+
if ( $customizations ) {
|
405 |
+
$key_pieces[] = $customizations;
|
406 |
+
}
|
407 |
+
|
408 |
+
return implode( '_', $key_pieces );
|
409 |
+
}
|
410 |
+
|
411 |
+
/**
|
412 |
+
* Request and parse oEmbed markup from Twitter's API servers
|
413 |
+
*
|
414 |
+
* @since 1.0.0
|
415 |
+
*
|
416 |
+
* @param array $query_parameters request parameters
|
417 |
+
*
|
418 |
+
* @return string HTML markup returned by the oEmbed endpoint
|
419 |
+
*/
|
420 |
+
public static function getOEmbedMarkup( array $query_parameters )
|
421 |
+
{
|
422 |
+
$cache_key = static::oEmbedCacheKey( $query_parameters );
|
423 |
+
if ( ! $cache_key ) {
|
424 |
+
return '';
|
425 |
+
}
|
426 |
+
|
427 |
+
// check for cached result
|
428 |
+
$html = get_transient( $cache_key );
|
429 |
+
if ( $html ) {
|
430 |
+
return $html;
|
431 |
+
}
|
432 |
+
|
433 |
+
$ttl = DAY_IN_SECONDS;
|
434 |
+
|
435 |
+
$oembed_response = \Twitter\WordPress\Helpers\TwitterAPI::getJSON( self::OEMBED_API_ENDPOINT, $query_parameters );
|
436 |
+
if ( ! $oembed_response || ! isset( $oembed_response->type ) || 'rich' !== $oembed_response->type || ! ( isset( $oembed_response->html ) && $oembed_response->html ) ) {
|
437 |
+
// do not rerequest errors with every page request
|
438 |
+
set_transient( $cache_key, ' ', $ttl );
|
439 |
+
return '';
|
440 |
+
}
|
441 |
+
|
442 |
+
$html = $oembed_response->html;
|
443 |
+
|
444 |
+
if ( isset( $oembed_response->cache_age ) ) {
|
445 |
+
$ttl = absint( $oembed_response->cache_age );
|
446 |
+
}
|
447 |
+
set_transient( $cache_key, $html, $ttl );
|
448 |
+
|
449 |
+
return $html;
|
450 |
+
}
|
451 |
+
}
|
src/Twitter/WordPress/Shortcodes/EmbeddedTweetVideo.php
ADDED
@@ -0,0 +1,206 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Shortcodes;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Display a video attached to a Tweet
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class EmbeddedTweetVideo extends EmbeddedTweet
|
34 |
+
{
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Shortcode tag to be matched
|
38 |
+
*
|
39 |
+
* @since 1.0.0
|
40 |
+
*
|
41 |
+
* @type string
|
42 |
+
*/
|
43 |
+
const SHORTCODE_TAG = 'twitter_video';
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Accepted shortcode attributes and their default values
|
47 |
+
*
|
48 |
+
* @since 1.0.0
|
49 |
+
*
|
50 |
+
* @type array
|
51 |
+
*/
|
52 |
+
public static $SHORTCODE_DEFAULTS = array( 'id' => '', 'status' => true );
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Attach handlers for Twitter embedded video
|
56 |
+
*
|
57 |
+
* @since 1.0.0
|
58 |
+
*
|
59 |
+
* @return void
|
60 |
+
*/
|
61 |
+
public static function init()
|
62 |
+
{
|
63 |
+
// register our shortcode and its handler
|
64 |
+
add_shortcode( self::SHORTCODE_TAG, array( __CLASS__, 'shortcodeHandler' ) );
|
65 |
+
}
|
66 |
+
|
67 |
+
/**
|
68 |
+
* Convert shortcode parameters into a clean set of Twitter embedded video options parameters
|
69 |
+
*
|
70 |
+
* @since 1.0.0
|
71 |
+
*
|
72 |
+
* @param array $attributes set of shortcode attribute-value pairs matching the WordPress shortcode regex {
|
73 |
+
* @type string attribute name
|
74 |
+
* @type mixed shortcode value
|
75 |
+
* }
|
76 |
+
*
|
77 |
+
* @return array cleaned up options ready for comparison {
|
78 |
+
* @type string option name
|
79 |
+
* @type string|bool option value
|
80 |
+
* }
|
81 |
+
*/
|
82 |
+
public static function sanitizeShortcodeParameters( $attributes = array() )
|
83 |
+
{
|
84 |
+
if ( ! is_array( $attributes ) ) {
|
85 |
+
return array();
|
86 |
+
}
|
87 |
+
|
88 |
+
$options = array();
|
89 |
+
|
90 |
+
// clean up Tweet ID
|
91 |
+
if ( isset( $attributes['id'] ) ) {
|
92 |
+
$tweet_id = static::sanitizeTweetID( (string) $attributes['id'] );
|
93 |
+
if ( $tweet_id ) {
|
94 |
+
$options['id'] = $tweet_id;
|
95 |
+
}
|
96 |
+
unset( $tweet_id );
|
97 |
+
}
|
98 |
+
|
99 |
+
// allow option style or oEmbed style parameter
|
100 |
+
if ( isset( $attributes['status'] ) ) {
|
101 |
+
if ( false === $attributes['status'] || '0' == $attributes['status'] || ( is_string( $attributes['status'] ) && in_array( strtolower( $attributes['status'] ), array( 'false', 'no', 'off' ) ) ) ) {
|
102 |
+
$options['status'] = false;
|
103 |
+
}
|
104 |
+
} else if ( isset( $attributes['hide_tweet'] ) ) {
|
105 |
+
if ( true === $attributes['hide_tweet'] || '1' == $attributes['hide_tweet'] || ( is_string( $attributes['hide_tweet'] ) && in_array( strtolower( $attributes['hide_tweet'] ), array( 'true', 'yes', 'on' ) ) ) ) {
|
106 |
+
$options['status'] = false;
|
107 |
+
}
|
108 |
+
}
|
109 |
+
|
110 |
+
return $options;
|
111 |
+
}
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Handle shortcode macro
|
115 |
+
*
|
116 |
+
* @since 1.0.0
|
117 |
+
*
|
118 |
+
* @param array $attributes shortcode attributes
|
119 |
+
* @param string $content shortcode content. no effect
|
120 |
+
*
|
121 |
+
* @return string HTML markup
|
122 |
+
*/
|
123 |
+
public static function shortcodeHandler( $attributes, $content = '' )
|
124 |
+
{
|
125 |
+
// clean up attribute to shortcode option mappings before passing to filter
|
126 |
+
// apply the same filter as shortcode_atts
|
127 |
+
/** This filter is documented in wp-includes/shortcodes.php */
|
128 |
+
$options = apply_filters(
|
129 |
+
'shortcode_atts_' . self::SHORTCODE_TAG,
|
130 |
+
array_merge(
|
131 |
+
static::$SHORTCODE_DEFAULTS,
|
132 |
+
static::sanitizeShortcodeParameters( (array) $attributes )
|
133 |
+
),
|
134 |
+
static::$SHORTCODE_DEFAULTS,
|
135 |
+
$attributes
|
136 |
+
);
|
137 |
+
|
138 |
+
if ( ! $options['id'] ) {
|
139 |
+
return '';
|
140 |
+
}
|
141 |
+
$tweet_id = $options['id'];
|
142 |
+
unset( $options['id'] );
|
143 |
+
|
144 |
+
$oembed_params = static::shortcodeParamsToOEmbedParams( $tweet_id, $options );
|
145 |
+
if ( empty( $oembed_params ) ) {
|
146 |
+
return '';
|
147 |
+
}
|
148 |
+
|
149 |
+
// fetch HTML markup from Twitter oEmbed endpoint for the given parameters
|
150 |
+
$html = trim( static::getOEmbedMarkup( $oembed_params ) );
|
151 |
+
if ( ! $html ) {
|
152 |
+
return '';
|
153 |
+
}
|
154 |
+
|
155 |
+
\Twitter\WordPress\JavaScriptLoaders\Widgets::enqueue();
|
156 |
+
return '<div class="twitter-video">' . $html . '</div>';
|
157 |
+
}
|
158 |
+
|
159 |
+
/**
|
160 |
+
* Convert shortcode parameters into query parameters supported by the Twitter oEmbed endpoint
|
161 |
+
*
|
162 |
+
* @since 1.0.0
|
163 |
+
*
|
164 |
+
* @param string $tweet_id Tweet identifier
|
165 |
+
* @param array $shortcode_options customizations specified in the shortcode
|
166 |
+
*
|
167 |
+
* @return array associative array of query parameters ready for http_build_query
|
168 |
+
*/
|
169 |
+
public static function shortcodeParamsToOEmbedParams( $tweet_id, $shortcode_options = array() )
|
170 |
+
{
|
171 |
+
$query_parameters = static::getBaseOEmbedParams( $tweet_id );
|
172 |
+
if ( empty( $query_parameters ) ) {
|
173 |
+
return array();
|
174 |
+
}
|
175 |
+
$query_parameters['widget_type'] = 'video';
|
176 |
+
|
177 |
+
if ( isset( $shortcode_options['status'] ) && false === $shortcode_options['status'] ) {
|
178 |
+
$query_parameters['hide_tweet'] = true;
|
179 |
+
}
|
180 |
+
|
181 |
+
return $query_parameters;
|
182 |
+
}
|
183 |
+
|
184 |
+
/**
|
185 |
+
* Generate a unique string representing oEmbed result customizations set by shortcode parameters
|
186 |
+
*
|
187 |
+
* @since 1.0.0
|
188 |
+
*
|
189 |
+
* @param array $query_parameters associative array of query parameters sent to the oEmbed endpoint {
|
190 |
+
* @type string query parameter name
|
191 |
+
* @type string|bool query parameter value
|
192 |
+
* }
|
193 |
+
*
|
194 |
+
* @return string cache key component
|
195 |
+
*/
|
196 |
+
public static function getOEmbedCacheKeyCustomParameters( array $query_parameters )
|
197 |
+
{
|
198 |
+
$customizations = '';
|
199 |
+
|
200 |
+
if ( isset( $query_parameters['hide_tweet'] ) && $query_parameters['hide_tweet'] ) {
|
201 |
+
$customizations .= 'h';
|
202 |
+
}
|
203 |
+
|
204 |
+
return $customizations;
|
205 |
+
}
|
206 |
+
}
|
src/Twitter/WordPress/Shortcodes/Follow.php
ADDED
@@ -0,0 +1,193 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Shortcodes;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Display a Follow button
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class Follow
|
34 |
+
{
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Shortcode tag to be matched
|
38 |
+
*
|
39 |
+
* @since 1.0.0
|
40 |
+
*
|
41 |
+
* @type string
|
42 |
+
*/
|
43 |
+
const SHORTCODE_TAG = 'twitter_follow';
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Accepted shortcode attributes and their default values
|
47 |
+
*
|
48 |
+
* @since 1.0.0
|
49 |
+
*
|
50 |
+
* @type array
|
51 |
+
*/
|
52 |
+
public static $SHORTCODE_DEFAULTS = array( 'screen_name' => '', 'show_count' => true, 'show_screen_name' => true, 'size' => 'medium' );
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Register shortcode macro and handler
|
56 |
+
*
|
57 |
+
* @since 1.0.0
|
58 |
+
*
|
59 |
+
* @return void
|
60 |
+
*/
|
61 |
+
public static function init()
|
62 |
+
{
|
63 |
+
add_shortcode( static::SHORTCODE_TAG, array( __CLASS__, 'shortcodeHandler' ) );
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Clean up provided shortcode values
|
68 |
+
*
|
69 |
+
* Be liberal in what we accept in shortcode syntax before constructing a Follow button
|
70 |
+
*
|
71 |
+
* @since 1.0.0
|
72 |
+
*
|
73 |
+
* @param array $attributes provided shortcode attributes {
|
74 |
+
* @type string shortcode attribute name
|
75 |
+
* @type mixed shortcode attribute value
|
76 |
+
* }
|
77 |
+
*
|
78 |
+
* @return array simplified shortcode values with defaults removed {
|
79 |
+
* @type string shortcode attribute name
|
80 |
+
* @type bool|string shortcode attribute value
|
81 |
+
* }
|
82 |
+
*/
|
83 |
+
public static function sanitizeShortcodeParameters( $attributes = array() )
|
84 |
+
{
|
85 |
+
if ( ! is_array( $attributes ) ) {
|
86 |
+
return array();
|
87 |
+
}
|
88 |
+
|
89 |
+
$options = array();
|
90 |
+
|
91 |
+
if ( isset( $attributes['screen_name'] ) ) {
|
92 |
+
$screen_name = \Twitter\Helpers\Validators\ScreenName::trim( $attributes['screen_name'] );
|
93 |
+
if ( $screen_name ) {
|
94 |
+
$options['screen_name'] = $screen_name;
|
95 |
+
}
|
96 |
+
unset( $screen_name );
|
97 |
+
}
|
98 |
+
|
99 |
+
foreach ( array( 'show_count', 'show_screen_name' ) as $falsey_option ) {
|
100 |
+
// check for falsey values passed to shortcode
|
101 |
+
if ( isset( $attributes[ $falsey_option ] ) ) {
|
102 |
+
if ( false === $attributes[ $falsey_option ] || '0' == $attributes[ $falsey_option ] || ( is_string( $attributes[ $falsey_option ] ) && in_array( strtolower( $attributes[ $falsey_option ] ), array( 'false', 'no', 'off' ) ) ) ) {
|
103 |
+
$options[ $falsey_option ] = false;
|
104 |
+
}
|
105 |
+
}
|
106 |
+
}
|
107 |
+
|
108 |
+
// large is the only option
|
109 |
+
if ( isset( $attributes['size'] ) ) {
|
110 |
+
if ( is_string( $attributes['size'] ) && in_array( strtolower( $attributes['size'] ), array( 'large', 'l' ) ) ) {
|
111 |
+
$options['size'] = 'large';
|
112 |
+
}
|
113 |
+
}
|
114 |
+
|
115 |
+
return $options;
|
116 |
+
}
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Get the Twitter screen name of the author of the current post
|
120 |
+
*
|
121 |
+
* @since 1.0.0
|
122 |
+
*
|
123 |
+
* @return string Twitter screen name or empty if no screen name stored
|
124 |
+
*/
|
125 |
+
public static function getScreenName()
|
126 |
+
{
|
127 |
+
if ( ! in_the_loop() ) {
|
128 |
+
return '';
|
129 |
+
}
|
130 |
+
|
131 |
+
$screen_name = \Twitter\WordPress\User\Meta::getTwitterUsername( get_the_author_meta( 'ID' ) );
|
132 |
+
if ( ! $screen_name ) {
|
133 |
+
return '';
|
134 |
+
}
|
135 |
+
|
136 |
+
return $screen_name;
|
137 |
+
}
|
138 |
+
|
139 |
+
/**
|
140 |
+
* Handle shortcode macro
|
141 |
+
*
|
142 |
+
* @since 1.0.0
|
143 |
+
*
|
144 |
+
* @param array $attributes shortcode attributes
|
145 |
+
* @param string $content shortcode content. no effect
|
146 |
+
*
|
147 |
+
* @return string Follow button HTML or empty string
|
148 |
+
*/
|
149 |
+
public static function shortcodeHandler( $attributes, $content = '' )
|
150 |
+
{
|
151 |
+
// clean up attribute to shortcode option mappings before passing to filter
|
152 |
+
// apply the same filter as shortcode_atts
|
153 |
+
/** This filter is documented in wp-includes/shortcodes.php */
|
154 |
+
$options = apply_filters(
|
155 |
+
'shortcode_atts_' . self::SHORTCODE_TAG,
|
156 |
+
array_merge(
|
157 |
+
static::$SHORTCODE_DEFAULTS,
|
158 |
+
static::sanitizeShortcodeParameters( (array) $attributes )
|
159 |
+
),
|
160 |
+
static::$SHORTCODE_DEFAULTS,
|
161 |
+
$attributes
|
162 |
+
);
|
163 |
+
|
164 |
+
$screen_name = '';
|
165 |
+
if ( isset( $options['screen_name'] ) ) {
|
166 |
+
$screen_name = $options['screen_name'];
|
167 |
+
unset( $options['screen_name'] );
|
168 |
+
}
|
169 |
+
if ( ! $screen_name ) {
|
170 |
+
$screen_name = static::getScreenName();
|
171 |
+
// follow target required
|
172 |
+
if ( ! $screen_name ) {
|
173 |
+
return '';
|
174 |
+
}
|
175 |
+
}
|
176 |
+
|
177 |
+
// update the options array with the Follow screen name
|
178 |
+
$options['screen_name'] = $screen_name;
|
179 |
+
|
180 |
+
$follow = \Twitter\Widgets\FollowButton::fromArray( $options );
|
181 |
+
if ( ! $follow ) {
|
182 |
+
return '';
|
183 |
+
}
|
184 |
+
|
185 |
+
$html = $follow->toHTML( _x( 'Follow %s', 'Follow a Twitter user', 'twitter' ), '\Twitter\WordPress\Helpers\HTMLBuilder' );
|
186 |
+
if ( ! $html ) {
|
187 |
+
return '';
|
188 |
+
}
|
189 |
+
|
190 |
+
\Twitter\WordPress\JavaScriptLoaders\Widgets::enqueue();
|
191 |
+
return '<div class="twitter-follow">' . $html . '</div>';
|
192 |
+
}
|
193 |
+
}
|
src/Twitter/WordPress/Shortcodes/Share.php
ADDED
@@ -0,0 +1,372 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Shortcodes;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Display a Tweet Web Intent and queue JavaScript for conversion to a Tweet button
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class Share
|
34 |
+
{
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Shortcode tag to be matched
|
38 |
+
*
|
39 |
+
* @since 1.0.0
|
40 |
+
*
|
41 |
+
* @type string
|
42 |
+
*/
|
43 |
+
const SHORTCODE_TAG = 'twitter_share';
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Accepted shortcode attributes and their default values
|
47 |
+
*
|
48 |
+
* @since 1.0.0
|
49 |
+
*
|
50 |
+
* @type array
|
51 |
+
*/
|
52 |
+
public static $SHORTCODE_DEFAULTS = array( 'in_reply_to' => '', 'text' => '', 'url' => '', 'hashtags' => array(), 'via' => '', 'related' => array(), 'size' => '', 'align' => '', 'count' => '', 'counturl' => '' );
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Attach handlers for Tweet button
|
56 |
+
*
|
57 |
+
* @since 1.0.0
|
58 |
+
*
|
59 |
+
* @return void
|
60 |
+
*/
|
61 |
+
public static function init()
|
62 |
+
{
|
63 |
+
add_shortcode( static::SHORTCODE_TAG, array( __CLASS__, 'shortcodeHandler' ) );
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Get any Tweet values stored for an individual post
|
68 |
+
*
|
69 |
+
* @since 1.0.0
|
70 |
+
*
|
71 |
+
* @return array post meta Tweet values or empty array if no values stored
|
72 |
+
*/
|
73 |
+
public static function getPostMeta()
|
74 |
+
{
|
75 |
+
$post = get_post();
|
76 |
+
|
77 |
+
if ( ! ( $post && isset( $post->ID ) ) ) {
|
78 |
+
return array();
|
79 |
+
}
|
80 |
+
|
81 |
+
$post_values = get_post_meta(
|
82 |
+
$post->ID,
|
83 |
+
\Twitter\WordPress\Admin\Post\TweetIntent::META_KEY,
|
84 |
+
true // single value
|
85 |
+
);
|
86 |
+
if ( ! is_array( $post_values ) ) {
|
87 |
+
return array();
|
88 |
+
}
|
89 |
+
return $post_values;
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Add post meta values to a Tweet button options array
|
94 |
+
*
|
95 |
+
* @since 1.0.0
|
96 |
+
*
|
97 |
+
* @param array $options Tweet button options array {
|
98 |
+
* @type string option name
|
99 |
+
* @type string|array option value
|
100 |
+
* }
|
101 |
+
*
|
102 |
+
* @return array Tweet button options array {
|
103 |
+
* @type string option name
|
104 |
+
* @type string|array option value
|
105 |
+
* }
|
106 |
+
*/
|
107 |
+
protected static function addPostMetaOptions( $options )
|
108 |
+
{
|
109 |
+
if ( ! is_array( $options ) ) {
|
110 |
+
$options = array();
|
111 |
+
}
|
112 |
+
|
113 |
+
$post_meta = static::getPostMeta();
|
114 |
+
if ( empty( $post_meta ) ) {
|
115 |
+
return $options;
|
116 |
+
}
|
117 |
+
|
118 |
+
// allow shortcode text to override post text
|
119 |
+
// example: multiple Tweet buttons in a post
|
120 |
+
if ( ! ( isset( $options['text'] ) && trim( $options['text'] ) ) ) {
|
121 |
+
if ( isset( $post_meta['text'] ) ) {
|
122 |
+
$text = trim( $post_meta['text'] );
|
123 |
+
if ( $text ) {
|
124 |
+
$options['text'] = $text;
|
125 |
+
}
|
126 |
+
unset( $text );
|
127 |
+
}
|
128 |
+
}
|
129 |
+
|
130 |
+
// allow shortcode hashtags to override post hashtags
|
131 |
+
// example: multiple Tweet buttons in a post
|
132 |
+
if ( ! isset( $options['hashtags'] ) || empty( $options['hashtags'] ) ) {
|
133 |
+
if ( isset( $post_meta['hashtags'] ) && is_array( $post_meta['hashtags'] ) && ! empty( $post_meta['hashtags'] ) ) {
|
134 |
+
$options['hashtags'] = $post_meta['hashtags'];
|
135 |
+
}
|
136 |
+
}
|
137 |
+
|
138 |
+
return $options;
|
139 |
+
}
|
140 |
+
|
141 |
+
/**
|
142 |
+
* Convert shortcode parameters, attributes, and defaults into a clean set of Tweet parameters
|
143 |
+
*
|
144 |
+
* @since 1.0.0
|
145 |
+
*
|
146 |
+
* @param array $attributes set of shortcode attribute-value pairs or positional content matching the WordPress shortcode regex {
|
147 |
+
* @type string|int attribute name or positional int
|
148 |
+
* @type mixed shortcode value
|
149 |
+
* }
|
150 |
+
*
|
151 |
+
* @return array cleaned up options ready for comparison {
|
152 |
+
* @type string option name
|
153 |
+
* @type string|bool option value
|
154 |
+
* }
|
155 |
+
*/
|
156 |
+
public static function sanitizeShortcodeParameters( $attributes = array() )
|
157 |
+
{
|
158 |
+
if ( ! is_array( $attributes ) ) {
|
159 |
+
return array();
|
160 |
+
}
|
161 |
+
|
162 |
+
$options = array();
|
163 |
+
|
164 |
+
if ( isset( $attributes['in_reply_to'] ) ) {
|
165 |
+
$tweet_id = \Twitter\WordPress\Shortcodes\EmbeddedTweet::sanitizeTweetID( (string) $attributes['in_reply_to'] );
|
166 |
+
if ( $tweet_id ) {
|
167 |
+
$options['in_reply_to'] = $tweet_id;
|
168 |
+
}
|
169 |
+
unset( $tweet_id );
|
170 |
+
}
|
171 |
+
|
172 |
+
if ( isset( $attributes['text'] ) && is_string( $attributes['text'] ) ) {
|
173 |
+
$options['text'] = $attributes['text'];
|
174 |
+
}
|
175 |
+
|
176 |
+
foreach ( array( 'url', 'counturl' ) as $url_param ) {
|
177 |
+
if ( ! ( isset( $attributes[ $url_param ] ) && $attributes[ $url_param ] ) ) {
|
178 |
+
continue;
|
179 |
+
}
|
180 |
+
|
181 |
+
// filter the URL
|
182 |
+
$url = esc_url_raw( trim( $attributes[ $url_param ] ), array( 'http', 'https' ) );
|
183 |
+
if ( $url ) {
|
184 |
+
$options[ $url_param ] = $url;
|
185 |
+
}
|
186 |
+
unset( $url );
|
187 |
+
}
|
188 |
+
|
189 |
+
if ( isset( $attributes['related'] ) ) {
|
190 |
+
$intent = \Twitter\Intents\Tweet::fromArray( array( 'related' => $attributes['related'] ) );
|
191 |
+
if ( $intent ) {
|
192 |
+
$related = $intent->getRelated();
|
193 |
+
if ( ! empty( $related ) ) {
|
194 |
+
$options['related'] = $related;
|
195 |
+
}
|
196 |
+
unset( $related );
|
197 |
+
}
|
198 |
+
unset( $intent );
|
199 |
+
}
|
200 |
+
|
201 |
+
if ( isset( $attributes['hashtags'] ) ) {
|
202 |
+
$intent = \Twitter\Intents\Tweet::fromArray( array( 'hashtags' => $attributes['hashtags'] ) );
|
203 |
+
if ( $intent ) {
|
204 |
+
$hashtags = $intent->getHashtags();
|
205 |
+
if ( ! empty( $hashtags ) ) {
|
206 |
+
$options['hashtags'] = $hashtags;
|
207 |
+
}
|
208 |
+
unset( $hashtags );
|
209 |
+
}
|
210 |
+
unset( $intent );
|
211 |
+
}
|
212 |
+
|
213 |
+
if ( isset( $attributes['align'] ) && is_string( $attributes['align'] ) && $attributes['align'] ) {
|
214 |
+
$align = strtolower( trim( $attributes['align'] ) );
|
215 |
+
if ( array_key_exists( $align, \Twitter\Widgets\TweetButton::$ALLOWED_ALIGN_VALUES ) ) {
|
216 |
+
$options['align'] = $align;
|
217 |
+
}
|
218 |
+
unset( $align );
|
219 |
+
}
|
220 |
+
|
221 |
+
if ( isset( $attributes['count'] ) && is_string( $attributes['count'] ) ) {
|
222 |
+
$count = strtolower( trim( $attributes['count'] ) );
|
223 |
+
if ( array_key_exists( $count, \Twitter\Widgets\TweetButton::$ALLOWED_COUNT_VALUES ) ) {
|
224 |
+
$options['count'] = $count;
|
225 |
+
}
|
226 |
+
unset( $count );
|
227 |
+
}
|
228 |
+
|
229 |
+
// large is the only option
|
230 |
+
if ( isset( $attributes['size'] ) ) {
|
231 |
+
if ( is_string( $attributes['size'] ) && in_array( strtolower( $attributes['size'] ), array( 'large', 'l' ) ) ) {
|
232 |
+
$options['size'] = 'large';
|
233 |
+
}
|
234 |
+
}
|
235 |
+
|
236 |
+
return $options;
|
237 |
+
}
|
238 |
+
|
239 |
+
/**
|
240 |
+
* Add explicit Tweet button data related to the post and its author
|
241 |
+
*
|
242 |
+
* @since 1.0.0
|
243 |
+
*
|
244 |
+
* @param array $options Tweet button options {
|
245 |
+
* @type string option name
|
246 |
+
* @type string|bool option value
|
247 |
+
* }
|
248 |
+
* @param WP_Post $post post of interest
|
249 |
+
*
|
250 |
+
* @return array Tweet button options with possible additions based on post data {
|
251 |
+
* @type string option name
|
252 |
+
* @type string|bool option value
|
253 |
+
* }
|
254 |
+
*/
|
255 |
+
protected static function addPostData( $options, $post )
|
256 |
+
{
|
257 |
+
if ( ! is_array( $options ) ) {
|
258 |
+
$options = array();
|
259 |
+
}
|
260 |
+
|
261 |
+
// explicitly define post URL
|
262 |
+
// maintains Tweet button context on a page listing multiple posts
|
263 |
+
if ( ! ( isset( $options['url'] ) && $options['url'] ) ) {
|
264 |
+
/**
|
265 |
+
* Filter the URL shared in Tweet text
|
266 |
+
*
|
267 |
+
* All URLs are wrapped in Twitter's t.co link wrapper
|
268 |
+
*
|
269 |
+
* @since 1.0.0
|
270 |
+
*
|
271 |
+
* @param string $url The URL returned by get_permalink() when in the loop
|
272 |
+
*/
|
273 |
+
$url = apply_filters( 'twitter_url', get_permalink( $post ) );
|
274 |
+
if ( $url ) {
|
275 |
+
$options['url'] = $url;
|
276 |
+
}
|
277 |
+
unset( $url );
|
278 |
+
}
|
279 |
+
|
280 |
+
$author_id = get_the_author_meta( 'ID' );
|
281 |
+
if ( $author_id ) {
|
282 |
+
$author_twitter_username = \Twitter\WordPress\User\Meta::getTwitterUsername( $author_id );
|
283 |
+
if ( $author_twitter_username ) {
|
284 |
+
$author_display_name = trim( get_the_author_meta( 'display_name', $author_id ) );
|
285 |
+
if ( ! isset( $options['related'] ) || ! is_array( $options['related'] ) ) {
|
286 |
+
$options['related'] = array();
|
287 |
+
}
|
288 |
+
if ( ! isset( $options['related'][ $author_twitter_username ] ) ) {
|
289 |
+
$options['related'][ $author_twitter_username ] = $author_display_name;
|
290 |
+
}
|
291 |
+
unset( $author_display_name );
|
292 |
+
}
|
293 |
+
unset( $author_twitter_username );
|
294 |
+
}
|
295 |
+
unset( $author_id );
|
296 |
+
|
297 |
+
return $options;
|
298 |
+
}
|
299 |
+
|
300 |
+
/**
|
301 |
+
* Handle shortcode macro
|
302 |
+
*
|
303 |
+
* @since 1.0.0
|
304 |
+
*
|
305 |
+
* @param array $attributes shortcode attributes
|
306 |
+
* @param string $content shortcode content. no effect
|
307 |
+
*
|
308 |
+
* @return string Tweet button HTML or empty string
|
309 |
+
*/
|
310 |
+
public static function shortcodeHandler( $attributes, $content = null )
|
311 |
+
{
|
312 |
+
// clean up attribute to shortcode option mappings before passing to filter
|
313 |
+
// apply the same filter as shortcode_atts
|
314 |
+
/** This filter is documented in wp-includes/shortcodes.php */
|
315 |
+
$options = apply_filters(
|
316 |
+
'shortcode_atts_' . self::SHORTCODE_TAG,
|
317 |
+
array_merge(
|
318 |
+
static::$SHORTCODE_DEFAULTS,
|
319 |
+
static::sanitizeShortcodeParameters( (array) $attributes )
|
320 |
+
),
|
321 |
+
static::$SHORTCODE_DEFAULTS,
|
322 |
+
$attributes
|
323 |
+
);
|
324 |
+
|
325 |
+
// add options shared to post meta
|
326 |
+
$options = static::addPostMetaOptions( $options );
|
327 |
+
|
328 |
+
// add parameters based on per-post render context
|
329 |
+
if ( in_the_loop() ) {
|
330 |
+
$post = get_post();
|
331 |
+
|
332 |
+
// do not share posts requiring a password to access
|
333 |
+
if ( $post && ! empty( $post->post_password ) ) {
|
334 |
+
return '';
|
335 |
+
}
|
336 |
+
|
337 |
+
// protect sites from themselves
|
338 |
+
// do not display Tweet button for non-public content to avoid leaking content
|
339 |
+
$post_status_object = get_post_status_object( get_post_status( $post ) );
|
340 |
+
if ( ! ( $post_status_object && isset( $post_status_object->public ) && $post_status_object->public ) ) {
|
341 |
+
return '';
|
342 |
+
}
|
343 |
+
unset( $post_status_object );
|
344 |
+
|
345 |
+
// add parameters based on post data
|
346 |
+
$options = static::addPostData( $options, $post );
|
347 |
+
|
348 |
+
unset( $post );
|
349 |
+
}
|
350 |
+
if ( ! ( isset( $options['via'] ) && $options['via'] ) ) {
|
351 |
+
// attribute the Tweet to the site Twitter username
|
352 |
+
$via_username = \Twitter\WordPress\Site\Username::getViaAttribution( ( in_the_loop() ? get_the_ID() : null ) );
|
353 |
+
if ( $via_username ) {
|
354 |
+
$options['via'] = $via_username;
|
355 |
+
}
|
356 |
+
unset( $via_username );
|
357 |
+
}
|
358 |
+
|
359 |
+
$button = \Twitter\Widgets\TweetButton::fromArray( $options );
|
360 |
+
if ( ! $button ) {
|
361 |
+
return '';
|
362 |
+
}
|
363 |
+
|
364 |
+
$html = $button->toHTML( _x( 'Tweet', 'Tweet verb. Sharing.', 'twitter' ), '\Twitter\WordPress\Helpers\HTMLBuilder' );
|
365 |
+
if ( ! $html ) {
|
366 |
+
return '';
|
367 |
+
}
|
368 |
+
|
369 |
+
\Twitter\WordPress\JavaScriptLoaders\Widgets::enqueue();
|
370 |
+
return '<div class="twitter-share">' . $html . '</div>';
|
371 |
+
}
|
372 |
+
}
|
src/Twitter/WordPress/Shortcodes/Tracking.php
ADDED
@@ -0,0 +1,166 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Shortcodes;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Track a Twitter conversion and/or remarketing audience
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class Tracking
|
34 |
+
{
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Shortcode tag to be matched
|
38 |
+
*
|
39 |
+
* @since 1.0.0
|
40 |
+
*
|
41 |
+
* @type string
|
42 |
+
*/
|
43 |
+
const SHORTCODE_TAG = 'twitter_tracking';
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Accepted shortcode attributes and their default values
|
47 |
+
*
|
48 |
+
* @since 1.0.0
|
49 |
+
*
|
50 |
+
* @type array
|
51 |
+
*/
|
52 |
+
public static $SHORTCODE_DEFAULTS = array( 'id' => '' );
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Stored tracking ids
|
56 |
+
*
|
57 |
+
* @since 1.0.0
|
58 |
+
*
|
59 |
+
* @type array
|
60 |
+
*/
|
61 |
+
protected static $tracking_ids = array();
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Register shortcode macro and handler
|
65 |
+
*
|
66 |
+
* @since 1.0.0
|
67 |
+
*
|
68 |
+
* @return void
|
69 |
+
*/
|
70 |
+
public static function init()
|
71 |
+
{
|
72 |
+
add_shortcode( static::SHORTCODE_TAG, array( __CLASS__, 'shortcodeHandler' ) );
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Handle shortcode macro
|
77 |
+
*
|
78 |
+
* @since 1.0.0
|
79 |
+
*
|
80 |
+
* @param array $attributes shortcode attributes
|
81 |
+
* @param string $content shortcode content. no effect
|
82 |
+
*
|
83 |
+
* @return string empty string. markup is queued for inclusion in wp_footer output
|
84 |
+
*/
|
85 |
+
public static function shortcodeHandler( $attributes, $content = null )
|
86 |
+
{
|
87 |
+
$options = shortcode_atts(
|
88 |
+
static::$SHORTCODE_DEFAULTS,
|
89 |
+
$attributes,
|
90 |
+
static::SHORTCODE_TAG
|
91 |
+
);
|
92 |
+
|
93 |
+
$tracking_id = trim( $options['id'] );
|
94 |
+
if ( ! $tracking_id ) {
|
95 |
+
return '';
|
96 |
+
}
|
97 |
+
|
98 |
+
\Twitter\WordPress\JavaScriptLoaders\Tracking::enqueue();
|
99 |
+
static::$tracking_ids[ $tracking_id ] = true;
|
100 |
+
|
101 |
+
if ( false === has_action( 'wp_footer', array( __CLASS__, 'trackerJavaScript' ) ) ) {
|
102 |
+
// execute script after wp_print_footer_scripts action completes at priority 20
|
103 |
+
add_action( 'wp_footer', array( __CLASS__, 'trackerJavaScript' ), 25 );
|
104 |
+
}
|
105 |
+
|
106 |
+
// execute all trackers just before </body>
|
107 |
+
return '';
|
108 |
+
}
|
109 |
+
|
110 |
+
/**
|
111 |
+
* Track a Twitter advertising event using the twttr.conversion.trackPid JavaScript function
|
112 |
+
*
|
113 |
+
* @since 1.0.0
|
114 |
+
*
|
115 |
+
* @param string $tracking_id Twitter ads tracking ID
|
116 |
+
*
|
117 |
+
* @return void
|
118 |
+
*/
|
119 |
+
protected static function trackEventUsingJavaScript( $tracking_id )
|
120 |
+
{
|
121 |
+
echo 'twttr.conversion.trackPid(' . ( function_exists( 'wp_json_encode' ) ? wp_json_encode( $tracking_id ) : json_encode( $tracking_id ) ) . ');';
|
122 |
+
}
|
123 |
+
|
124 |
+
/**
|
125 |
+
* Track a Twitter advertising event using 1x1 images
|
126 |
+
*
|
127 |
+
* @since 1.0.0
|
128 |
+
*
|
129 |
+
* @param string $tracking_id Twitter ads tracking ID
|
130 |
+
*
|
131 |
+
* @return void
|
132 |
+
*/
|
133 |
+
protected static function trackEventUsingFallbackImages( $tracking_id )
|
134 |
+
{
|
135 |
+
$query_parameters = http_build_query( array( 'txn_id' => $tracking_id, 'p_id' => 'Twitter' ), '', '&' );
|
136 |
+
|
137 |
+
echo '<img height="1" width="1" alt=" " src="' . esc_url( 'https://analytics.twitter.com/i/adsct?' . $query_parameters, array( 'https', 'http' ) ) . '"' . \Twitter\WordPress\Helpers\HTMLBuilder::closeVoidHTMLElement() . '>';
|
138 |
+
echo '<img height="1" width="1" alt=" " src="' . esc_url( 'https://t.co/i/adsct?' . $query_parameters, array( 'https', 'http' ) ) . '"' . \Twitter\WordPress\Helpers\HTMLBuilder::closeVoidHTMLElement() . '>';
|
139 |
+
}
|
140 |
+
|
141 |
+
/**
|
142 |
+
* Record tracking ID actions
|
143 |
+
*
|
144 |
+
* @since 1.0.0
|
145 |
+
*
|
146 |
+
* @return void
|
147 |
+
*/
|
148 |
+
public static function trackerJavaScript()
|
149 |
+
{
|
150 |
+
if ( empty( static::$tracking_ids ) ) {
|
151 |
+
return;
|
152 |
+
}
|
153 |
+
|
154 |
+
$tracking_ids = array_keys( static::$tracking_ids );
|
155 |
+
|
156 |
+
// JavaScript available
|
157 |
+
echo '<script type="text/javascript">';
|
158 |
+
array_walk( $tracking_ids, array( __CLASS__, 'trackEventUsingJavaScript' ) );
|
159 |
+
echo '</script>';
|
160 |
+
|
161 |
+
// JavaScript unavailable
|
162 |
+
echo '<noscript>';
|
163 |
+
array_walk( $tracking_ids, array( __CLASS__, 'trackEventUsingFallbackImages' ) );
|
164 |
+
echo '</noscript>';
|
165 |
+
}
|
166 |
+
}
|
src/Twitter/WordPress/Site/Username.php
ADDED
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Site;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Associate site Twitter username(s) with hooks used across the site
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class Username
|
34 |
+
{
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Attribute a webpage to a Twitter @username for the site or site section
|
38 |
+
*
|
39 |
+
* Similar to a site byline or masthead with Twitter attribution
|
40 |
+
* Affects Twitter Analytics
|
41 |
+
*
|
42 |
+
* @since 1.0.0
|
43 |
+
*
|
44 |
+
* @link https://dev.twitter.com/cards/markup#twitter-site Twitter Card site attribution
|
45 |
+
* @link https://dev.twitter.com/cards/analytics Twitter Card analytics
|
46 |
+
*
|
47 |
+
* @param int|string|bool|null $post_id WP_Post->ID, false response of get_the_ID, proprietary post ID, or null if outside of a post context or no post ID found
|
48 |
+
*
|
49 |
+
* @return string Twitter username or empty string
|
50 |
+
*/
|
51 |
+
public static function getSiteAttribution( $post_id = null )
|
52 |
+
{
|
53 |
+
// simplify passed types for filter
|
54 |
+
if ( false === $post_id ) {
|
55 |
+
$post_id = null;
|
56 |
+
}
|
57 |
+
|
58 |
+
$username = get_option( \Twitter\WordPress\Admin\Settings\SiteAttribution::OPTION_NAME, '' );
|
59 |
+
|
60 |
+
if ( ! is_string( $username ) ) {
|
61 |
+
$username = '';
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Allow sites to provide a WordPress site or site section Twitter username through a filter
|
66 |
+
*
|
67 |
+
* A username should be provided without its @ prefix.
|
68 |
+
* A site username might be overridden if a better match is available based on the post or archive context, such as AcmeSports overriding a general site username of Acme when displaying content inside the sports category
|
69 |
+
*
|
70 |
+
* @since 1.0.0
|
71 |
+
*
|
72 |
+
* @param string $username Twitter username stored for the site
|
73 |
+
* @param int|string|null $post_id WP_Post->ID, proprietary post ID, or null if outside of a post context or no post ID found
|
74 |
+
*/
|
75 |
+
return apply_filters( 'twitter_site_username', $username, $post_id );
|
76 |
+
}
|
77 |
+
|
78 |
+
/**
|
79 |
+
* Attribute a Tweet created through a link on your site to a Twitter username
|
80 |
+
*
|
81 |
+
* @since 1.0.0
|
82 |
+
*
|
83 |
+
* @link https://dev.twitter.com/web/tweet-button/web-intent#tweet-web-intent-via Tweet Web Intent via parameter
|
84 |
+
*
|
85 |
+
* @param int|string|null $post_id WP_Post->ID, proprietary post ID, or null if outside of a post context or no post ID found
|
86 |
+
*
|
87 |
+
* @return string Twitter username or empty string
|
88 |
+
*/
|
89 |
+
public static function getViaAttribution( $post_id = null )
|
90 |
+
{
|
91 |
+
/**
|
92 |
+
* Allow sites to provide a WordPress site or site section Twitter username through a filter
|
93 |
+
*
|
94 |
+
* A username should be provided without its @ prefix
|
95 |
+
*
|
96 |
+
* @since 1.0.0
|
97 |
+
*
|
98 |
+
* @param @param string $username Twitter username stored for the site
|
99 |
+
* @param int|string|null $post_id WP_Post->ID, proprietary post ID, or null if outside of a post context or no post ID found
|
100 |
+
*/
|
101 |
+
return apply_filters( 'twitter_via_username', static::getSiteAttribution( $post_id ), $post_id );
|
102 |
+
}
|
103 |
+
}
|
src/Twitter/WordPress/User/Meta.php
ADDED
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\User;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Get WordPress user meta values
|
30 |
+
*
|
31 |
+
* @since 1.0.0
|
32 |
+
*/
|
33 |
+
class Meta
|
34 |
+
{
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Get a Twitter @username stored for a given WordPress user identifier
|
38 |
+
*
|
39 |
+
* @since 1.0.0
|
40 |
+
*
|
41 |
+
* @param int|string $user_id WordPress user identifier. may be WP_User->ID or a separate identifier used by an extending system
|
42 |
+
*
|
43 |
+
* @return string Twitter username value stored for the given WordPress user identifier
|
44 |
+
*/
|
45 |
+
public static function getTwitterUsername( $user_id )
|
46 |
+
{
|
47 |
+
// basic test for invalid passed parameter
|
48 |
+
if ( ! $user_id ) {
|
49 |
+
return '';
|
50 |
+
}
|
51 |
+
|
52 |
+
$meta_key = 'twitter';
|
53 |
+
if ( function_exists( 'get_user_attribute' ) ) {
|
54 |
+
$username = get_user_attribute( $user_id, $meta_key );
|
55 |
+
} else {
|
56 |
+
$username = get_user_meta( $user_id, $meta_key, /* single */ true );
|
57 |
+
}
|
58 |
+
|
59 |
+
if ( ! is_string( $username ) ) {
|
60 |
+
$username = '';
|
61 |
+
}
|
62 |
+
|
63 |
+
// pass a username through a filter if not explicitly defined through user meta
|
64 |
+
if ( ! $username ) {
|
65 |
+
/**
|
66 |
+
* Allow sites to provide a WordPress user's Twitter username through a filter
|
67 |
+
*
|
68 |
+
* @since 1.0.0
|
69 |
+
*
|
70 |
+
* @param string $username Twitter username associated with a WordPress user ID
|
71 |
+
* @param int|string $user_id WordPress user identifier. may be WP_User->ID or a separate identifier used by an extending system
|
72 |
+
*/
|
73 |
+
$username = apply_filters( 'twitter_username', $username, $user_id );
|
74 |
+
}
|
75 |
+
|
76 |
+
return $username;
|
77 |
+
}
|
78 |
+
}
|
src/Twitter/WordPress/Widgets/Follow.php
ADDED
@@ -0,0 +1,205 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
namespace Twitter\WordPress\Widgets;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Add Twitter Follow Button as a WordPress widget
|
30 |
+
*
|
31 |
+
* @link http://codex.wordpress.org/Widgets_API WordPress widgets API
|
32 |
+
*
|
33 |
+
* @since 1.0.0
|
34 |
+
*/
|
35 |
+
class Follow extends \WP_Widget
|
36 |
+
{
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Widget base ID
|
40 |
+
*
|
41 |
+
* Widget identifiers will derive from the base based on their positioning. e.g. twitter-follow-1
|
42 |
+
*
|
43 |
+
* @since 1.0.0
|
44 |
+
*
|
45 |
+
* @type string
|
46 |
+
*/
|
47 |
+
const BASE_ID = 'twitter-follow';
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Register widget with WordPress
|
51 |
+
*
|
52 |
+
* @since 1.0.0
|
53 |
+
*
|
54 |
+
* @return void
|
55 |
+
*/
|
56 |
+
public function __construct()
|
57 |
+
{
|
58 |
+
parent::__construct(
|
59 |
+
static::BASE_ID, // Base ID
|
60 |
+
__( 'Twitter Follow Button', 'twitter' ), // name
|
61 |
+
array(
|
62 |
+
'description' => __( 'Lets a viewer follow your Twitter account', 'twitter' ) // args
|
63 |
+
)
|
64 |
+
);
|
65 |
+
}
|
66 |
+
|
67 |
+
/**
|
68 |
+
* Front-end display of widget
|
69 |
+
*
|
70 |
+
* @since 1.0.0
|
71 |
+
*
|
72 |
+
* @param array $args Display arguments including before_title, after_title, before_widget, and after_widget.
|
73 |
+
* @param array $instance The settings for the particular instance of the widget
|
74 |
+
*
|
75 |
+
* @return void
|
76 |
+
*/
|
77 |
+
public function widget( $args, $instance )
|
78 |
+
{
|
79 |
+
// no follow target
|
80 |
+
if ( empty( $instance['screen_name'] ) ) {
|
81 |
+
return;
|
82 |
+
}
|
83 |
+
|
84 |
+
$follow_button_html = \Twitter\WordPress\Shortcodes\Follow::shortcodeHandler( $instance );
|
85 |
+
if ( ! $follow_button_html ) {
|
86 |
+
return;
|
87 |
+
}
|
88 |
+
|
89 |
+
echo $args['before_widget'];
|
90 |
+
|
91 |
+
/** This filter is documented in wp-includes/default-widgets.php */
|
92 |
+
$title = apply_filters( 'widget_title', empty( $instance['title'] ) ? '' : $instance['title'], $instance, $this->id_base );
|
93 |
+
if ( $title ) {
|
94 |
+
echo $args['before_title'] . $title . $args['after_title'];
|
95 |
+
}
|
96 |
+
|
97 |
+
// escaped in markup builder
|
98 |
+
// @codingStandardsIgnoreStart WordPress.XSS.EscapeOutput
|
99 |
+
echo $follow_button_html;
|
100 |
+
// @codingStandardsIgnoreEnd WordPress.XSS.EscapeOutput
|
101 |
+
|
102 |
+
echo $args['after_widget'];
|
103 |
+
}
|
104 |
+
|
105 |
+
/**
|
106 |
+
* Settings update form
|
107 |
+
*
|
108 |
+
* @since 1.0.0
|
109 |
+
*
|
110 |
+
* @param array $instance Current settings
|
111 |
+
*
|
112 |
+
* @return void
|
113 |
+
*/
|
114 |
+
public function form( $instance )
|
115 |
+
{
|
116 |
+
$instance = wp_parse_args(
|
117 |
+
(array) $instance,
|
118 |
+
array_merge(
|
119 |
+
array( 'title' => '' ),
|
120 |
+
\Twitter\WordPress\Shortcodes\Follow::$SHORTCODE_DEFAULTS
|
121 |
+
)
|
122 |
+
);
|
123 |
+
|
124 |
+
$close_void_element = \Twitter\WordPress\Helpers\HTMLBuilder::closeVoidHTMLElement();
|
125 |
+
?>
|
126 |
+
<p><label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"><?php echo esc_html( __( 'Title:' ) ); ?></label>
|
127 |
+
<input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" type="text" value="<?php echo esc_attr( trim( strip_tags( $instance['title'] ) ) ); ?>"<?php echo $close_void_element; ?>></p>
|
128 |
+
|
129 |
+
<p><label for="<?php echo esc_attr( $this->get_field_id( 'screen_name' ) ); ?>"><?php echo esc_html( __( '@username:', 'twitter' ) ); ?></label>
|
130 |
+
<input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'screen_name' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'screen_name' ) ); ?>" type="text" pattern="[a-zA-Z0-9_]{1,20}" value="<?php echo esc_attr( $instance['screen_name'] ); ?>"<?php echo $close_void_element; ?>></p>
|
131 |
+
|
132 |
+
<p><input class="checkbox" type="checkbox" id="<?php echo esc_attr( $this->get_field_id( 'show_screen_name' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'show_screen_name' ) ); ?>" value="1"<?php checked( $instance['show_screen_name'] ); echo $close_void_element; ?>>
|
133 |
+
<label for="<?php echo esc_attr( $this->get_field_id( 'show_screen_name' ) ); ?>"><?php echo esc_html( __( 'Show username?', 'twitter' ) ); ?></label></p>
|
134 |
+
|
135 |
+
<p><input class="checkbox" type="checkbox" id="<?php echo esc_attr( $this->get_field_id( 'show_count' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'show_count' ) ); ?>" value="1"<?php checked( $instance['show_count'] ); echo $close_void_element; ?>>
|
136 |
+
<label for="<?php echo esc_attr( $this->get_field_id( 'show_count' ) ); ?>"><?php echo esc_html( __( 'Show number of followers?', 'twitter' ) ); ?></label></p>
|
137 |
+
|
138 |
+
<p><label for="<?php echo esc_attr( $this->get_field_id( 'size' ) ); ?>"><?php echo esc_html( __( 'Button size:', 'twitter' ) ); ?></label>
|
139 |
+
<fieldset id="<?php echo esc_attr( $this->get_field_id( 'size' ) ); ?>">
|
140 |
+
<label><input type="radio" name="<?php echo esc_attr( $this->get_field_name( 'size' ) ); ?>" value="medium"<?php checked( 'large' != $instance['size'] ); echo $close_void_element; ?>> <?php echo esc_html( _x( 'medium', 'medium size button', 'twitter' ) ); ?> </label>
|
141 |
+
<label><input type="radio" name="<?php echo esc_attr( $this->get_field_name( 'size' ) ); ?>" value="large"<?php checked( 'large' == $instance['size'] ); echo $close_void_element; ?>> <?php echo esc_html( _x( 'large', 'large size button', 'twitter' ) ); ?> </label>
|
142 |
+
</fieldset></p>
|
143 |
+
<?php
|
144 |
+
}
|
145 |
+
|
146 |
+
/**
|
147 |
+
* Update a widget instance
|
148 |
+
*
|
149 |
+
* @since 1.0.0
|
150 |
+
*
|
151 |
+
* @param array $new_instance New settings for this instance as input by the user via form()
|
152 |
+
* @param array $old_instance Old settings for this instance
|
153 |
+
*
|
154 |
+
* @return bool|array settings to save or false to cancel saving
|
155 |
+
*/
|
156 |
+
public function update( $new_instance, $old_instance )
|
157 |
+
{
|
158 |
+
$instance = array();
|
159 |
+
$new_instance = (array) $new_instance;
|
160 |
+
$title = trim( strip_tags( $new_instance['title'] ) );
|
161 |
+
if ( $title ) {
|
162 |
+
$instance['title'] = $title;
|
163 |
+
}
|
164 |
+
unset( $new_instance['title'] );
|
165 |
+
|
166 |
+
foreach ( array( 'show_screen_name', 'show_count' ) as $bool_option ) {
|
167 |
+
if ( isset( $new_instance[ $bool_option ] ) && $new_instance[ $bool_option ] ) {
|
168 |
+
$new_instance[ $bool_option ] = true;
|
169 |
+
} else {
|
170 |
+
$new_instance[ $bool_option ] = false;
|
171 |
+
}
|
172 |
+
}
|
173 |
+
|
174 |
+
$follow_button = \Twitter\Widgets\FollowButton::fromArray( $new_instance );
|
175 |
+
if ( ! $follow_button ) {
|
176 |
+
return false;
|
177 |
+
}
|
178 |
+
|
179 |
+
$filtered_options = $follow_button->toArray( /* dashed_keys */ false );
|
180 |
+
if ( empty( $filtered_options ) ) {
|
181 |
+
return false;
|
182 |
+
}
|
183 |
+
$screen_name = $follow_button->getScreenName();
|
184 |
+
if ( $screen_name ) {
|
185 |
+
$filtered_options['screen_name'] = $screen_name;
|
186 |
+
}
|
187 |
+
unset( $screen_name );
|
188 |
+
|
189 |
+
// convert string to bool equivalent
|
190 |
+
if ( isset( $filtered_options['show-screen-name'] ) ) {
|
191 |
+
if ( 'false' == $filtered_options['show-screen-name'] ) {
|
192 |
+
$filtered_options['show_screen_name'] = false;
|
193 |
+
}
|
194 |
+
unset( $filtered_options['show-screen-name'] );
|
195 |
+
}
|
196 |
+
if ( isset( $filtered_options['show-count'] ) ) {
|
197 |
+
if ( 'false' == $filtered_options['show-count'] ) {
|
198 |
+
$filtered_options['show_count'] = false;
|
199 |
+
}
|
200 |
+
unset( $filtered_options['show-count'] );
|
201 |
+
}
|
202 |
+
|
203 |
+
return array_merge( $instance, $filtered_options );
|
204 |
+
}
|
205 |
+
}
|
static/css/admin/post/edit.min.css
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
#twitter-custom table{margin:0;width:100%;border:1px solid #dfdfdf;border-spacing:0;background-color:#f9f9f9}#twitter-custom thead th{padding:5px 8px 8px;background-color:#f1f1f1}#twitter-custom input{width:96%;margin:8px}#tweet-intent{width:100%}#twitter-card{width:100%}
|
twitter.php
ADDED
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @package twitter
|
4 |
+
* @version 1.0.0
|
5 |
+
*/
|
6 |
+
/*
|
7 |
+
Plugin Name: Twitter
|
8 |
+
Plugin URI: http://wordpress.org/plugins/twitter/
|
9 |
+
Description: Official Twitter plugin for WordPress. Embed Twitter content and grow your audience on Twitter. Requires PHP 5.4 or newer.
|
10 |
+
Version: 1.0.0
|
11 |
+
Author: Twitter
|
12 |
+
Author URI: https://dev.twitter.com/
|
13 |
+
License: MIT
|
14 |
+
Text Domain: twitter
|
15 |
+
Domain Path: /languages/
|
16 |
+
*/
|
17 |
+
|
18 |
+
/*
|
19 |
+
The MIT License (MIT)
|
20 |
+
|
21 |
+
Copyright (c) 2015 Twitter Inc.
|
22 |
+
|
23 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
24 |
+
of this software and associated documentation files (the "Software"), to deal
|
25 |
+
in the Software without restriction, including without limitation the rights
|
26 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
27 |
+
copies of the Software, and to permit persons to whom the Software is
|
28 |
+
furnished to do so, subject to the following conditions:
|
29 |
+
|
30 |
+
The above copyright notice and this permission notice shall be included in
|
31 |
+
all copies or substantial portions of the Software.
|
32 |
+
|
33 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
34 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
35 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
36 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
37 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
38 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
39 |
+
THE SOFTWARE.
|
40 |
+
*/
|
41 |
+
|
42 |
+
|
43 |
+
// make sure the plugin does not expose any info if called directly
|
44 |
+
if ( ! function_exists( 'add_action' ) ) {
|
45 |
+
if ( ! headers_sent() ) {
|
46 |
+
if ( function_exists( 'http_response_code' ) ) {
|
47 |
+
http_response_code( 403 );
|
48 |
+
} else {
|
49 |
+
header( 'HTTP/1.1 403 Forbidden', true, 403 );
|
50 |
+
}
|
51 |
+
}
|
52 |
+
exit( 'Hi there! I am a WordPress plugin requiring functions included with WordPress. I am not meant to be addressed directly.' );
|
53 |
+
}
|
54 |
+
|
55 |
+
// plugin requires PHP 5.4 or newer
|
56 |
+
if ( version_compare( PHP_VERSION, '5.4.0', '<' ) ) {
|
57 |
+
trigger_error( 'The Twitter plugin for WordPress requires PHP version 5.4 or higher.' );
|
58 |
+
return;
|
59 |
+
}
|
60 |
+
|
61 |
+
// PHP namespace autoloader
|
62 |
+
require_once( dirname( __FILE__ ) . '/autoload.php' );
|
63 |
+
|
64 |
+
// initialize on plugins loaded
|
65 |
+
add_action(
|
66 |
+
'plugins_loaded',
|
67 |
+
array( '\\Twitter\\WordPress\\PluginLoader', 'init' ),
|
68 |
+
0, // priority
|
69 |
+
0 // expected arguments
|
70 |
+
);
|
uninstall.php
ADDED
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
The MIT License (MIT)
|
4 |
+
|
5 |
+
Copyright (c) 2015 Twitter Inc.
|
6 |
+
|
7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 |
+
of this software and associated documentation files (the "Software"), to deal
|
9 |
+
in the Software without restriction, including without limitation the rights
|
10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 |
+
copies of the Software, and to permit persons to whom the Software is
|
12 |
+
furnished to do so, subject to the following conditions:
|
13 |
+
|
14 |
+
The above copyright notice and this permission notice shall be included in
|
15 |
+
all copies or substantial portions of the Software.
|
16 |
+
|
17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 |
+
THE SOFTWARE.
|
24 |
+
*/
|
25 |
+
|
26 |
+
if (
|
27 |
+
! defined( 'WP_UNINSTALL_PLUGIN' )
|
28 |
+
||
|
29 |
+
! WP_UNINSTALL_PLUGIN
|
30 |
+
||
|
31 |
+
dirname( WP_UNINSTALL_PLUGIN ) != dirname( plugin_basename( __FILE__ ) )
|
32 |
+
) {
|
33 |
+
if ( ! headers_sent() ) {
|
34 |
+
if ( function_exists( 'status_header' ) ) {
|
35 |
+
status_header( 404 );
|
36 |
+
} else if ( function_exists( 'http_response_code' ) ) {
|
37 |
+
http_response_code( 404 );
|
38 |
+
} else {
|
39 |
+
header( 'HTTP/1.1 404 Not Found', true, 404 );
|
40 |
+
}
|
41 |
+
}
|
42 |
+
exit;
|
43 |
+
}
|
44 |
+
|
45 |
+
// site options
|
46 |
+
if ( function_exists( 'delete_option' ) ) {
|
47 |
+
// Delete all admin options
|
48 |
+
$__options = array(
|
49 |
+
'twitter_widgets',
|
50 |
+
'twitter_site_attribution',
|
51 |
+
'twitter_share',
|
52 |
+
);
|
53 |
+
array_walk( $__options, 'delete_option' );
|
54 |
+
}
|
55 |
+
|
56 |
+
// post meta
|
57 |
+
if ( function_exists( 'delete_post_meta_by_key' ) ) {
|
58 |
+
// delete Twitter customizations stored at the post level
|
59 |
+
$__post_meta_keys = array(
|
60 |
+
'twitter_share',
|
61 |
+
'twitter_card',
|
62 |
+
);
|
63 |
+
array_walk( $__post_meta_keys, 'delete_post_meta_by_key' );
|
64 |
+
}
|
65 |
+
|
66 |
+
// user meta
|
67 |
+
if ( function_exists( 'delete_metadata' ) ) {
|
68 |
+
// delete Twitter customizations stored for a WordPress user account
|
69 |
+
delete_metadata(
|
70 |
+
'user', // meta type
|
71 |
+
0, // user ID (ignored)
|
72 |
+
'twitter', // meta key
|
73 |
+
'', // delete all values
|
74 |
+
true // delete all. ignore passed user id
|
75 |
+
);
|
76 |
+
}
|