wp-insider / simple-membership Goto Github PK
View Code? Open in Web Editor NEWGithub repository for the simple membership plugin
Github repository for the simple membership plugin
Hi,
I've been using Paypal in Sandbox mode in order to test the payments on my website before going live.
Things are working fine, in the sense that I have been able to pay and get an upgraded membership level.
But it looks like the Paypal API is doing multiple attempts (9 in total so far) to send the transaction notification to my website, and even if the transaction information payload is the same every time, the SWPM plugin keeps creating new transactions rows in the swpm_payments_tbl transaction table.
So it looks like the plugin is not made to be able to handle multiple identical payment confirmations API response from Paypal.
Maybe Paypal is expecting a specific type of answer, when doing the API response, that would tell Paypal that we have accepted the payment payload ?
I know that Paypal can try to "spam" remote websites to return the transaction response, or at least that's a behavior that I'm not surprised about from Paypal.
So I guess the fix has to be implemented on SWPM side, and it would make sense for the SWPM plugin to verify the content of the database before trying to save a new duplicated payment.
It's eventually possible that this problem is only happening in Sandbox mode, but I think it would be worth implementing a check to only insert new entry in the databases if the entry is not already present.
Here is the logs of the first API response I received from Paypal after doing the payment with my test user, and as we can see, it's updating the membership level of the user, so that's normal.
First API response from Paypal :
[2020/09/29 21:27:41] - SUCCESS: Paypal Class Initiated by 173.0.82.126
[2020/09/29 21:27:41] - SUCCESS: Post string : mc_gross=239.00&protection_eligibility=Eligible&payer_id=54HV6BCW3Z999&payment_date=12%3A27%3A06+Sep+29%2C+2020+PDT&payment_status=Completed&charset=UTF-8&first_name=John&mc_fee=8.48¬ify_version=3.9&custom=subsc_ref%253D14%2526user_ip%253D195.50.999.999%2526swpm_id%253D4&payer_status=verified&business=test-seller-987%40business.example.com&quantity=1&verify_sign=A16WiluyyUmHPN5zJ9aVEXVHLf.nAqBhusAvAtihZmZ2CJKZ9qfP6kdw&payer_email=test-buyer-123%40personal.example.com&txn_id=9176661881570324V&payment_type=instant&last_name=Doe&receiver_email=test-seller-987%40business.example.com&payment_fee=&shipping_discount=0.00&receiver_id=L77CH3CRDX999&insurance_amount=0.00&txn_type=web_accept&item_name=Acheter&discount=0.00&mc_currency=EUR&item_number=279&residence_country=EE&test_ipn=1&shipping_method=Default&transaction_subject=&payment_gross=&ipn_track_id=db55d4efe2e08&
[2020/09/29 21:27:41] - SUCCESS: Checking if PayPal IPN response is valid
[2020/09/29 21:27:41] - SUCCESS: Connecting to: https://www.sandbox.paypal.com/cgi-bin/webscr
[2020/09/29 21:27:44] - SUCCESS: IPN successfully verified.
[2020/09/29 21:27:44] - SUCCESS: Creating product Information to send.
[2020/09/29 21:27:44] - SUCCESS: Transaction Type: Buy Now/Subscribe
[2020/09/29 21:27:44] - SUCCESS: Item Number: 279
[2020/09/29 21:27:44] - SUCCESS: Item Name: Acheter
[2020/09/29 21:27:44] - SUCCESS: Item Quantity: 1
[2020/09/29 21:27:44] - SUCCESS: Item Total: 239.00
[2020/09/29 21:27:44] - SUCCESS: Item Currency: EUR
[2020/09/29 21:27:44] - SUCCESS: Membership payment paid for membership level ID: 14
[2020/09/29 21:27:44] - SUCCESS: Transaction type: web_accept. Creating member account...
[2020/09/29 21:27:44] - SUCCESS: swpm_handle_subsc_signup_stand_alone(). Custom value: subsc_ref=14&user_ip=195.50.999.999&swpm_id=4, Unique reference: 9176661881570324V
[2020/09/29 21:27:44] - SUCCESS: Modifying the existing membership profile... Member ID: 4
[2020/09/29 21:27:44] - SUCCESS: Setting access starts date value to: 2020-09-29
[2020/09/29 21:27:44] - SUCCESS: Updating the current membership level (13) of this member to the newly paid level (14)
[2020/09/29 21:27:44] - SUCCESS: swpm_membership_level_changed action triggered. Member ID: 4, Old Level: 13, New Level: 14
[2020/09/29 21:27:44] - SUCCESS: Retrieving user record for member ID: 4
[2020/09/29 21:27:44] - SUCCESS: Calling user role update function.
[2020/09/29 21:27:44] - SUCCESS: User role updated.
[2020/09/29 21:27:47] - SUCCESS: Member upgrade/update completion email successfully sent to: [email protected]
[2020/09/29 21:27:47] - SUCCESS: Saving transaction data to the database table.
And then I have received 8 other API responses, that are all identical, except that they are coming with 40 seconds interval approximately. And since the membership level is already set correctly, it's not doing much (but it's still adding a new transaction in the swpm_payments_tbl table).
Here are 2 of the API response I received (I will not copy/paste all of them, since they are identical) :
[2020/09/29 21:27:51] - SUCCESS: Paypal Class Initiated by 173.0.82.126
[2020/09/29 21:27:51] - SUCCESS: Post string : mc_gross=239.00&protection_eligibility=Eligible&payer_id=54HV6BCW3Z999&payment_date=12%3A27%3A06+Sep+29%2C+2020+PDT&payment_status=Completed&charset=UTF-8&first_name=John&mc_fee=8.48¬ify_version=3.9&custom=subsc_ref%253D14%2526user_ip%253D195.50.999.999%2526swpm_id%253D4&payer_status=verified&business=test-seller-987%40business.example.com&quantity=1&verify_sign=A16WiluyyUmHPN5zJ9aVEXVHLf.nAqBhusAvAtihZmZ2CJKZ9qfP6kdw&payer_email=test-buyer-123%40personal.example.com&txn_id=9176661881570324V&payment_type=instant&last_name=Doe&receiver_email=test-seller-987%40business.example.com&payment_fee=&shipping_discount=0.00&receiver_id=L77CH3CRDX999&insurance_amount=0.00&txn_type=web_accept&item_name=Acheter&discount=0.00&mc_currency=EUR&item_number=279&residence_country=EE&test_ipn=1&shipping_method=Default&transaction_subject=&payment_gross=&ipn_track_id=db55d4efe2e08&
[2020/09/29 21:27:51] - SUCCESS: Checking if PayPal IPN response is valid
[2020/09/29 21:27:51] - SUCCESS: Connecting to: https://www.sandbox.paypal.com/cgi-bin/webscr
[2020/09/29 21:27:53] - SUCCESS: IPN successfully verified.
[2020/09/29 21:27:53] - SUCCESS: Creating product Information to send.
[2020/09/29 21:27:53] - SUCCESS: Transaction Type: Buy Now/Subscribe
[2020/09/29 21:27:53] - SUCCESS: Item Number: 279
[2020/09/29 21:27:53] - SUCCESS: Item Name: Acheter
[2020/09/29 21:27:53] - SUCCESS: Item Quantity: 1
[2020/09/29 21:27:53] - SUCCESS: Item Total: 239.00
[2020/09/29 21:27:53] - SUCCESS: Item Currency: EUR
[2020/09/29 21:27:53] - SUCCESS: Membership payment paid for membership level ID: 14
[2020/09/29 21:27:53] - SUCCESS: Transaction type: web_accept. Creating member account...
[2020/09/29 21:27:53] - SUCCESS: swpm_handle_subsc_signup_stand_alone(). Custom value: subsc_ref=14&user_ip=195.50.999.999&swpm_id=4, Unique reference: 9176661881570324V
[2020/09/29 21:27:53] - SUCCESS: Modifying the existing membership profile... Member ID: 4
[2020/09/29 21:27:53] - SUCCESS: Setting access starts date value to: 2020-09-29
[2020/09/29 21:27:53] - SUCCESS: Updating the current membership level (14) of this member to the newly paid level (14)
[2020/09/29 21:27:53] - SUCCESS: swpm_membership_level_changed action triggered. Member ID: 4, Old Level: 14, New Level: 14
[2020/09/29 21:27:53] - SUCCESS: The to (Level ID: 14) and from (Level ID: 14) values are the same. Nothing to do here.
[2020/09/29 21:27:53] - SUCCESS: Member upgrade/update completion email successfully sent to: [email protected]
[2020/09/29 21:27:53] - SUCCESS: Saving transaction data to the database table.
[2020/09/29 21:28:06] - SUCCESS: Paypal Class Initiated by 173.0.82.126
[2020/09/29 21:28:06] - SUCCESS: Post string : mc_gross=239.00&protection_eligibility=Eligible&payer_id=54HV6BCW3Z999&payment_date=12%3A27%3A06+Sep+29%2C+2020+PDT&payment_status=Completed&charset=UTF-8&first_name=John&mc_fee=8.48¬ify_version=3.9&custom=subsc_ref%253D14%2526user_ip%253D195.50.999.999%2526swpm_id%253D4&payer_status=verified&business=test-seller-987%40business.example.com&quantity=1&verify_sign=A16WiluyyUmHPN5zJ9aVEXVHLf.nAqBhusAvAtihZmZ2CJKZ9qfP6kdw&payer_email=test-buyer-123%40personal.example.com&txn_id=9176661881570324V&payment_type=instant&last_name=Doe&receiver_email=test-seller-987%40business.example.com&payment_fee=&shipping_discount=0.00&receiver_id=L77CH3CRDX999&insurance_amount=0.00&txn_type=web_accept&item_name=Acheter&discount=0.00&mc_currency=EUR&item_number=279&residence_country=EE&test_ipn=1&shipping_method=Default&transaction_subject=&payment_gross=&ipn_track_id=db55d4efe2e08&
[2020/09/29 21:28:06] - SUCCESS: Checking if PayPal IPN response is valid
[2020/09/29 21:28:06] - SUCCESS: Connecting to: https://www.sandbox.paypal.com/cgi-bin/webscr
[2020/09/29 21:28:08] - SUCCESS: IPN successfully verified.
[2020/09/29 21:28:08] - SUCCESS: Creating product Information to send.
[2020/09/29 21:28:08] - SUCCESS: Transaction Type: Buy Now/Subscribe
[2020/09/29 21:28:08] - SUCCESS: Item Number: 279
[2020/09/29 21:28:08] - SUCCESS: Item Name: Acheter
[2020/09/29 21:28:08] - SUCCESS: Item Quantity: 1
[2020/09/29 21:28:08] - SUCCESS: Item Total: 239.00
[2020/09/29 21:28:08] - SUCCESS: Item Currency: EUR
[2020/09/29 21:28:08] - SUCCESS: Membership payment paid for membership level ID: 14
[2020/09/29 21:28:08] - SUCCESS: Transaction type: web_accept. Creating member account...
[2020/09/29 21:28:08] - SUCCESS: swpm_handle_subsc_signup_stand_alone(). Custom value: subsc_ref=14&user_ip=195.50.999.999&swpm_id=4, Unique reference: 9176661881570324V
[2020/09/29 21:28:08] - SUCCESS: Modifying the existing membership profile... Member ID: 4
[2020/09/29 21:28:08] - SUCCESS: Setting access starts date value to: 2020-09-29
[2020/09/29 21:28:08] - SUCCESS: Updating the current membership level (14) of this member to the newly paid level (14)
[2020/09/29 21:28:08] - SUCCESS: swpm_membership_level_changed action triggered. Member ID: 4, Old Level: 14, New Level: 14
[2020/09/29 21:28:08] - SUCCESS: The to (Level ID: 14) and from (Level ID: 14) values are the same. Nothing to do here.
[2020/09/29 21:28:09] - SUCCESS: Member upgrade/update completion email successfully sent to: [email protected]
[2020/09/29 21:28:09] - SUCCESS: Saving transaction data to the database table.
And here is the output of the mysql table :
mysql wp_testwp04 -e "SELECT id,first_name,member_id,membership_level,txn_date,txn_id,payment_amount,gateway,status FROM wp_swpm_payments_tbl WHERE txn_id = '9176661881570324V'"
+----+------------+-----------+------------------+------------+-------------------+----------------+---------+-----------+
| id | first_name | member_id | membership_level | txn_date | txn_id | payment_amount | gateway | status |
+----+------------+-----------+------------------+------------+-------------------+----------------+---------+-----------+
| 34 | John | 4 | 14 | 2020-09-29 | 9176661881570324V | 239.00 | paypal | Completed |
| 35 | John | 4 | 14 | 2020-09-29 | 9176661881570324V | 239.00 | paypal | Completed |
| 36 | John | 4 | 14 | 2020-09-29 | 9176661881570324V | 239.00 | paypal | Completed |
| 37 | John | 4 | 14 | 2020-09-29 | 9176661881570324V | 239.00 | paypal | Completed |
| 38 | John | 4 | 14 | 2020-09-29 | 9176661881570324V | 239.00 | paypal | Completed |
| 40 | John | 4 | 14 | 2020-09-29 | 9176661881570324V | 239.00 | paypal | Completed |
| 41 | John | 4 | 14 | 2020-09-29 | 9176661881570324V | 239.00 | paypal | Completed |
| 42 | John | 4 | 14 | 2020-09-29 | 9176661881570324V | 239.00 | paypal | Completed |
| 43 | John | 4 | 14 | 2020-09-29 | 9176661881570324V | 239.00 | paypal | Completed |
+----+------------+-----------+------------------+------------+-------------------+----------------+---------+-----------+
What do you think is the correct way to handle this problem ?
Thanks
Thomas
Braintree payment form shows PayPal button which customer could click and proceed with payment via his\her PayPal account instead of entering credit card info. If the process goes this way, payment is failing with following error message:
Cannot 3D Secure a non-credit card payment instrument
Possible fix: detect which payment method is being used and do not try to do 3D Secure check on PayPal payment method.
WordPress: 6.4.3
Plugin: 4.4.2
After a successful login, the browser is redirected to a localhost
address.
The browser should be redirected to the actual site.
I think the problem happens because my instance is running inside a Docker image.
The following code for get_current_page_url
works. However, I don't know if I broke anything else:
public static function get_current_page_url() {
$pageURL = 'http';
if ( isset( $_SERVER['SCRIPT_URI'] ) && ! empty( $_SERVER['SCRIPT_URI'] ) ) {
$pageURL = $_SERVER['SCRIPT_URI'];
$pageURL = str_replace(':443', '', $pageURL);//remove any port number from the URL value (some hosts include the port number with this).
$pageURL = apply_filters( 'swpm_get_current_page_url_filter', $pageURL );
return $pageURL;
}
//Check if 'SERVER_NAME' is set. If not, try get the URL from WP.
if( !isset( $_SERVER['SERVER_NAME'] ) ) {
global $wp;
if( is_object( $wp ) && isset( $wp->request ) ){
//Try to get the URL from WP
$pageURL = home_url( add_query_arg( array(), $wp->request ) );
$pageURL = apply_filters( 'swpm_get_current_page_url_filter', $pageURL );
return $pageURL;
}
}
$pageURL = '';
$homeURL = home_url();
if ( isset( $_SERVER['SERVER_PORT'] ) && ( $_SERVER['SERVER_PORT'] != '80' ) && ( $_SERVER['SERVER_PORT'] != '443' ) ) {
$pageURL .= ltrim( $homeURL, '.*' ) . ':' . $_SERVER['SERVER_PORT'] . $_SERVER['REQUEST_URI'];
} else {
$pageURL .= ltrim( $homeURL, '.*' ) . $_SERVER['REQUEST_URI'];
}
//Clean any known port numbers from the URL (some hosts may include these port numbers).
$pageURL = str_replace(':8080', '', $pageURL);
//Trigger filter
$pageURL = apply_filters( 'swpm_get_current_page_url_filter', $pageURL );
return $pageURL;
}
Is there a simple possibility to save a timestamp with every change in subscriber data (membership level, address - we use the form builder plugin)? We need to create invoices for clients and thus would like to see where changes have occurred since the last invoice.
We would even be interested in paying for a solution.
Hello,
Can we have hooks firing before a member is added, edited or deleted?
for example:
before_member_added
before_member_edited
before_member_deleted
This way we can check and allow or prevent the process.
Thanks!
Hi,
I think I've discovered a bug with deleted users.
Basically, an user that is logged on its SWPM account can keep accessing the website even if it's account has been deleted.
I guess this bug is due to the presence of the cookie, that remains in the user's browser.
I believe the problem is with the function SwpmAuth::get_instance() -> is_logged_in
, that seems to keep returning true
even if the user doesn't have an account anymore, as long as the cookie remains valid in the browser.
I've been trying to investigate, but I've not been able to identify exactly which part of the code is responsible for this behavior.
For information, the official WordPress function is_user_logged_in
is detecting correctly that the user is not logged in anymore once the account got deleted. Only the SWPM is_logged_in
function seems not detecting it correctly.
Thomas
WP 5.3 introduced some changes related to date handling https://make.wordpress.org/core/2019/09/23/date-time-improvements-wp-5-3/
It's not recommended to use date_default_timezone_set()
function. Also one of the customers reports this function breaks functionality of other plugins https://wordpress.org/support/topic/wordpress-5-3-incompatibility/
It's being used in two files:
Since WP sets default timezone to UTC when it runs, it's safe to comment out all the lines in function except of $timestamp = strftime('%Y-%m-%dT%TZ');
This is related to "Use WordPress Timezone" setting of the plugin. When this option enabled, the code sets PHP default timezone to the one set in WP general settings. And this is what breaks the functionality of other plugins.
Will investigate this to find a proper solution.
Hello there,
Unless I'm missing something, custom email body using swpm_registration_complete_email_body
and swpm_email_registration_complete_body
will not pass by the text replacing mechanism, so any variables within them will not be replaced.
In this case, these lines should be moved to the top of the function in order to allow variable replacing.
Also, I do not really understand the point of this line since the same result can be achieved with the swpm_registration_complete_email_body
filter which is just above? Maybe just leave one of the two?
Thanks!
class.swpm_members prepare_items() exceeding available memory
Was retrieving every record in the join of swpm_members and swpm_membership. This is a heavy query being run twice and can exceed available memory when there are many members and category/page protections. Change to only retrieve the record count in the first query, and only retrieve the required columns in the second limited/paginated query.
PR with patch submitted
Hi,
I've just realized that the email address of the buyer was not forwarded correctly to Affiliates Manager.
The problem was in the SWPM Affiliate Manager Integration plugin.
In Affiliates Manager, the following function support to receive the buyer email :
# source/Tracking/RequestTracker.php, line 68 :
public function handleCheckoutWithRefKey( $purchaseLogId, $purchaseAmount, $strRefKey, $email = '') {
But in the SWPM Affiliates Manager Integration, only the 3 first parameters were provided :
# affiliatemgr-simple-membership-integration.php, line 60 :
$requestTracker->handleCheckoutWithRefKey( $purchaseLogId, $purchaseAmount, $strRefKey);
I've improved the code, so now the email address is forwarded to Affiliates Manager, and we can see the buyer email in the Admin Pages > Commissions page of Affiliates Manager.
You can see the changes here :
https://github.com/Th0masL/affiliates-manager-simple-membership-integration/compare/fix_missing_email
Feel free to add this change to the official SWPM Affiliate Manager Integration plugin code.
Have a good day.
Thomas
How to reproduce:
Activate Twentyseventeen theme.
Make sure after login redirection is turned off.
Try to register.
After submitting rego form, you'll see a blank page with no rego success msg.
This happens because after rego msg is wrapped into div with class "updated". Twentyseventeen theme has this in CSS:
.byline, .updated:not(.published) { display: none; }
...which makes the message invisible.
To solve this, class 'published' should be added, e.g. class="updated published".
Allow capturing of emails into specific MailChimp groups or segments within MailChimp lists.
https://www.php.net/manual/en/function.parse-str.php
All the occurenes https://github.com/wp-insider/simple-membership/search?q=parse_str&unscoped_q=parse_str should be replaced to something like following:
Before:
parse_str($ipn_data['custom']);
Should be replaced to:
$custom_vars=parse_str($ipn_data['custom']);
.. and should be handled properly in the code then. Example: parse_str() is producing $user_ip var. After the modification, var would become $custom_vars['user_ip'].
There is a typo in the German translation. I filed a PR some time ago, but the typo persists. It should read:
msgid "Type password here"
msgstr "Passwort hier eingeben"
Or is there a better way than a PR, to get this change into the official plugin?
I was wondering if it would be a good idea to add the [swpm_mini_login] strings to the following plugin?
https://wordpress.org/plugins/simple-membership-custom-messages/
What do you think? The reason why I am asking is because of the following forum post question.
Thank you
This hook doesn't work:
swpm_load_template_files
This filter can be used to override the template loading path. Useful if you are doing custom template.
Used like this:
function custom_swpm_load_template_files($template_files) {
$custom_template = get_stylesheet_directory() . '/simple-membership/add.php';
if (file_exists($custom_template)) {
$template_files['add.php'] = $custom_template;
}
return $template_files;
}
add_filter('swpm_load_template_files', 'custom_swpm_load_template_files');
That could be happening?
Thank you so much!
Hello there,
I have a SWPM setup with custom roles that can access it in order to manage users. Although I have set a level_0 capability to those roles, they can view and edit all users that are registered as SWPM users, including Administrators.
This means that the website can be easily taken over by changing an admin or other user's password and logging in.
Even if I override the edit form, a malicious user could probably manage to do that with a POST request.
Examining the code as well as I could, I don't think I have a way to handle this in a really secure way.
Is there anything that can be done?
Related: https://wordpress.org/support/topic/give-swpm-dashboard-access-to-custom-user-roles/
Hi,
I'm using SWPM with WP Affiliates Membership plugin (and with the add-on that allows to link those two plugins together).
I wanted to be able to use SWPM Partial Protection to show/restrict pages content based on the status of the WP Affiliate Membership account of the user.
Since I couldn't find the Github repository for SWPM Partial Protection plugin, I've created a repo in my Github account, based on the current ZIP content (v1.3), and I've applied the changes to a new branch.
I'm writing this post to suggest my changes as a PR to SWPM Partial Protection plugin.
Please follow this link to see the changes I made to SWPM Partial Protection to add support for WordPress Affiliates Manager.
https://github.com/Th0masL/swpm-partial-protection/compare/wpam_support
I've added the following 'visible_to' values :
And for a more precise filtering, also supports any of the official WPAM account status names, with 'wpam_' appended in the front :
Also, the 'visible_to' filter supports multiple values separated with '-', example : visible_to="wpam_active-wpam_applied-wpam_confirmed".
Feel free to apply this improvement to the Master branch of SWPM Partial Protection plugin, if you find them useful.
Thanks
Thomas
Language strings need to be translatable:
https://simple-membership-plugin.com/forums/topic/registration-form-language-bug/
Thanks for addressing the problem of plain text passwords being stored in the database.
However, I am not at all happy with the solution and I have explained it over on the forum.
A decryptable password in a database is a serious bug. Please reconsider your "solution" and release a new version, which fixes the bug.
Allow the "visible_to" parameter to have more than one account status.
Currently this works: [swpm_protected visible_to="expired"]
Should enhance it so the following can work too:
[swpm_protected visible_to="expired, inactive"]
Need to add an API option to create users like the following:
https://www.tipsandtricks-hq.com/wordpress-membership/api-creating-a-member-account-using-http-get-or-post-447
Update user here:
https://simple-membership-plugin.com/forums/topic/creatingupdating-smwp-user-accounts-remotely/
Hi,
I'm referring to the code located here.
Right now, I'm forced to return a space character which is a hack to satisfy the function's flow.
This code forces to return something for output. However, the output might have been done when using the hook, because some times it's not just HTML or it can be so complicated that enclosing everything within string quotes might be a hassle.
My proposal: Allow user to return true
, and check it with the ===
operator. So if $form === true then return. For example:
$form = apply_filters( 'swpm_admin_registration_form_override', '' );
if ( $form === true ) { return; } // Added line
if ( ! empty( $form ) ) {
echo $form;
return;
}
In our WordPress setup, I needed to reverse proxy the request to an internal IP address, e.g. 10.0.0.1.
I use the After Login Redirection Addon. This gets the value of its swpm_redirect_to
-Parameter from SwpmMiscUtils::get_current_page_url()
, which uses $_SERVER["SERVER_NAME"]
, which is 10.0.0.1. Thus, the redirect cannot work as that address is not accessible from the outside.
Could you switch the use of $_SERVER["SERVER_NAME"]
to $_SERVER["HTTP_HOST"]
instead?
I did a little research on possible downsides to such a switch. Amongst others, I found this interesting discussion on Stackoverflow.
In essence: $_SERVER["HTTP_HOST"]
solves my issue and I do not see any downsides to make this change in the code permanently.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.