WC_POS_Template

Responsible for the POS front-end.

Defined (1)

The class is defined in the following location(s).

/includes/class-wc-pos-template.php  
  1. class WC_POS_Template { 
  2.  
  3. /** @var POS url slug */ 
  4. private $slug; 
  5.  
  6. /** @var regex match for rewite_rule */ 
  7. private $regex; 
  8.  
  9. /** @var WC_POS_Params instance */ 
  10. public $params; 
  11.  
  12. /** @var array external libraries */ 
  13. static public $external_libs = array( 
  14. 'min' => array( 
  15. 'jquery' => 'https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js',  
  16. 'lodash' => 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js',  
  17. 'backbone' => 'https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.2.3/backbone-min.js',  
  18. 'radio' => 'https://cdnjs.cloudflare.com/ajax/libs/backbone.radio/1.0.2/backbone.radio.min.js',  
  19. 'marionette' => 'https://cdnjs.cloudflare.com/ajax/libs/backbone.marionette/2.4.3/backbone.marionette.min.js',  
  20. 'handlebars' => 'https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.3/handlebars.min.js',  
  21. 'idb-wrapper' => 'https://cdnjs.cloudflare.com/ajax/libs/idbwrapper/1.6.0/idbstore.min.js',  
  22. 'moment' => 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.min.js',  
  23. 'accounting' => 'https://cdnjs.cloudflare.com/ajax/libs/accounting.js/0.4.1/accounting.min.js',  
  24. 'jquery.color' => 'https://cdnjs.cloudflare.com/ajax/libs/jquery-color/2.1.2/jquery.color.min.js',  
  25. ),  
  26. 'debug' => array( 
  27. 'jquery' => 'https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.js',  
  28. 'lodash' => 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js',  
  29. 'backbone' => 'https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.2.3/backbone.js',  
  30. 'radio' => 'https://cdnjs.cloudflare.com/ajax/libs/backbone.radio/1.0.2/backbone.radio.js',  
  31. 'marionette' => 'https://cdnjs.cloudflare.com/ajax/libs/backbone.marionette/2.4.3/backbone.marionette.js',  
  32. 'handlebars' => 'https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.3/handlebars.js',  
  33. 'idb-wrapper' => 'https://cdnjs.cloudflare.com/ajax/libs/idbwrapper/1.6.0/idbstore.min.js',  
  34. 'moment' => 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.js',  
  35. 'accounting' => 'https://cdnjs.cloudflare.com/ajax/libs/accounting.js/0.4.1/accounting.js',  
  36. 'jquery.color' => 'https://cdnjs.cloudflare.com/ajax/libs/jquery-color/2.1.2/jquery.color.js',  
  37. ); 
  38.  
  39. /** 
  40. * Constructor 
  41. */ 
  42. public function __construct() { 
  43.  
  44. if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) { 
  45. add_action( 'wp_ajax_wc_pos_payload', array( $this, 'payload' ) ); 
  46.  
  47. return; 
  48.  
  49. $this->slug = WC_POS_Admin_Permalink::get_slug(); 
  50. $this->regex = '^' . $this->slug . '/?$'; 
  51.  
  52. add_rewrite_tag( '%pos%', '([^&]+)' ); 
  53. add_rewrite_rule( $this->regex, 'index.php?pos=1', 'top' ); 
  54. add_filter( 'option_rewrite_rules', array( $this, 'rewrite_rules' ), 1 ); 
  55. add_action( 'template_redirect', array( $this, 'template_redirect' ), 1 ); 
  56.  
  57. /** 
  58. * Make sure cache contains POS rewrite rule 
  59. * @param $rules 
  60. * @return bool 
  61. */ 
  62. public function rewrite_rules( $rules ) { 
  63. return isset( $rules[ $this->regex ] ) ? $rules : false; 
  64.  
  65. /** 
  66. * Output the POS template 
  67. */ 
  68. public function template_redirect() { 
  69. // check is pos 
  70. if ( !is_pos( 'template' ) ) 
  71. return; 
  72.  
  73. // check auth 
  74. if ( !is_user_logged_in() ) { 
  75. add_filter( 'login_url', array( $this, 'login_url' ) ); 
  76. auth_redirect(); 
  77.  
  78. // check privileges 
  79. if ( !current_user_can( 'access_woocommerce_pos' ) ) 
  80. /** translators: wordpress */ 
  81. wp_die( __( 'You do not have sufficient permissions to access this page.' ) ); 
  82.  
  83. // disable cache plugins 
  84. $this->no_cache(); 
  85.  
  86. // last chance before template is rendered 
  87. do_action( 'woocommerce_pos_template_redirect' ); 
  88.  
  89. // add head & footer actions 
  90. add_action( 'woocommerce_pos_head', array( $this, 'head' ) ); 
  91. add_action( 'woocommerce_pos_footer', array( $this, 'footer' ) ); 
  92.  
  93. // now show the page 
  94. include 'views/template.php'; 
  95. exit; 
  96.  
  97.  
  98. /** 
  99. * Add variable to login url to signify POS login 
  100. * @param $login_url 
  101. * @return mixed 
  102. */ 
  103. public function login_url( $login_url ) { 
  104. return add_query_arg( 'pos', '1', $login_url ); 
  105.  
  106. /** 
  107. * Disable caching conflicts 
  108. */ 
  109. private function no_cache() { 
  110.  
  111. // disable W3 Total Cache minify 
  112. if ( !defined( 'DONOTMINIFY' ) ) 
  113. define( 'DONOTMINIFY', true ); 
  114.  
  115. // disable WP Super Cache 
  116. if ( !defined( 'DONOTCACHEPAGE' ) ) 
  117. define( 'DONOTCACHEPAGE', true ); 
  118.  
  119.  
  120. /** 
  121. * @return array 
  122. */ 
  123. static public function get_external_js_libraries() { 
  124. return defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? self::$external_libs[ 'debug' ] : self::$external_libs[ 'min' ]; 
  125.  
  126. /** 
  127. * Output the head scripts 
  128. */ 
  129. public function head() { 
  130.  
  131. // enqueue and print javascript 
  132. $styles = apply_filters( 'woocommerce_pos_enqueue_head_css', array( 
  133. 'pos-css' => WC_POS_PLUGIN_URL . 'assets/css/pos.min.css?ver=' . WC_POS_VERSION 
  134. ) ); 
  135.  
  136. foreach ( $styles as $style ) { 
  137. echo $this->format_css( trim( $style ) ) . "\n"; 
  138.  
  139. // enqueue and print javascript 
  140. $js = array( 
  141. 'modernizr' => WC_POS_PLUGIN_URL . 'assets/js/vendor/modernizr.custom.min.js?ver=' . WC_POS_VERSION,  
  142. ); 
  143.  
  144. $scripts = apply_filters( 'woocommerce_pos_enqueue_head_js', $js ); 
  145. foreach ( $scripts as $script ) { 
  146. echo $this->format_js( trim( $script ) ) . "\n"; 
  147.  
  148. /** 
  149. * Output the footer scripts 
  150. */ 
  151. public function footer() { 
  152. $build = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? 'build' : 'min'; 
  153.  
  154. $js = self::get_external_js_libraries(); 
  155. $js[ 'scrollIntoView' ] = WC_POS_PLUGIN_URL . 'assets/js/vendor/jquery.scrollIntoView.min.js?ver=' . WC_POS_VERSION; 
  156. $js[ 'app' ] = WC_POS_PLUGIN_URL . 'assets/js/app.' . $build . '.js?ver=' . WC_POS_VERSION; 
  157. $scripts = apply_filters( 'woocommerce_pos_enqueue_footer_js', $js ); 
  158.  
  159. foreach ( $scripts as $script ) { 
  160. echo $this->format_js( trim( $script ) ) . "\n"; 
  161.  
  162. /** 
  163. * Makes sure css is in the right format for template 
  164. * @param $style 
  165. * @return string 
  166. */ 
  167. private function format_css( $style ) { 
  168. if ( substr( $style, 0, 5 ) === '<link' ) 
  169. return $style; 
  170.  
  171. if ( substr( $style, 0, 4 ) === 'http' ) 
  172. return '<link rel="stylesheet" href="' . $style . '" type="text/css" />'; 
  173.  
  174. return '<style>' . $style . '</style>'; 
  175.  
  176. /** 
  177. * Makes sure javascript is in the right format for template 
  178. * @param $script 
  179. * @return string 
  180. */ 
  181. private function format_js( $script ) { 
  182. if ( substr( $script, 0, 7 ) === '<script' ) 
  183. return $script; 
  184.  
  185. if ( substr( $script, 0, 4 ) === 'http' ) 
  186. return '<script src="' . $script . '"></script>'; 
  187.  
  188. return '<script>' . $script . '</script>'; 
  189.  
  190. /** 
  191. * Sanitize payment icon 
  192. * - some gateways include junk in icon property, eg: paypal link 
  193. * @param WC_Payment_Gateway $gateway 
  194. * @return string 
  195. */ 
  196. protected function sanitize_icon( WC_Payment_Gateway $gateway ) { 
  197. $icon = $gateway->show_icon ? $gateway->get_icon() : ''; 
  198. if ( $icon !== '' ) { 
  199. // simple preg_match 
  200. preg_match( '/< *img[^>]*src *= *["\']?([^"\']*)/i', $icon, $src ); 
  201. $icon = $src[ 1 ]; 
  202.  
  203. return $icon; 
  204.  
  205. /** 
  206. * Sanitize payment fields 
  207. * - some gateways include js in their payment fields 
  208. * @param WC_Payment_Gateway $gateway 
  209. * @return mixed|string 
  210. */ 
  211. protected function sanitize_payment_fields( WC_Payment_Gateway $gateway ) { 
  212. $html = ''; 
  213. if ( $gateway->has_fields() || $gateway->get_description() ) { 
  214.  
  215. ob_start(); 
  216. $gateway->payment_fields(); 
  217. $html = ob_get_contents(); 
  218. ob_end_clean(); 
  219.  
  220. // remove script tags 
  221. $html = $this->removeDomNodes( $html, '//script' ); 
  222.  
  223. return self::trim_html_string( $html );; 
  224.  
  225. /** 
  226. * Removes dom nodes, eg: <script> elements 
  227. * @param $html 
  228. * @param $xpathString 
  229. * @return string 
  230. */ 
  231. private function removeDomNodes( $html, $xpathString ) { 
  232. if( ! class_exists('DOMDocument') ) { 
  233. return preg_replace('/<script.+?<\/script>/im', '', $html); 
  234. $dom = new DOMDocument(); 
  235. // suppress warnings for malformed HTML 
  236. libxml_use_internal_errors(true); 
  237. // Libxml constants not available on all servers (Libxml < 2.7.8) 
  238. // $html->loadHTML($content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); 
  239. $dom->loadHtml( '<?xml encoding="UTF-8">' . '<div class="form-group">' . $html . '</div>' ); 
  240. $dom->preserveWhiteSpace = false; 
  241. // remove <!DOCTYPE 
  242. $dom->removeChild( $dom->doctype ); 
  243. // remove <?xml encoding="UTF-8"> 
  244. $dom->removeChild( $dom->firstChild ); 
  245. // <html><body></body></html> 
  246. $dom->replaceChild( $dom->firstChild->firstChild->firstChild, $dom->firstChild ); 
  247. // remove the required node 
  248. $xpath = new DOMXPath( $dom ); 
  249. while ( $node = $xpath->query( $xpathString )->item( 0 ) ) { 
  250. $node->parentNode->removeChild( $node ); 
  251. return $dom->saveHTML(); 
  252.  
  253. /** 
  254. * Returns an assoc array of all default tmpl-*.php paths 
  255. * - uses SPL iterators 
  256. * @param $partials_dir 
  257. * @return array 
  258. */ 
  259. static public function locate_default_template_files( $partials_dir = '' ) { 
  260. if ( empty( $partials_dir ) ) 
  261. $partials_dir = self::get_template_dir(); 
  262.  
  263. $iterator = new RecursiveIteratorIterator( 
  264. new RecursiveDirectoryIterator( $partials_dir ),  
  265. RecursiveIteratorIterator::SELF_FIRST 
  266. ); 
  267.  
  268. $regex = new RegexIterator( 
  269. $iterator, '/^.+tmpl-[a-z-]+\.php$/i',  
  270. RecursiveRegexIterator::GET_MATCH 
  271. ); 
  272.  
  273. $paths = array_keys( iterator_to_array( $regex ) ); 
  274. $templates = array(); 
  275.  
  276. foreach ( $paths as $path ) { 
  277. $slug = str_replace( array( $partials_dir, '.php' ), '', $path ); 
  278. $templates[ $slug ] = $path; 
  279. }; 
  280.  
  281. return $templates; 
  282.  
  283. /** 
  284. * Returns an array of template paths 
  285. * @param $partials_dir 
  286. * @return array 
  287. */ 
  288. static public function locate_template_files( $partials_dir = '' ) { 
  289. $files = array(); 
  290. foreach ( self::locate_default_template_files( $partials_dir ) as $slug => $path ) { 
  291. $files[ $slug ] = self::locate_template_file( $path ); 
  292. }; 
  293.  
  294. return $files; 
  295.  
  296. /** 
  297. * Locate a single template partial 
  298. * @param string $default_path 
  299. * @return string 
  300. */ 
  301. static public function locate_template_file( $default_path = '' ) { 
  302. $custom_path1 = str_replace( self::get_template_dir(), 'woocommerce-pos', $default_path ); 
  303. $custom_path2 = str_replace( 'tmpl-', '', $custom_path1 ); 
  304. $custom = locate_template( array( $custom_path1, $custom_path2 ) ); 
  305.  
  306. return $custom ? $custom : $default_path; 
  307.  
  308. /** 
  309. * Returns the partials directory 
  310. * @return string 
  311. */ 
  312. static public function get_template_dir() { 
  313. return realpath( WC_POS_PLUGIN_PATH . 'includes/views' ); 
  314.  
  315. /** 
  316. * @param $partials_dir 
  317. * @return array 
  318. */ 
  319. static public function create_templates_array( $partials_dir = '' ) { 
  320. $templates = array(); 
  321.  
  322. foreach ( self::locate_template_files( $partials_dir ) as $slug => $file ) { 
  323. $keys = explode( substr( $slug, 0, 1 ), substr( $slug, 1 ) ); 
  324. $template = array_reduce( array_reverse( $keys ), function ( $result, $key ) { 
  325. if ( is_string( $result ) ) 
  326. $key = preg_replace( '/^tmpl-/i', '', $key ); 
  327.  
  328. return array( $key => $result ); 
  329. }, self::template_output( $file ) ); 
  330. $templates = array_merge_recursive( $templates, $template ); 
  331.  
  332. return $templates; 
  333.  
  334. /** 
  335. * Output template partial as string 
  336. * @param $file 
  337. * @return string 
  338. */ 
  339. static public function template_output( $file ) { 
  340. ob_start(); 
  341. include $file; 
  342. $template = ob_get_clean(); 
  343.  
  344. return self::trim_html_string( $template ); 
  345.  
  346. /** 
  347. * Remove newlines and code spacing 
  348. * @param $str 
  349. * @return mixed 
  350. */ 
  351. static private function trim_html_string( $str ) { 
  352. return preg_replace( '/^\s+|\n|\r|\s+$/m', '', $str ); 
  353.  
  354. /** 
  355. * @return array 
  356. */ 
  357. private function gateways_templates() { 
  358. $settings = WC_POS_Admin_Settings_Checkout::get_instance(); 
  359. $gateways = $settings->load_enabled_gateways(); 
  360. $templates = array(); 
  361.  
  362. if ( $gateways ): foreach ( $gateways as $gateway ): 
  363. $this->params->gateways[] = array( 
  364. 'method_id' => $gateway->id,  
  365. 'method_title' => esc_html( $gateway->get_title() ),  
  366. 'icon' => $this->sanitize_icon( $gateway ),  
  367. 'active' => $gateway->default 
  368. ); 
  369. $templates[ $gateway->id ] = $this->sanitize_payment_fields( $gateway ); 
  370. endforeach; endif; 
  371.  
  372. return $templates; 
  373.  
  374. /** 
  375. * @return mixed|void 
  376. */ 
  377. public function payload() { 
  378. WC_POS_Server::check_ajax_referer(); 
  379.  
  380. $this->params = new WC_POS_Params(); 
  381.  
  382. $payload = array( 
  383. 'templates' => $this->templates_payload(),  
  384. 'params' => $this->params->payload(),  
  385. 'i18n' => WC_POS_i18n::payload() 
  386. ); 
  387.  
  388. WC_POS_Server::response( $payload ); 
  389.  
  390. /** 
  391. * @return mixed|void 
  392. */ 
  393. public function templates_payload() { 
  394. $templates = self::create_templates_array(); 
  395. $templates[ 'pos' ][ 'checkout' ][ 'gateways' ] = $this->gateways_templates(); 
  396.  
  397. return apply_filters( 'woocommerce_pos_templates', $templates ); 
  398.