diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..89e08fb --- /dev/null +++ b/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/README.md b/README.md deleted file mode 100644 index 8675a48..0000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -# sizeme-woocommerce-extension diff --git a/classes/class-wc-settings-sizeme-measurements.php b/classes/class-wc-settings-sizeme-measurements.php new file mode 100644 index 0000000..d872e34 --- /dev/null +++ b/classes/class-wc-settings-sizeme-measurements.php @@ -0,0 +1,250 @@ +id = 'sizeme_measurements'; + $this->label = __( 'SizeMe Measurements', 'sizeme' ); + + parent::__construct(); + } + + /** + * Get sections. + * + * Returns the sections for the settings page. + * + * @since 1.0.0 + * + * @return array + */ + public function get_sections() { + $sections = array( + '' => __( 'Settings', 'sizeme' ), + ); + + return apply_filters( 'woocommerce_get_sections_' . $this->id, $sections ); + } + + /** + * Get settings array. + * + * Returns the settings form. + * + * @since 1.0.0 + * + * @return array + */ + public function get_settings() { + + $settings = array( + array( + 'title' => __( 'General settings', 'sizeme' ), + 'type' => 'title', + 'id' => 'general_settings', + ), + array( + 'title' => __( 'Custom size selection', 'sizeme' ), + 'desc' => __( 'Use custom size selection ', 'sizeme' ), + 'type' => 'checkbox', + 'default' => 'no', + 'id' => WC_SizeMe_Measurements::CUSTOM_SIZE_SELECTION_ID, + ), + array( + 'title' => __( 'Service status', 'sizeme' ), + 'type' => 'select', + 'options' => array( + '' => __( 'Select service status', 'sizeme' ), + self::SERVICE_STATUS_TEST => 'Test', + self::SERVICE_STATUS_ON => 'On', + self::SERVICE_STATUS_OFF => 'Off', + ), + 'id' => WC_SizeMe_Measurements::SERVICE_STATUS_ID, + ), + array( + 'type' => 'sectionend', + 'id' => 'general_settings', + ), + array( + 'title' => __( 'Attribute settings', 'sizeme' ), + 'type' => 'title', + 'id' => 'attribute_settings', + ), + array( + 'title' => __( 'Product Size Attributes', 'sizeme' ), + 'desc' => __( 'Select the attributes for sizes', 'sizeme' ), + 'type' => 'multiselect', + 'options' => self::load_size_attribute_options(), + 'css' => 'width: 150px; height: 150px;', + 'id' => 'size_attributes', + ), + array( + 'type' => 'sectionend', + 'id' => 'attribute_settings', + ), + array( + 'title' => __( 'UI options', 'sizeme' ), + 'type' => 'title', + 'id' => 'ui_options', + ), + array( + 'title' => __( 'Append content to element', 'sizeme' ), + 'type' => 'text', + 'default' => get_option( WC_SizeMe_Measurements::APPEND_CONTENT_TO, '' ), + 'id' => WC_SizeMe_Measurements::APPEND_CONTENT_TO, + ), + array( + 'title' => __( 'Append splash to element', 'sizeme' ), + 'type' => 'text', + 'default' => get_option( WC_SizeMe_Measurements::APPEND_SPLASH_TO, '' ), + 'id' => WC_SizeMe_Measurements::APPEND_SPLASH_TO, + ), + array( + 'title' => __( 'Add to cart element', 'sizeme' ), + 'type' => 'text', + 'default' => get_option( WC_SizeMe_Measurements::ADD_TO_CART_ELEMENT, '' ), + 'id' => WC_SizeMe_Measurements::ADD_TO_CART_ELEMENT, + ), + array( + 'title' => __( 'Add to cart event', 'sizeme' ), + 'type' => 'text', + 'default' => get_option( WC_SizeMe_Measurements::ADD_TO_CART_EVENT, '' ), + 'id' => WC_SizeMe_Measurements::ADD_TO_CART_EVENT, + ), + array( + 'title' => __( 'Size selection container element', 'sizeme' ), + 'type' => 'text', + 'default' => get_option( WC_SizeMe_Measurements::SIZE_SELECTION_CONTAINER_ELEMENT, '' ), + 'id' => WC_SizeMe_Measurements::SIZE_SELECTION_CONTAINER_ELEMENT, + ), + array( + 'type' => 'sectionend', + 'id' => 'ui_options', + ), + + ); + + return apply_filters( 'woocommerce_get_settings_' . $this->id, $settings ); + } + + /** + * Output the settings. + * + * Outputs the settings form. + * + * @since 1.0.0 + */ + public function output() { + $settings = $this->get_settings(); + WC_Admin_Settings::output_fields( $settings ); + } + + /** + * Save settings. + * + * Saves the settings form in the wp_options table. + * + * @since 1.0.0 + */ + public function save() { + $settings = $this->get_settings(); + WC_Admin_Settings::save_fields( $settings ); + } + + /** + * Load the size attribute options. + * + * Return a list of attribute_name => attribute_label. + * + * @since 1.0.0 + * + * @return array + */ + public function load_size_attribute_options() { + $taxonomies = wc_get_attribute_taxonomies(); + $result = array(); + foreach ( $taxonomies as $taxonomy ) { + // Skip the SizeMe attributes in the list. + if ( strpos( $taxonomy->attribute_name, 'sm_' ) === 0 + || strpos( $taxonomy->attribute_name, 'smi_' ) === 0 + ) { + continue; + } + $result[ $taxonomy->attribute_name ] = $taxonomy->attribute_label; + } + + return $result; + } +} + +return new WC_Settings_SizeMe_Measurements(); diff --git a/classes/class-wc-sizeme-measurements-attributes.php b/classes/class-wc-sizeme-measurements-attributes.php new file mode 100644 index 0000000..af3791f --- /dev/null +++ b/classes/class-wc-sizeme-measurements-attributes.php @@ -0,0 +1,121 @@ + Attributes -> Add new`: label: Size, slug: size + + Click the cogwheel to add attribute values (these values are just for example): + + * label: XS, slug: extra-small + * label: S, slug: small + * label: M, slug: medium + * label: L, slug: large + * label: XL, slug: extra-large + + If you have any other size attributes, go ahead and add them as well, e.g. Shoe size, Hat size etc. +4. Configure the plugin at `wp-admin/admin.php?page=wc-settings&tab=sizeme_measurements` (`WooCommerce -> Settings -> SizeMe Measurements`) + + ##General settings + * Custom size selection: Whether to use the custom size selection buttons that SizeMe provides or not + * Service status: The SizeMe service status + * Test: Testing + * On: Service is in use in production + * Off: Service is off + + ##Attribute settings + * Product size attributes: Select all your size attributes that you might use, e.g. Size, Shoe size etc. + + ##UI Options + * These options are the HTML class names where you want the SizeMe Measurements plugin to be shown. + The defaults here are suitable for the WooCommerce theme Storefront. + You will need to adjust these values according to your theme, or if you want to place the SizeMe plugin in another HTML element. +5. Creating a product + + When creating a new product, or updating an old one, you will need to add the SizeMe Measurements attributes to the product. + + **NOTE:** Only a "Variable Product" can use the SizeMe Measurements attributes. + + Navigate to the "Product Data" section, and choose the "Attributes" tab. + You MUST have only ONE (1) size attribute selected for the product. If you have multiple, the plugin won't work. + Remember to check the check-box "Used for variations". + + Navigate to the "SizeMe" tab in the "Product Data" section. + You MUST add the following SizeMe attributes for the product (these are general attributes for the whole product): + + * SizeMe Item Type (as defined in SizeMe for product types - Shirts, Shoes etc.) + * SizeMe Item Layer + * SizeMe Item Thickness + * SizeMe Item Stretch + + To save the "SizeMe Item" attributes, you need to save the whole product by clicking on the "Publish" or "Update" button + in the top right-hand side of the page. + + Now you should add the SizeMe attributes to your product variations: + Navigate to the "Variations" tab in the "Product Data" section. + + Add or choose a variation, and fill in the necessary SizeMe attributes for the variation (e.g. for shoes): + + * Shoe inside width + * Shoe inside length + + Hoodies: + + * Chest + * Waist + * Sleeve + * Sleeve top width + * Wrist width + * Shoulder width + * Front height + * Hips + * Hood height + + Click "Save changes" to save the updated values. + +== Changelog == + += 1.0.0 = +* Initial release. diff --git a/sizeme-wordpress.php b/sizeme-wordpress.php new file mode 100644 index 0000000..49f4a8d --- /dev/null +++ b/sizeme-wordpress.php @@ -0,0 +1,862 @@ +plugin_dir = untrailingslashit( plugin_dir_path( __FILE__ ) ); + $this->plugin_url = plugin_dir_url( __FILE__ ); + $this->plugin_name = plugin_basename( __FILE__ ); + + register_activation_hook( $this->plugin_name, array( $this, 'activate' ) ); + // The uninstall hook callback needs to be a static class method or function. + register_uninstall_hook( $this->plugin_name, array( __CLASS__, 'uninstall' ) ); + } + + /** + * Initializes the plugin. + * + * Register hooks outputting SizeMe block in frontend. + * Handles the backend admin page integration. + * + * @since 1.0.0 + */ + public function init() { + if ( is_admin() ) { + $this->init_admin(); + } else { + $this->init_frontend(); + } + } + + /** + * Register scripts. + * + * Registers the necessary JavaScript and stylesheets. + * + * @since 1.0.0 + */ + public function register_scripts() { + global $post; + + // Get the product object, and make sure it is a variable product. + $product = wc_get_product( $post ); + if ( $product instanceof WC_Product_Variable ) { + wp_enqueue_script( 'sizeme_deps_js', 'http://sizeme.com/2.1/js/sizeme-woocommerce-with-deps.min.js' ); + wp_enqueue_style( 'sizeme_css', 'http://sizeme.com/2.1/css/sizeme-woocommerce.min.css' ); + } + } + + /** + * Check if the given attribute is a SizeMe Measurement attribute. + * + * Checks against the pre-configured SizeMe attributes, if the given attribute is one of them. + * + * @since 1.0.0 + * + * @param string $attribute_name The attribute name to check. + * + * @return bool True if it is a SizeMe attribute, false otherwise. + */ + public function is_sizeme_attribute( $attribute_name ) { + $this->load_class( 'WC_SizeMe_Measurements_Attributes' ); + + if ( empty( $attribute_name ) || substr( $attribute_name, 0, strlen( '_sm_' ) ) !== '_sm_' ) { + return false; + } + + // Remove the underscore from the attribute name, e.g. _sm_waist => sm_waist. + $attribute = substr( $attribute_name, 1 ); + + return in_array( $attribute, WC_SizeMe_Measurements_Attributes::get_attribute_names(), true ); + } + + /** + * Get the service status. + * + * Gets the service status from the configuration. + * One of 'test', 'on', 'off' + * + * @since 1.0.0 + * + * @return string The service status. + */ + public function get_service_status() { + return get_option( self::SERVICE_STATUS_ID ); + } + + /** + * Get the custom size selection. + * + * Gets if the SizeMe Measurements custom size selection should be used. + * + * @since 1.0.0 + * + * @return string Custom size selection, yes, no. + */ + public function get_custom_size_selection() { + return get_option( self::CUSTOM_SIZE_SELECTION_ID ); + } + + /** + * Get a configured UI option. + * + * Gets the value of the given option from the configuration. + * + * @since 1.0.0 + * + * @param string $option The UI option to get. + * @param mixed|false $default The default if option not found. Defaults to false. + * + * @return string|mixed The option value. + */ + public function get_ui_option( $option, $default = false ) { + return get_option( $option, $default ); + } + + /** + * Returns a map of SizeMe attribute names with their corresponding values. + * + * The map can be directly converted into and JS SizeMe product item in the + * view file. + * + * Format: + * + * array( + * "chest" => 530, + * "waist" => 510, + * "sleeve" => 220, + * "sleeve_top_width" => 208, + * "wrist_width" => 175, + * "underbust" => 0, + * "neck_opening_width" => 0, + * "shoulder_width" => 126, + * "front_height" => 720, + * "pant_waist" => 0, + * "hips" => 510, + * "inseam" => 0, + * "outseam" => 0, + * "thigh_width" => 0, + * "knee_width" => 0, + * "calf_width" => 0, + * "pant_sleeve_width" => 0, + * "shoe_inside_length" => 0, + * "shoe_inside_width" => 0, + * "hat_width" => 0, + * "hood_height" => 0, + * ) + * + * @since 1.0.0 + * + * @param WC_Product_Variable $product The product. + * + * @return array The attribute map, or empty array if not correct product. + */ + public function get_variation_sizeme_attributes( WC_Product_Variable $product ) { + + if ( is_product() ) { + // Only for variable products. + if ( $product instanceof WC_Product_Variable ) { + return $this->load_attributes( $product ); + } + } + + return array(); + } + + /** + * Load the SizeMe Measurements attributes. + * + * Loads the SizeMe attributes in the attributes array. + * + * @since 1.0.0 + * @access protected + * + * @param WC_Product_Variable $product The product. + * + * @return array The attributes. + */ + protected function load_attributes( WC_Product_Variable $product ) { + if ( empty( self::$attributes[ $product->id ] ) ) { + $variations = $product->get_available_variations(); + foreach ( $variations as $variation ) { + $variation_meta = get_post_meta( $variation['variation_id'] ); + if ( is_array( $variation_meta ) && count( $variation_meta ) > 0 ) { + $size_attribute = $this->get_size_attribute( $product ); + foreach ( $variation_meta as $attribute => $value ) { + if ( ! is_array( $value ) || ! isset( $value[0] ) ) { + continue; + } + + if ( $this->is_sizeme_attribute( $attribute ) ) { + // Remove '_sm_' from the attribute, as we only want "chest", "waist" etc. + $attribute = substr( $attribute, strlen( '_sm_' ), strlen( $attribute ) ); + if ( isset( $variation['attributes'][ 'attribute_pa_' . $size_attribute ] ) ) { + // The attribute code value here is the attribute_pa_size, which is "small","extra-small","large", or whatever the slug is. + $attribute_code = $variation['attributes'][ 'attribute_pa_' . $size_attribute ]; + if ( ! isset( self::$attributes[ $product->id ][ $attribute_code ][ $attribute ] ) ) { + self::$attributes[ $product->id ][ $attribute_code ][ $attribute ] = $value[0]; + } + } + } + } + } + } + } + + return self::$attributes[ $product->id ]; + } + + /** + * Get the configured size attribute(s). + * + * Gets the name(s) of the configured size attributes. Can be 'size', 'shoe_size' etc. + * + * @since 1.0.0 + * @access protected + * + * @param WC_Product_Variable $product The product. + * @param bool|true $one Whether to get all size attributes, or just one. + * + * @return array|string If parameter $one is true, returns a string of attribute name, otherwise an array of names. + */ + protected function get_size_attribute( WC_Product_Variable $product, $one = true ) { + $size_attributes = get_option( 'size_attributes', array() ); + $product_attributes = $product->get_attributes(); + $attribute_names = array(); + foreach ( $product_attributes as $attribute_name => $attribute_data ) { + $attribute = substr( $attribute_name, strlen( 'pa_' ) ); + if ( in_array( $attribute, $size_attributes, true ) ) { + $attribute_names[] = $attribute; + } + } + + return $one ? array_pop( $attribute_names ) : $attribute_names; + } + + /** + * Check if given attribute is a size attribute. + * + * Checks given attribute against configured size attributes. + * + * @since 1.0.0 + * + * @param WC_Product_Variable $product The product. + * @param string $attribute The attribute name to check. + * + * @return bool True if the attribute is a size attribute, false otherwise. + */ + public function is_size_attribute( WC_Product_Variable $product, $attribute ) { + $size_attributes = $this->get_size_attribute( $product, false ); + + return in_array( substr( $attribute, strlen( 'pa_' ) ), $size_attributes, true ); + } + + /** + * Get the smi_item_* attribute for the product. + * + * Returns the set value for the smi_item_* attributes for the product. + * + * @param WC_Product_Variable $product The product variable. + * @param string $type The type to get. + * + * @return string|null The value for the smi_item_* or null if not found. + */ + public function get_smi_item( WC_Product_Variable $product, $type ) { + $post_meta = get_post_meta( $product->id ); + + return isset( $post_meta[ '_' . $type ][0] ) ? $post_meta[ '_' . $type ][0] : null; + } + + /** + * Add the SizeMe Measurement scripts to the product page. + * + * Renders the template that contains the JavaScript. + * + * @since 1.0.0 + */ + public function add_sizeme_scripts() { + if ( is_product() ) { + global $product; + // Make sure we only render for variable products. + if ( $product instanceof WC_Product_Variable ) { + $this->load_class( 'WC_SizeMe_Measurements_Attributes' ); + $this->render( 'sizeme-product', array( 'product' => $product, 'sizeme' => $this ) ); + } + } + } + + /** + * Renders a template file. + * + * The file is expected to be located in the plugin "templates" directory. + * + * @since 1.0.0 + * @access protected + * + * @param string $template The name of the template. + * @param array $data The data to pass to the template file. + */ + protected function render( $template, array $data = array() ) { + if ( is_array( $data ) ) { + // Instead of using extract() here (discouraged), make variable variables. + foreach ( $data as $key => $value ) { + ${$key} = $value; + } + } + $file = $template . '.php'; + if ( file_exists( $this->plugin_dir . '/templates/' . $file ) ) { + require( $this->plugin_dir . '/templates/' . $file ); + } + } + + /** + * Hook callback function for activating the plugin. + * + * @since 1.0.0 + */ + public function activate() { + // Check dependencies and die. + $this->check_dependencies(); + } + + /** + * Hook callback function for uninstalling the plugin. + * + * @since 1.0.0 + */ + public static function uninstall() { + // Todo: remove product attributes and everything else related to this plugin. + } + + /** + * Getter for the plugin base name. + * + * Gets the plugin name. + * + * @since 1.0.0 + * + * @return string + */ + public function get_plugin_name() { + return $this->plugin_name; + } + + /** + * Adds the settings page to WooCommerce settings. + * + * @since 1.0.0 + * + * @param array $settings List of settings. + * + * @return array The updated list of settings. + */ + public function add_setting_page( $settings ) { + $settings[] = require_once( 'classes/class-wc-settings-sizeme-measurements.php' ); + + return $settings; + } + + /** + * Initializes the plugin frontend part. + * + * Adds all hooks needed by the plugin in the frontend. + * + * @since 1.0.0 + */ + protected function init_frontend() { + + add_action( 'wp_enqueue_scripts', array( $this, 'register_scripts' ) ); + add_action( 'woocommerce_before_single_product', array( $this, 'add_sizeme_scripts' ), 20, 0 ); + + add_filter( 'woocommerce_locate_template', array( $this, 'locate_template' ), 10, 3 ); + } + + /** + * Initializes the plugin admin part. + * + * Adds a new integration into the WooCommerce settings structure. + * + * @since 1.0.0 + */ + protected function init_admin() { + add_filter( 'woocommerce_get_settings_pages', array( $this, 'add_setting_page' ) ); + add_filter( 'woocommerce_product_data_tabs', array( $this, 'product_data_tabs' ) ); + + add_action( 'woocommerce_save_product_variation', array( $this, 'save_product_variation' ), 10, 2 ); + add_action( 'woocommerce_product_after_variable_attributes', + array( $this, 'product_after_variable_attributes' ), 10, 3 ); + add_action( 'woocommerce_product_data_panels', array( $this, 'product_data_panels' ) ); + add_action( 'woocommerce_process_product_meta_variable', array( $this, 'process_product_meta_variable' ) ); + add_action( 'admin_notices', array( $this, 'admin_notices' ) ); + } + + /** + * Save product variation. + * + * Saves the SizeMe attributes for the given variation. + * + * @param int $variation_id The variation id. + * @param int $i The "loop", e.g. current variation. + * + * @since 1.0.0 + * + * @return void If nonce verification fails. + */ + public function save_product_variation( $variation_id, $i ) { + if ( empty( $_POST['sizeme_product_nonce'] ) || ( ! wp_verify_nonce( wp_unslash( $_POST['sizeme_product_nonce'] ), // Input var okay. + 'sizeme_save_product_variation' ) ) + ) { + return; + } + $this->load_class( 'WC_SizeMe_Measurements_Attributes' ); + foreach ( WC_SizeMe_Measurements_Attributes::get_attribute_names() as $attribute_name ) { + if ( isset( $_POST[ 'variable_' . $attribute_name ][ $i ] ) ) { // Input var okay. + $value = sanitize_text_field( wp_unslash( $_POST[ 'variable_' . $attribute_name ][ $i ] ) ); // Input var okay. + // Allow value to be reset to empty. + if ( '' === $value || intval( $value ) > 0 ) { + update_post_meta( $variation_id, '_' . $attribute_name, $value ); + } + } + } + } + + /** + * Render SizeMe attributes. + * + * Renders the SizeMe attributes on the product data section in the variations tab. + * + * @param int $loop The "loop" in which we are, e.g. current variation. + * @param array $variation_data The variation data. + * @param WP_Post $variation The current variation. + * + * @since 1.0.0 + */ + public function product_after_variable_attributes( $loop, $variation_data, $variation ) { + $this->load_class( 'WC_SizeMe_Measurements_Attributes' ); + + $variation_meta = get_post_meta( $variation->ID ); + $data = array(); + + // Build the data for the view. + foreach ( WC_SizeMe_Measurements_Attributes::get_attribute_names() as $attribute_name ) { + // Skip smi_* attributes. + if ( substr( $attribute_name, 0, strlen( 'smi_' ) ) === 'smi_' ) { + continue; + } + + $value = null; + if ( isset( $variation_meta[ '_' . $attribute_name ][0] ) ) { + $value = $variation_meta[ '_' . $attribute_name ][0]; + } + + $label = ucfirst( str_replace( '_', ' ', substr( $attribute_name, strlen( 'sm_' ) ) ) ); + + $data[ '_' . $attribute_name ] = array( + 'label' => __( $label, 'sizeme' ), + 'name' => 'variable_' . $attribute_name . '[' . $loop . ']', + 'value' => $value, + ); + } + + // Print out the nonce field. + wp_nonce_field( 'sizeme_save_product_variation', 'sizeme_product_nonce' ); + + $this->render( 'sizeme-product-variation', array( 'attribute_data' => $data ) ); + } + + /** + * Add product data tab. + * + * Adds a new SizeMe tab to the product data. + * + * @param array $tabs The current tabs. + * + * @since 1.0.0 + * + * @return array The tabs. + */ + public function product_data_tabs( $tabs ) { + $tabs['sizeme'] = array( + 'label' => __( 'SizeMe', 'sizeme' ), + 'target' => 'sizeme_product_data', + 'class' => array( 'hide_if_grouped', 'show_if_variable' ), + ); + + return $tabs; + } + + /** + * Process product meta. + * + * Handles saving of the SizeMe smi_item_* attributes. + * + * @param int $post_id The post id. + * + * @since 1.0.0 + */ + public function process_product_meta_variable( $post_id ) { + if ( empty( $_POST['sizeme_data_nonce'] ) || ( ! wp_verify_nonce( wp_unslash( $_POST['sizeme_data_nonce'] ), // Input var okay. + 'sizeme_product_data_panels' ) ) + ) { + return; + } + $attributes = array( + '_smi_item_type', + '_smi_item_layer', + '_smi_item_thickness', + '_smi_item_stretch', + ); + foreach ( $attributes as $attribute ) { + if ( isset( $_POST[ $attribute ] ) ) { // Input var okay. + $value = sanitize_text_field( wp_unslash( $_POST[ $attribute ] ) ); // Input var okay. + if ( '' === $value || intval( $value ) > 0 ) { + update_post_meta( $post_id, $attribute, $value ); + } + } + } + } + + /** + * Render data panels + * + * Renders the content of the SizeMe panel in the product administration. + * + * @since 1.0.0 + */ + public function product_data_panels() { + wp_nonce_field( 'sizeme_product_data_panels', 'sizeme_data_nonce' ); + $this->render( 'sizeme-data-panels' ); + } + + /** + * Show admin notice. + * + * Shows a notice if the SizeMe size attribute is not defined and the status of the service is ON. + * + * @since 1.0.0 + */ + public function admin_notices() { + $size_attributes = get_option( 'size_attributes', array() ); + if ( empty( $size_attributes ) ) { + $this->render( 'admin-notice' ); + } + } + + /** + * Load class file based on class name. + * + * The file are expected to be located in the plugin "classes" directory. + * + * @since 1.0.0 + * + * @param string $class_name The name of the class to load. + */ + protected function load_class( $class_name = '' ) { + $file = 'class-' . strtolower( str_replace( '_', '-', $class_name ) ) . '.php'; + if ( file_exists( $this->plugin_dir . '/classes/' . $file ) ) { + require_once( $this->plugin_dir . '/classes/' . $file ); + } + } + + /** + * Checks plugin dependencies. + * + * Mainly that the WordPress and WooCommerce versions are equal to or greater than + * the defined minimums. + * + * @since 1.0.0 + * + * @return bool True if dependency check OK, false otherwise. + */ + protected function check_dependencies() { + global $wp_version; + + $title = sprintf( __( 'WooCommerce SizeMe %s not compatible.' ), self::VERSION ); + $error = ''; + $args = array( + 'back_link' => true, + ); + + if ( version_compare( $wp_version, self::MIN_WP_VERSION, '<' ) ) { + $error = sprintf( + __( 'Looks like you\'re running an older version of WordPress, you need to be running at least + WordPress %1$s to use WooCommerce SizeMe Measurements %2$s.' ), + self::MIN_WP_VERSION, + self::VERSION + ); + } + + if ( ! defined( 'WOOCOMMERCE_VERSION' ) ) { + $error = sprintf( + __( 'Looks like you\'re not running any version of WooCommerce, you need to be running at least + WooCommerce %1$s to use WooCommerce SizeMe Measurements %2$s.' ), + self::MIN_WC_VERSION, + self::VERSION + ); + } else if ( version_compare( WOOCOMMERCE_VERSION, self::MIN_WC_VERSION, '<' ) ) { + $error = sprintf( + __( 'Looks like you\'re running an older version of WooCommerce, you need to be running at least + WooCommerce %1$s to use WooCommerce SizeMe Measurements %2$s.' ), + self::MIN_WC_VERSION, + self::VERSION + ); + } + + if ( ! empty( $error ) ) { + deactivate_plugins( $this->plugin_name ); + wp_die( $error, $title, $args ); // WPCS: XSS ok. + + return false; + } + + return true; + } + + /** + * Override the locate_template function. + * + * Adds support for overriding a WooCommerce template in our plugin. + * + * @since 1.0.0 + * + * @param string $template The template to override. + * @param string $template_name The template name. + * @param string $template_path The template path. + * + * @return string The full path to the template. + */ + public function locate_template( $template, $template_name, $template_path ) { + global $woocommerce; + + $_template = $template; + + if ( ! $template_path ) { + $template_path = $woocommerce->template_url; + } + + $plugin_path = $this->plugin_dir . '/woocommerce/'; + + // Look within passed path within the theme - this is priority. + $template = locate_template( array( $template_path . $template_name, $template_name ) ); + + // Modification: Get the template from this plugin, if it exists. + if ( ! $template && file_exists( $plugin_path . $template_name ) ) { + $template = $plugin_path . $template_name; + } + + // Use default template. + if ( ! $template ) { + $template = $_template; + } + + // Return what we found. + return $template; + } +} + +add_action( 'plugins_loaded', array( WC_SizeMe_Measurements::get_instance(), 'init' ) ); diff --git a/templates/admin-notice.php b/templates/admin-notice.php new file mode 100644 index 0000000..814786a --- /dev/null +++ b/templates/admin-notice.php @@ -0,0 +1,34 @@ + + +
+

