├── LICENSE ├── README.md ├── inc ├── class-sb-woocommerce.php ├── class-wpapi-login.php └── class-wpapi-mods.php └── sb-app-integration.php /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Scott Bolinger 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WordPress App Integration 2 | 3 | This is a plugin to integrate WordPress with a mobile app or PWA. 4 | 5 | It was meant to go with this tutorial http://scottbolinger.com/ionic-wordpress-app/ but it does not have to be used with Ionic. 6 | 7 | ## Usage 8 | 9 | Download this repository, and then upload it to your WordPress wp-content/plugins directory. You can also zip the file and upload it through Plugins => Add new in your wp-admin. 10 | 11 | Activate the plugin. 12 | 13 | ## WP-API Login 14 | 15 | This plugin adds an endpoint to the WP-API to allow a simple verification of a WordPress user. It is meant as a simple login for a mobile app, it is not secure enough to replace oAuth or any other existing protocol. 16 | 17 | Once the plugin is activated, you can make a POST request to https://mysite.com/wp-json/app/v1/login 18 | 19 | Include the following: 20 | 21 | - `$_POST['security']` is the security phrase 22 | - `$_POST['logout']` if set to "true" it will log the user out 23 | - `$_POST['username']` or `$_SERVER['PHP_AUTH_USER']` (not all servers accept authentication headers) 24 | - `$_POST['password']` or `$_SERVER['PHP_AUTH_PW']` (not all servers accept authentication headers) 25 | 26 | **Be sure to change the security passphrase in class-wpapi-login.php, preferably a hash of some sort.** 27 | 28 | If a valid username, password, and security phrase is sent, a json success message will be returned that you can use in your app: 29 | 30 | $return = array( 31 | 'message' => 'The log in you have entered is not valid.', 32 | 'signon' => $info['user_login'], 33 | 'line' => __LINE__, 34 | 'success' => false 35 | ); 36 | 37 | ## WP-API Mods 38 | 39 | This plugin also adds featured image urls to the post response to make it easier to display features images in post lists. The field added is featured_image_urls, with all available urls for each image size returned. -------------------------------------------------------------------------------- /inc/class-sb-woocommerce.php: -------------------------------------------------------------------------------- 1 | hooks(); 19 | } 20 | 21 | return self::$instance; 22 | } 23 | 24 | public function hooks() { 25 | 26 | // Props https://wordpress.org/plugins/wc-rest-payment/ 27 | add_action( 'rest_api_init', array( $this, 'wc_rest_payment_endpoints' ) ); 28 | } 29 | 30 | public function wc_rest_payment_endpoints() { 31 | 32 | /** 33 | * Handle Payment Method request. 34 | */ 35 | register_rest_route( 'wc/v2', 'stripe-payment', array( 36 | 'methods' => 'POST', 37 | 'callback' => array( $this, 'wc_rest_payment_endpoint_handler' ), 38 | ) ); 39 | 40 | } 41 | 42 | public function wc_rest_payment_endpoint_handler( $request = null ) { 43 | 44 | $response = array(); 45 | $parameters = $request->get_params(); 46 | $payment_method = sanitize_text_field( $parameters['payment_method'] ); 47 | $order_id = sanitize_text_field( $parameters['order_id'] ); 48 | $payment_token = sanitize_text_field( $parameters['payment_token'] ); 49 | $error = new WP_Error(); 50 | 51 | if ( empty( $payment_method ) ) { 52 | $error->add( 400, __( "Payment Method 'payment_method' is required.", 'wc-rest-payment' ), array( 'status' => 400 ) ); 53 | return $error; 54 | } 55 | if ( empty( $order_id ) ) { 56 | $error->add( 401, __( "Order ID 'order_id' is required.", 'wc-rest-payment' ), array( 'status' => 400 ) ); 57 | return $error; 58 | } else if ( wc_get_order($order_id) == false ) { 59 | $error->add( 402, __( "Order ID 'order_id' is invalid. Order does not exist.", 'wc-rest-payment' ), array( 'status' => 400 ) ); 60 | return $error; 61 | } else if ( wc_get_order($order_id)->get_status() !== 'pending' ) { 62 | $error->add( 403, __( "Order status is NOT 'pending', meaning order had already received payment. Multiple payment to the same order is not allowed. ", 'wc-rest-payment' ), array( 'status' => 400 ) ); 63 | return $error; 64 | } 65 | if ( empty( $payment_token ) ) { 66 | $error->add( 404, __( "Payment Token 'payment_token' is required.", 'wc-rest-payment' ), array( 'status' => 400 ) ); 67 | return $error; 68 | } 69 | 70 | if ( $payment_method === "stripe" ) { 71 | $wc_gateway_stripe = new WC_Gateway_Stripe(); 72 | $_POST['stripe_token'] = $payment_token; 73 | $payment_result = $wc_gateway_stripe->process_payment( $order_id ); 74 | if ( $payment_result['result'] === "success" ) { 75 | $response['code'] = 200; 76 | $response['message'] = __( "Your Payment was Successful", "wc-rest-payment" ); 77 | 78 | $order = wc_get_order( $order_id ); 79 | 80 | // set order to completed 81 | if( $order->get_status() == 'processing' ) { 82 | $order->update_status( 'completed' ); 83 | } 84 | 85 | } else { 86 | return new WP_REST_Response( array("c"), 123 ); 87 | $response['code'] = 401; 88 | $response['message'] = __( "Please enter valid card details", "wc-rest-payment" ); 89 | } 90 | } else { 91 | $response['code'] = 405; 92 | $response['message'] = __( "Please select an available payment method. Supported payment method can be found at https://wordpress.org/plugins/wc-rest-payment/#description", "wc-rest-payment" ); 93 | } 94 | 95 | return new WP_REST_Response( $response, 123 ); 96 | } 97 | 98 | } 99 | 100 | $SB_WooCommerce = new SB_WooCommerce(); 101 | $SB_WooCommerce->instance(); 102 | 103 | } // End if class_exists check -------------------------------------------------------------------------------- /inc/class-wpapi-login.php: -------------------------------------------------------------------------------- 1 | hooks(); 16 | } 17 | 18 | return self::$instance; 19 | } 20 | 21 | public function hooks() { 22 | 23 | add_action( 'rest_api_init', array( $this, 'login_endpoint' ) ); 24 | } 25 | 26 | public function login_endpoint() { 27 | 28 | register_rest_route( 'app/v1', '/login', array( 29 | 'methods' => 'POST', 30 | 'callback' => array( $this, 'app_login' ), 31 | ) ); 32 | 33 | } 34 | 35 | /** 36 | * Login 37 | */ 38 | public function app_login() { 39 | 40 | @header( 'Access-Control-Allow-Origin: *' ); 41 | 42 | // TODO: you should probably make this a token and verify using a hash 43 | if( empty( $_POST['security'] ) || $_POST['security'] != 'my-secure-phrase' ) { 44 | wp_send_json_error( array( 45 | 'message' => 'You are not allowed to do that.' ) ); 46 | } 47 | 48 | if( isset( $_POST['logout'] ) && $_POST['logout'] == "true" ) { 49 | wp_logout(); 50 | 51 | wp_send_json_success( array( 'message' => 'Successfully logged out.', 'logout' => true ) ); 52 | } 53 | 54 | $info = array(); 55 | 56 | // this handles auth headers if you want, but not all servers support them 57 | $info['user_login'] = ( $_POST['username'] ? $_POST['username'] : $_SERVER['PHP_AUTH_USER'] ); 58 | $info['user_password'] = ( $_POST['password'] ? $_POST['password'] : $_SERVER['PHP_AUTH_PW'] ); 59 | 60 | $info['remember'] = true; 61 | 62 | $user_signon = wp_signon( $info, false ); 63 | 64 | if( is_wp_error( $user_signon ) ) { 65 | 66 | $return = array( 67 | 'message' => 'The log in you have entered is not valid.', 68 | 'signon' => $info['user_login'], 69 | 'line' => __LINE__, 70 | 'success' => false 71 | ); 72 | wp_send_json_error( $return ); 73 | 74 | } else { 75 | 76 | $return = array( 77 | 'message' => 'Login successful!', 78 | 'username' => $info['user_login'], 79 | 'success' => true 80 | ); 81 | 82 | wp_send_json_success( $return ); 83 | 84 | } 85 | } 86 | 87 | /** 88 | * Logout, used via postmessage in AP3 apps 89 | * @since 3.0.2 90 | */ 91 | public function app_logout() { 92 | 93 | @header( 'Access-Control-Allow-Origin: *' ); 94 | 95 | wp_logout(); 96 | 97 | $response = array( 98 | 'message' => __('Logout success.', 'apppresser') 99 | ); 100 | 101 | $redirect = $this->get_logout_redirect(); 102 | if($redirect) { 103 | $response['logout_redirect'] = $redirect; 104 | } 105 | 106 | wp_send_json_success( $response ); 107 | 108 | } 109 | 110 | } 111 | 112 | $SB_App_Login = new SB_App_Login(); 113 | $SB_App_Login->instance(); 114 | 115 | } // End if class_exists check -------------------------------------------------------------------------------- /inc/class-wpapi-mods.php: -------------------------------------------------------------------------------- 1 | hooks(); 16 | } 17 | 18 | return self::$instance; 19 | } 20 | 21 | public function hooks() { 22 | 23 | add_action( 'rest_api_init', array( $this, 'add_featured_urls' ) ); 24 | } 25 | 26 | /*** 27 | * Add featured image urls to post response. 28 | * Sample usage in the app files would be data.featured_image_urls.thumbnail 29 | ***/ 30 | public function add_featured_urls() { 31 | register_rest_field( 'post', 32 | 'featured_image_urls', 33 | array( 34 | 'get_callback' => array( $this, 'image_sizes' ), 35 | 'update_callback' => null, 36 | 'schema' => null, 37 | ) 38 | ); 39 | } 40 | 41 | public function image_sizes( $post ) { 42 | 43 | $featured_id = get_post_thumbnail_id( $post['id'] ); 44 | 45 | $sizes = wp_get_attachment_metadata( $featured_id ); 46 | 47 | $size_data = new stdClass(); 48 | 49 | if ( ! empty( $sizes['sizes'] ) ) { 50 | 51 | foreach ( $sizes['sizes'] as $key => $size ) { 52 | // Use the same method image_downsize() does 53 | $image_src = wp_get_attachment_image_src( $featured_id, $key ); 54 | 55 | if ( ! $image_src ) { 56 | continue; 57 | } 58 | 59 | $size_data->$key = $image_src[0]; 60 | 61 | } 62 | 63 | } 64 | 65 | return $size_data; 66 | 67 | } 68 | 69 | } 70 | 71 | $SB_WPAPI_Mods = new SB_WPAPI_Mods(); 72 | $SB_WPAPI_Mods->instance(); 73 | 74 | } // End if class_exists check -------------------------------------------------------------------------------- /sb-app-integration.php: -------------------------------------------------------------------------------- 1 | includes(); 29 | } 30 | 31 | return self::$instance; 32 | } 33 | 34 | /** 35 | * Include necessary files 36 | * 37 | * @access private 38 | * @since 0.1.0 39 | * @return void 40 | */ 41 | private function includes() { 42 | 43 | require_once plugin_dir_path( __FILE__ ) . 'inc/class-wpapi-login.php'; 44 | 45 | require_once plugin_dir_path( __FILE__ ) . 'inc/class-wpapi-mods.php'; 46 | 47 | require_once plugin_dir_path( __FILE__ ) . 'inc/class-sb-woocommerce.php'; 48 | 49 | } 50 | 51 | } 52 | } // End if class_exists check 53 | 54 | 55 | /** 56 | * The main function responsible for returning the instance 57 | * 58 | * @since 0.1.0 59 | * @return SB_App_Integration::instance() 60 | * 61 | */ 62 | function sb_app_integration_load() { 63 | return SB_App_Integration::instance(); 64 | } 65 | add_action( 'plugins_loaded', 'sb_app_integration_load' ); --------------------------------------------------------------------------------