├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── autoload.php ├── compatibility-notice.php ├── composer.json ├── index.php ├── phpcs.xml ├── phpunit.xml ├── readme.txt ├── src └── Twitter │ ├── Cards │ ├── Card.php │ ├── Components │ │ ├── Account.php │ │ ├── Creator.php │ │ ├── Description.php │ │ ├── Image.php │ │ └── SingleImage.php │ ├── Summary.php │ └── SummaryLargeImage.php │ ├── Helpers │ ├── HTMLBuilder.php │ ├── TwitterURL.php │ └── Validators │ │ ├── Hashtag.php │ │ ├── PeriscopeUsername.php │ │ ├── ScreenName.php │ │ └── WebsiteTag.php │ ├── Intents │ ├── Follow.php │ ├── Traits │ │ └── Related.php │ └── Tweet.php │ ├── Widgets │ ├── Base.php │ ├── Buttons │ │ ├── Follow.php │ │ ├── Periscope │ │ │ └── OnAir.php │ │ └── Tweet.php │ ├── Embeds │ │ ├── Moment.php │ │ ├── Theme.php │ │ ├── Timeline.php │ │ ├── Timeline │ │ │ ├── Collection.php │ │ │ ├── Profile.php │ │ │ ├── Search.php │ │ │ └── TwitterList.php │ │ ├── Tweet.php │ │ ├── Tweet │ │ │ ├── Base.php │ │ │ └── Video.php │ │ └── Vine.php │ └── Language.php │ └── WordPress │ ├── Admin │ ├── Post │ │ ├── MetaBox.php │ │ ├── TweetIntent.php │ │ └── TwitterCard.php │ ├── Profile │ │ ├── PeriscopeUser.php │ │ └── User.php │ └── Settings │ │ ├── Buttons │ │ └── Tweet.php │ │ ├── Cards │ │ └── SiteAttribution.php │ │ ├── Embeds │ │ └── Theme.php │ │ ├── Loader.php │ │ ├── SettingsSection.php │ │ └── SinglePage.php │ ├── Cards │ ├── Compatibility.php │ ├── Generator.php │ ├── ImageHandler.php │ └── Sanitize.php │ ├── Content │ └── Buttons │ │ └── Tweet.php │ ├── Features.php │ ├── Head │ ├── AuthorshipLink.php │ ├── CardsMetaElements.php │ ├── MetaElement.php │ └── WidgetsMetaElements.php │ ├── Helpers │ ├── HTMLBuilder.php │ ├── TwitterAPI.php │ ├── TwitterOEmbed.php │ └── VineOEmbed.php │ ├── JavaScriptLoaders │ ├── AsyncJavaScript.php │ ├── Tracking.php │ ├── VineEmbed.php │ └── Widgets.php │ ├── Language.php │ ├── PluginLoader.php │ ├── Shortcodes │ ├── Advertising │ │ └── Tracking.php │ ├── AuthorContext.php │ ├── Buttons │ │ ├── Follow.php │ │ ├── Periscope │ │ │ └── OnAir.php │ │ └── Share.php │ ├── Embeds │ │ ├── Moment.php │ │ ├── Timeline.php │ │ ├── Timeline │ │ │ ├── Collection.php │ │ │ ├── CollectionGrid.php │ │ │ ├── Profile.php │ │ │ ├── Search.php │ │ │ └── TwitterList.php │ │ ├── Tweet.php │ │ ├── Tweet │ │ │ └── Video.php │ │ └── Vine.php │ ├── Helpers │ │ └── Attributes.php │ ├── OEmbedTrait.php │ ├── PublishOEmbedEndpoint.php │ └── ShortcodeInterface.php │ ├── Site │ └── Username.php │ ├── User │ └── Meta.php │ └── Widgets │ ├── Advertising │ └── Tracking.php │ ├── Buttons │ ├── Follow.php │ └── Periscope │ │ └── OnAir.php │ ├── Embeds │ ├── Timeline.php │ └── Timeline │ │ ├── Collection.php │ │ ├── Profile.php │ │ ├── Search.php │ │ └── TwitterList.php │ ├── Widget.php │ └── WidgetInterface.php ├── static └── css │ └── admin │ └── post │ ├── edit.min.css │ └── edit.scss ├── tests └── phpunit │ ├── Cards │ ├── Card.php │ ├── Components │ │ ├── Account.php │ │ ├── Creator.php │ │ ├── Description.php │ │ ├── Image.php │ │ └── SingleImage.php │ ├── Summary.php │ └── SummaryLargeImage.php │ ├── CommonProviders.php │ ├── Helpers │ ├── HTMLBuilder.php │ ├── TwitterURL.php │ └── Validators │ │ ├── Hashtag.php │ │ ├── ScreenName.php │ │ └── WebsiteTag.php │ ├── Intents │ ├── Follow.php │ └── Tweet.php │ ├── TestWithPrivateAccess.php │ ├── Widgets │ ├── Base.php │ ├── Buttons │ │ ├── Follow.php │ │ ├── Periscope │ │ │ └── OnAir.php │ │ └── Tweet.php │ ├── Embeds │ │ ├── Moment.php │ │ ├── Theme.php │ │ ├── Timeline.php │ │ ├── Timeline │ │ │ ├── Collection.php │ │ │ ├── Profile.php │ │ │ ├── Search.php │ │ │ └── TwitterList.php │ │ ├── Tweet.php │ │ └── Tweet │ │ │ └── Base.php │ └── Language.php │ ├── WordPress │ ├── Shortcodes │ │ ├── Buttons │ │ │ ├── Follow.php │ │ │ ├── Periscope │ │ │ │ └── OnAir.php │ │ │ └── Share.php │ │ └── Embeds │ │ │ ├── Timeline.php │ │ │ ├── Tweet.php │ │ │ └── Tweet │ │ │ └── Video.php │ └── Widgets │ │ └── Embeds │ │ └── Timeline │ │ └── Profile.php │ ├── autoload.php │ └── bootstrap.php ├── twitter.php └── uninstall.php /.travis.yml: -------------------------------------------------------------------------------- 1 | # Travis CI Configuration file 2 | # @link https://travis-ci.org/ 3 | 4 | # Use new Travis container-based infrastructure 5 | # http://docs.travis-ci.com/user/workers/container-based-infrastructure/ 6 | sudo: false 7 | 8 | # PHP 9 | # @link http://docs.travis-ci.com/user/languages/php/ 10 | language: php 11 | 12 | # Declare versions of PHP to test 13 | php: 14 | # aliased to a recent 7.1.x version 15 | - 7.1 16 | # aliased to a recent 7.0.x version 17 | - 7.0 18 | # aliased to a recent 5.6.x version 19 | - 5.6 20 | 21 | # WordPress comes from the Git mirror, where 'master' mirrors svn 'trunk' and 22 | # x.y mirrors the latest from the x.y branch 23 | env: 24 | # WordPress 5.2 25 | - WP_VERSION=5.2 26 | # WordPress 5.1 27 | - WP_VERSION=5.1 28 | # WordPress 5.0 29 | - WP_VERSION=5.0 30 | # WordPress 4.9 31 | - WP_VERSION=4.9 32 | # WordPress 4.8 33 | - WP_VERSION=4.8 34 | # WordPress 4.7 35 | - WP_VERSION=4.7 36 | 37 | matrix: 38 | fast_finish: true 39 | 40 | # before_install: Failures in this section will result in build status 'errored' 41 | before_install: 42 | # set up WP install 43 | - export WP_DEVELOP_DIR=/tmp/wordpress/ 44 | - mkdir -p $WP_DEVELOP_DIR 45 | - git clone --depth=1 --branch="$WP_VERSION" git://develop.git.wordpress.org/ $WP_DEVELOP_DIR 46 | - plugin_slug=$(basename $(pwd)) 47 | - plugin_dir=$WP_DEVELOP_DIR/src/wp-content/plugins/$plugin_slug 48 | - cd .. 49 | - mv $plugin_slug $plugin_dir 50 | # set up tests config 51 | - cd $WP_DEVELOP_DIR 52 | - echo $WP_DEVELOP_DIR 53 | - cp wp-tests-config-sample.php wp-tests-config.php 54 | - sed -i "s/youremptytestdbnamehere/wordpress_test/" wp-tests-config.php 55 | - sed -i "s/yourusernamehere/travis/" wp-tests-config.php 56 | - sed -i "s/yourpasswordhere//" wp-tests-config.php 57 | # create database 58 | - mysql -e 'CREATE DATABASE wordpress_test;' -uroot 59 | # prepare for running the tests 60 | - cd $plugin_dir 61 | 62 | script: phpunit 63 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Looking to contribute something? Here's how you can help. 4 | 5 | ## Bug reports 6 | 7 | A bug is a _demonstrable problem_ that is caused by the code in the 8 | repository. Good bug reports are extremely helpful - thank you! 9 | 10 | Guidelines for bug reports: 11 | 12 | 1. **Use the GitHub issue search** — check if the issue has already been 13 | reported. 14 | 15 | 2. **Check if the issue has been fixed** — try to reproduce it using the 16 | latest `master` or development branch in the repository. 17 | 18 | 3. **Isolate the problem** — ideally create a reduced test 19 | case and a live example. 20 | 21 | 4. Please try to be as detailed as possible in your report. Include specific 22 | information about the environment - web host, PHP version, WordPress 23 | version, browser and version, operating system and version 24 | ... and steps required to reproduce the issue. 25 | 26 | ## Feature requests & contribution enquiries 27 | 28 | Feature requests are welcome. But take a moment to find out whether your idea 29 | fits with the scope and aims of the project. It's up to *you* to make a strong 30 | case for the inclusion of your feature applicable to all sites. 31 | Please provide as much detail and context as possible. 32 | 33 | Contribution enquiries should take place before any significant pull request, 34 | otherwise you risk spending a lot of time working on something that we might 35 | have good reasons for rejecting. 36 | 37 | ## Pull requests 38 | 39 | Good pull requests - patches, improvements, new features - are a fantastic 40 | help. They should remain focused in scope and avoid containing unrelated 41 | commits. 42 | 43 | Make sure to adhere to the 44 | [WordPress coding conventions](https://make.wordpress.org/core/handbook/coding-standards/php/) 45 | (indentation, accurate comments, etc.) and any other requirements (such as test 46 | coverage). 47 | 48 | Please follow this process; it's the best way to get your work included in the 49 | project: 50 | 51 | 1. Create a new topic branch to contain your feature, change, or fix: 52 | 53 | 2. Commit your changes in logical chunks. Provide clear and explanatory commit 54 | messages. Use git's [interactive rebase](https://help.github.com/articles/interactive-rebase) 55 | feature to tidy up your commits before making them public. 56 | 57 | 3. Locally merge (or rebase) the upstream development branch into your topic branch: 58 | 59 | 4. Push your topic branch up to your fork: 60 | 61 | 5. [Open a Pull Request](http://help.github.com/send-pull-requests/) with a 62 | clear title and description. 63 | 64 | ## License 65 | 66 | By contributing your code: 67 | 68 | You agree to license your contribution under the terms of the 69 | [MIT license](LICENSE) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 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 | 23 | -------------------------------------------------------------------------------- /autoload.php: -------------------------------------------------------------------------------- 1 | =5.6.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: -------------------------------------------------------------------------------- 1 | 2 | 3 | Twitter plugin for WordPress rules for PHP_CodeSniffer 4 | 5 | src/Twitter/WordPress 6 | twitter.php 7 | compatibility-notice.php 8 | uninstall.php 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | ^/src/Twitter/Cards/* 21 | 22 | 23 | 24 | 25 | 26 | 27 | warning 28 | 29 | 30 | 31 | warning 32 | 33 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | tests/phpunit 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Twitter/Cards/Card.php: -------------------------------------------------------------------------------- 1 | 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 self 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 self 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 | } 169 | -------------------------------------------------------------------------------- /src/Twitter/Cards/Components/Account.php: -------------------------------------------------------------------------------- 1 | setScreenName($screen_name); 64 | 65 | if (! $account->hasScreenName()) { 66 | return null; 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 null; 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 self 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 | } 183 | -------------------------------------------------------------------------------- /src/Twitter/Cards/Components/Creator.php: -------------------------------------------------------------------------------- 1 | creator = $creator; 55 | } 56 | 57 | return $this; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Twitter/Cards/Components/Description.php: -------------------------------------------------------------------------------- 1 | description = $description; 81 | } 82 | 83 | return $this; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Twitter/Cards/Components/SingleImage.php: -------------------------------------------------------------------------------- 1 | = 0 )) { 62 | $width = 0; 63 | } 64 | if (! ( is_int($height) && $height >= 0 )) { 65 | $height = 0; 66 | } 67 | if (! is_string($alt)) { 68 | $alt = ''; 69 | } 70 | 71 | $image = null; 72 | $preset = false; 73 | if (is_a($url, '\Twitter\Cards\Components\Image')) { 74 | $preset = true; 75 | $image = $url; 76 | $width = $url->getWidth(); 77 | $height = $url->getHeight(); 78 | $alt = $url->getAlternativeText(); 79 | } elseif (is_string($url)) { 80 | try { 81 | $image = new \Twitter\Cards\Components\Image($url); 82 | } catch (\Exception $e) { 83 | return $this; 84 | } 85 | } 86 | 87 | if (! $image) { 88 | return $this; 89 | } 90 | 91 | // only set dimensions if both width and height exist 92 | if (is_int($width) && $width && is_int($height) && $height) { 93 | // test if minimum width and height requirements are met for the card type 94 | if (defined(__CLASS__ . '::MIN_IMAGE_WIDTH') && defined(__CLASS__ . '::MIN_IMAGE_HEIGHT')) { 95 | if ($width >= self::MIN_IMAGE_WIDTH && $height >= self::MIN_IMAGE_HEIGHT) { 96 | if (! $preset) { 97 | $image->setWidth($width); 98 | $image->setHeight($height); 99 | } 100 | } else { 101 | // do not store image if minimum requirements not met 102 | return $this; 103 | } 104 | } else { 105 | if (! $preset) { 106 | $image->setWidth($width); 107 | $image->setHeight($height); 108 | } 109 | } 110 | } 111 | if (is_string($alt) && $alt) { 112 | $image->setAlternativeText($alt); 113 | } 114 | 115 | $this->image = $image; 116 | 117 | return $this; 118 | } 119 | 120 | /** 121 | * Output the image properties of a Twitter card 122 | * 123 | * Suitable for merging with a larger Twitter Card property array 124 | * 125 | * @since 1.0.0 126 | * 127 | * @return array { 128 | * @type string image property 129 | * @type array Twitter Card image values { 130 | * @type string structured property: src, width, height 131 | * @type string|int URL and dimensions 132 | * } 133 | * } 134 | */ 135 | protected function imageCardProperties() 136 | { 137 | if (! isset($this->image)) { 138 | return array(); 139 | } 140 | 141 | $card_properties = $this->image->asCardProperties(); 142 | if (empty($card_properties)) { 143 | return array(); 144 | } 145 | 146 | return $card_properties; 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/Twitter/Cards/Summary.php: -------------------------------------------------------------------------------- 1 | description) && $this->description) { 93 | $card['description'] = $this->description; 94 | } 95 | 96 | $image_properties = $this->imageCardProperties(); 97 | if (! empty($image_properties)) { 98 | $card['image'] = $image_properties; 99 | } 100 | unset($image_properties); 101 | 102 | if (isset($this->creator) && $this->creator) { 103 | $creator = $this->creator->asCardProperties(); 104 | if ($creator) { 105 | $card['creator'] = $creator; 106 | } 107 | unset($creator); 108 | } 109 | 110 | return $card; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/Twitter/Cards/SummaryLargeImage.php: -------------------------------------------------------------------------------- 1 | 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 | } 114 | -------------------------------------------------------------------------------- /src/Twitter/Intents/Traits/Related.php: -------------------------------------------------------------------------------- 1 | related[ $comparison_username ])) { 68 | if (property_exists(get_called_class(), 'validate_inputs') && $this->validate_inputs) { 69 | if (\Twitter\Helpers\Validators\ScreenName::isValid($username)) { 70 | $this->related[ $comparison_username ] = trim($label); 71 | } 72 | } else { 73 | $this->related[ $comparison_username ] = trim($label); 74 | } 75 | } 76 | } 77 | 78 | return $this; 79 | } 80 | 81 | /** 82 | * Get related Twitter usernames 83 | * 84 | * @since 2.0.0 85 | * 86 | * @return array { 87 | * @type string username in lowercase 88 | * @type string description of how the username relates to Tweet content 89 | * } 90 | */ 91 | public function getRelated() 92 | { 93 | return $this->related; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/Twitter/Widgets/Base.php: -------------------------------------------------------------------------------- 1 | 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 self 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 self 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 Base 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 self 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 | } 149 | -------------------------------------------------------------------------------- /src/Twitter/Widgets/Embeds/Moment.php: -------------------------------------------------------------------------------- 1 | setGridTemplate(); 57 | } 58 | 59 | /** 60 | * Return Moment parameters suitable for conversion to data-* 61 | * 62 | * @since 2.0.0 63 | * 64 | * @return array Moment timeline parameter array { 65 | * @type string dashed parameter name 66 | * @type string parameter value 67 | * } 68 | */ 69 | public function toArray() 70 | { 71 | $data = parent::toArray(); 72 | 73 | unset($data['widget-type']); 74 | 75 | return $data; 76 | } 77 | 78 | /** 79 | * Output Moment as an array suitable for use as oEmbed query parameters 80 | * 81 | * @since 2.0.0 82 | * 83 | * @return array Moment parameter array { 84 | * @type string query parameter name 85 | * @type string query parameter value 86 | * } 87 | */ 88 | public function toOEmbedParameterArray() 89 | { 90 | $query_parameters = parent::toOEmbedParameterArray(); 91 | 92 | unset($query_parameters['widget_type']); 93 | 94 | return $query_parameters; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/Twitter/Widgets/Embeds/Tweet/Video.php: -------------------------------------------------------------------------------- 1 | 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 | 'el' => 'Greek', 51 | 'en' => 'English', 52 | 'es' => 'Spanish', 53 | 'fa' => 'Persian', 54 | 'fi' => 'Finnish', 55 | 'fil' => 'Filipino', 56 | 'fr' => 'French', 57 | 'he' => 'Hebrew', 58 | 'hi' => 'Hindi', 59 | 'hu' => 'Hungarian', 60 | 'id' => 'Indonesian', 61 | 'it' => 'Italian', 62 | 'ja' => 'Japanese', 63 | 'ko' => 'Korean', 64 | 'msa' => 'Malay', 65 | 'nl' => 'Dutch', 66 | 'no' => 'Norwegian', 67 | 'pl' => 'Polish', 68 | 'pt' => 'Portuguese', 69 | 'ro' => 'Romanian', 70 | 'ru' => 'Russian', 71 | 'sv' => 'Swedish', 72 | 'th' => 'Thai', 73 | 'tr' => 'Turkish', 74 | 'uk' => 'Ukrainian', 75 | 'ur' => 'Urdu', 76 | 'vi' => 'Vietnamese', 77 | 'zh-cn' => 'Simplified Chinese', 78 | 'zh-tw' => 'Traditional Chinese', 79 | ); 80 | 81 | /** 82 | * Is the passed language a valid Twitter production language code? 83 | * 84 | * @since 1.0.0 85 | * 86 | * @param string $lang language code 87 | * 88 | * @return bool true if passed language exists in list of Twitter production language codes 89 | */ 90 | public static function isSupportedLanguage($lang) 91 | { 92 | return ( is_string($lang) && $lang && isset(static::$SUPPORTED_LANGUAGES[$lang]) ); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/Twitter/WordPress/Admin/Profile/PeriscopeUser.php: -------------------------------------------------------------------------------- 1 | \Twitter\WordPress\Admin\Settings\SinglePage::PAGE_SLUG ) ) ) . '">' . __( 'Settings' ) . '' ); 62 | } 63 | 64 | return $links; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Twitter/WordPress/Admin/Settings/SettingsSection.php: -------------------------------------------------------------------------------- 1 | '; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Twitter/WordPress/Head/CardsMetaElements.php: -------------------------------------------------------------------------------- 1 | pairs 38 | * 39 | * @since 1.0.0 40 | * 41 | * @return string HTML 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 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( 74 | ( 'src' === $structured_name ) ? $name : $name . ':' . $structured_name, 75 | $structured_value 76 | ); 77 | } 78 | } else { 79 | $html .= \Twitter\WordPress\Head\MetaElement::fromNameContentPair( $name, $content ); 80 | } 81 | } 82 | return $html; 83 | } 84 | 85 | /** 86 | * Output a HTML containing all card elements for the current context 87 | * 88 | * @since 1.0.0 89 | * 90 | * @return void 91 | */ 92 | public static function outputMetaElements() 93 | { 94 | echo "\n"; 95 | 96 | // Escaped when building individual elements 97 | // @codingStandardsIgnoreLine WordPress.XSS.EscapeOutput.OutputNotEscaped 98 | echo static::buildMetaElements(); 99 | 100 | echo "\n"; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/Twitter/WordPress/Head/MetaElement.php: -------------------------------------------------------------------------------- 1 | '; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Twitter/WordPress/Helpers/HTMLBuilder.php: -------------------------------------------------------------------------------- 1 | 'application/json' ); 56 | 57 | /** 58 | * Build a Twitter REST API URL 59 | * 60 | * @since 1.2.0 61 | * 62 | * @param string $relative_path Publisher oEmbed 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 = 'oembed', $query_parameters = null, $response_format = 'json' ) 69 | { 70 | if ( ! is_array( $query_parameters ) ) { 71 | return ''; 72 | } 73 | 74 | // Minimal information not provided 75 | if ( ! ( isset( $query_parameters['id'] ) || isset( $query_parameters['url'] ) ) ) { 76 | return ''; 77 | } 78 | 79 | if ( ! is_string( $relative_path ) ) { 80 | $relative_path = ''; 81 | } else { 82 | $relative_path = trim( trim( $relative_path, '/' ) ); 83 | } 84 | if ( ! $relative_path ) { 85 | $relative_path = 'oembed'; 86 | } 87 | 88 | if ( ! ( is_string( $response_format ) && $response_format && isset( static::$RESPONSE_FORMATS[ $response_format ] ) ) ) { 89 | $response_format = ''; 90 | } 91 | 92 | $url = 'https://' . implode( '/', array( static::HOST, $relative_path ) ); 93 | if ( $response_format ) { 94 | $url .= '.' . $response_format; 95 | } 96 | $url .= '?' . http_build_query( $query_parameters, '', '&' ); 97 | 98 | return $url; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/Twitter/WordPress/Helpers/VineOEmbed.php: -------------------------------------------------------------------------------- 1 | ' . $script . ''; 98 | } 99 | 100 | return $script; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/Twitter/WordPress/JavaScriptLoaders/VineEmbed.php: -------------------------------------------------------------------------------- 1 | ' . $script . ''; 97 | } 98 | return $script; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/Twitter/WordPress/Language.php: -------------------------------------------------------------------------------- 1 | 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 | } 92 | -------------------------------------------------------------------------------- /src/Twitter/WordPress/Shortcodes/AuthorContext.php: -------------------------------------------------------------------------------- 1 | getID() ) ) { 116 | return ''; 117 | } 118 | 119 | return static::getHTMLForTimeline( $timeline ); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/Twitter/WordPress/Shortcodes/OEmbedTrait.php: -------------------------------------------------------------------------------- 1 | true, 50 | ); 51 | 52 | // attempt to customize text for site language 53 | $lang = \Twitter\WordPress\Language::localeToTwitterLang(); 54 | if ( $lang ) { 55 | $query_parameters['lang'] = $lang; 56 | } 57 | 58 | return $query_parameters; 59 | } 60 | 61 | /** 62 | * Request and parse oEmbed markup from Twitter's servers 63 | * 64 | * @since 1.3.0 65 | * 66 | * @param array $query_parameters query parameters to be passed to the oEmbed endpoint 67 | * @param string $cache_key key to retrieve and store HTML values for the given configuration 68 | * 69 | * @return string HTML markup returned by the oEmbed endpoint 70 | */ 71 | public static function getOEmbedMarkup( $query_parameters, $cache_key ) 72 | { 73 | if ( ! (is_string( $cache_key ) && $cache_key ) ) { 74 | return ''; 75 | } 76 | 77 | // check for cached result 78 | $html = get_transient( $cache_key ); 79 | if ( $html ) { 80 | return $html; 81 | } 82 | 83 | $classname = get_called_class(); 84 | if ( ! ( defined( $classname . '::OEMBED_API_CLASS' ) && static::OEMBED_API_CLASS ) ) { 85 | return ''; 86 | } 87 | $oembed_api_class = static::OEMBED_API_CLASS; 88 | if ( ! ( class_exists( $oembed_api_class ) && method_exists( $oembed_api_class, 'getJSON' ) ) ) { 89 | return ''; 90 | } 91 | 92 | if ( ! isset( $query_parameters['url'] ) ) { 93 | if ( defined( $classname . '::BASE_URL' ) && isset( $query_parameters['id'] ) ) { 94 | // convert ID to full URL to allow more flexibility for oEmbed endpoint 95 | $query_parameters['url'] = static::BASE_URL . $query_parameters['id']; 96 | unset( $query_parameters['id'] ); 97 | } else { 98 | return ''; 99 | } 100 | } 101 | 102 | $allowed_resource_types = array( 'rich' => true, 'video' => true ); 103 | $ttl = DAY_IN_SECONDS; 104 | 105 | $oembed_response = $oembed_api_class::getJSON( static::OEMBED_API_ENDPOINT, $query_parameters ); 106 | if ( ! ($oembed_response 107 | && isset( $oembed_response->type ) 108 | && isset( $allowed_resource_types[ $oembed_response->type ] ) 109 | && isset( $oembed_response->html ) 110 | && $oembed_response->html ) 111 | ) { 112 | // do not rerequest errors with every page request 113 | set_transient( $cache_key, ' ', $ttl ); 114 | return ''; 115 | } 116 | 117 | $html = $oembed_response->html; 118 | 119 | if ( isset( $oembed_response->cache_age ) ) { 120 | $ttl = absint( $oembed_response->cache_age ); 121 | } 122 | set_transient( $cache_key, $html, $ttl ); 123 | 124 | return $html; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/Twitter/WordPress/Shortcodes/PublishOEmbedEndpoint.php: -------------------------------------------------------------------------------- 1 | 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\Cards\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 | } 104 | -------------------------------------------------------------------------------- /src/Twitter/WordPress/User/Meta.php: -------------------------------------------------------------------------------- 1 | ID or a separate identifier used by an extending system 42 | * @param string $key user attribute or meta key storing the username of interest 43 | * 44 | * @return string stored username. empty string if no user_id provided or no username found 45 | */ 46 | public static function getSocialUsername( $user_id, $key ) 47 | { 48 | // basic test for invalid passed parameter 49 | if ( ! $user_id ) { 50 | return ''; 51 | } 52 | if ( ! is_string( $key ) || ! $key ) { 53 | return ''; 54 | } 55 | 56 | if ( function_exists( 'get_user_attribute' ) ) { 57 | $username = get_user_attribute( $user_id, $key ); 58 | } else { 59 | $username = get_user_meta( $user_id, $key, /* single */ true ); 60 | } 61 | 62 | if ( ! is_string( $username ) ) { 63 | $username = ''; 64 | } 65 | 66 | // pass a username through a filter if not explicitly defined through user meta 67 | if ( ! $username ) { 68 | /** 69 | * Allow sites to provide a WordPress user's Twitter username through a filter 70 | * 71 | * @since 1.0.0 72 | * 73 | * @param string $username Twitter username associated with a WordPress user ID 74 | * @param int|string $user_id WordPress user identifier. may be WP_User->ID or a separate identifier used by an extending system 75 | */ 76 | $username = apply_filters( $key . '_username', $username, $user_id ); 77 | } 78 | 79 | return $username; 80 | } 81 | 82 | /** 83 | * Get a Twitter @username stored for a given WordPress user identifier 84 | * 85 | * @since 1.0.0 86 | * 87 | * @param int|string $user_id WordPress user identifier. may be WP_User->ID or a separate identifier used by an extending system 88 | * 89 | * @return string Twitter username value stored for the given WordPress user identifier 90 | */ 91 | public static function getTwitterUsername( $user_id ) 92 | { 93 | return static::getSocialUsername( $user_id, 'twitter' ); 94 | } 95 | 96 | /** 97 | * Get a Periscope username stored for a given WordPress identifier 98 | * 99 | * @since 1.3.0 100 | * 101 | * @param int|string $user_id WordPress user identifier. may be WP_User->ID or a separate identifier used by an extending system 102 | * 103 | * @return string Periscope username value stored for the given WordPress user identifier 104 | */ 105 | public static function getPeriscopeUsername( $user_id ) 106 | { 107 | return static::getSocialUsername( $user_id, 'periscope' ); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/Twitter/WordPress/Widgets/Embeds/Timeline/Collection.php: -------------------------------------------------------------------------------- 1 |

