├── log.txt ├── .gitignore ├── libs └── parse.com-php-library │ ├── parseGeoPoint.php │ ├── parseConfig.php │ ├── parseFile.php │ ├── parseACL.php │ ├── parseObject.php │ ├── parsePush.php │ ├── parseUser.php │ ├── parse.php │ └── parseQuery.php ├── includes ├── class-wp-parse-api-admin-settings.php ├── class-wp-parse-api-helpers.php └── class-wp-parse-api-admin-settings-template.php ├── wp-parse-api.php └── Readme.md /log.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | log 2 | -------------------------------------------------------------------------------- /libs/parse.com-php-library/parseGeoPoint.php: -------------------------------------------------------------------------------- 1 | lat = $lat; 11 | $this->long = $long; 12 | $this->location = $this->dataType('geopoint', array($this->lat, $this->long)); 13 | } 14 | 15 | public function __toString(){ 16 | return json_encode($this->location); 17 | 18 | } 19 | 20 | public function get(){ 21 | return json_encode($this->location); 22 | 23 | } 24 | 25 | } 26 | 27 | ?> 28 | -------------------------------------------------------------------------------- /libs/parse.com-php-library/parseConfig.php: -------------------------------------------------------------------------------- 1 | _contentType = $contentType; 11 | $this->data = $data; 12 | } 13 | 14 | parent::__construct(); 15 | 16 | } 17 | 18 | public function save($fileName){ 19 | if($fileName != '' && $this->_contentType != '' && $this->data != ''){ 20 | $request = $this->request(array( 21 | 'method' => 'POST', 22 | 'requestUrl' => 'files/'.$fileName, 23 | 'contentType' => $this->_contentType, 24 | 'data' => $this->data, 25 | )); 26 | return $request; 27 | } 28 | else{ 29 | $this->throwError('Please make sure you are passing a proper filename as string (e.g. hello.txt)'); 30 | } 31 | } 32 | 33 | public function delete($parseFileName){ 34 | if($parseFileName != ''){ 35 | $request = $this->request(array( 36 | 'method' => 'DELETE', 37 | 'requestUrl' => 'files/'.$parseFileName, 38 | 'contentType' => $this->_contentType, 39 | )); 40 | return $request; 41 | 42 | } 43 | } 44 | 45 | 46 | 47 | } 48 | 49 | ?> -------------------------------------------------------------------------------- /libs/parse.com-php-library/parseACL.php: -------------------------------------------------------------------------------- 1 | __set('hello','world'); 6 | 7 | // This instantiates a ACL object with NO rights! 8 | $acl = new parseACL(); 9 | $acl->setPublicReadAccess(false); 10 | $acl->setReadAccessForId('user_id',true); 11 | $acl->setWriteAccessForRole('role_name',true); 12 | 13 | $object->ACL($acl); 14 | $object->save(); 15 | */ 16 | class parseACL{ 17 | public $acl; 18 | public function __construct(){ 19 | $this->acl = new stdClass(); 20 | } 21 | private function setAccessForKey($access,$key,$bool){ 22 | if(!($access == 'read' || $access == 'write')) return; 23 | if(is_object($this->acl)) $this->acl = array(); 24 | if($bool) $this->acl[$key][$access] = true; 25 | else { 26 | if(isset($this->acl[$key])){ 27 | unset($this->acl[$key][$access]); 28 | if(sizeof($this->acl[$key]) == 0) unset($this->acl[$key]); 29 | } 30 | if(sizeof($this->acl) == 0) $this->acl = new stdClass(); 31 | } 32 | } 33 | public function setPublicReadAccess($bool){ 34 | $this->setAccessForKey('read','*',$bool); 35 | } 36 | public function setPublicWriteAccess($bool){ 37 | $this->setAccessForKey('write','*',$bool); 38 | } 39 | public function setReadAccessForId($userId,$bool){ 40 | $this->setAccessForKey('read',$userId,$bool); 41 | } 42 | public function setWriteAccessForId($userId,$bool){ 43 | $this->setAccessForKey('write',$userId,$bool); 44 | } 45 | public function setReadAccessForRole($role,$bool){ 46 | $this->setAccessForKey('read','role:'.$role,$bool); 47 | } 48 | public function setWriteAccessForRole($role,$bool){ 49 | $this->setAccessForKey('write','role:'.$role,$bool); 50 | } 51 | } 52 | ?> -------------------------------------------------------------------------------- /libs/parse.com-php-library/parseObject.php: -------------------------------------------------------------------------------- 1 | _className = $class; 10 | } 11 | else{ 12 | $this->throwError('include the className when creating a parseObject'); 13 | } 14 | 15 | parent::__construct(); 16 | } 17 | 18 | public function __set($name,$value){ 19 | if($name != '_className'){ 20 | $this->data[$name] = $value; 21 | } 22 | } 23 | 24 | public function save(){ 25 | if(count($this->data) > 0 && $this->_className != ''){ 26 | $request = $this->request(array( 27 | 'method' => 'POST', 28 | 'requestUrl' => 'classes/'.$this->_className, 29 | 'data' => $this->data, 30 | )); 31 | return $request; 32 | } 33 | } 34 | 35 | public function get($id){ 36 | if($this->_className != '' || !empty($id)){ 37 | $request = $this->request(array( 38 | 'method' => 'GET', 39 | 'requestUrl' => 'classes/'.$this->_className.'/'.$id 40 | )); 41 | 42 | if(!empty($this->_includes)){ 43 | $request['include'] = implode(',', $this->_includes); 44 | } 45 | 46 | return $request; 47 | } 48 | } 49 | 50 | public function update($id){ 51 | if($this->_className != '' || !empty($id)){ 52 | $request = $this->request(array( 53 | 'method' => 'PUT', 54 | 'requestUrl' => 'classes/'.$this->_className.'/'.$id, 55 | 'data' => $this->data, 56 | )); 57 | 58 | return $request; 59 | } 60 | } 61 | 62 | public function increment($field,$amount){ 63 | $this->data[$field] = $this->dataType('increment', $amount); 64 | } 65 | 66 | public function decrement($id){ 67 | $this->data[$field] = $this->dataType('decrement', $amount); 68 | } 69 | 70 | 71 | public function delete($id){ 72 | if($this->_className != '' || !empty($id)){ 73 | $request = $this->request(array( 74 | 'method' => 'DELETE', 75 | 'requestUrl' => 'classes/'.$this->_className.'/'.$id 76 | )); 77 | 78 | return $request; 79 | } 80 | } 81 | 82 | public function addInclude($name){ 83 | $this->_includes[] = $name; 84 | } 85 | } 86 | 87 | ?> -------------------------------------------------------------------------------- /libs/parse.com-php-library/parsePush.php: -------------------------------------------------------------------------------- 1 | _globalMsg = $globalMsg; 18 | } 19 | 20 | parent::__construct(); 21 | 22 | } 23 | 24 | public function __set($name,$value){ 25 | if($name != 'channel' || $name != 'channels' || $name != 'expiration_time' || $name != 'expiration_interval' || $name != 'type' || $name != 'data'){ 26 | $this->data[$name] = $value; 27 | } 28 | } 29 | 30 | public function send(){ 31 | if($this->_globalMsg != ''){ 32 | $request = $this->request(array( 33 | 'method' => 'POST', 34 | 'requestUrl' => 'push', 35 | 'data' => array( 36 | 'channel' => '', 37 | 'data' => array( 38 | 'alert' => $this->_globalMsg 39 | ) 40 | ), 41 | )); 42 | return $request; 43 | 44 | } 45 | else{ 46 | if(count($this->data) > 0){ 47 | if($this->channel == '' && empty($this->channels)){ 48 | $this->throwError('No push channel has been set'); 49 | } 50 | $params = array( 51 | 'method' => 'POST', 52 | 'requestUrl' => 'push', 53 | 'data' => array( 54 | 'data' => $this->data 55 | ) 56 | ); 57 | 58 | if(!empty($this->channels)){ 59 | $params['data']['channels'] = $this->channels; 60 | } 61 | if(!empty($this->channel)){ 62 | $params['data']['channel'] = $this->channel; 63 | } 64 | if(!empty($this->expiration_time)){ 65 | $params['data']['expiration_time'] = $this->expiration_time; 66 | } 67 | if(!empty($this->expiration_time_interval)){ 68 | $params['data']['expiration_interval'] = $this->expiration_interval; 69 | } 70 | if(!empty($this->content_available)){ 71 | //changed back to content-available... underscores are much easier to deal with in PHP 72 | $params['data']['content-available'] = $this->content_available; 73 | } 74 | if(!empty($this->type)){ 75 | $params['data']['type'] = $this->type; 76 | } 77 | 78 | $request = $this->request($params); 79 | return $request; 80 | 81 | } 82 | else{ 83 | $this->throwError('No push data has been set, you must set at least data. Please see the docs. '); 84 | } 85 | } 86 | } 87 | } 88 | 89 | ?> -------------------------------------------------------------------------------- /includes/class-wp-parse-api-admin-settings.php: -------------------------------------------------------------------------------- 1 | $numberposts, 36 | 'offset' => ($_GET['wp-parse-api-page'] * $numberposts) - $numberposts, 37 | ); 38 | 39 | $wp_posts = get_posts($options); 40 | 41 | if (count($wp_posts) == 0) { 42 | wp_redirect( 'options-general.php?page=wp-parse-api-options' ); 43 | exit; 44 | } 45 | 46 | foreach ($wp_posts as $wp) { 47 | if ($wp->post_status != 'publish') continue; 48 | 49 | $post = WpParseApiHelpers::postToObject($wp->ID); 50 | $q = new parseQuery(WP_PARSE_API_OBJECT_NAME); 51 | $q->whereEqualTo('wpId', $wp->ID); 52 | $q->setLimit(1); 53 | $result = $q->find(); 54 | 55 | if ($result->results[0]) { 56 | $post->update($result->results[0]->objectId); 57 | } else { 58 | $post->save(); 59 | } 60 | } 61 | 62 | ++$_GET['wp-parse-api-page']; 63 | $url = $_SERVER['PHP_SELF']; 64 | 65 | foreach ($_GET as $k=>$v): 66 | $qs = (strpos($url, '?') === false ? '?' : '&'); 67 | $url .= sprintf("%s%s=%s", $qs, $k, $v); 68 | endforeach; 69 | 70 | //wp_redirect( $url ); 71 | echo "Page:". ($_GET['wp-parse-api-page']-1) .""; 72 | exit; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /includes/class-wp-parse-api-helpers.php: -------------------------------------------------------------------------------- 1 | array(), // Default 6 | 'es' => array( 7 | 'Jan' => 'Ene', 8 | 'Apr' => 'Abr', 9 | 'Aug' => 'Ago', 10 | 'Dec' => 'Dic' 11 | ) 12 | ); 13 | 14 | static public function postToObject($post_id) { 15 | // Get the post 16 | $wp_post = get_post($post_id); 17 | // Init the parse object 18 | $post = new parseObject(WP_PARSE_API_OBJECT_NAME); 19 | // Get the categories 20 | $_categories = get_the_category($post_id); 21 | 22 | // Initializing vars 23 | $categories = array(); 24 | $photos = array(); 25 | $videos = array(); 26 | 27 | // Add the categories 28 | foreach ($_categories as $row) { 29 | $categories[] = $row->name; 30 | } 31 | 32 | // Set the date in spanish format 33 | $keys = array_keys(self::$lang); 34 | $lang = self::$lang[in_array(get_option('lang'), $keys) ? get_option('lang') : $keys[0]]; 35 | $date = strtr(date("d/M/Y", strtotime($wp_post->post_date)), $lang); 36 | 37 | // Add the thumbnails 38 | $thumbnails = array( 39 | 'thumbnail' => wp_get_attachment_image_src( get_post_thumbnail_id( $post_id ), 'thumbnail' ), 40 | 'medium' => wp_get_attachment_image_src( get_post_thumbnail_id( $post_id ), 'medium' ), 41 | 'large' => wp_get_attachment_image_src( get_post_thumbnail_id( $post_id ), 'large' ), 42 | 'full' => wp_get_attachment_image_src( get_post_thumbnail_id( $post_id ), 'full' ) 43 | ); 44 | 45 | foreach ($thumbnails as $k=>$v): 46 | if (!is_array($v)) unset($thumbnails[$k]); 47 | else $thumbnails[$k] = array_shift($v); 48 | endforeach; 49 | 50 | if (count($thumbnails) == 0) $thumbnails = new stdClass(); 51 | 52 | // Extract the photos from the content 53 | preg_match_all('/]+src=[\'"]([^\'"]+)[\'"].*>/i', $wp_post->post_content, $photos); 54 | 55 | // Extract the youtube video id's from the content 56 | $urls = array('#http://www.youtube.com/embed/([A-Za-z0-9\-_]+)#s', '#http://www.youtube.com/watch?v=([A-Za-z0-9\-_]+)#s'); 57 | 58 | foreach ($urls as $url) : 59 | $tmp = array(); 60 | preg_match_all($url, $wp_post->post_content, $tmp); 61 | foreach ($tmp[1] as $v) : 62 | if (!in_array($v, $videos)) $videos[] = $v; 63 | endforeach; 64 | endforeach; 65 | 66 | // Remove unwanted strings from contents 67 | $content = preg_replace('/\[.*?\](.+?)\[\/.*?\]/is', '', $wp_post->post_content); 68 | $content = strtr($content, array('

 

