PageRenderTime 59ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/ph-salesforce.php

https://bitbucket.org/esilverman/ph-salesforce
PHP | 1480 lines | 739 code | 450 blank | 291 comment | 111 complexity | 3ad03cebfb348502c425110c2bbe1290 MD5 | raw file
  1. <?php /*
  2. **************************************************************************
  3. Plugin Name: Project Homecoming Salesforce Integration
  4. Plugin URI: http://projecthomecoming.net/
  5. Description: Sync Project Homecoming Salesforce data with WordPress..
  6. Version: 0.0.1
  7. Author: Caliper Creative
  8. Author URI: http://madebycaliper.com
  9. License: GPLv2 or later
  10. **************************************************************************/
  11. // Make sure we don't expose any info if called directly
  12. if ( !function_exists( 'add_action' ) ) {
  13. echo 'PH Salesforce Plugin can\'t be called directly!';
  14. exit;
  15. }
  16. global $chrome_php_enabled;
  17. $chrome_php_enabled = defined('CHROME_PHP') && CHROME_PHP;
  18. // Autoload global composer libs
  19. if ( isset( $_SERVER['HTTP_HOST'] ) && strstr( $_SERVER['HTTP_HOST'], 'localhost' ) ) :
  20. if( $chrome_php_enabled ) {
  21. require_once '/Users/krumpla/.composer/vendor/autoload.php';
  22. }
  23. endif;
  24. date_default_timezone_set("America/Chicago");
  25. define( 'PH_SF_DEBUG', TRUE );
  26. require_once 'core/includes/helper-functions.php';
  27. if ( ! class_exists('PH_Salesforce')) {
  28. // Don't activate on anything less than PHP & WP Requirments
  29. $php_min_version = '5.3';
  30. $wp_min_version = '3.2';
  31. if ( version_compare( PHP_VERSION, $php_min_version, '<' ) || version_compare( get_bloginfo( 'version' ), $wp_min_version, '<' ) ) {
  32. require_once ABSPATH . 'wp-admin/includes/plugin.php';
  33. deactivate_plugins( basename( __FILE__ ) );
  34. if ( isset( $_GET['action'] ) && ( $_GET['action'] == 'activate' || $_GET['action'] == 'error_scrape' ) )
  35. die( __( "PH Salesforce requires PHP version $php_min_version or greater and WordPress $wp_min_version or greater.", 'ph-salesforce' ) );
  36. }
  37. class PH_Salesforce {
  38. const PLUGIN_NAME = 'PH_Salesforce';
  39. const PLUGIN_SLUG = 'ph_salesforce';
  40. const PLUGIN_PREFIX = 'phs_';
  41. const PLUGIN_VERSION = '0.1.0';
  42. const MIN_WP_VERSION = '3.6.0';
  43. private $cpts = array();
  44. // Options table settings
  45. const SETTINGS_GROUP_NAME = 'ph_sf_settings';
  46. const SETTINGS_SLUG = 'ph_sf';
  47. public $settings = array();
  48. public $opts = array();
  49. // Instance vars
  50. public $plugin_path;
  51. public $json_path;
  52. public $sf_api_path;
  53. public $projects;
  54. public $the_project;
  55. public $volunteer_orgs = array();
  56. public $the_vol_org;
  57. public $volunteers = array();
  58. public $accounts;
  59. public $account_lookup = array();
  60. public $work_records = array();
  61. public $project_udpates = array();
  62. public $the_emply;
  63. public $emply_meta = array();
  64. public $run_time;
  65. public $current_project_sf_id = 0;
  66. public $current_project_key = '';
  67. public $import_results = array(
  68. 'projects' => array(),
  69. 'employees' => array()
  70. );
  71. protected static $api;
  72. /**
  73. * Hook into init and admin/non-admin actions.
  74. * Include, initialize & add theme support for widgets.
  75. *
  76. * @access public
  77. * @return void
  78. */
  79. function __construct() {
  80. // Initialize the plugin
  81. add_action( 'init', array(&$this, 'init' ) );
  82. if ( is_admin() ) {
  83. // Initialize admin settings and enqueue assets for admin
  84. add_action( 'admin_init', array( &$this, 'admin_init' ) );
  85. // Add Plugin Settings Page
  86. add_action( 'admin_menu', array( &$this, 'add_admin_menu' ) );
  87. } else { // Non-Admin
  88. // Process the_content based on settings and content type
  89. add_action( 'pre_get_posts' , array( &$this, 'pre_get_posts' ) );
  90. }
  91. } // END __construct()
  92. ///////////////// Activation & Deactivation
  93. /**
  94. * Setup plugin for the first time
  95. * Register Post Types
  96. * Flush Rewrite Rules
  97. *
  98. * @access public
  99. * @return void
  100. */
  101. function activate() {
  102. if ( ! $this->_get_options() ) {
  103. // If no options exist, set initial vars
  104. $this->_update_options( FALSE , 'has_imported');
  105. }
  106. // Register post types then flush rewrite rules
  107. $this->register_post_types();
  108. flush_rewrite_rules( true );
  109. } // END activate()
  110. /**
  111. * Clear the WP scheduled events and flush rewrite rules.
  112. *
  113. * @access public
  114. * @return void
  115. */
  116. function deactivate() {
  117. wp_clear_scheduled_hook('try_import_event_hook');
  118. flush_rewrite_rules();
  119. } // END deactivate()
  120. // END Activation & Deactivation
  121. /**
  122. * Initialize plugin: Post Types, variables, terms
  123. *
  124. * Check if plugin is configured and either push notice
  125. * or get API instance.
  126. *
  127. * @access public
  128. * @return void
  129. */
  130. function init() {
  131. ///// Things that should happen on every page load
  132. // Included classes that should be available from the get go
  133. $this->include_classes();
  134. // Initial Class properties/variables
  135. $this->init_vars();
  136. // Register CPTs
  137. $this->register_post_types();
  138. if( is_admin() ) {
  139. // Add Import/Refresh AJAX action for Settings page
  140. add_action( 'wp_ajax_ph_sf_refresh_all', array( &$this, 'ajax_refresh_all' ) );
  141. // Change the title of the Options page
  142. if( function_exists('acf_set_options_page_title') )
  143. {
  144. acf_set_options_page_title( __('Project Homecoming Organization Info') );
  145. }
  146. // Rename Options Page in Admin Menu
  147. if( function_exists('acf_set_options_page_menu') )
  148. {
  149. acf_set_options_page_menu( __('PH Info') );
  150. }
  151. } else { // Non-Admin pages
  152. // Front End Scripts & Styles
  153. // add_action( 'wp_enqueue_scripts', array( &$this , 'enqueue_scripts_and_styles' ) );
  154. }
  155. // Allow manual import triggered by command line
  156. $this->opts = getopt( "", array('import::','no-sf-query::', 'migrate') );
  157. if( isset( $this->opts['import'] ) && $this->opts['import'] ) {
  158. $this->run_import();
  159. } else if ( isset( $this->opts['migrate'] ) ) {
  160. _log('Running migration...');
  161. $this->run_migration();
  162. }
  163. } // END init()
  164. /**
  165. * Initialize plugin with relevant admin behaviors.
  166. *
  167. * @access public
  168. * @return void
  169. */
  170. function admin_init() {
  171. // Include Plugin Scripts & Styling for Admin pages
  172. add_action( 'admin_enqueue_scripts', array( &$this, 'add_admin_assets' ) );
  173. // Add settings update notice, if updated
  174. if( isset( $_GET['settings-updated'] ) ) {
  175. add_action( 'admin_notices', array( &$this, 'admin_notice_settings_updated' ) );
  176. }
  177. } // END admin_init()
  178. function add_admin_menu() {
  179. add_options_page(
  180. 'Project Homecoming Salesforce Options',
  181. 'PH Salesforce',
  182. 'manage_options',
  183. $this->settings_page_slug,
  184. array( $this, 'plugin_settings_page' )
  185. );
  186. } // end add_admin_menu()
  187. function include_classes() {
  188. include_once 'core/classes/class-ph-project.php';
  189. include_once 'core/classes/class-ph-employee.php';
  190. include_once 'core/classes/class-ph-vol-org.php';
  191. include_once 'core/api.php';
  192. } // END include_classes()
  193. /**
  194. * Initialize variables that depend on Constants
  195. *
  196. * @access public
  197. * @return void
  198. */
  199. private function init_vars() {
  200. // Set this' settings to settings from options table
  201. $this->settings = $this->_get_options();
  202. $this->settings_page_slug = self::PLUGIN_PREFIX . "settings";
  203. $this->plugin_path = plugin_dir_path( __FILE__ );
  204. $this->json_path = "{$this->plugin_path}json/";
  205. $this->sf_api_path = "{$this->plugin_path}vendor/developerforce/force.com-toolkit-for-php";
  206. $this->run_time = date('y-m-d_Hms', time() );
  207. $this->ph_sf_api = new PH_Salesforce_API();
  208. // Set menu and related properties
  209. $this->main_menu_slug = self::PLUGIN_PREFIX . 'main-menu';
  210. $this->menu_pages = array(
  211. 'Settings' => array(
  212. 'page_title' => 'PH Salesforce Settings',
  213. 'capability' => 'read_private_posts',
  214. 'menu_slug' => $this->settings_page_slug,
  215. 'function' => array( &$this, 'plugin_settings_page' )
  216. )
  217. );
  218. // Setup Custom Post Types
  219. $this->cpts = array(
  220. PH_Project::CPT_NAME => array(
  221. 'singular' => 'Project',
  222. 'plural' => 'Projects',
  223. 'show_in_menu' => true,
  224. 'supports' => array('excerpt'),
  225. 'taxonomies' => array('post_tag','category'),
  226. 'has_archive' => true,
  227. 'public' => true,
  228. 'rewrite_slug' => 'projects'
  229. ),
  230. PH_Employee::CPT_NAME => array(
  231. 'singular' => 'Staff',
  232. 'plural' => 'Staff',
  233. 'show_in_menu' => true,
  234. 'supports' => array('excerpt'),
  235. 'taxonomies' => array('post_tag','category'),
  236. 'has_archive' => true,
  237. 'public' => true,
  238. 'rewrite_slug' => 'staff'
  239. ),
  240. PH_Volunteer_Org::CPT_NAME => array(
  241. 'singular' => 'Volunteer Org',
  242. 'plural' => 'Volunteer Orgs',
  243. 'show_in_menu' => true,
  244. // 'supports' => array('excerpt'),
  245. 'taxonomies' => array('post_tag','category'),
  246. 'has_archive' => false,
  247. 'public' => true,
  248. 'rewrite_slug' => 'volunteer-orgs'
  249. )
  250. );
  251. } // END init_vars()
  252. /**
  253. * Register and add support for PH-SF CPTs, flush rewrite rules.
  254. *
  255. * @access public
  256. * @return void
  257. */
  258. private function register_post_types() {
  259. global $db_cpt_name;
  260. foreach ($this->cpts as $key => $cpt) {
  261. $db_cpt_name = $key;
  262. $singular = $cpt['singular'];
  263. $plural = $cpt['plural'];
  264. $show_in_menu = $cpt['show_in_menu'];
  265. $passed_supports_args = (isset($cpt['supports']) ? (array) $cpt['supports'] : array() );
  266. $passed_taxonomies = (isset($cpt['taxonomies']) ? (array) $cpt['taxonomies'] : array() );
  267. $supports_defaults = array( 'title', 'editor', 'comments', 'thumbnail', 'custom-fields' );
  268. $supports_array = array_merge($supports_defaults, $passed_supports_args);
  269. $taxonomies_defaults = array('');
  270. $taxonomies_array = array_merge($taxonomies_defaults, $passed_taxonomies);
  271. $hasArchive = isset($cpt['has_archive']) ? $cpt['has_archive'] : true;
  272. $exclude_from_search = isset($cpt['exclude_from_search']) ? $cpt['exclude_from_search'] : false;
  273. $public = isset($cpt['public']) ? $cpt['public'] : false;
  274. $rewrite_slug = (isset($cpt['rewrite_slug']) ? $cpt['rewrite_slug'] : $cpt['plural'] );
  275. register_post_type( $db_cpt_name,
  276. array(
  277. 'labels' => array(
  278. 'name' => $plural,
  279. 'singular_name' => $singular,
  280. 'add_new' => 'Add New',
  281. 'add_new_item' => 'Add New '. $singular,
  282. 'edit' => 'Edit',
  283. 'edit_item' => 'Edit '. $singular,
  284. 'new_item' => 'New '. $singular,
  285. 'view' => 'View',
  286. 'view_item' => 'View '. $singular,
  287. 'search_items' => 'Search '. $plural,
  288. 'not_found' => 'No '. $plural .' found',
  289. 'not_found_in_trash' => 'No '. $plural .' found in Trash',
  290. 'parent' => 'Parent '. $singular
  291. ),
  292. 'public' => $public,
  293. 'menu_position' => 15,
  294. 'supports' => $supports_array,
  295. 'taxonomies' => $taxonomies_array,
  296. // 'menu_icon' => get_bloginfo('stylesheet_directory') . '/images/'.strtolower($plural).'.png',
  297. 'has_archive' => $hasArchive,
  298. 'rewrite' => array( 'slug' => $rewrite_slug ),
  299. // 'rewrite' => true,
  300. 'show_in_menu' => $show_in_menu,
  301. /* 'exclude_from_search' => $exclude_from_search, */
  302. )
  303. );
  304. } // end foreach cpt
  305. // Add theme support for thumbnails
  306. if ( function_exists( 'add_theme_support' ) ) {
  307. add_theme_support( 'post-thumbnails' );
  308. }
  309. flush_rewrite_rules( true );
  310. } // register_post_types()
  311. /**
  312. * Adds filter hooks that add content before and/or after posts,
  313. * depending on Settings.
  314. *
  315. * @access public
  316. * @return void
  317. */
  318. function pre_get_posts() {
  319. } // END pre_get_posts
  320. /**
  321. * Add admin assets to relevant pages
  322. *
  323. * @access public
  324. * @return void
  325. */
  326. function add_admin_assets() {
  327. if( ! $this->is_ph_sf_admin_page() )
  328. return;
  329. // Javascript
  330. wp_enqueue_script(
  331. self::PLUGIN_SLUG . '_admin_js',
  332. plugin_dir_url( __FILE__ ) . 'assets/js/admin.js',
  333. array('jquery'),
  334. self::PLUGIN_VERSION ,
  335. true
  336. );
  337. // Get current page protocol
  338. $protocol = isset( $_SERVER['HTTPS'] ) ? 'https://' : 'http://' ;
  339. // Output admin-ajax.php URL with same protocol as current page
  340. $params = array(
  341. 'ajaxurl' => admin_url( 'admin-ajax.php' , $protocol )
  342. );
  343. wp_localize_script( 'ph_salesforce_admin_js' , 'ph_salesforce_admin_js', $params );
  344. // CSS
  345. wp_register_style( 'ph_salesforce_admin_css', plugin_dir_url( __FILE__ ) . 'assets/css/admin.css', false, self::PLUGIN_VERSION );
  346. wp_enqueue_style( 'ph_salesforce_admin_css' );
  347. } // END add_admin_js
  348. // Options Helpers
  349. /**
  350. * Get all of the plugin's options.
  351. *
  352. * @access public
  353. * @return void
  354. */
  355. public function _get_options() {
  356. if( empty( $this->settings ) )
  357. $this->settings = get_option( self::SETTINGS_GROUP_NAME );
  358. return $this->settings;
  359. } // END _get_options()
  360. /**
  361. * Get a specified key from the options array
  362. *
  363. * @access public
  364. * @param mixed $key
  365. * @return void
  366. */
  367. function _get_the_option( $key = false ) {
  368. if ( !$key )
  369. return false;
  370. $options = $this->_get_options();
  371. return isset( $options[ $key ] ) ? $options[ $key ] : false;
  372. } // END _get_the_option()
  373. /**
  374. * Update one or all options saved in the WP Options table
  375. *
  376. * @access private
  377. * @param mixed $value : New value to save into option
  378. * @param String $key (default: null) : option key to modify
  379. * @return void
  380. */
  381. private function _update_options( $value = null, $key = null ) {
  382. if( is_null( $value ) )
  383. return false;
  384. // Get plugin options
  385. $options = $this->_get_options();
  386. // If the key is not set, overwrite all options
  387. if ( !isset($key) ) {
  388. $options = $value;
  389. } else {
  390. // Set the key to the new value
  391. $options[ $key ] = $value;
  392. }
  393. // Update options with new values
  394. update_option(self::SETTINGS_GROUP_NAME, $options );
  395. // Update the obj settings
  396. return $this->settings = $options;
  397. } // END _update_options()
  398. // Import Functions
  399. /**
  400. * Schedule an import event to run from wp-cron.php
  401. *
  402. * @access public
  403. * @return void
  404. */
  405. function schedule_import() {
  406. if ( !wp_next_scheduled( 'try_import_event_hook' ) ) {
  407. wp_schedule_event( time(), 'hourly', array( &$this, 'try_import_event_hook' ) );
  408. }
  409. add_filter('cron_schedules', array( &$this, 'add_schedules' ) );
  410. } // END schedule_import
  411. function add_schedules($schedules) {
  412. // interval in seconds
  413. $schedules['every10min'] = array('interval' => 10*60, 'display' => 'Every 10 minutes');
  414. return $schedules;
  415. } // END my_additional_schedules
  416. /**
  417. * Try to run the import script.
  418. * Will only execute if called from the shell and DOING_CRON
  419. *
  420. * @access public
  421. */
  422. function try_import( ) {
  423. $doing_cron = defined( 'DOING_CRON' ) && DOING_CRON;
  424. $called_from_shell = !isset( $_SERVER['HTTP_HOST'] );
  425. // Make sure we don't expose any info if called directly
  426. if ( !function_exists( 'add_action' ) ) {
  427. _log('PH Salesforce Plugin can\'t be called directly!');
  428. exit;
  429. }
  430. // If this is a WP-Cron call, not from shell, return
  431. if ( !$called_from_shell ) {
  432. _log( "try_import() Not called from shell. Returning...");
  433. return false;
  434. }
  435. // _log($_SERVER, 'server');
  436. if ( $doing_cron ) {
  437. _log("\t -------- try_import() Called from shell && DOING_CRON -------- ");
  438. _log("\t Executing import script...");
  439. // Determine caller function
  440. $backtrace = debug_backtrace();
  441. if ( isset( $backtrace[1] ) ) {
  442. $caller = $backtrace[1];
  443. }
  444. if ( !empty( $caller['file'] ) )
  445. _log("from ".$caller["function"]."() in ".$caller["file"] , 'importing...');
  446. return $this->run_import();
  447. } else {
  448. // Triggered from SHELL/CRON but not doing_wp_cron
  449. _log("\t---- Called from shell but not DOING_CRON ----");
  450. }
  451. return false;
  452. } // END try_import
  453. /**
  454. * Fetch all Salesforce data and Import/Update WP Objects
  455. *
  456. * @access public
  457. */
  458. function run_import() {
  459. $this->fetch_salesforce_data();
  460. _log(' Finished Fetching SF Data...');
  461. $this->add_relational_data_to_projects();
  462. _log(' ========== Finished Processing SF Data ==========');
  463. $this->remove_stale_cache();
  464. _log(' Saving Sforce Data to WP...');
  465. $this->save_sforce_data_to_wp();
  466. $this->_update_options( TRUE, 'has_imported');
  467. $this->_update_options( time(), 'last_import_time');
  468. $this->_update_options( $this->import_results, 'last_import_results');
  469. return $this->import_results;
  470. } // END run_import()
  471. function echo_import_results() {
  472. $last_import_results = $this->_get_the_option('last_import_results');
  473. if( !$last_import_results ) return '';
  474. $html = '<ul class="response-list">';
  475. if( !empty( $last_import_results['projects']['created'] ) ) {
  476. $html .= "<h3>Newly Imported Projects</h3>";
  477. unset( $project_names );
  478. foreach ($last_import_results['projects']['created'] as $project) {
  479. $project_names[] = sprintf( "<li class='project created'>[ %s ]</li>", $project['details']->Name );
  480. }
  481. $html .= implode(', ', $project_names);
  482. }
  483. if( !empty( $last_import_results['projects']['updated'] ) ) {
  484. $html .= "<h3>Updated Projects</h3>";
  485. unset( $project_names );
  486. foreach ($last_import_results['projects']['updated'] as $project) {
  487. $project_names[] = $project['details']->Name;
  488. }
  489. $html .= sprintf( "<p class='updated-projects'>%s.</p>", implode(', ', $project_names) );
  490. }
  491. if( !empty( $last_import_results['employees']['created'] ) ) {
  492. $html .= "<h3>Newly Imported Employees</h3>";
  493. unset( $employee_names );
  494. foreach ($last_import_results['employees']['created'] as $employee_name ) {
  495. $employee_names[] = sprintf( "<li class='employee created'>[ %s ]</li>", $employee_name );
  496. }
  497. $html .= implode(', ', $employee_names);
  498. }
  499. if( !empty( $last_import_results['employees']['updated'] ) ) {
  500. $html .= "<h3>Updated employees</h3>";
  501. unset( $employee_names );
  502. foreach ( $last_import_results['employees']['updated'] as $employee_name ) {
  503. $employee_names[] = $employee_name;
  504. }
  505. $html .= sprintf( "<p class='updated-employees'>%s.</p>", implode(', ', $employee_names) );
  506. }
  507. $html .= "</ul>";
  508. echo $html;
  509. } // END echo_import_results()
  510. function fetch_salesforce_data() {
  511. $this->get_projects();
  512. $this->save_employees_json();
  513. $this->get_volunteers();
  514. $this->save_volunteers_to_json();
  515. $this->get_volunteer_orgs();
  516. $this->save_volunteer_orgs_to_json();
  517. $this->build_account_lookup_hash();
  518. } // END fetch_salesforce_data()
  519. /**
  520. * Fetch projects from Salesforce.
  521. */
  522. function get_projects() {
  523. $this->projects = $this->ph_sf_api->get_projects();
  524. } // end get_projects()
  525. /**
  526. * Fetch employees from Salesforce and save them to JSON.
  527. */
  528. function save_employees_json() {
  529. $this->employees = $this->ph_sf_api->get_unsuppressed_employees();
  530. // $fp = fopen( $this->json_path . "employees-{$this->run_time}.json", "w");
  531. $fp = fopen( $this->json_path . "employees.json", "w");
  532. // $this->employees['timestamp'] = date("Y-m-d g:i:s a");
  533. fwrite( $fp, json_encode( $this->employees ) );
  534. fclose( $fp );
  535. } // end save_employees_json()
  536. /**
  537. * Fetch volunteers from Salesforce.
  538. */
  539. function get_volunteers() {
  540. $this->volunteers = $this->ph_sf_api->get_all_volunteers();
  541. } // end get_volunteers()
  542. /**
  543. * Fetch volunteers from Salesforce.
  544. */
  545. function get_volunteer_orgs() {
  546. _log_v('Fetching all Volunteer Orgs..');
  547. $this->volunteer_orgs = $this->ph_sf_api->get_all_volunteer_orgs();
  548. } // end get_volunteer_orgs()
  549. /**
  550. * Build account lookup hash.
  551. */
  552. function build_account_lookup_hash() {
  553. $this->accounts = $this->ph_sf_api->get_all_accounts();
  554. foreach ( $this->accounts as $account ) {
  555. $this->account_lookup[ $account['Id'] ]['name']= $account['Name'];
  556. $this->account_lookup[ $account['Id'] ]['startDate']= $account['Start_Date__c'];
  557. $this->account_lookup[ $account['Id'] ]['location'] = $account['Team_Reg_Location__c'];
  558. }
  559. // Recovery Memory / temp storage
  560. unset( $this->accounts );
  561. }
  562. /**
  563. * Iterates through all the projects and adds relational data.
  564. */
  565. function add_relational_data_to_projects() {
  566. _mem_v('Looping Each Project to add Relational Data...');
  567. $num_projs = 0;
  568. foreach( $this->projects as $project_key => $project ) :
  569. // "Globalize" current Project data for access in functions
  570. $this->current_project = $project;
  571. $this->current_project_sf_id = $this->get_project_field_value('Project_SF_ID__c');
  572. $this->current_project_key = $project_key;
  573. $this->add_project_donors();
  574. $this->add_funding_partners();
  575. $this->add_work_records();
  576. $this->add_project_updates();
  577. if( !isset( $this->opts['no-sf-query'] ) || ( isset( $this->opts['no-sf-query'] ) && !$this->opts['no-sf-query'] ) ) {
  578. _mem("Proj #" . $num_projs++ );
  579. // $this->_log_queries();
  580. } else {
  581. _log_v( sprintf("Proj #%d ( %s )", $num_projs++, $project['Name'] ) );
  582. }
  583. endforeach;
  584. $this->save_projects_to_json();
  585. _log('Done looping each project');
  586. } // end add_relational_data_to_projects()
  587. /**
  588. * Add Project Donor data to the projects Obj.
  589. */
  590. function add_project_donors() {
  591. // _mem('donors...');
  592. $donors = $this->ph_sf_api->get_project_donors();
  593. if( !empty( $donors ) ) {
  594. $this->projects[ $this->current_project_key ]['Donors'] = $donors;
  595. }
  596. } // end connect_project_donors()
  597. /**
  598. * Add Funding Partners data to the projects Obj.
  599. */
  600. function add_funding_partners() {
  601. // $this->_log_queries();
  602. // _mem('Funding Partners...');
  603. $partners = $this->ph_sf_api->get_funding_partners();
  604. // Don't iterate through this project if there aren't partners
  605. if( empty( $partners ) ) { return; }
  606. foreach ( $partners as $partner ) {
  607. if ( isset( $partner['Contact__c'] ) ) {
  608. $partner['Donor_Name'] = $this->ph_sf_api->get_contact( $partner['Contact__c'] );
  609. // Sanitize partner URL
  610. if( isset( $partner['Funder_Website__c'] ) ) {
  611. // Replace double http:// and missing colon with proper one
  612. $scheme = 'http';
  613. $partner['Funder_Website__c'] = str_replace( array("{$scheme}://{$scheme}://","{$scheme}//"), "{$scheme}://", $partner['Funder_Website__c'] );
  614. // Same for https
  615. $scheme = 'https';
  616. $partner['Funder_Website__c'] = str_replace( array("{$scheme}://{$scheme}://","{$scheme}//"), "{$scheme}://", $partner['Funder_Website__c'] );
  617. // Prepend the scheme if it ain't got one
  618. if( preg_match("#https?://#", $partner['Funder_Website__c'] ) === 0 ) {
  619. $partner['Funder_Website__c'] = 'http://'.$partner['Funder_Website__c'];
  620. }
  621. }
  622. $this->projects[ $this->current_project_key ]['Funding_Partners'][] = $partner;
  623. } else {
  624. // _log($partner, 'partner does not have contact__c');
  625. }
  626. } // END foreach partners
  627. } // end add_funding_partners()
  628. /**
  629. * Add Work Records to the projects Obj.
  630. */
  631. function add_work_records() {
  632. // $this->_log_queries();
  633. // _mem('Work Records...');
  634. $work_records = &$this->work_records;
  635. $the_project = &$this->projects[ $this->current_project_key ];
  636. $work_records[ $this->current_project_key ] = $this->ph_sf_api->get_project_work_records();
  637. $site_managers = $work_records[ $this->current_project_key ]['Site_Managers'];
  638. $volunteer_orgs = $work_records[ $this->current_project_key ]['Volunteer_Orgs'];
  639. if( count( $site_managers ) ) { // If there are site managers listed on the current work record...
  640. // Iterate through each site manager and to the project's work records
  641. foreach( $site_managers as $site_manager_key => $site_manager_id ){
  642. $site_manager_obj = $this->ph_sf_api->get_contact( $site_manager_id );
  643. $the_project['work_records']['Site_Managers'][ $site_manager_id ] = $site_manager_obj;
  644. $this->add_project_to_emply( $site_manager_id );
  645. }
  646. }
  647. $constr_mgr_id = $this->get_project_field_value('proj_cm__c');
  648. if( !empty( $constr_mgr_id ) ) {
  649. $constr_mgr_obj = $this->ph_sf_api->get_contact( $constr_mgr_id );
  650. $the_project['work_records']['Site_Managers'][ $constr_mgr_id ] = $constr_mgr_obj;
  651. $this->add_project_to_emply( $constr_mgr_id );
  652. }
  653. if( count( $volunteer_orgs ) ) :
  654. // add all IDs to the work record obj
  655. $the_project['Volunteer_Orgs'] = $volunteer_orgs;
  656. foreach( $volunteer_orgs as $org_id ) :
  657. $this->add_project_to_volunteer_org( $org_id );
  658. endforeach;
  659. endif;
  660. } // end add_work_records()
  661. /**
  662. * Add a project ID to an Employee related projects hash.
  663. */
  664. function add_project_to_emply( $emply_id = 0 ) {
  665. if( !$emply_id ) return false;
  666. $project = PH_Project::get_project_from_sf_id( $this->current_project_sf_id );
  667. if( "publish" == $project->post_status ) // Only add the published Projects to the emply details
  668. $this->projects_by_emply[ $emply_id ][] = $project->ID;
  669. } // END add_project_to_emply()
  670. /**
  671. * Add a project ID to Vol. Org's related projects hash.
  672. */
  673. function add_project_to_volunteer_org( $org_id = 0 ) {
  674. if( !$org_id ) return false;
  675. $project = PH_Project::get_project_from_sf_id( $this->current_project_sf_id );
  676. // _log_v("Adding org id {$org_id} to project {$project->post_title}...");
  677. $this->projects_by_volunteer_org[ $org_id ][] = $project->ID;
  678. } // END add_project_to_volunteer_org()
  679. /**
  680. * Add Volunteer data to the projects Obj.
  681. */
  682. function add_volunteers() {
  683. // $this->_log_queries();
  684. // _mem('Volunteers...');
  685. $project_key = $this->current_project_key;
  686. $work_records = &$this->work_records;
  687. if( count( $work_records[ $project_key ]['Volunteer_Registrations'])){
  688. foreach( $work_records[ $project_key ]['Volunteer_Registrations'] as $volreg_key ){
  689. $teamreg = $this->get_project_volunteer_single( $volreg_key );
  690. $team_sf_ID = $teamreg[0]['Team_Reg__c'];
  691. if ( $team_sf_ID ){
  692. $this->projects[ $project_key ]['work_records']['Volunteer_Registrations'][ $team_sf_ID ] = array(
  693. 'contact' => $accountLookup[ $team_sf_ID ]['name'],
  694. 'startDate' => $accountLookup[ $team_sf_ID ]['startDate'],
  695. 'location' => $accountLookup[ $team_sf_ID ]['location']
  696. );
  697. }
  698. }
  699. }
  700. } // end add_volunteers()
  701. /**
  702. * Add Project Updates to the projects Objs.
  703. */
  704. function add_project_updates(){
  705. $proj_updates = &$this->proj_updates;
  706. $the_project = &$this->projects[ $this->current_project_key ];
  707. $proj_updates[ $this->current_project_key ] = $this->ph_sf_api->get_project_updates();
  708. $the_updates = $proj_updates[ $this->current_project_key ];
  709. if( count( $the_updates ) ) {
  710. $the_project['updates'] = $the_updates;
  711. }
  712. } // END add_project_updates()
  713. /**
  714. * Save Projects to JSON.
  715. */
  716. function save_projects_to_json() {
  717. _log_v('Saving projects to JSON...');
  718. $fp = fopen( $this->json_path . "projects.json", "w");
  719. // $this->projects['timestamp'] = date("Y-m-d g:i:s a");
  720. fwrite( $fp, json_encode( $this->projects ) );
  721. fclose( $fp );
  722. } // end save_projects_to_json()
  723. /**
  724. * Save volunteers to JSON.
  725. */
  726. function save_volunteers_to_json() {
  727. $fp = fopen( $this->json_path . "volunteers.json", "w");
  728. $this->volunteers['timestamp'] = date("Y-m-d g:i:s a");
  729. fwrite( $fp, json_encode( $this->volunteers ) );
  730. fclose( $fp );
  731. // Recovery Memory / temp storage
  732. // unset( $this->volunteers );
  733. } // end save_volunteers_to_json()
  734. function save_volunteer_orgs_to_json() {
  735. _log_v('Saving Volunteer Orgs to JSON...');
  736. $fp = fopen( $this->json_path . "volunteer-orgs.json", "w");
  737. // $this->volunteer_orgs['timestamp'] = date("Y-m-d g:i:s a");
  738. fwrite( $fp, json_encode( $this->volunteer_orgs ) );
  739. fclose( $fp );
  740. _log_v('Volunteer Orgs saved.');
  741. // Recovery Memory / temp storage
  742. // unset( $this->volunteers );
  743. } // end save_volunteer_orgs_to_json()
  744. function remove_stale_cache() {
  745. // Return if told not to ping SF
  746. if( isset( $this->opts['no-sf-query'] ) && $this->opts['no-sf-query'] ) return false;
  747. // Remove all old cache folders
  748. $hour_stamp = date("Y-m-d_H");
  749. $cache_dir = "sf_cache_$hour_stamp";
  750. $cache_base_dir = $this->plugin_path . "query-cache";
  751. $iterator = new DirectoryIterator( $cache_base_dir );
  752. _log("cache dir : $cache_base_dir/$cache_dir/");
  753. foreach ($iterator as $fileinfo) {
  754. $target_dir = $cache_base_dir. "/" . $fileinfo->getFilename() . "/";
  755. if (!$fileinfo->isDot()) {
  756. if( $fileinfo->getFilename() !== $cache_dir ) {
  757. _log("deleting : $target_dir");
  758. if( $fileinfo->isDir() ) $this->delete_files( $target_dir );
  759. } else {
  760. _log("Saving : $target_dir" );
  761. }
  762. }
  763. }
  764. _log('Finished Removing Stale Cache...');
  765. } // END remove_stale_cache()
  766. function save_sforce_data_to_wp() {
  767. _mem_v('Saving to WP...');
  768. $sf_projects = $this->get_decoded_json_file('projects');
  769. $sf_employees = $this->get_decoded_json_file('employees.json');
  770. $sf_volunteer_orgs = $this->get_decoded_json_file('volunteer-orgs.json');
  771. // Try to retrieve some memory...
  772. unset( $this->projects, $this->work_records );
  773. _log('Importing projects to WP...');
  774. $proj_import_success = $this->import_projects_to_wp( $sf_projects );
  775. // _log('Importing Employees to WP...');
  776. $emply_import_success = $this->import_employees_to_wp( $sf_employees );
  777. // _log('Importing Vol. Orgs to WP...');
  778. $vol_org_import_success = $this->import_volunteer_orgs_to_wp( $sf_volunteer_orgs );
  779. if( $proj_import_success && $emply_import_success && $vol_org_import_success ) {
  780. _mem_v('Finished import');
  781. _log('');
  782. _log('=======================================');
  783. _log('========== Done Saving to WP ==========');
  784. _log('=======================================');
  785. _log('');
  786. } else {
  787. return false;
  788. _log('IMPORT FAILED');
  789. }
  790. } // end save_sforce_data_to_wp()
  791. function import_projects_to_wp( $projects = 0 ) {
  792. if( !$projects ) return false;
  793. foreach ( $projects as $details ) :
  794. // "Globalize" this project
  795. $project_args = array(
  796. 'details' => (object) $details
  797. );
  798. $project = new PH_Project( $project_args );
  799. $this->the_project = $project;
  800. if ( $project->get_wp_id() ) :
  801. $this->import_results['projects']['updated'][] = (array) $project;
  802. $project->update_in_wp();
  803. else :
  804. $this->import_results['projects']['created'][] = (array) $project;
  805. $project->create_in_wp();
  806. endif; // If Project exists in WP
  807. endforeach;
  808. _log_v('Done importing Projects to WP.');
  809. return $projects;
  810. } // END import_projects_to_wp()
  811. function import_employees_to_wp( $employees = 0 ) {
  812. if( !$employees ) return false;
  813. foreach ( $employees as $details ) :
  814. // Add related projects, if available in the 'global' hash
  815. if( isset( $this->projects_by_emply[ $details->Id ] ) ) {
  816. $details->related_projects = (array) $this->projects_by_emply[ $details->Id ];
  817. }
  818. $employee_args = array(
  819. 'details' => (object) $details
  820. );
  821. $employee = new PH_Employee( $employee_args );
  822. // "Globalize" this employee
  823. $this->the_employee = $employee;
  824. if ( $employee->get_wp_id() ) {
  825. $this->import_results['employees']['updated'][] = $employee->detail('Name');
  826. $employee->update_in_wp();
  827. } else {
  828. $this->import_results['employees']['created'][] = $employee->detail('Name');
  829. $employee->create_in_wp();
  830. } // If Employee exists in WP
  831. endforeach;
  832. _log_v('Done importing Employees to WP.');
  833. return $employees;
  834. } // END import_employees_to_wp()
  835. function import_volunteer_orgs_to_wp( $vol_orgs = 0 ) {
  836. if( !$vol_orgs ) return false;
  837. _log_v('Importing Volunteer Orgs to WP...');
  838. foreach ( $vol_orgs as $details ) :
  839. // Add related projects, if available in the 'global' hash
  840. if( isset( $this->projects_by_volunteer_org[ $details->Id ] ) ) {
  841. $details->related_projects = (array) $this->projects_by_volunteer_org[ $details->Id ];
  842. }
  843. $vol_org_args = array(
  844. 'details' => (object) $details
  845. );
  846. $vol_org = new PH_Volunteer_Org( $vol_org_args );
  847. // "Globalize" this vol_org
  848. $this->the_vol_org = $vol_org;
  849. if ( $vol_org->get_wp_id() ) {
  850. $vol_org->update_in_wp();
  851. } else {
  852. $vol_org->create_in_wp();
  853. } // If vol_org exists in WP
  854. endforeach;
  855. _log_v('Done importing Volunteer Orgs to WP.');
  856. return $vol_orgs;
  857. } // END import_volunteer_orgs_to_wp()
  858. function get_decoded_json_file( $file_name = 0 ) {
  859. if( !$file_name ) return false;
  860. // Append '.json' if the $file_name don't have it
  861. $has_json_ext = strpos( $file_name, '.json' );
  862. if( $has_json_ext === false ) { // <---- the triple equals is important ===
  863. $file_name .= '.json';
  864. }
  865. $file_contents = file_get_contents( $this->json_path . $file_name ); // Get .json file as string
  866. $return_obj = json_decode( $file_contents ); // Convert file to PHP array
  867. return isset_or_false( $return_obj );
  868. } // END get_decoded_json_file()
  869. /*
  870. * php delete function that deals with directories recursively
  871. */
  872. function delete_files($target) {
  873. if(is_dir($target)){
  874. $files = glob( $target . '*', GLOB_MARK ); //GLOB_MARK adds a slash to directories returned
  875. foreach( $files as $file ) {
  876. $this->delete_files( $file );
  877. }
  878. rmdir( $target );
  879. } elseif(is_file($target)) {
  880. unlink( $target );
  881. }
  882. } // END delete_files()
  883. /*======================================
  884. = AJAX Functions =
  885. ======================================*/
  886. /**
  887. * Handle AJAX call to import all data from Salesforce.
  888. *
  889. * Echoes JSON econded list of imported results.
  890. *
  891. * @access public
  892. * @return void
  893. */
  894. function ajax_refresh_all() {
  895. $this->run_import();
  896. echo json_encode( $this->import_results );
  897. die();
  898. } // END ajax_refresh_all()
  899. /*===============================================
  900. = Settings Page Functions =
  901. ===============================================*/
  902. function plugin_settings_page() {
  903. if ( !current_user_can( 'manage_options' ) ) {
  904. wp_die( __( 'You do not have sufficient permissions to access this page.' ) );
  905. }
  906. // Render the settings template
  907. include_once( plugin_dir_path( __FILE__ ) . 'core/settings/settings.php' );
  908. }
  909. function admin_notice_settings_updated() {
  910. ?>
  911. <div id="message" class="updated">
  912. <p><strong>Plugin Settings updated.</strong></p>
  913. </div>
  914. <?php
  915. }
  916. /*===============================================
  917. = Misc & Helper Functions =
  918. ===============================================*/
  919. /**
  920. * Get the value of a Project Field if it exists
  921. */
  922. function get_project_field_value( $key = 0 ) {
  923. if ( !$key ) { return false; }
  924. // If that key is set, return it. Otherwise return false.
  925. return isset( $this->current_project[ $key ] ) ? $this->current_project[ $key ] : false;
  926. } // END get_project_field_value
  927. function get_project_volunteer_single( $id ) {
  928. return !empty( $this->volunteers[ $id ] ) ? $this->volunteers[ $id ] : false;
  929. }
  930. function stored_emply_meta( $wp_id ) {
  931. return isset_or_false( $this->emply_meta[ $wp_id ] );
  932. } // END stored_emply_meta()
  933. /**
  934. * Keep track of the number of queries run on the Sforce DB
  935. **/
  936. function _log_queries() {
  937. error_log("Queries: " . $_SESSION['queries']);
  938. _log("Queries: " . $_SESSION['queries']);
  939. } // end _log_queries()
  940. /**
  941. * Echo the HTML markup for the current post's title linked to the post permalink.
  942. *
  943. * @access public
  944. * @param mixed $args
  945. * @return void
  946. */
  947. function permalinked_title( $args ) {
  948. $defaults = array (
  949. 'class' => '',
  950. 'post_id' => 0
  951. );
  952. $args = wp_parse_args( $args, $defaults );
  953. extract( $args, EXTR_SKIP );
  954. if( !$post_id )
  955. {
  956. global $post;
  957. if( $post )
  958. {
  959. $post_id = intval( $post->ID );
  960. }
  961. }
  962. $title = get_the_title( $post_id );
  963. ?>
  964. <a class="<?php echo $class; ?>" href="<?php echo get_permalink( $post_id ); ?>" title="<?php echo $title ; ?>"><?php echo $title; ?></a>
  965. <?php
  966. } // END permalinked_title()
  967. /**
  968. * Used to determine whether admin assets should be loaded
  969. *
  970. * @access public
  971. * @return bool
  972. */
  973. function is_ph_sf_admin_page() {
  974. $screen = get_current_screen();
  975. $is_settings_page = isset( $_GET['page'] ) && $_GET['page'] == $this->settings_page_slug;
  976. $is_cpt_page = $screen->post_type == PH_Project::CPT_NAME || $screen->post_type == PH_Employee::CPT_NAME;
  977. return $is_settings_page || $is_cpt_page;
  978. } // END is_ph_sf_admin_page()
  979. function run_migration() {
  980. global $ph_migrator;
  981. include_once 'core/includes/migration.php';
  982. $ph_migrator = new PH_Migrator();
  983. } // end run_migration
  984. } // end PH_Salesforce class def
  985. } // end if !class_exists("PH_Salesforce")
  986. $doing_ajax = defined('DOING_AJAX') && DOING_AJAX ;
  987. $is_local = ( isset( $_SERVER['HTTP_HOST'] ) && strstr( $_SERVER['HTTP_HOST'], 'localhost' ) ) || isset( $_SERVER['TERM'] );
  988. if( !$doing_ajax && !$chrome_php_enabled && $is_local )
  989. _log("\t\t--------- Runnin ".date('Y-m-d h:i:s A', time() )." EST ---------\n");
  990. if( class_exists('PH_Salesforce') ) {
  991. global $ph_salesforce;
  992. $ph_salesforce = new PH_Salesforce();
  993. // Installation and uninstallation hooks
  994. register_activation_hook(__FILE__, array( &$ph_salesforce, 'activate'));
  995. register_deactivation_hook(__FILE__, array( &$ph_salesforce, 'deactivate'));
  996. add_action('try_import_event_hook', array( &$ph_salesforce, 'try_import' ) );
  997. if( isset( $ph_salesforce ) ) { // Add the settings link to the plugins page
  998. include_once 'core/includes/public-functions.php';
  999. /**
  1000. * Add Plugin Settings page link next to the Edit / Activate links on the Plugins page
  1001. */
  1002. function plugin_settings_link($links) {
  1003. global $ph_salesforce;
  1004. $settings_link = '<a href="admin.php?page=' .$ph_salesforce->settings_page_slug .'">Settings</a>';
  1005. array_unshift($links, $settings_link);
  1006. return $links;
  1007. } //end plugin_settings_link
  1008. $plugin = plugin_basename(__FILE__);
  1009. add_filter("plugin_action_links_$plugin", 'plugin_settings_link');
  1010. //Add custom classes to body
  1011. function ph_sf_cpt_body_class( $classes ){
  1012. global $post;
  1013. // If this is a single page w/a post type param
  1014. if( is_single() && isset( $post->post_type ) ) {
  1015. $post_type_obj = get_post_type_object( $post->post_type );
  1016. $rewrite_slug = '';
  1017. if( is_array( $post_type_obj->rewrite ) ) {
  1018. $rewrite_slug = $post_type_obj->rewrite['slug'];
  1019. }
  1020. $classes[] = 'single-' . sanitize_html_class( $rewrite_slug );
  1021. }
  1022. return $classes;
  1023. } // END ph_sf_cpt_body_class()
  1024. add_filter( 'body_class', 'ph_sf_cpt_body_class' );
  1025. }
  1026. } // END class_exists('PH_Salesforce')
  1027. ?>