>

getID() && method_exists( $timeline, 'toArray' ) ) ) { 118 | return false; 119 | } 120 | 121 | $data_attributes = $timeline->toArray(); 122 | if ( isset( $data_attributes['tweet-limit'] ) ) { 123 | $data_attributes['limit'] = $data_attributes['tweet-limit']; 124 | } 125 | 126 | return array_merge( $instance, $data_attributes ); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/Twitter/WordPress/Widgets/Embeds/Timeline/Profile.php: -------------------------------------------------------------------------------- 1 |

79 | >

toArray(); 117 | // convert data-* dashes to shortcode underscores 118 | if ( isset( $data_attributes['screen-name'] ) ) { 119 | $data_attributes['screen_name'] = $data_attributes['screen-name']; 120 | unset( $data_attributes['screen-name'] ); 121 | } 122 | if ( isset( $data_attributes['tweet-limit'] ) ) { 123 | $data_attributes['limit'] = $data_attributes['tweet-limit']; 124 | } 125 | 126 | return array_merge( $instance, $data_attributes ); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/Twitter/WordPress/Widgets/Widget.php: -------------------------------------------------------------------------------- 1 |

47 | >

card = new \Twitter\Cards\Card('summary'); 52 | } 53 | 54 | /** 55 | * Test cleaning up the title before storing 56 | * 57 | * @since 1.0.0 58 | * 59 | * @covers ::sanitizeTitle 60 | * @small 61 | * 62 | * @dataProvider sanitizeTitleProvider 63 | * 64 | * @param string $title passed title 65 | * @param string $expected_sanitized expected result of sanitization 66 | * @param string $message error message to display on negative assertion 67 | * 68 | * @return void 69 | */ 70 | public function testSanitizeTitle($title, $expected_sanitized, $message = '') 71 | { 72 | $this->assertEquals( 73 | $expected_sanitized, 74 | \Twitter\Cards\Card::sanitizeTitle($title), 75 | $message 76 | ); 77 | } 78 | 79 | /** 80 | * Provide titles for testing by the sanitizer 81 | * 82 | * @since 1.0.0 83 | * 84 | * @return array title values { 85 | * @type array provided title, expected sanitized value, error message 86 | * } 87 | */ 88 | public static function sanitizeTitleProvider() 89 | { 90 | return array( 91 | array( 'Hello world', 'Hello world', 'Failed to sanitize basic title' ), 92 | array( ' Hello world ', 'Hello world', 'Failed to trim whitespace' ), 93 | ); 94 | } 95 | 96 | /** 97 | * Test setting a Twitter Card title 98 | * 99 | * @since 1.0.0 100 | * 101 | * @covers ::setTitle 102 | * @small 103 | * 104 | * @return void 105 | */ 106 | public function testSetTitle() 107 | { 108 | $title = 'Hello world'; 109 | $this->card->setTitle($title); 110 | $this->assertEquals($title, self::getProperty($this->card, 'title'), 'Failed to set title'); 111 | } 112 | 113 | /** 114 | * Test setting a site 115 | * 116 | * @since 1.0.0 117 | * 118 | * @covers ::setSite 119 | * @small 120 | * 121 | * @uses \Twitter\Cards\Components\Account 122 | * 123 | * @return void 124 | */ 125 | public function testSetSite() 126 | { 127 | $this->assertNotNull(\Twitter\Cards\Components\Account::fromScreenName('twitter'), 'Failed to set site'); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /tests/phpunit/Cards/Components/Creator.php: -------------------------------------------------------------------------------- 1 | creator = $this->getMockForTrait('\Twitter\Cards\Components\Creator'); 53 | } 54 | 55 | /** 56 | * Test setting the creator property 57 | * 58 | * @since 1.0.0 59 | * 60 | * @covers ::setCreator 61 | * @small 62 | * 63 | * @return void 64 | */ 65 | public function testSetCreator() 66 | { 67 | $this->creator->setCreator( 68 | $this->getMockBuilder('\Twitter\Cards\Components\Account')->getMock() 69 | ); 70 | $this->assertNotNull(self::getProperty($this->creator, 'creator'), 'Failed to set creator property'); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tests/phpunit/Cards/Components/Description.php: -------------------------------------------------------------------------------- 1 | description = $this->getMockForTrait('\Twitter\Cards\Components\Description'); 53 | } 54 | 55 | /** 56 | * Test sanitizing a passed Twitter Card description 57 | * 58 | * @since 1.0.0 59 | * 60 | * @covers ::sanitizeDescription 61 | * @small 62 | * 63 | * @dataProvider descriptionProvider 64 | * 65 | * @return string sanitized description 66 | */ 67 | public function testSanitizeDescription($test_value, $expected_result, $message = '') 68 | { 69 | $sanitized_description = $this->description->sanitizeDescription($test_value); 70 | $this->assertEquals($expected_result, $sanitized_description, $message); 71 | 72 | return $sanitized_description; 73 | } 74 | 75 | /** 76 | * Provide description test values 77 | * 78 | * @since 1.0.0 79 | * 80 | * @return array descriptions { 81 | * @type array test value, expected result, error message 82 | * } 83 | */ 84 | public static function descriptionProvider() 85 | { 86 | $test_value = 'hello world'; 87 | return array( 88 | array( $test_value, $test_value, 'failed to handle valid description' ), 89 | array( ' ' . $test_value . ' ', $test_value, 'failed to trim a description' ), 90 | ); 91 | } 92 | 93 | /** 94 | * Test setting the description property 95 | * 96 | * @since 1.0.0 97 | * 98 | * @covers ::setDescription 99 | * @depends testSanitizeDescription 100 | * @small 101 | * 102 | * @return void 103 | */ 104 | public function testSetDescription() 105 | { 106 | $description = 'The quick brown fox jumps over the lazy dog'; 107 | $this->description->setDescription($description); 108 | $this->assertEquals($description, self::getProperty($this->description, 'description'), 'Failed to set description'); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /tests/phpunit/Cards/Summary.php: -------------------------------------------------------------------------------- 1 | getMockBuilder('\Twitter\Cards\Summary')->setMethods(array('imageCardProperties'))->getMock(); 48 | $card->method('imageCardProperties')->willReturn($image_url); 49 | 50 | // mock an account for stored creator 51 | $creator_screen_name = '@twitter'; 52 | $creator = $this->getMockBuilder('\Twitter\Cards\Components\Account')->setMethods(array('asCardProperties'))->getMock(); 53 | $creator->method('asCardProperties')->willReturn($creator_screen_name); 54 | self::setProperty($card, 'creator', $creator); 55 | unset($creator); 56 | 57 | $description = 'Hello world'; 58 | self::setProperty($card, 'description', $description); 59 | 60 | // generate the array 61 | $properties = $card->toArray(); 62 | $this->assertEquals($properties['card'], 'summary', 'Summary card type not set'); 63 | $this->assertTrue((isset($properties['description']) && $properties['description'] === $description), 'Failed to output description'); 64 | $this->assertTrue((isset($properties['creator']) && $properties['creator'] === $creator_screen_name), 'Failed to output stored creator screen name'); 65 | $this->assertTrue((isset($properties['image']) && $properties['image'] === $image_url), 'Failed to output image URL'); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /tests/phpunit/Cards/SummaryLargeImage.php: -------------------------------------------------------------------------------- 1 | toArray(); 49 | $this->assertEquals($properties['card'], 'summary_large_image', 'Summary large image card type not set'); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tests/phpunit/CommonProviders.php: -------------------------------------------------------------------------------- 1 | assertEquals( 52 | 'hashtag', 53 | \Twitter\Helpers\Validators\Hashtag::trim($test_string), 54 | $message 55 | ); 56 | } 57 | 58 | /** 59 | * Define multiple strings that should all evaluate to 'hashtag' after passing through \Twitter\Helpers\Validators\Hashtag::trim 60 | * 61 | * @since 1.0.0 62 | * 63 | * @return array { 64 | * @type array test string and error string 65 | * } 66 | */ 67 | public static function trimmableHashtagProvider() 68 | { 69 | return array( 70 | array( '#hashtag', 'failed to trim symbol' ), 71 | array( '#hashtag', 'failed to trim unicode symbol' ), 72 | array( ' #hashtag ', 'failed to trim whitespace' ), 73 | array( 'hashtag', 'failed when no trim needed' ) 74 | ); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /tests/phpunit/Helpers/Validators/WebsiteTag.php: -------------------------------------------------------------------------------- 1 | assertTrue( $is_valid, $message ); 54 | } else { 55 | $this->assertFalse( $is_valid, $message ); 56 | } 57 | } 58 | 59 | /** 60 | * Test cleaning a provided website tag 61 | * 62 | * @since 2.0.0 63 | * 64 | * @covers ::sanitize 65 | * @small 66 | * 67 | * @dataProvider websiteTagProvider 68 | * 69 | * @param string $test_value website tag 70 | * @param bool $expected_valid expected validity of the provided test value 71 | * @param string $message (optional) message to display on test failure 72 | * 73 | * @return void 74 | */ 75 | public function testSanitize( $test_value, $expected_valid, $message = '' ) 76 | { 77 | $clean_value = \Twitter\Helpers\Validators\WebsiteTag::sanitize($test_value); 78 | if ( $expected_valid ) { 79 | $this->assertEquals( strtolower($clean_value), $clean_value, $message ); 80 | } else { 81 | $this->assertEquals( '', $clean_value, $message ); 82 | } 83 | } 84 | 85 | /** 86 | * Provide possible website tag values and expected validity 87 | * 88 | * @since 2.0.0 89 | * 90 | * @return array website tag value, 91 | */ 92 | public static function websiteTagProvider() 93 | { 94 | return array( 95 | array( 'a1b2c', true, 'Failed to accept simple website tag' ), 96 | array( 'A1B2C', true, 'Failed to accept simple website tag with uppercase alpha characters' ), 97 | array( 'a1b2c3', false, 'Accepted a value beyond the maximum allowed length of a website tag' ), 98 | array( 'a1&b2', false, 'Accepted a website tag with an ampersand' ), 99 | ); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /tests/phpunit/TestWithPrivateAccess.php: -------------------------------------------------------------------------------- 1 | getProperty($property_name); 54 | $property->setAccessible(true); 55 | 56 | return $property->getValue($class); 57 | } 58 | 59 | /** 60 | * Set a private or protected property 61 | * 62 | * @since 1.0.0 63 | * 64 | * @param object $class initialized class 65 | * @param string $property_name class property name 66 | * @param mixed $value desired property value 67 | * 68 | * @return void 69 | */ 70 | public static function setProperty($class, $property_name, $value) 71 | { 72 | if (! $property_name) { 73 | return; 74 | } 75 | 76 | $reflection = new \ReflectionClass($class); 77 | 78 | $property = $reflection->getProperty($property_name); 79 | $property->setAccessible(true); 80 | 81 | return $property->setValue($class, $value); 82 | } 83 | 84 | /** 85 | * Make a private or protected method available for testing 86 | * 87 | * @since 1.0.0 88 | * 89 | * @param object $class initialized class 90 | * @param string $method_name class method name 91 | * 92 | * @return ReflectionMethod 93 | */ 94 | public static function getMethod($class, $method_name) 95 | { 96 | if (! $method_name) { 97 | return; 98 | } 99 | 100 | $reflection = new \ReflectionClass($class); 101 | $method = $reflection->getMethod($method_name); 102 | $method->setAccessible(true); 103 | 104 | return $method; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /tests/phpunit/Widgets/Buttons/Tweet.php: -------------------------------------------------------------------------------- 1 | button = new \Twitter\Widgets\Buttons\Tweet(); 52 | } 53 | 54 | /** 55 | * Test setting button sizes 56 | * 57 | * @since 1.0.0 58 | * 59 | * @covers ::setSize 60 | * @small 61 | * 62 | * @dataProvider sizeProvider 63 | * 64 | * @param string $size button size configuration 65 | * @param bool $expected_valid expected validity 66 | * @param string $message error message to display on negative assertion 67 | * 68 | * @return void 69 | */ 70 | public function testSetSize($size, $expected_valid, $message = '') 71 | { 72 | $this->button->setSize($size); 73 | $property = self::getProperty($this->button, 'size'); 74 | 75 | if ($expected_valid) { 76 | $this->assertEquals($size, $property, $message); 77 | } else { 78 | $this->assertNull($property, $message); 79 | } 80 | } 81 | 82 | /** 83 | * Button sizes 84 | * 85 | * @since 1.0.0 86 | * 87 | * @return array sizes { 88 | * @type array size, expected validity, error message 89 | * } 90 | */ 91 | public static function sizeProvider() 92 | { 93 | return array( 94 | array( 'large', true, 'Failed to set a valid size' ), 95 | array( 'small', false, 'Set an invalid size' ), 96 | ); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /tests/phpunit/Widgets/Embeds/Moment.php: -------------------------------------------------------------------------------- 1 | assertEquals(self::VALID_MOMENT_ID, self::getProperty($timeline, 'id'), 'Moment constructor did not set valid ID'); 55 | $this->assertEquals(\Twitter\Widgets\Embeds\Moment::WIDGET_TYPE_GRID, self::getProperty($timeline, 'widget_type'), 'Moment constructor did not set grid widget type'); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tests/phpunit/Widgets/Embeds/Tweet/Base.php: -------------------------------------------------------------------------------- 1 | widget = $this->getMockBuilder('\Twitter\Widgets\Embeds\Tweet\Base')->setConstructorArgs(array(self::VALID_TWEET_ID))->getMockForAbstractClass(); 61 | } 62 | 63 | /** 64 | * Test Tweet ID validity 65 | * 66 | * @since 2.0.0 67 | * 68 | * @dataProvider idProvider 69 | * 70 | * @covers ::isValidID 71 | * 72 | * @param string $id Tweet ID 73 | * @param bool $expected_valid expected validity of the passed ID 74 | * @param string $message error message to display 75 | * 76 | * @return void 77 | */ 78 | public function testIsValidID($id, $expected_valid, $message = '') 79 | { 80 | $class = $this->widget; 81 | $validity = $class::isValidID($id); 82 | if ($expected_valid) { 83 | $this->assertTrue($validity, $message); 84 | } else { 85 | $this->assertFalse($validity, $message); 86 | } 87 | } 88 | 89 | /** 90 | * Test setting a Tweet ID 91 | * 92 | * @since 2.0.0 93 | * 94 | * @depends testIsValidID 95 | * 96 | * @covers ::setId 97 | * 98 | * @return void 99 | */ 100 | public function testSetID() 101 | { 102 | self::setProperty($this->widget, 'id', null); 103 | $this->widget->setID('foo'); 104 | $this->assertNull(self::getProperty($this->widget, 'id'), 'Set an invalid ID'); 105 | $this->widget->setID(self::VALID_TWEET_ID); 106 | $this->assertEquals(self::VALID_TWEET_ID, self::getProperty($this->widget, 'id'), 'Failed to set a valid ID'); 107 | } 108 | 109 | /** 110 | * Tweet ID values for testing 111 | * 112 | * @since 2.0.0 113 | * 114 | * @return array value to test, expected validity, error message 115 | */ 116 | public static function idProvider() 117 | { 118 | return array( 119 | array( self::VALID_TWEET_ID, true, 'Failed to accept a valid ID string' ), 120 | array( 'foo', false, 'Accepted a non-numeric identifier' ), 121 | ); 122 | } 123 | 124 | /** 125 | * Test retrieving the id property through a getter method 126 | * 127 | * @since 2.0.0 128 | * 129 | * @covers ::getID 130 | * 131 | * @return void 132 | */ 133 | public function testGetID() 134 | { 135 | self::setProperty($this->widget, 'id', self::VALID_TWEET_ID); 136 | $this->assertEquals(self::VALID_TWEET_ID, $this->widget->getID(), 'Failed to retrieve Tweet ID property'); 137 | } 138 | 139 | /** 140 | * Test building an absolute URL for the Tweet 141 | * 142 | * @since 2.0.0 143 | * 144 | * @covers ::getURL 145 | * 146 | * @return void 147 | */ 148 | public function testGetURL() 149 | { 150 | self::setProperty($this->widget, 'id', self::VALID_TWEET_ID); 151 | $this->assertEquals('https://twitter.com/_/status/'.self::VALID_TWEET_ID, $this->widget->getURL(), 'Failed to build URL'); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /tests/phpunit/Widgets/Language.php: -------------------------------------------------------------------------------- 1 | assertTrue(\Twitter\Widgets\Language::isSupportedLanguage($language_code), $message); 54 | } else { 55 | $this->assertFalse(\Twitter\Widgets\Language::isSupportedLanguage($language_code), $message); 56 | } 57 | } 58 | 59 | /** 60 | * Test language codes 61 | * 62 | * @since 1.0.0 63 | * 64 | * @return array language codes with expected validity { 65 | * @type array language code, validity 66 | * } 67 | */ 68 | public static function languagesProvider() 69 | { 70 | return array( 71 | array( 'es', true, 'Did not accept Spanish as a valid language' ), 72 | array( 'eo', false, 'Accepted Esperanto as a valid language' ), 73 | array( '' , false, 'Failed to properly handle empty string' ) 74 | ); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /tests/phpunit/WordPress/Shortcodes/Buttons/Follow.php: -------------------------------------------------------------------------------- 1 | $screen_name )); 54 | $this->assertTrue(( isset($options['screen_name']) && $options['screen_name'] === $expected ), 'Failed to extract screen name from attribute'); 55 | } 56 | 57 | /** 58 | * Twitter screen name provider 59 | * 60 | * @since 2.0.0 61 | * 62 | * @return array array of arrays of Twitter screen names 63 | */ 64 | public static function screenNameProvider() 65 | { 66 | return array( 67 | array( 'TwitterDev' ), 68 | array( '@TwitterDev' ), 69 | array( ' TwitterDev ' ), 70 | ); 71 | } 72 | 73 | /** 74 | * Test hiding Tweet counts through a shortcode attribute value 75 | * 76 | * @since 2.0.0 77 | * 78 | * @covers ::getShortcodeAttributes 79 | * @small 80 | * 81 | * @dataProvider falseyShortcodeParameterProvider 82 | * 83 | * @param bool|int|string $truthy_value truthy value to test 84 | * 85 | * @return void 86 | */ 87 | public function testGetShortcodeAttributesShowCount($truthy_value) 88 | { 89 | $options = \Twitter\WordPress\Shortcodes\Buttons\Follow::getShortcodeAttributes(array( 'show_count' => $truthy_value )); 90 | $this->assertTrue(( isset($options['show_count']) && false === $options['show_count'] ), 'Failed to enable follow count from attribute'); 91 | } 92 | 93 | /** 94 | * Test hiding Twitter screen name through a shortcode attribute value 95 | * 96 | * @since 2.0.0 97 | * 98 | * @covers ::getShortcodeAttributes 99 | * @small 100 | * 101 | * @dataProvider falseyShortcodeParameterProvider 102 | * 103 | * @param bool|int|string $falsey_value falsey value to test 104 | * 105 | * @return void 106 | */ 107 | public function testGetShortcodeAttributes($falsey_value) 108 | { 109 | $options = \Twitter\WordPress\Shortcodes\Buttons\Follow::getShortcodeAttributes(array( 'show_screen_name' => $falsey_value )); 110 | $this->assertTrue(( isset($options['show_screen_name']) && false === $options['show_screen_name'] ), 'Failed to disable screen name display from attribute'); 111 | } 112 | 113 | /** 114 | * Show count falsey value provider 115 | * 116 | * @since 2.0.0 117 | * 118 | * @return array array of shortcode falsey values 119 | */ 120 | public static function falseyShortcodeParameterProvider() 121 | { 122 | return array( 123 | array( false ), 124 | array( 0 ), 125 | array( '0' ), 126 | array( 'false' ), 127 | array( 'FALSE' ), 128 | array( 'no' ), 129 | array( 'NO' ), 130 | array( 'off' ), 131 | array( 'OFF' ), 132 | ); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /tests/phpunit/WordPress/Shortcodes/Buttons/Periscope/OnAir.php: -------------------------------------------------------------------------------- 1 | $username )); 54 | $this->assertTrue(( isset($options['username']) && $options['username'] === $expected ), 'Failed to extract screen name from attribute'); 55 | } 56 | 57 | /** 58 | * Periscope username provider 59 | * 60 | * @since 2.0.0 61 | * 62 | * @return array array of arrays of Periscope usernames 63 | */ 64 | public static function usernameProvider() 65 | { 66 | return array( 67 | array( 'twitter' ), 68 | array( '@twitter' ), 69 | array( ' twitter ' ), 70 | ); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tests/phpunit/WordPress/Shortcodes/Embeds/Tweet/Video.php: -------------------------------------------------------------------------------- 1 | $tweet_id )); 54 | $this->assertTrue(( isset($options['id']) && $options['id'] === $expected ), 'Failed to extract ID from attribute'); 55 | } 56 | 57 | /** 58 | * Provide Tweet values which should all evaluate to a Tweet ID of 20 59 | * 60 | * @since 2.0.0 61 | * 62 | * @return array array of test values 63 | */ 64 | public static function tweetIDProvider() 65 | { 66 | return array( 67 | array( 'https://twitter.com/twitter/status/560070183650213889' ), 68 | array( 'https://twitter.com/twitter/statuses/560070183650213889' ), 69 | array( '560070183650213889' ), 70 | array( ' 560070183650213889 ' ), 71 | ); 72 | } 73 | 74 | /** 75 | * Test building a unique cache key component for shortcode customizations 76 | * 77 | * @since 2.0.0 78 | * 79 | * @covers ::getOEmbedCacheKeyCustomParameters 80 | * @small 81 | * 82 | * @return void 83 | */ 84 | public function testGetOEmbedCacheKeyCustomParameters() 85 | { 86 | $this->assertEquals( 87 | '', 88 | \Twitter\WordPress\Shortcodes\Embeds\Tweet\Video::getOEmbedCacheKeyCustomParameters(array( 'hide_tweet' => true )), 89 | 'Failed to set an empty cache modifier key' 90 | ); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /tests/phpunit/WordPress/Widgets/Embeds/Timeline/Profile.php: -------------------------------------------------------------------------------- 1 | widget = new \Twitter\WordPress\Widgets\Embeds\Timeline\Profile(); 53 | } 54 | 55 | /** 56 | * Test widget constructor 57 | * 58 | * @since 2.0.0 59 | * 60 | * @covers ::__construct 61 | * @small 62 | * 63 | * @return void 64 | */ 65 | public function testConstructor() 66 | { 67 | $this->assertEquals(\Twitter\WordPress\Shortcodes\Embeds\Timeline\Profile::HTML_CLASS, $this->widget->id_base, 'Base ID not set'); 68 | $this->assertEquals('Twitter Profile', $this->widget->name, 'Widget name not set'); 69 | } 70 | 71 | /** 72 | * Test frontend output of widget 73 | * 74 | * @since 2.0.0 75 | * 76 | * @covers ::widget 77 | 78 | public function testWidget() 79 | { 80 | ob_start(); 81 | $args = array( 82 | 'before_widget' => '
', 83 | 'after_widget' => "
\n", 84 | 'before_title' => '

', 85 | 'after_title' => "

\n", 86 | ); 87 | $shortcode_stub = $this->getMock('\Twitter\WordPress\Shortcodes\Embeds\Timeline\Profile'); 88 | $shortcode_stub->expects($this->any()) 89 | ->method('shortcodeHandler') 90 | ->will($this->returnValue('
')); 91 | 92 | $instance = array('title' => 'Tweets', 'screen_name' => 'Twitter'); 93 | $this->widget->_set( 2 ); 94 | $this->widget->widget( $args, $instance ); 95 | $output = ob_get_clean(); 96 | 97 | $this->assertNotContains( 'no-options-widget', $output ); 98 | $this->assertContains( '

Tweets

', $output, 'No title wrappers' ); 99 | $this->assertContains( '
', $output, 'No customization before widget' ); 100 | $this->assertContains( '
', $output, 'No customization after widget' ); 101 | }*/ 102 | } 103 | -------------------------------------------------------------------------------- /tests/phpunit/autoload.php: -------------------------------------------------------------------------------- 1 |