{"action":"created","comment":{"url":"https://api.github.com/repos/woothemes/woocommerce/pulls/comments/51935184","id":51935184,"diff_hunk":"@@ -0,0 +1,169 @@\n+<?php\n+\n+if ( ! defined( 'ABSPATH' ) ) {\n+\texit; // Exit if accessed directly\n+}\n+\n+/**\n+ * WooCommerce Payment Token\n+ *\n+ * Representation of a general payment token to be extended by individuals types of tokens\n+ * examples: Credit Card, eCheck.\n+ *\n+ * @class \t\tWC_Payment_Token\n+ * @since\t\t2.6.0\n+ * @package\t\tWooCommerce/Abstracts\n+ * @category\tAbstract Class\n+ * @author\t\tWooThemes\n+ */\n+ abstract class WC_Payment_Token {\n+\n+ \t/** @protected int Token ID */\n+ \tprotected $id;\n+ \t/** @protected array Core Token Data (stored in the payment_tokens table) */\n+ \tprotected $data;\n+ \t/** @protected array Meta Token Data (extra data associated with a payment token, stored in the payment_token_meta table) */\n+ \tprotected $meta;\n+\n+ \t/**\n+\t * Initialize a payment token\n+\t *\n+\t * These fields are accepted by all payment tokens:\n+\t * default      - boolean Optional - Indicates this is the default payment token for a user\n+\t * type         - string  Required - WC core ships with 'cc' or 'echeck' but other values can be used for custom payment token types\n+\t * token        - string  Required - The actual token to store\n+\t * gateway_id   - string  Required - Identifier for the gateway this token is associated with\n+\t * customer_id  - int     Optional - ID for the customer this token is associated with. 0 if this token is not associated with a user\n+\t *\n+\t * @since 2.6.0\n+\t * @param string $id Token ID\n+\t * @param array $data Core token data\n+\t * @param array $meta Meta token data\n+\t */\n+\tpublic function __construct( $id, $data, $meta ) {\n+\t\t$this->id = $id;\n+\t\t$this->data = $data;\n+\t\t$this->meta = $meta;\n+\t}\n+\n+\t/**\n+\t * Returns the payment token ID\n+\t *\n+\t * @since 2.6.0\n+\t * @return string Token ID\n+\t */\n+\tpublic function get_id() {\n+\t\treturn $this->id;\n+\t}\n+\n+\t/**\n+\t * Returns the raw payment token\n+\t *\n+\t * @since 2.6.0\n+\t * @return string Raw token\n+\t */\n+\tpublic function get_token() {\n+\t\treturn $this->data['token'];\n+\t}\n+\n+\t/**\n+\t * Set the raw payment token\n+\t *\n+\t * @since 2.6.0\n+\t * @param string $token\n+\t */\n+\tpublic function set_token( $token ) {\n+\t\t$this->data['token'] = $token;\n+\t}\n+\n+\t/**\n+\t * Returns the type of this payment token (cc, echeck, or something else)\n+\t *\n+\t * @since 2.6.0\n+\t * @return string Payment token type\n+\t */\n+\tpublic function get_type() {\n+\t\treturn isset( $this->data['type'] ) ? $this->data['type'] : null;\n+\t}\n+\n+\t/**\n+\t * Set the payment token type\n+\t *\n+\t * @since 2.6.0\n+\t * @param string $type\n+\t */\n+\tpublic function set_type( $type ) {\n+\t\t$this->data['type'] = $type;\n+\t}\n+\n+\t/**\n+\t * Returns the customer ID associated with the token or false if this token is not associated\n+\t *\n+\t * @since 2.6.0\n+\t * @return mixed Customer ID if this token is associated with a user or false.\n+\t */\n+\tpublic function get_customer_id() {","path":"includes/abstracts/abstract-wc-payment-token.php","position":105,"original_position":105,"commit_id":"0b90374ec4e4fa3328c1a8b7caa67e2a087dd84c","original_commit_id":"bc346a9402cd1abe61f02cdacad402ef6fb9f3b7","user":{"login":"justinshreve","id":689165,"avatar_url":"https://avatars.githubusercontent.com/u/689165?v=3","gravatar_id":"","url":"https://api.github.com/users/justinshreve","html_url":"https://github.com/justinshreve","followers_url":"https://api.github.com/users/justinshreve/followers","following_url":"https://api.github.com/users/justinshreve/following{/other_user}","gists_url":"https://api.github.com/users/justinshreve/gists{/gist_id}","starred_url":"https://api.github.com/users/justinshreve/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/justinshreve/subscriptions","organizations_url":"https://api.github.com/users/justinshreve/orgs","repos_url":"https://api.github.com/users/justinshreve/repos","events_url":"https://api.github.com/users/justinshreve/events{/privacy}","received_events_url":"https://api.github.com/users/justinshreve/received_events","type":"User","site_admin":false},"body":"I went back and forth on this actually - but agreed it should probably match WC_Order.","created_at":"2016-02-04T20:50:13Z","updated_at":"2016-02-04T20:50:13Z","html_url":"https://github.com/woothemes/woocommerce/pull/10260#discussion_r51935184","pull_request_url":"https://api.github.com/repos/woothemes/woocommerce/pulls/10260","_links":{"self":{"href":"https://api.github.com/repos/woothemes/woocommerce/pulls/comments/51935184"},"html":{"href":"https://github.com/woothemes/woocommerce/pull/10260#discussion_r51935184"},"pull_request":{"href":"https://api.github.com/repos/woothemes/woocommerce/pulls/10260"}}},"pull_request":{"url":"https://api.github.com/repos/woothemes/woocommerce/pulls/10260","id":58158143,"html_url":"https://github.com/woothemes/woocommerce/pull/10260","diff_url":"https://github.com/woothemes/woocommerce/pull/10260.diff","patch_url":"https://github.com/woothemes/woocommerce/pull/10260.patch","issue_url":"https://api.github.com/repos/woothemes/woocommerce/issues/10260","number":10260,"state":"open","locked":false,"title":"Payment Token API","user":{"login":"justinshreve","id":689165,"avatar_url":"https://avatars.githubusercontent.com/u/689165?v=3","gravatar_id":"","url":"https://api.github.com/users/justinshreve","html_url":"https://github.com/justinshreve","followers_url":"https://api.github.com/users/justinshreve/followers","following_url":"https://api.github.com/users/justinshreve/following{/other_user}","gists_url":"https://api.github.com/users/justinshreve/gists{/gist_id}","starred_url":"https://api.github.com/users/justinshreve/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/justinshreve/subscriptions","organizations_url":"https://api.github.com/users/justinshreve/orgs","repos_url":"https://api.github.com/users/justinshreve/repos","events_url":"https://api.github.com/users/justinshreve/events{/privacy}","received_events_url":"https://api.github.com/users/justinshreve/received_events","type":"User","site_admin":false},"body":"See #9095 \r\n\r\nThis is a first pass at a Payment Token API taking the original GH proposal, provided feedback, and the Trello card into consideration. The first pass only focuses on validating, storing, and retrieving (no UI), it can still use some cleanup, and there are no committed tests yet. There are other improvements to make (validation for example can check to make sure expiry is correct format, etc) but I wanted to go ahead and post for feedback.\r\n\r\nI went with the approach recommended by @maxrice to try to make this extendable and not tied down to just cards:\r\n\r\n* There is an abstract WC_Payment_Token class. It contains fields shared by all payment tokens: The token itself, token ID, gateway ID, customer ID if there is one, default status, and 'type'. This data is stored in a dedicated tokens table.\r\n* There are two bundled payment token types: Credit Card & eCheck.\r\n    * Credit cards contain expiration fields, last 4, and card type (visa, master card, etc).\r\n    * eCheck just contains last 4.\r\n    * Other extensions can add new token types.\r\n* Meta is supported so extra fields can be stored if new payment token types are added. Anything outside of the above shared fields is stored in a meta table, but easily exposed. \r\n\r\nI want to work on getting some good committable tests written next, improving upon the above code, and then finally UI stuff. I imagine since we can support different token types (which might display differently as a row on checkout/my account) we'll need some fallback UI plus a way for token types (card, eCheck, ..) to say what they are displaying.","created_at":"2016-02-03T16:03:26Z","updated_at":"2016-02-04T20:50:13Z","closed_at":null,"merged_at":null,"merge_commit_sha":"ff8b216a8b73cb9e6fc659a9ddeaeb9e987b2517","assignee":{"login":"justinshreve","id":689165,"avatar_url":"https://avatars.githubusercontent.com/u/689165?v=3","gravatar_id":"","url":"https://api.github.com/users/justinshreve","html_url":"https://github.com/justinshreve","followers_url":"https://api.github.com/users/justinshreve/followers","following_url":"https://api.github.com/users/justinshreve/following{/other_user}","gists_url":"https://api.github.com/users/justinshreve/gists{/gist_id}","starred_url":"https://api.github.com/users/justinshreve/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/justinshreve/subscriptions","organizations_url":"https://api.github.com/users/justinshreve/orgs","repos_url":"https://api.github.com/users/justinshreve/repos","events_url":"https://api.github.com/users/justinshreve/events{/privacy}","received_events_url":"https://api.github.com/users/justinshreve/received_events","type":"User","site_admin":false},"milestone":{"url":"https://api.github.com/repos/woothemes/woocommerce/milestones/51","html_url":"https://github.com/woothemes/woocommerce/milestones/2.6","labels_url":"https://api.github.com/repos/woothemes/woocommerce/milestones/51/labels","id":1425734,"number":51,"title":"2.6","description":"","creator":{"login":"mikejolley","id":90977,"avatar_url":"https://avatars.githubusercontent.com/u/90977?v=3","gravatar_id":"","url":"https://api.github.com/users/mikejolley","html_url":"https://github.com/mikejolley","followers_url":"https://api.github.com/users/mikejolley/followers","following_url":"https://api.github.com/users/mikejolley/following{/other_user}","gists_url":"https://api.github.com/users/mikejolley/gists{/gist_id}","starred_url":"https://api.github.com/users/mikejolley/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mikejolley/subscriptions","organizations_url":"https://api.github.com/users/mikejolley/orgs","repos_url":"https://api.github.com/users/mikejolley/repos","events_url":"https://api.github.com/users/mikejolley/events{/privacy}","received_events_url":"https://api.github.com/users/mikejolley/received_events","type":"User","site_admin":false},"open_issues":27,"closed_issues":10,"state":"open","created_at":"2015-11-23T18:25:09Z","updated_at":"2016-02-03T17:23:58Z","due_on":"2016-04-30T23:00:00Z","closed_at":null},"commits_url":"https://api.github.com/repos/woothemes/woocommerce/pulls/10260/commits","review_comments_url":"https://api.github.com/repos/woothemes/woocommerce/pulls/10260/comments","review_comment_url":"https://api.github.com/repos/woothemes/woocommerce/pulls/comments{/number}","comments_url":"https://api.github.com/repos/woothemes/woocommerce/issues/10260/comments","statuses_url":"https://api.github.com/repos/woothemes/woocommerce/statuses/0b90374ec4e4fa3328c1a8b7caa67e2a087dd84c","head":{"label":"justinshreve:token-api","ref":"token-api","sha":"0b90374ec4e4fa3328c1a8b7caa67e2a087dd84c","user":{"login":"justinshreve","id":689165,"avatar_url":"https://avatars.githubusercontent.com/u/689165?v=3","gravatar_id":"","url":"https://api.github.com/users/justinshreve","html_url":"https://github.com/justinshreve","followers_url":"https://api.github.com/users/justinshreve/followers","following_url":"https://api.github.com/users/justinshreve/following{/other_user}","gists_url":"https://api.github.com/users/justinshreve/gists{/gist_id}","starred_url":"https://api.github.com/users/justinshreve/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/justinshreve/subscriptions","organizations_url":"https://api.github.com/users/justinshreve/orgs","repos_url":"https://api.github.com/users/justinshreve/repos","events_url":"https://api.github.com/users/justinshreve/events{/privacy}","received_events_url":"https://api.github.com/users/justinshreve/received_events","type":"User","site_admin":false},"repo":{"id":36830592,"name":"woocommerce","full_name":"justinshreve/woocommerce","owner":{"login":"justinshreve","id":689165,"avatar_url":"https://avatars.githubusercontent.com/u/689165?v=3","gravatar_id":"","url":"https://api.github.com/users/justinshreve","html_url":"https://github.com/justinshreve","followers_url":"https://api.github.com/users/justinshreve/followers","following_url":"https://api.github.com/users/justinshreve/following{/other_user}","gists_url":"https://api.github.com/users/justinshreve/gists{/gist_id}","starred_url":"https://api.github.com/users/justinshreve/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/justinshreve/subscriptions","organizations_url":"https://api.github.com/users/justinshreve/orgs","repos_url":"https://api.github.com/users/justinshreve/repos","events_url":"https://api.github.com/users/justinshreve/events{/privacy}","received_events_url":"https://api.github.com/users/justinshreve/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/justinshreve/woocommerce","description":"[Fork to push changes upstream] An open source eCommerce plugin for WordPress created by WooThemes.","fork":true,"url":"https://api.github.com/repos/justinshreve/woocommerce","forks_url":"https://api.github.com/repos/justinshreve/woocommerce/forks","keys_url":"https://api.github.com/repos/justinshreve/woocommerce/keys{/key_id}","collaborators_url":"https://api.github.com/repos/justinshreve/woocommerce/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/justinshreve/woocommerce/teams","hooks_url":"https://api.github.com/repos/justinshreve/woocommerce/hooks","issue_events_url":"https://api.github.com/repos/justinshreve/woocommerce/issues/events{/number}","events_url":"https://api.github.com/repos/justinshreve/woocommerce/events","assignees_url":"https://api.github.com/repos/justinshreve/woocommerce/assignees{/user}","branches_url":"https://api.github.com/repos/justinshreve/woocommerce/branches{/branch}","tags_url":"https://api.github.com/repos/justinshreve/woocommerce/tags","blobs_url":"https://api.github.com/repos/justinshreve/woocommerce/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/justinshreve/woocommerce/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/justinshreve/woocommerce/git/refs{/sha}","trees_url":"https://api.github.com/repos/justinshreve/woocommerce/git/trees{/sha}","statuses_url":"https://api.github.com/repos/justinshreve/woocommerce/statuses/{sha}","languages_url":"https://api.github.com/repos/justinshreve/woocommerce/languages","stargazers_url":"https://api.github.com/repos/justinshreve/woocommerce/stargazers","contributors_url":"https://api.github.com/repos/justinshreve/woocommerce/contributors","subscribers_url":"https://api.github.com/repos/justinshreve/woocommerce/subscribers","subscription_url":"https://api.github.com/repos/justinshreve/woocommerce/subscription","commits_url":"https://api.github.com/repos/justinshreve/woocommerce/commits{/sha}","git_commits_url":"https://api.github.com/repos/justinshreve/woocommerce/git/commits{/sha}","comments_url":"https://api.github.com/repos/justinshreve/woocommerce/comments{/number}","issue_comment_url":"https://api.github.com/repos/justinshreve/woocommerce/issues/comments{/number}","contents_url":"https://api.github.com/repos/justinshreve/woocommerce/contents/{+path}","compare_url":"https://api.github.com/repos/justinshreve/woocommerce/compare/{base}...{head}","merges_url":"https://api.github.com/repos/justinshreve/woocommerce/merges","archive_url":"https://api.github.com/repos/justinshreve/woocommerce/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/justinshreve/woocommerce/downloads","issues_url":"https://api.github.com/repos/justinshreve/woocommerce/issues{/number}","pulls_url":"https://api.github.com/repos/justinshreve/woocommerce/pulls{/number}","milestones_url":"https://api.github.com/repos/justinshreve/woocommerce/milestones{/number}","notifications_url":"https://api.github.com/repos/justinshreve/woocommerce/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/justinshreve/woocommerce/labels{/name}","releases_url":"https://api.github.com/repos/justinshreve/woocommerce/releases{/id}","deployments_url":"https://api.github.com/repos/justinshreve/woocommerce/deployments","created_at":"2015-06-03T21:05:53Z","updated_at":"2016-02-01T15:35:29Z","pushed_at":"2016-02-04T20:46:03Z","git_url":"git://github.com/justinshreve/woocommerce.git","ssh_url":"git@github.com:justinshreve/woocommerce.git","clone_url":"https://github.com/justinshreve/woocommerce.git","svn_url":"https://github.com/justinshreve/woocommerce","homepage":"http://www.woothemes.com/woocommerce/","size":107645,"stargazers_count":0,"watchers_count":0,"language":"PHP","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"woothemes:master","ref":"master","sha":"563a557909d4b8cbbdc4b99d814533ec654a1f81","user":{"login":"woothemes","id":473596,"avatar_url":"https://avatars.githubusercontent.com/u/473596?v=3","gravatar_id":"","url":"https://api.github.com/users/woothemes","html_url":"https://github.com/woothemes","followers_url":"https://api.github.com/users/woothemes/followers","following_url":"https://api.github.com/users/woothemes/following{/other_user}","gists_url":"https://api.github.com/users/woothemes/gists{/gist_id}","starred_url":"https://api.github.com/users/woothemes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/woothemes/subscriptions","organizations_url":"https://api.github.com/users/woothemes/orgs","repos_url":"https://api.github.com/users/woothemes/repos","events_url":"https://api.github.com/users/woothemes/events{/privacy}","received_events_url":"https://api.github.com/users/woothemes/received_events","type":"Organization","site_admin":false},"repo":{"id":2179920,"name":"woocommerce","full_name":"woothemes/woocommerce","owner":{"login":"woothemes","id":473596,"avatar_url":"https://avatars.githubusercontent.com/u/473596?v=3","gravatar_id":"","url":"https://api.github.com/users/woothemes","html_url":"https://github.com/woothemes","followers_url":"https://api.github.com/users/woothemes/followers","following_url":"https://api.github.com/users/woothemes/following{/other_user}","gists_url":"https://api.github.com/users/woothemes/gists{/gist_id}","starred_url":"https://api.github.com/users/woothemes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/woothemes/subscriptions","organizations_url":"https://api.github.com/users/woothemes/orgs","repos_url":"https://api.github.com/users/woothemes/repos","events_url":"https://api.github.com/users/woothemes/events{/privacy}","received_events_url":"https://api.github.com/users/woothemes/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/woothemes/woocommerce","description":"An open source eCommerce plugin for WordPress created by WooThemes.","fork":false,"url":"https://api.github.com/repos/woothemes/woocommerce","forks_url":"https://api.github.com/repos/woothemes/woocommerce/forks","keys_url":"https://api.github.com/repos/woothemes/woocommerce/keys{/key_id}","collaborators_url":"https://api.github.com/repos/woothemes/woocommerce/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/woothemes/woocommerce/teams","hooks_url":"https://api.github.com/repos/woothemes/woocommerce/hooks","issue_events_url":"https://api.github.com/repos/woothemes/woocommerce/issues/events{/number}","events_url":"https://api.github.com/repos/woothemes/woocommerce/events","assignees_url":"https://api.github.com/repos/woothemes/woocommerce/assignees{/user}","branches_url":"https://api.github.com/repos/woothemes/woocommerce/branches{/branch}","tags_url":"https://api.github.com/repos/woothemes/woocommerce/tags","blobs_url":"https://api.github.com/repos/woothemes/woocommerce/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/woothemes/woocommerce/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/woothemes/woocommerce/git/refs{/sha}","trees_url":"https://api.github.com/repos/woothemes/woocommerce/git/trees{/sha}","statuses_url":"https://api.github.com/repos/woothemes/woocommerce/statuses/{sha}","languages_url":"https://api.github.com/repos/woothemes/woocommerce/languages","stargazers_url":"https://api.github.com/repos/woothemes/woocommerce/stargazers","contributors_url":"https://api.github.com/repos/woothemes/woocommerce/contributors","subscribers_url":"https://api.github.com/repos/woothemes/woocommerce/subscribers","subscription_url":"https://api.github.com/repos/woothemes/woocommerce/subscription","commits_url":"https://api.github.com/repos/woothemes/woocommerce/commits{/sha}","git_commits_url":"https://api.github.com/repos/woothemes/woocommerce/git/commits{/sha}","comments_url":"https://api.github.com/repos/woothemes/woocommerce/comments{/number}","issue_comment_url":"https://api.github.com/repos/woothemes/woocommerce/issues/comments{/number}","contents_url":"https://api.github.com/repos/woothemes/woocommerce/contents/{+path}","compare_url":"https://api.github.com/repos/woothemes/woocommerce/compare/{base}...{head}","merges_url":"https://api.github.com/repos/woothemes/woocommerce/merges","archive_url":"https://api.github.com/repos/woothemes/woocommerce/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/woothemes/woocommerce/downloads","issues_url":"https://api.github.com/repos/woothemes/woocommerce/issues{/number}","pulls_url":"https://api.github.com/repos/woothemes/woocommerce/pulls{/number}","milestones_url":"https://api.github.com/repos/woothemes/woocommerce/milestones{/number}","notifications_url":"https://api.github.com/repos/woothemes/woocommerce/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/woothemes/woocommerce/labels{/name}","releases_url":"https://api.github.com/repos/woothemes/woocommerce/releases{/id}","deployments_url":"https://api.github.com/repos/woothemes/woocommerce/deployments","created_at":"2011-08-09T15:12:11Z","updated_at":"2016-02-04T17:15:41Z","pushed_at":"2016-02-04T20:46:04Z","git_url":"git://github.com/woothemes/woocommerce.git","ssh_url":"git@github.com:woothemes/woocommerce.git","clone_url":"https://github.com/woothemes/woocommerce.git","svn_url":"https://github.com/woothemes/woocommerce","homepage":"http://www.woothemes.com/woocommerce/","size":115217,"stargazers_count":2530,"watchers_count":2530,"language":"PHP","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":2026,"mirror_url":null,"open_issues_count":60,"forks":2026,"open_issues":60,"watchers":2530,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/woothemes/woocommerce/pulls/10260"},"html":{"href":"https://github.com/woothemes/woocommerce/pull/10260"},"issue":{"href":"https://api.github.com/repos/woothemes/woocommerce/issues/10260"},"comments":{"href":"https://api.github.com/repos/woothemes/woocommerce/issues/10260/comments"},"review_comments":{"href":"https://api.github.com/repos/woothemes/woocommerce/pulls/10260/comments"},"review_comment":{"href":"https://api.github.com/repos/woothemes/woocommerce/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/woothemes/woocommerce/pulls/10260/commits"},"statuses":{"href":"https://api.github.com/repos/woothemes/woocommerce/statuses/0b90374ec4e4fa3328c1a8b7caa67e2a087dd84c"}}}}