+
diff --git a/templates/sizeme-data-panels.php b/templates/sizeme-data-panels.php new file mode 100644 index 0000000..a334a88 --- /dev/null +++ b/templates/sizeme-data-panels.php @@ -0,0 +1,70 @@ + +
+

+
+ '_smi_item_type', + 'label' => '' . __( 'SizeMe Item Type', + 'sizeme' ) . '', + 'desc_tip' => 'true', + 'description' => __( 'Item type', 'sizeme' ), + ) ); + + woocommerce_wp_text_input( array( + 'id' => '_smi_item_layer', + 'label' => '' . __( 'SizeMe Item Layer', 'sizeme' ) . '', + 'desc_tip' => 'true', + 'description' => __( 'Item layer', 'sizeme' ), + ) ); + + woocommerce_wp_text_input( array( + 'id' => '_smi_item_thickness', + 'label' => '' . __( 'SizeMe Item Thickness', 'sizeme' ) . '', + 'desc_tip' => 'true', + 'description' => __( 'Item thickness', 'sizeme' ), + ) ); + + woocommerce_wp_text_input( array( + 'id' => '_smi_item_stretch', + 'label' => '' . __( 'SizeMe Item Stretch', 'sizeme' ) . '', + 'desc_tip' => 'true', + 'description' => __( 'Item stretch', 'sizeme' ), + ) ); + ?> + +
+ +
diff --git a/templates/sizeme-product-variation.php b/templates/sizeme-product-variation.php new file mode 100644 index 0000000..8fa2068 --- /dev/null +++ b/templates/sizeme-product-variation.php @@ -0,0 +1,42 @@ + +
+