'=>'')); 69 | // $content = strip_tags($content, "


  • "); 70 | $content = explode('', $content); 71 | $content[0] = strip_tags($content[0]); 72 | $content = implode('', $content); 73 | 74 | // Set the post properties 75 | $post->categories = $categories; 76 | $post->content = $content; 77 | $post->date = $date; 78 | $post->guid = $wp_post->guid; 79 | $post->photos = $photos[1]; 80 | $post->thumbnail = $thumbnails; 81 | $post->title = $wp_post->post_title; 82 | $post->videos = $videos; 83 | $post->wpId = (int)$post_id; 84 | 85 | // Return the post 86 | return $post; 87 | } 88 | 89 | public static function log($message) { 90 | if (!defined('LOG')) return; 91 | file_put_contents(LOG, "{$message}\n", FILE_APPEND); 92 | } 93 | } -------------------------------------------------------------------------------- /includes/class-wp-parse-api-admin-settings-template.php: -------------------------------------------------------------------------------- 1 | 8 |
    9 |

    10 |

    Parse Api

    11 | 12 |

    Register your app on parse.com then complete this form with the information about your app.

    13 | 14 |
    15 | 16 | 17 | 18 |

    Settings

    19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 47 | 48 | 49 | 50 | 58 | 59 |
    App ID
    App Masterkey
    App Rest Key
    App URL (https://<yoururl>/<yourendpoint>)
    Push notifications 40 | 46 |
    Select date language 51 | 57 |
    60 | 61 |

    Parse Object

    62 | 63 |

    64 | Also you need to create a class in the Data Browser with a name you like or create an class named same as the Object Name (i.e. Post), 65 | with those fields: 66 |

    67 | 68 |

    69 |

      70 |
    • - categories (Array)
    • 71 |
    • - content (String)
    • 72 |
    • - date (String)
    • 73 |
    • - guid (String)
    • 74 |
    • - photos (Array)
    • 75 |
    • - thumbnail (Object)
    • 76 |
    • - title (String)
    • 77 |
    • - wpId (Number)
    • 78 |
    79 |

    80 | 81 | 82 | 83 | 84 | 87 | 88 |
    Object Name* 85 | "> 86 |
    89 | 90 | 91 | 92 |

    * if null object name Post will be used.

    93 | 94 | 95 |
    96 |

    Sync

    97 | 98 |

    If you have old post that you want to upload into your parse app, then use this button.

    99 | 100 | 101 | 102 | 103 |
    104 |
    105 | -------------------------------------------------------------------------------- /libs/parse.com-php-library/parseUser.php: -------------------------------------------------------------------------------- 1 | data[$name] = $value; 8 | } 9 | 10 | public function signup($username='',$password=''){ 11 | if($username != '' && $password != ''){ 12 | $this->username = $username; 13 | $this->password = $password; 14 | } 15 | 16 | if($this->data['username'] != '' && $this->data['password'] != ''){ 17 | $request = $this->request(array( 18 | 'method' => 'POST', 19 | 'requestUrl' => 'users', 20 | 'data' => $this->data 21 | )); 22 | 23 | return $request; 24 | 25 | } 26 | else{ 27 | $this->throwError('username and password fields are required for the signup method'); 28 | } 29 | 30 | } 31 | 32 | public function login(){ 33 | if(!empty($this->data['username']) || !empty($this->data['password']) ){ 34 | $request = $this->request(array( 35 | 'method' => 'GET', 36 | 'requestUrl' => 'login', 37 | 'data' => array( 38 | 'password' => $this->data['password'], 39 | 'username' => $this->data['username'] 40 | ) 41 | )); 42 | 43 | return $request; 44 | 45 | } 46 | else{ 47 | $this->throwError('username and password field are required for the login method'); 48 | } 49 | 50 | } 51 | 52 | public function get($objectId){ 53 | if($objectId != ''){ 54 | $request = $this->request(array( 55 | 'method' => 'GET', 56 | 'requestUrl' => 'users/'.$objectId, 57 | )); 58 | 59 | return $request; 60 | 61 | } 62 | else{ 63 | $this->throwError('objectId is required for the get method'); 64 | } 65 | 66 | } 67 | //TODO: should make the parseUser contruct accept the objectId and update and delete would only require the sessionToken 68 | public function update($objectId,$sessionToken){ 69 | if(!empty($objectId) || !empty($sessionToken)){ 70 | $request = $this->request(array( 71 | 'method' => 'PUT', 72 | 'requestUrl' => 'users/'.$objectId, 73 | 'sessionToken' => $sessionToken, 74 | 'data' => $this->data 75 | )); 76 | 77 | return $request; 78 | } 79 | else{ 80 | $this->throwError('objectId and sessionToken are required for the update method'); 81 | } 82 | 83 | } 84 | 85 | public function delete($objectId,$sessionToken){ 86 | if(!empty($objectId) || !empty($sessionToken)){ 87 | $request = $this->request(array( 88 | 'method' => 'DELETE', 89 | 'requestUrl' => 'users/'.$objectId, 90 | 'sessionToken' => $sessionToken 91 | )); 92 | 93 | return $request; 94 | } 95 | else{ 96 | $this->throwError('objectId and sessionToken are required for the delete method'); 97 | } 98 | 99 | } 100 | 101 | public function addAuthData($authArray){ 102 | if(is_array($authArray)){ 103 | $this->authData[$authArray['type']] = $authArray['authData']; 104 | } 105 | else{ 106 | $this->throwError('authArray must be an array containing a type key and a authData key in the addAuthData method'); 107 | } 108 | } 109 | 110 | public function linkAccounts($objectId,$sessionToken){ 111 | if(!empty($objectId) || !empty($sessionToken)){ 112 | $request = $this->request( array( 113 | 'method' => 'PUT', 114 | 'requestUrl' => 'users/'.$objectId, 115 | 'sessionToken' => $sessionToken, 116 | 'data' => array( 117 | 'authData' => $this->authData 118 | ) 119 | )); 120 | 121 | return $request; 122 | } 123 | else{ 124 | $this->throwError('objectId and sessionToken are required for the linkAccounts method'); 125 | } 126 | } 127 | 128 | public function unlinkAccount($objectId,$sessionToken,$type){ 129 | $linkedAccount[$type] = null; 130 | 131 | if(!empty($objectId) || !empty($sessionToken)){ 132 | $request = $this->request( array( 133 | 'method' => 'PUT', 134 | 'requestUrl' => 'users/'.$objectId, 135 | 'sessionToken' => $sessionToken, 136 | 'data' => array( 137 | 'authData' => $linkedAccount 138 | ) 139 | )); 140 | 141 | return $request; 142 | } 143 | else{ 144 | $this->throwError('objectId and sessionToken are required for the linkAccounts method'); 145 | } 146 | 147 | } 148 | 149 | public function requestPasswordReset($email){ 150 | if(!empty($email)){ 151 | $this->email - $email; 152 | $request = $this->request(array( 153 | 'method' => 'POST', 154 | 'requestUrl' => 'requestPasswordReset', 155 | 'email' => $email, 156 | 'data' => $this->data 157 | )); 158 | 159 | return $request; 160 | } 161 | else{ 162 | $this->throwError('email is required for the requestPasswordReset method'); 163 | } 164 | 165 | } 166 | 167 | 168 | } 169 | 170 | ?> -------------------------------------------------------------------------------- /wp-parse-api.php: -------------------------------------------------------------------------------- 1 | option_name . '_nonce' ], $this->action)) return; 90 | // WpParseApiHelpers::log("WpParseApi::save_post($post_id) | nonce passed"); 91 | // Verify post status 92 | if (get_post_status($post_id) != 'publish') return; 93 | WpParseApiHelpers::log("WpParseApi::save_post($post_id) | status passed"); 94 | 95 | $post = WpParseApiHelpers::postToObject($post_id); 96 | 97 | // Creates a new post on parse.com 98 | if (!get_post_meta($post_id, 'wp_parse_api_code_run', true)) { 99 | update_post_meta($post_id, 'wp_parse_api_code_run', true); 100 | 101 | $categories = array(); 102 | 103 | foreach ($post->data['categories'] as $row) { 104 | $row = trim(preg_replace('/[^a-zA-Z]/', '', $row)); 105 | if ($row != '') $categories[] = $row; 106 | } 107 | 108 | // Check if there is no categories or push notifications are disabled 109 | if (is_array($categories) && count($categories) > 0 && get_option('app_push_notifications') != 'Off') { 110 | try { 111 | $push = new parsePush(); 112 | $push->alert = $post->data['title']; 113 | $push->channels = $categories; 114 | $push->badge = "increment"; 115 | $push->sound = "example.caf"; 116 | $push->post_id = $post->data[wpId]; 117 | $push->url = $post->data['guid']; 118 | $push->category = "ACTIONABLE"; 119 | $push->send(); } 120 | catch (Exception $e) { 121 | // do nothing, this was added because 122 | // parse lib throws an exception if the account 123 | // has not been configured 124 | // special thanks to raymondmuller for find the issue 125 | } 126 | } 127 | 128 | $post->save(); 129 | // Update an existin post on parse.com 130 | } else { 131 | $q = new parseQuery(WP_PARSE_API_OBJECT_NAME); 132 | $q->where('wpId', (int)$post_id); 133 | $r = $q->find(); 134 | 135 | if (is_array($r->results)) $r = array_shift($r->results); 136 | if ($r != null) $post->update($r->objectId); 137 | } 138 | 139 | WpParseApiHelpers::log("WpParseApi::save_post($post_id) | END"); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | ## Parse its shutting down their BaaS, but they open sourced it at [parse-server](https://github.com/ParsePlatform/parse-server), please consider this before try to use this plugin, b/c its not prepared for use outside parse, it can be used but need to point all the endpoints urls to your own parse server 2 | 3 | Also I'm not maintaining anymore this plugin, you can fork it and make your changes or submit al pullrequest 4 | 5 | # WordPress Parse Api 6 | 7 | [![Join the chat at https://gitter.im/norman784/wp-parse-api](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/norman784/wp-parse-api?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 8 | 9 | Bridge between [Parse](http://parse.com) api and [WordPress](http://wordpress.org) 10 | 11 | ## Description 12 | 13 | The goal of this plugin its to replicate all your posts to [Parse](http://parse.com) so you can easily 14 | develop mobile apps, because I find very useful their SDK and help us to develop 15 | apps faster without worring about the security or if someone else can read data from our blog 16 | and use it. 17 | 18 | ## Features 19 | 20 | * Post object saved (create/update) to [Parse](http://parse.com) 21 | * Push notifications when new post published 22 | * Turn on/off push notifications when new post published 23 | * Sync old post to [Parse](http://parse.com) 24 | * Plugin can be updated from github, thanks to [WordPress Github Plugin Updater](https://github.com/jkudish/WordPress-GitHub-Plugin-Updater) 25 | 26 | ## Installation 27 | 28 | 1. Create your account on [Parse](http://parse.com) 29 | 2. Create an app 30 | 3. Create an class in the data browser with those fields: 31 | * categories (Array) 32 | * content (String) 33 | * date (String) 34 | * guid (String) 35 | * photos (Array) 36 | * thumbnail (Object) 37 | * title (String) 38 | * videos (Array) 39 | * wpId (Number) 40 | 4. Upload `wp-parse-api` to the `/wp-content/plugins/` directory 41 | 5. Activate the plugin through the 'Plugins' menu in WordPress 42 | 6. Go to Settings -> Parse Api 43 | 7. Fill the form with the data from your Parse.com app dashboard 44 | 8. At this point it must be ready to use it 45 | 46 | ## Frequently Asked Questions 47 | 48 | ### Why Parse.com? 49 | 50 | Because I find there a well documented SDK's for the most popular mobile platforms. 51 | 52 | ### How it works? 53 | 54 | Configure the plugin under Settings -> Parse Api as describe in the instalation. 55 | Every time you publish or save a published post it will create/update their 56 | respective row on [Parse](http://parse.com) 57 | 58 | Then use the SDK of your prefered platform and start coding. 59 | 60 | ## TODO 61 | 62 | * Better way to handle synchronization (don't research so much if wp has a build in cronjob) 63 | * Prepare for submit into the wordpress plugin repository 64 | * Built a log event registry and visualization 65 | * Add test case files 66 | 67 | ## Changelog 68 | 69 | **0.5.1** 70 | * Check that the app url ends with `/`, if not we add it 71 | 72 | **0.5.0** 73 | * Added date internationalization support (English, Español) 74 | * Bug fixes 75 | 76 | **0.4.1** 77 | * Bug fixes 78 | 79 | **0.4** 80 | * Added support for youtube videos 81 | * Added some comments on the source code 82 | 83 | **0.3.1** 84 | * Fixed bug that send push notification if category is null or an empty string, seems that my previous fixes not work :( 85 | 86 | **0.3.0** 87 | * Added an option to turn on/off push notifications 88 | * Added github plugin updater 89 | 90 | **0.2.9** 91 | * Fix issue if no push certificate or valid push certificate was configured (thanks to raymondmuller) 92 | 93 | **0.2.8** 94 | * Small improvement, if categories are empty no push notification will be send 95 | 96 | **0.2.7** 97 | * Fix push notifications, now it get the categories from the post 98 | 99 | **0.2.6** 100 | * Fix to remove the bbcode and their content 101 | 102 | **0.2.5** 103 | * Fix sync, now update/insert works 104 | * Added log helper 105 | 106 | **0.2.4** 107 | * Fix sync, now update/insert works 108 | * Fix img src isolation 109 | * Changed limit per page from 20 to 10 110 | 111 | **0.2.3** 112 | * Fix sync, now the pagination works fine 113 | * Now refresh via javascript, instead of php wp_rediect to prevent browser error "too many redirections" 114 | * Changed sort tag php with full php tag 115 | 116 | **0.2.2** 117 | * Added guid and photos fields 118 | * Embed photos in the content field will be extracted and pushed on photos field 119 | * Strip all html tags from the intro content 120 | * Strip certain html tags from the extended content 121 | 122 | **0.2.1** 123 | * Fix: now sync all posts instead of the first 5 124 | 125 | **0.2** 126 | * Add a fix for the 3rd party class parseRestClient to get to work in php < 5.3 127 | * Readme: changed thumbnail type to Object 128 | * Fixed thumbnails tag img was returned before the fix, now returns the url 129 | * In wp-parse-api.php changed functions to class 130 | 131 | **0.1** 132 | Initial Commit 133 | 134 | ## About 135 | 136 | Contributors: normanpaniagua 137 | 138 | Tags: parse.com, api 139 | 140 | Requires at least: 3.0.1 (not tested) 141 | 142 | Tested up to: 3.5 143 | 144 | License: GPLv2 or later 145 | 146 | License URI: http://www.gnu.org/licenses/gpl-2.0.html 147 | -------------------------------------------------------------------------------- /libs/parse.com-php-library/parse.php: -------------------------------------------------------------------------------- 1 | _appid = $parseConfig->APPID; 27 | $this->_masterkey = $parseConfig->MASTERKEY; 28 | $this->_restkey = $parseConfig->RESTKEY; 29 | $this->_parseurl = $parseConfig->PARSEURL; 30 | 31 | if(empty($this->_appid) || empty($this->_restkey) || empty($this->_masterkey)){ 32 | $this->throwError('You must set your Application ID, Master Key and REST API Key'); 33 | } 34 | 35 | $version = curl_version(); 36 | $ssl_supported = ( $version['features'] & CURL_VERSION_SSL ); 37 | 38 | if(!$ssl_supported){ 39 | $this->throwError('CURL ssl support not found'); 40 | } 41 | 42 | } 43 | 44 | /* 45 | * All requests go through this function 46 | * 47 | * 48 | */ 49 | public function request($args){ 50 | $isFile = false; 51 | $c = curl_init(); 52 | curl_setopt($c, CURLOPT_TIMEOUT, 30); 53 | curl_setopt($c, CURLOPT_USERAGENT, 'parse.com-php-library/2.0'); 54 | curl_setopt($c, CURLOPT_RETURNTRANSFER, true); 55 | curl_setopt($c, CURLINFO_HEADER_OUT, true); 56 | if(substr($args['requestUrl'],0,5) == 'files'){ 57 | curl_setopt($c, CURLOPT_HTTPHEADER, array( 58 | 'Content-Type: '.$args['contentType'], 59 | 'X-Parse-Application-Id: '.$this->_appid, 60 | 'X-Parse-Master-Key: '.$this->_masterkey 61 | )); 62 | $isFile = true; 63 | } 64 | else if(substr($args['requestUrl'],0,5) == 'users' && isset($args['sessionToken'])){ 65 | curl_setopt($c, CURLOPT_HTTPHEADER, array( 66 | 'Content-Type: application/json', 67 | 'X-Parse-Application-Id: '.$this->_appid, 68 | 'X-Parse-REST-API-Key: '.$this->_restkey, 69 | 'X-Parse-Session-Token: '.$args['sessionToken'] 70 | )); 71 | } 72 | else{ 73 | curl_setopt($c, CURLOPT_HTTPHEADER, array( 74 | 'Content-Type: application/json', 75 | 'X-Parse-Application-Id: '.$this->_appid, 76 | 'X-Parse-REST-API-Key: '.$this->_restkey, 77 | 'X-Parse-Master-Key: '.$this->_masterkey 78 | )); 79 | } 80 | curl_setopt($c, CURLOPT_CUSTOMREQUEST, $args['method']); 81 | $url = $this->_parseurl . $args['requestUrl']; 82 | 83 | if($args['method'] == 'PUT' || $args['method'] == 'POST'){ 84 | if($isFile){ 85 | $postData = $args['data']; 86 | } 87 | else{ 88 | $postData = json_encode($args['data']); 89 | } 90 | 91 | curl_setopt($c, CURLOPT_POSTFIELDS, $postData ); 92 | } 93 | 94 | if($args['requestUrl'] == 'login'){ 95 | $urlParams = http_build_query($args['data'], '', '&'); 96 | $url = $url.'?'.$urlParams; 97 | } 98 | if(array_key_exists('urlParams',$args)){ 99 | $urlParams = http_build_query($args['urlParams'], '', '&'); 100 | $url = $url.'?'.$urlParams; 101 | } 102 | 103 | curl_setopt($c, CURLOPT_URL, $url); 104 | 105 | $response = curl_exec($c); 106 | $responseCode = curl_getinfo($c, CURLINFO_HTTP_CODE); 107 | 108 | $expectedCode = '200'; 109 | if($args['method'] == 'POST' && substr($args['requestUrl'],0,4) != 'push'){ 110 | $expectedCode = '201'; 111 | } 112 | 113 | if($expectedCode != $responseCode){ 114 | //BELOW HELPS WITH DEBUGGING 115 | //print_r($response); 116 | //print_r($args); 117 | } 118 | 119 | return $this->checkResponse($response,$responseCode,$expectedCode); 120 | } 121 | 122 | public function dataType($type,$params){ 123 | if($type != ''){ 124 | switch($type){ 125 | case 'date': 126 | $return = array( 127 | "__type" => "Date", 128 | "iso" => date("c", strtotime($params)) 129 | ); 130 | break; 131 | case 'bytes': 132 | $return = array( 133 | "__type" => "Bytes", 134 | "base64" => base64_encode($params) 135 | ); 136 | break; 137 | case 'pointer': 138 | $return = array( 139 | "__type" => "Pointer", 140 | "className" => $params[0], 141 | "objectId" => $params[1] 142 | ); 143 | break; 144 | case 'geopoint': 145 | $return = array( 146 | "__type" => "GeoPoint", 147 | "latitude" => floatval($params[0]), 148 | "longitude" => floatval($params[1]) 149 | ); 150 | break; 151 | case 'file': 152 | $return = array( 153 | "__type" => "File", 154 | "name" => $params[0], 155 | ); 156 | break; 157 | case 'increment': 158 | $return = array( 159 | "__op" => "Increment", 160 | "amount" => $params[0] 161 | ); 162 | break; 163 | case 'decrement': 164 | $return = array( 165 | "__op" => "Decrement", 166 | "amount" => $params[0] 167 | ); 168 | break; 169 | default: 170 | $return = false; 171 | break; 172 | } 173 | 174 | return $return; 175 | } 176 | } 177 | 178 | public function throwError($msg,$code=0){ 179 | throw new ParseLibraryException($msg,$code); 180 | } 181 | 182 | private function checkResponse($response,$responseCode,$expectedCode){ 183 | //TODO: Need to also check for response for a correct result from parse.com 184 | if($responseCode != $expectedCode){ 185 | $error = json_decode($response); 186 | $this->throwError($error->error,$error->code); 187 | } 188 | else{ 189 | //check for empty return 190 | if($response == '{}'){ 191 | return true; 192 | } 193 | else{ 194 | return json_decode($response); 195 | } 196 | } 197 | } 198 | } 199 | 200 | 201 | class ParseLibraryException extends Exception{ 202 | public function __construct($message, $code = 0, Exception $previous = null) { 203 | //codes are only set by a parse.com error 204 | if($code != 0){ 205 | $message = "parse.com error: ".$message; 206 | } 207 | 208 | parent::__construct($message, $code, $previous); 209 | } 210 | 211 | public function __toString() { 212 | return __CLASS__ . ": [{$this->code}]: {$this->message}\n"; 213 | } 214 | 215 | } 216 | 217 | ?> -------------------------------------------------------------------------------- /libs/parse.com-php-library/parseQuery.php: -------------------------------------------------------------------------------- 1 | _requestUrl = $class; 14 | } 15 | elseif($class != ''){ 16 | $this->_requestUrl = 'classes/'.$class; 17 | } 18 | else{ 19 | $this->throwError('include the className when creating a parseQuery'); 20 | } 21 | 22 | parent::__construct(); 23 | 24 | } 25 | 26 | public function find(){ 27 | if(empty($this->_query)){ 28 | $this->throwError('No query set yet.'); 29 | } 30 | else{ 31 | $urlParams = array( 32 | 'where' => json_encode( $this->_query ) 33 | ); 34 | if(!empty($this->_include)){ 35 | $urlParams['include'] = implode(',',$this->_include); 36 | } 37 | if(!empty($this->_order)){ 38 | $urlParams['order'] = implode(',',$this->_order); 39 | } 40 | if(!empty($this->_limit)){ 41 | $urlParams['limit'] = $this->_limit; 42 | } 43 | if(!empty($this->_skip)){ 44 | $urlParams['skip'] = $this->_skip; 45 | } 46 | if($this->_count == 1){ 47 | $urlParams['count'] = '1'; 48 | $urlParams['limit'] = '0'; 49 | } 50 | 51 | $request = $this->request(array( 52 | 'method' => 'GET', 53 | 'requestUrl' => $this->_requestUrl, 54 | 'urlParams' => $urlParams, 55 | )); 56 | 57 | return $request; 58 | } 59 | } 60 | 61 | public function getCount(){ 62 | $this->_count = 1; 63 | $this->_limit = 0; 64 | return $this->find(); 65 | } 66 | 67 | public function setLimit($int){ 68 | if ($int >= 1 && $int <= 1000){ 69 | $this->_limit = $int; 70 | } 71 | else{ 72 | $this->throwError('parse requires the limit parameter be between 1 and 1000'); 73 | } 74 | } 75 | 76 | public function setSkip($int){ 77 | $this->_skip = $int; 78 | } 79 | 80 | public function orderBy($field){ 81 | if(!empty($field)){ 82 | $this->_order[] = $field; 83 | } 84 | } 85 | 86 | public function orderByAscending($value){ 87 | if(is_string($value)){ 88 | $this->_order[] = $value; 89 | } 90 | else{ 91 | $this->throwError('the order parameter on a query must be a string'); 92 | } 93 | } 94 | 95 | public function orderByDescending($value){ 96 | if(is_string($value)){ 97 | $this->_order[] = '-'.$value; 98 | } 99 | else{ 100 | $this->throwError('the order parameter on parseQuery must be a string'); 101 | } 102 | } 103 | 104 | public function whereInclude($value){ 105 | if(is_string($value)){ 106 | $this->_include[] = $value; 107 | } 108 | else{ 109 | $this->throwError('the include parameter on parseQuery must be a string'); 110 | } 111 | } 112 | 113 | public function where($key,$value){ 114 | $this->whereEqualTo($key,$value); 115 | } 116 | 117 | public function whereEqualTo($key,$value){ 118 | if(isset($key) && isset($value)){ 119 | $this->_query[$key] = $value; 120 | } 121 | else{ 122 | $this->throwError('the $key and $value parameters must be set when setting a "where" query method'); 123 | } 124 | } 125 | 126 | public function whereNotEqualTo($key,$value){ 127 | if(isset($key) && isset($value)){ 128 | $this->_query[$key] = array( 129 | '$ne' => $value 130 | ); 131 | } 132 | else{ 133 | $this->throwError('the $key and $value parameters must be set when setting a "where" query method'); 134 | } 135 | } 136 | 137 | public function whereGreaterThan($key,$value){ 138 | if(isset($key) && isset($value)){ 139 | $this->_query[$key] = array( 140 | '$gt' => $value 141 | ); 142 | } 143 | else{ 144 | $this->throwError('the $key and $value parameters must be set when setting a "where" query method'); 145 | } 146 | 147 | } 148 | 149 | public function whereLessThan($key,$value){ 150 | if(isset($key) && isset($value)){ 151 | $this->_query[$key] = array( 152 | '$lt' => $value 153 | ); 154 | } 155 | else{ 156 | $this->throwError('the $key and $value parameters must be set when setting a "where" query method'); 157 | } 158 | 159 | } 160 | 161 | public function whereGreaterThanOrEqualTo($key,$value){ 162 | if(isset($key) && isset($value)){ 163 | $this->_query[$key] = array( 164 | '$gte' => $value 165 | ); 166 | } 167 | else{ 168 | $this->throwError('the $key and $value parameters must be set when setting a "where" query method'); 169 | } 170 | 171 | } 172 | 173 | public function whereLessThanOrEqualTo($key,$value){ 174 | if(isset($key) && isset($value)){ 175 | $this->_query[$key] = array( 176 | '$lte' => $value 177 | ); 178 | } 179 | else{ 180 | $this->throwError('the $key and $value parameters must be set when setting a "where" query method'); 181 | } 182 | 183 | } 184 | 185 | public function whereContainedIn($key,$value){ 186 | if(isset($key) && isset($value)){ 187 | if(is_array($value)){ 188 | $this->_query[$key] = array( 189 | '$in' => $value 190 | ); 191 | } 192 | else{ 193 | $this->throwError('$value must be an array to check through'); 194 | } 195 | } 196 | else{ 197 | $this->throwError('the $key and $value parameters must be set when setting a "where" query method'); 198 | } 199 | 200 | } 201 | 202 | public function whereNotContainedIn($key,$value){ 203 | if(isset($key) && isset($value)){ 204 | if(is_array($value)){ 205 | $this->_query[$key] = array( 206 | '$nin' => $value 207 | ); 208 | } 209 | else{ 210 | $this->throwError('$value must be an array to check through'); 211 | } 212 | } 213 | else{ 214 | $this->throwError('the $key and $value parameters must be set when setting a "where" query method'); 215 | } 216 | 217 | } 218 | 219 | public function whereExists($key){ 220 | if(isset($key)){ 221 | $this->_query[$key] = array( 222 | '$exists' => true 223 | ); 224 | } 225 | } 226 | 227 | public function whereDoesNotExist($key){ 228 | if(isset($key)){ 229 | $this->_query[$key] = array( 230 | '$exists' => false 231 | ); 232 | } 233 | } 234 | 235 | public function whereRegex($key,$value,$options=''){ 236 | if(isset($key) && isset($value)){ 237 | $this->_query[$key] = array( 238 | '$regex' => $value 239 | ); 240 | 241 | if(!empty($options)){ 242 | $this->_query[$key]['options'] = $options; 243 | } 244 | } 245 | else{ 246 | $this->throwError('the $key and $value parameters must be set when setting a "where" query method'); 247 | } 248 | 249 | } 250 | 251 | public function wherePointer($key,$className,$objectId){ 252 | if(isset($key) && isset($className)){ 253 | $this->_query[$key] = $this->dataType('pointer', array($className,$objectId)); 254 | } 255 | else{ 256 | $this->throwError('the $key and $className parameters must be set when setting a "where" pointer query method'); 257 | } 258 | 259 | } 260 | 261 | public function whereInQuery($key,$className,$inQuery){ 262 | if(isset($key) && isset($className)){ 263 | $this->_query[$key] = array( 264 | '$inQuery' => $inQuery, 265 | 'className' => $className 266 | ); 267 | } 268 | else{ 269 | $this->throwError('the $key and $value parameters must be set when setting a "where" query method'); 270 | } 271 | 272 | } 273 | 274 | public function whereNotInQuery($key,$className,$inQuery){ 275 | if(isset($key) && isset($className)){ 276 | $this->_query[$key] = array( 277 | '$notInQuery' => $inQuery, 278 | 'className' => $className 279 | ); 280 | } 281 | else{ 282 | $this->throwError('the $key and $value parameters must be set when setting a "where" query method'); 283 | } 284 | 285 | } 286 | } 287 | 288 | ?> --------------------------------------------------------------------------------