+
+ $data ) : ?> +

+ + +

+ +
diff --git a/templates/sizeme-product.php b/templates/sizeme-product.php new file mode 100644 index 0000000..b0f2d09 --- /dev/null +++ b/templates/sizeme-product.php @@ -0,0 +1,70 @@ + + + diff --git a/woocommerce/single-product/add-to-cart/variable.php b/woocommerce/single-product/add-to-cart/variable.php new file mode 100644 index 0000000..7385859 --- /dev/null +++ b/woocommerce/single-product/add-to-cart/variable.php @@ -0,0 +1,132 @@ + + +
+ + + +

+ +

+ + + + $options ) : + $selected = isset( $_REQUEST[ 'attribute_' . sanitize_title( $attribute_name ) ] ) ? + wc_clean( $_REQUEST[ 'attribute_' . sanitize_title( $attribute_name ) ] ) : + $product->get_variation_default_attribute( $attribute_name ); // Input var okay. + + if ( $sizeme->is_size_attribute( $product, $attribute_name ) && ! $size_set ) { + $class = 'sizeme-selection-container'; + $class_override = $sizeme->get_ui_option( WC_SizeMe_Measurements::SIZE_SELECTION_CONTAINER_ELEMENT, + '' ); + if ( ! empty( $class_override ) ) { + $class .= ' ' . $class_override; + } + $size_set = true; + } else { + $class = ''; + } ?> + + + + + + +
+ + + $options, + 'attribute' => $attribute_name, + 'product' => $product, + 'selected' => $selected, + ) ); + echo end( $attribute_keys ) === $attribute_name ? apply_filters( 'woocommerce_reset_variations_link', + '' . __( 'Clear', 'woocommerce' ) . '' ) : ''; + ?> +
+ + + +
+ +
+ + + + + +
+ +