       1:    2:    3:    4:    5:    6:    7:    8:    9:   10:   11:   12:   13:   14:   15:   16:   17:   18:   19:   20:   21:   22:   23:   24:   25:   26:   27:   28:   29:   30:   31:   32:   33:   34:   35:   36:   37:   38:   39:   40:   41:   42:   43:   44:   45:   46:   47:   48:   49:   50:   51:   52:   53:   54:   55:   56:   57:   58:   59:   60:   61:   62:   63:   64:   65:   66:   67:   68:   69:   70:   71:   72:   73:   74:   75:   76:   77:   78:   79:   80:   81:   82:   83:   84:   85:   86:   87:   88:   89:   90:   91:   92:   93:   94:   95:   96:   97:   98:   99:  100:  101:  102:  103:  104:  105:  106:  107:  108:  109:  110:  111:  112:  113:  114:  115:  116:  117:  118:  119:  120:  121:  122:  123:  124:  125:  126:  127:  128:  129:  130:  131:  132:  133:  134:  135:  136:  137:  138:  139:  140:  141:  142:  143:  144:  145:  146:  147:  148:  149:  150:  151:  152:  153:  154:  155:  156:  157:  158:  159:  160:  161:  162:  163:  164:  165:  166:  167:  168:  169:  170:  171:  172:  173:  174:  175:  176:  177:  178:  179:  180:  181:  182:  183:  184:  185:  186:  187:  188:  189:  190:  191:  192:  193:  194:  195:  196:  197:  198:  199:  200:  201:  202:  203:  204:  205:  206:  207:  208:  209:  210:  211:  212:  213:  214:  215:  216:  217:  218:  219:  220:  221:  222:  223:  224:  225:  226:  227:  228:  229:  230:  231:  232:  233:  234:  235:  236:  237:  238:  239:  240:  241:  242:  243:  244:  245:  246:  247:  248:  249:  250:  251:  252:  253:  254:  255:  256:  257:  258:  259:  260:  261:  262:  263:  264:  265:  266:  267:  268:  269:  270:  271:  272:  273:  274:  275:  276:  277:  278:  279:  280:  281:  282:  283:  284:  285:  286:  287:  288:  289:  290:  291:  292:  293:  294:  295:  296:  297:  298:  299:  300:  301:  302:  303:  304:  305:  306:  307:  308:  309:  310:  311:  312:  313:  314:  315:  316:  317:  318:  319:  320:  321:  322:  323:  324:  325:  326:  327:  328:  329:  330:  331:  332:  333:  334:  335:  336:  337:  338:  339:  340:  341:  342:  343:  344:  345:  346:  347:  348:  349:  350:  351:  352:  353:  354:  355:  356:  357:  358:  359:  360:  361:  362:  363:  364:  365:  366:  367:  368:  369:  370:  371:  372:  373:  374:  375:  376:  377:  378:  379:  380:  381:  382:  383:  384:  385:  386:  387:  388:  389:  390:  391:  392:  393:  394:  395:  396:  397:  398:  399:  400:  401:  402:  403:  404:  405:  406:  407:  408:  409:  410:  411:  412:  413:  414:  415:  416:  417:  418:  419:  420:  421:  422:  423:  424:  425:  426:  427:  428:  429:  430:  431:  432:  433:  434:  435:  436:  437:  438:  439:  440:  441:  442:  443:  444:  445:  446:  447:  448:  449:  450:  451:  452:  453:  454:  455:  456:  457:  458:  459:  460:  461:  462:  463:  464:  465:  466:  467:  468:  469:  470:  471:  472:  473:  474:  475:  476:  477:  478:  479:  480:  481:  482:  483:  484:  485:  486:  487:  488:  489:  490:  491:  492:  493:  494:  495:  496:  497:  498:  499:  500:  501:  502:  503:  504:  505:  506:  507:  508:  509:  510:  511:  512:  513:  514:  515:  516:  517:  518:  519:  520:  521:  522:  523:  524:  525:  526:  527:  528:  529:  530:  531:  532:  533:  534:  535:  536:  537:  538:  539:  540:  541:  542:  543:  544:  545:  546:  547:  548:  549:  550:  551:  552:  553:  554:  555:  556:  557:  558:  559:  560:  561:  562:  563:  564:  565:  566:  567:  568:  569:  570:  571:  572:  573:  574:  575:  576:  577:  578:  579:  580:  581:  582:  583:  584:  585:  586:  587:  588:  589:  590:  591:  592:  593:  594:  595:  596:  597:  598:  599:  600:  601:  602:  603:  604:  605:  606:  607:  608:  609:  610:  611:  612:  613:  614:  615:  616:  617:  618:  619:  620:  621:  622:  623:  624:  625:  626:  627:  628:  629:  630:  631:  632:  633:  634:  635:  636:  637:  638:  639:  640:  641:  642:  643:  644:  645:  646:  647:  648:  649:  650:  651:  652:  653:  654:  655:  656:  657:  658:  659:  660:  661:  662:  663:  664:  665:  666:  667:  668:  669:  670:  671:  672:  673:  674:  675:  676:  677:  678:  679:  680:  681:  682:  683:  684:  685:  686:  687:  688:  689:  690:  691:  692:  693:  694:  695:  696:  697:  698:  699:  700:  701:  702:  703:  704:  705:  706:  707:  708:  709:  710:  711:  712:  713:  714:  715:  716:  717:  718:  719:  720:  721:  722:  723:  724:  725:  726:  727:  728:  729:  730:  731:  732:  733:  734:  735:  736:  737:  738:  739:  740:  741:  742:  743:  744:  745:  746:  747:  748:  749:  750:  751:  752:  753:  754:  755:  756:  757:  758:  759:  760:  761:  762:  763:  764:  765:  766:  767:  768:  769:  770:  771:  772:  773:  774:  775:  776:  777:  778:  779:  780:  781:  782:  783:  784:  785:  786:  787:  788:  789:  790:  791:  792:  793:  794:  795:  796:  797:  798:  799:  800:  801:  802:  803:  804:  805:  806:  807:  808:  809:  810:  811:  812:  813:  814:  815:  816:  817:  818:  819:  820:  821:  822:  823:  824:  825:  826:  827:  828:  829:  830:  831:  832:  833:  834:  835:  836:  837:  838:  839:  840:  841:  842:  843:  844:  845:  846:  847:  848:  849:  850:  851:  852:  853:  854:  855:  856:  857:  858:  859:  860:  861:  862:  863:  864:  865:  866:  867:  868:  869:  870:  871:  872:  873:  874:  875:  876:  877:  878:  879:  880:  881:  882:  883:  884:  885:  886:  887:  888:  889:  890:  891:  892:  893:  894:  895:  896:  897:  898:  899:  900:  901:  902:  903:  904:  905:  906:  907:  908:  909:  910:  911:  912:  913:  914:  915:  916:  917:  918:  919:  920:  921:  922:  923:  924:  925:  926:  927:  928:  929:  930:  931:  932:  933:  934:  935:  936:  937:  938:  939:  940:  941:  942:  943:  944:  945:  946:  947:  948:  949:  950:  951:  952:  953:  954:  955:  956:  957:  958:  959:  960:  961:  962:  963:  964:  965:  966:  967:  968:  969:  970:  971:  972:  973:  974:  975:  976:  977:  978:  979:  980:  981:  982:  983:  984:  985:  986:  987:  988:  989:  990:  991:  992:  993:  994:  995:  996:  997:  998:  999: 1000: 1001: 1002: 1003: 1004: 1005: 1006: 1007: 1008: 1009: 1010: 1011: 1012: 1013: 1014: 1015: 1016: 1017: 1018: 1019: 1020: 1021: 1022: 1023: 1024: 1025: 1026: 1027: 1028: 1029: 1030: 1031: 1032: 1033:

    <?php
    /**
     * WP Google Maps Pro Import / Export API
     *
     * @package WPGMapsPro\ImportExport
     * @since 7.0.0
     */

    namespace WPGMZA;

    /**
     * Import and export classes.
     */

    $path = plugin_dir_path( __FILE__ );

    require_once( $path . 'class.import.php' );
    require_once( $path . 'class.import-csv.php' );
    require_once( $path . 'class.import-gpx.php' );
    require_once( $path . 'class.import-json.php' );
    require_once( $path . 'class.import-kml.php' );
    require_once( $path . 'class.export.php' );

    add_action( 'admin_init', 'WPGMZA\\load_advanced_menu_page_hooks' );
    /**
     * Attach actions to load-{page} hook for the Advanced menu page.
     */
    function load_advanced_menu_page_hooks() {

        add_action( 'load-' . sanitize_title( __( 'Maps', 'wp-google-maps' ) ) . '_page_wp-google-maps-menu-advanced', 'WPGMZA\\import_export_download' );

    }

    /**
     * Export downloading processing.
     */
    function import_export_download() {

        // Export download.
        if ( wpgmza_user_can_edit_maps() && isset( $_GET['action'], $_GET['export_nonce'] ) &&
             wp_verify_nonce( $_GET['export_nonce'], 'wpgmza_export_file' ) && 'export_json' === $_GET['action'] ) {

            $export_args = array(
                'maps'         => isset( $_GET['maps'] ) ? explode( ',', $_GET['maps'] ) : array(),
                'categories'   => isset( $_GET['categories'] ) ? true : false,
                'customfields' => isset( $_GET['customfields'] ) ? true : false,
                'markers'      => isset( $_GET['markers'] ) ? true : false,
                'circles'      => isset( $_GET['circles'] ) ? true : false,
                'polygons'     => isset( $_GET['polygons'] ) ? true : false,
                'polylines'    => isset( $_GET['polylines'] ) ? true : false,
                'rectangles'   => isset( $_GET['rectangles'] ) ? true : false,
                'datasets'     => isset( $_GET['datasets'] ) ? true : false,
            );

            $export = new Export( $export_args );
            $export->download();
            die();

        }

        wp_enqueue_script( 'wp-util' );
        wp_enqueue_script( 'jquery-ui-slider' );

    }

    add_filter( 'wp_check_filetype_and_ext', 'WPGMZA\\import_wp_check_filetype_and_ext', 10, 4 );
    function import_wp_check_filetype_and_ext($types, $file, $filename, $mimes)
    {
        $ext = strtolower( pathinfo($filename, PATHINFO_EXTENSION) );

        switch($ext)
        {
            case 'json':

                $types['ext'] = 'json';
                $types['type'] = 'application/json';

                break;

            case 'csv':

                $types['ext'] = 'json';
                $types['type'] = 'application/json';

                break;

            case 'kml':
            case 'gpx':

                $types['ext'] = $ext;
                $types['type'] = 'application/xml';

                break;

            default:
                break;
        }

        return $types;
    }

    add_action( 'wp_ajax_wpgmza_import_upload', 'WPGMZA\\import_ajax_handle_upload' );
    /**
     * Import AJAX handle upload file.
     */
    function import_ajax_handle_upload() {

        add_filter('upload_mimes', 'WPGMZA\\import_mimes');

        if ( ! wpgmza_user_can_edit_maps() || ! current_user_can( 'upload_files' ) ) {

            wp_send_json_error( __( "You don't have permission to upload files.", 'wp-google-maps' ) );

        }

        if ( ! isset( $_FILES['wpgmaps_import_file'] ) || ! wp_verify_nonce( $_POST['wpgmaps_security'], 'wpgmaps_import' ) ) {

            wp_send_json_error( __( 'No file upload or failed security check.', 'wp-google-maps' ) );

        }

        if ( ! function_exists( 'wp_handle_upload' ) ) {

            require_once( ABSPATH . 'wp-admin/includes/file.php' );

        }

        $overrides = array(
            'test_form' => false,
            'mimes'     => import_mimes(),
        );

        $upload = wp_handle_upload( $_FILES['wpgmaps_import_file'], $overrides );

        if ( isset( $upload['error'] ) ) {

            wp_send_json_error( $upload['error'] );

        }

        $id = wp_insert_attachment( array(
            'post_title'     => basename( $upload['file'] ),
            'post_content'   => $upload['url'],
            'post_mime_type' => $upload['type'],
            'guid'           => $upload['url'],
            'context'        => 'wpgmaps-import',
            'post_status'    => 'private',
        ), $upload['file'] );

        if ( $id > 0 ) {

            wp_send_json_success( array(
                'id'    => $id,
                'title' => basename( $upload['file'] ),
            ) );

        }

        wp_send_json_error( __( 'Unable to add file to database.', 'wp-google-maps' ) );

    }

    add_action( 'wp_ajax_wpgmza_import_delete', 'WPGMZA\\import_ajax_handle_delete' );
    /**
     * Import AJAX delete file handle.
     */
    function import_ajax_handle_delete() {

        if ( ! wpgmza_user_can_edit_maps() || ! isset( $_POST['import_id'], $_POST['wpgmaps_security'] ) ||
             ! wp_verify_nonce( $_POST['wpgmaps_security'], 'wpgmaps_import' ) ) {

            wp_send_json_error( __( 'No file specified or failed security check.', 'wp-google-maps' ) );

        }

        $id = absint( $_POST['import_id'] );

        if ( $id < 1 || get_post_meta( $id, '_wp_attachment_context', true ) !== 'wpgmaps-import' ) {

            wp_send_json_error( __( 'Deletion not allowed. File is not a valid WP Google Maps import upload.', 'wp-google-maps' ) );

        }

        wp_delete_attachment( $id, true );

        wp_send_json_success( array(
            'id' => $id,
        ) );
    }

    add_action( 'wp_ajax_wpgmza_import_file_options', 'WPGMZA\\import_ajax_file_options' );
    /**
     * Import AJAX retrieve options html for import file.
     */
    function import_ajax_file_options() {

        if ( ! empty( $_POST['schedule_id'] ) ) {

            $import_schedule = get_option( 'wpgmza_import_schedule' );
            $import_options = $import_schedule[ $_POST['schedule_id'] ]['options'];
            $import_options['start'] = get_date_from_gmt( date( 'Y-m-d H:i:s', $import_schedule[ $_POST['schedule_id'] ]['start'] ), 'Y-m-d' );
            $import_options['interval'] = $import_schedule[ $_POST['schedule_id'] ]['interval'];

            if ( ! empty( $import_schedule[ $_POST['schedule_id'] ]['import_id'] ) ) {

                $_POST['import_id'] = $import_schedule[ $_POST['schedule_id'] ]['import_id'];

            }

            if ( ! empty( $import_schedule[ $_POST['schedule_id'] ]['import_url'] ) ) {

                $_POST['import_url'] = $import_schedule[ $_POST['schedule_id'] ]['import_url'];

            }
        } else {

            $import_options = array();

        }

        if ( ! wpgmza_user_can_edit_maps() || ( ! isset( $_POST['import_id'] ) && ! isset( $_POST['import_url'] ) ) || ! isset( $_POST['wpgmaps_security'] ) ||
             ! wp_verify_nonce( $_POST['wpgmaps_security'], 'wpgmaps_import' ) ) {

            wp_send_json_error( __( 'No file or url specified or failed security check.', 'wp-google-maps' ) );

        }

        $import_mimes = import_mimes();

        if ( ! empty( $_POST['import_id'] ) && is_numeric( $_POST['import_id'] ) ) {

            $id = absint( $_POST['import_id'] );

            if ( $id < 1 || get_post_meta( $id, '_wp_attachment_context', true ) !== 'wpgmaps-import' ) {

                wp_send_json_error( __( 'Importing not allowed. File is not a valid WP Google Maps import upload.', 'wp-google-maps' ) );

            }

            $import_file     = get_attached_file( $id );
            $import_file_url = wp_get_attachment_url( $id );
            $extension       = pathinfo( $import_file, PATHINFO_EXTENSION );

        } elseif ( ! empty( $_POST['import_url'] ) ) {

            $import_file      = '';
            $import_file_url  = $_POST['import_url'];
            $extension        = pathinfo( $import_file_url, PATHINFO_EXTENSION );
            $google_sheets_id = array();

            if ( preg_match( '@/spreadsheets/d/([a-zA-Z0-9-_]+)@', $import_file_url, $google_sheets_id ) ) {

                $import_file_url = "https://docs.google.com/spreadsheets/d/{$google_sheets_id[1]}/gviz/tq?tqx=out:csv";
                $extension = 'csv';

            }
            else
                $extension = 'json';    // Assume JSON

        }

        if ( ! empty( $extension ) /*&& array_key_exists( strtolower( $extension ), $import_mimes )*/ ) {

            $import_class = 'WPGMZA\\Import' . strtoupper( $extension );

            if ( class_exists( $import_class ) ) {

                try {

                    $import       = new $import_class( $import_file, $import_file_url, $import_options );
                    $options_html = $import->admin_options();
                    $notices_html = $import->get_admin_notices();

                    wp_send_json_success( array(
                        'id'            => empty( $id ) ? 0 : $id,
                        'url'           => empty( $import_file_url ) ? '' : $import_file_url,
                        'options_html'  => $options_html,
                        'notices_html'  => $notices_html
                    ) );

                } catch ( \Exception $e ) {

                    wp_send_json_error( $e->getMessage() );

                }
            }
        }

        wp_send_json_error( __( 'Unable to import file.', 'wp-google-maps' ) );

    }

    add_action( 'wp_ajax_wpgmza_import', 'WPGMZA\\import_ajax_import' );
    /**
     * Import AJAX do import.
     */
    function import_ajax_import() {

        if ( ! wpgmza_user_can_edit_maps() || ( ! isset( $_POST['import_id'] ) && ! isset( $_POST['import_url'] ) ) ||
             ! isset( $_POST['wpgmaps_security'] ) || ! wp_verify_nonce( $_POST['wpgmaps_security'], 'wpgmaps_import' ) ) {

            wp_send_json_error( __( 'No file specified or failed security check.', 'wp-google-maps' ) );

        }

        $import_mimes = import_mimes();

        if ( ! empty( $_POST['import_id'] ) && is_numeric( $_POST['import_id'] ) ) {

            $id = absint( $_POST['import_id'] );

            if ( $id < 1 || get_post_meta( $id, '_wp_attachment_context', true ) !== 'wpgmaps-import' ) {

                wp_send_json_error( __( 'Importing not allowed. File is not a valid WP Google Maps import upload.', 'wp-google-maps' ) );

            }

            $import_file     = get_attached_file( $id );
            $import_file_url = wp_get_attachment_url( $id );
            $extension       = pathinfo( $import_file, PATHINFO_EXTENSION );

        } elseif ( ! empty( $_POST['import_url'] ) ) {

            $import_file      = '';
            $import_file_url  = esc_url_raw( $_POST['import_url'] );
            $extension        = pathinfo( $import_file_url, PATHINFO_EXTENSION );
            $google_sheets_id = array();

            if ( preg_match( '@/spreadsheets/d/([a-zA-Z0-9-_]+)@', $import_file_url, $google_sheets_id ) ) {

                $import_file_url = "https://docs.google.com/spreadsheets/d/{$google_sheets_id[1]}/gviz/tq?tqx=out:csv";
                $extension = 'csv';

            }
            else if($extension == 'php')
                $extension = 'json';    // Assume JSON
        }

        if ( ! empty( $extension ) /*&& array_key_exists( strtolower( $extension ), $import_mimes )*/ ) {

            $import_class = 'WPGMZA\\Import' . strtoupper( $extension );

            if ( class_exists( $import_class ) ) {

                try {

                    $notices = array();

                    /*if(!set_time_limit( 1200 ))
                    {

                    }

                    var_dump(ini_get('max_execution_time'));
                    echo "Testing";
                    exit;*/

                    $import = new $import_class( $import_file, $import_file_url, $_POST['options'] );
                    $import->import();

                    $delete = 0;

                    if ( ! empty( $id ) && isset( $_POST['options']['delete'] ) ) {

                        wp_delete_attachment( $id, true );
                        $delete = 1;

                    }

                    wp_send_json_success( array(
                        'id'  => empty( $id ) ? 0 : $id,
                        'url' => empty( $import_file_url ) ? '' : $import_file_url,
                        'del' => $delete,
                        'notices' => $import->get_admin_notices()
                    ) );

                } catch ( \Exception $e ) {

                    wp_send_json_error( $e->getMessage() );

                }
            }
        }

        wp_send_json_error( __( 'Unable to import file.', 'wp-google-maps' ) );

    }

    add_action( 'wpgmza_import_cron', 'WPGMZA\\import_cron_import' );
    /**
     * Import CRON.
     *
     * @param string $schedule_id Schedule id to import.
     */
    function import_cron_import( $schedule_id ) {

        $import_schedule = get_option( 'wpgmza_import_schedule' );

        if ( ! isset( $import_schedule[ $schedule_id ] ) ) {

            wp_clear_scheduled_hook( 'wpgmza_import_cron', array( $schedule_id ) );
            return;

        }

        $import_schedule[ $schedule_id ]['last_run_message'] = __( 'Last Run', 'wp-google-maps' ) . ': ' . current_time( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) ) . ' ';

        $import_mimes = import_mimes();

        if ( ! empty( $import_schedule[ $schedule_id ]['import_id'] ) && is_numeric( $import_schedule[ $schedule_id ]['import_id'] ) ) {

            $id = absint( $import_schedule[ $schedule_id ]['import_id'] );

            if ( $id < 1 || get_post_meta( $id, '_wp_attachment_context', true ) !== 'wpgmaps-import' ) {

                $import_schedule[ $schedule_id ]['last_run_message'] .= __( 'Importing not allowed. File is not a valid WP Google Maps import upload.', 'wp-google-maps' );
                update_option( 'wpgmza_import_schedule', $import_schedule );
                return;

            }

            $import_file     = get_attached_file( $id );
            $import_file_url = wp_get_attachment_url( $id );
            $extension       = pathinfo( $import_file, PATHINFO_EXTENSION );

        } elseif ( ! empty( $import_schedule[ $schedule_id ]['import_url'] ) ) {

            $import_file      = '';
            $import_file_url  = esc_url_raw( $import_schedule[ $schedule_id ]['import_url'] );
            $extension        = pathinfo( $import_file_url, PATHINFO_EXTENSION );
            $google_sheets_id = array();

            if ( preg_match( '@/spreadsheets/d/([a-zA-Z0-9-_]+)@', $import_file_url, $google_sheets_id ) ) {

                $import_file_url = "https://docs.google.com/spreadsheets/d/{$google_sheets_id[1]}/gviz/tq?tqx=out:csv";
                $extension = 'csv';

            }
        }
        else
            $extension = 'json';    // Assume JSON

        if ( ! empty( $extension ) && array_key_exists( strtolower( $extension ), $import_mimes ) ) {

            $import_class = 'WPGMZA\\Import' . strtoupper( $extension );

            if ( class_exists( $import_class ) ) {

                try {

                    set_time_limit( 1200 );

                    $import = new $import_class( $import_file, $import_file_url, $import_schedule[ $schedule_id ]['options'] );
                    $import->import();

                    $import_schedule[ $schedule_id ]['last_run_message'] .= __( 'Import completed.', 'wp-google-maps' );
                    update_option( 'wpgmza_import_schedule', $import_schedule );

                    return;

                } catch ( \Exception $e ) {

                    $import_schedule[ $schedule_id ]['last_run_message'] .= $e->getMessage();
                    update_option( 'wpgmza_import_schedule', $import_schedule );
                    return;

                }
            }
        }

        $import_schedule[ $schedule_id ]['last_run_message'] .= __( 'Unable to import file.', 'wp-google-maps' );
        update_option( 'wpgmza_import_schedule', $import_schedule );

    }

    /**
     * Import allowed mime types.
     */
    function import_mimes() {

        return array(
            'txt|asc|c|cc|h|srt|csv|json'   => 'text/plain',
            'csv'                           => 'text/csv',
            'gpx'                           => 'application/xml',
            // 'json'                           => 'application/json',
            'kml'                           => 'application/xml',
        );

    }

    add_action( 'wpgmza_admin_advanced_options_tabs', 'WPGMZA\\import_export_admin_tabs' );
    /**
     * Import/export admin page tabs.
     */
    function import_export_admin_tabs() {

        ?>
        <li><a href="#import-tab"><?php esc_html_e( 'Import' , 'wp-google-maps' ); ?></a></li>
        <li><a href="#schedule-tab"><?php esc_html_e( 'Schedule', 'wp-google-maps' ); ?></a></li>
        <li><a href="#export-tab"><?php esc_html_e( 'Export' , 'wp-google-maps' ); ?></a></li>
        <?php

    }

    add_filter( 'cron_schedules', 'WPGMZA\\import_cron_schedules' );
    /**
     * Adds custom cron schedules.
     *
     * @param array $schedules An array of non-default cron schedules.
     * @return array Filtered array of non-default cron schedules.
     */
    function import_cron_schedules( $schedules ) {

        $schedules['weekly'] = array(
            'interval' => WEEK_IN_SECONDS,
            'display'  => __( 'Once Weekly', 'wp-google-maps' ),
        );

        $schedules['monthly'] = array(
            'interval' => MONTH_IN_SECONDS,
            'display'  => __( 'Once Monthly', 'wp-google-maps' ),
        );

        return $schedules;

    }

    /**
     * Get maps list helper function.
     *
     * @global wpdb   $wpdb                WordPress database class.
     * @global string $wpgmza_tblname_maps Maps database table name.
     *
     * @param string     $context  Context of the list, used to create ids and classes.
     * @param array|bool $selected Array of selected map ids.
     * @return array|string Table rows and columns of maps. Array of map ids if $content passed as 'ids'.
     */
    function import_export_get_maps_list( $context, $selected = false ) {

        static $maps = null;

        if ( null === $maps ) {

            global $wpdb;
            global $wpgmza_tblname_maps;

            $maps = $wpdb->get_results( "SELECT `id`, `map_title` FROM `$wpgmza_tblname_maps` WHERE `active`=0 ORDER BY `id` DESC" );

        }

        if ( empty( $maps ) ) {

            return 'ids' === $context ? array() : '';

        }

        $ret = 'ids' === $context ? array() : '';

        $context = sanitize_html_class( $context );

        foreach ( $maps as $map ) {

            $id = intval( $map->id );

            if ( 'ids' === $context ) {

                $ret[] = $id;

            } else {

                $title = esc_html( stripslashes( $map->map_title ) );
                $ret .= "<tr style='display:block;width:100%;'><td style='width:2.2em;'><div class='switch'><input id='maps_{$context}_{$id}' type='checkbox' value='{$id}' class='maps_{$context} cmn-toggle cmn-toggle-round-flat' " . ( false === $selected ? 'checked' : ( is_array( $selected ) && in_array( $id, $selected, true ) ? 'checked' : '' ) ) . "><label for='maps_{$context}_{$id}'></label></div></td><td style='width:80px;'>{$id}</td><td>{$title}</td></tr>";
            }
        }

        return $ret;

    }

    add_action( 'wp_ajax_wpgmza_import_schedule', 'WPGMZA\\import_ajax_schedule' );
    /**
     * AJAX schedule an import CRON event.
     */
    function import_ajax_schedule() {

        if ( ! wpgmza_user_can_edit_maps() || ( ! isset( $_POST['import_id'] ) && ! isset( $_POST['import_url'] ) ) ||
             ! isset( $_POST['wpgmaps_security'], $_POST['options'] ) || ! wp_verify_nonce( $_POST['wpgmaps_security'], 'wpgmaps_import' ) ) {

            wp_send_json_error( __( 'No file specified or failed security check.', 'wp-google-maps' ) );

        }

        $import_mimes = import_mimes();

        if ( is_numeric( $_POST['import_id'] ) ) {

            $id = absint( $_POST['import_id'] );

            if ( $id < 1 || get_post_meta( $id, '_wp_attachment_context', true ) !== 'wpgmaps-import' ) {

                wp_send_json_error( __( 'Importing not allowed. File is not a valid WP Google Maps import upload.', 'wp-google-maps' ) );

            }

            $import_file     = get_attached_file( $id );
            $import_file_url = wp_get_attachment_url( $id );
            $extension       = pathinfo( $import_file, PATHINFO_EXTENSION );

        } elseif ( ! empty( $_POST['import_url'] ) ) {

            $import_file     = '';
            $import_file_url = esc_url_raw( $_POST['import_url'] );
            $extension       = pathinfo( $import_file_url, PATHINFO_EXTENSION );

            if ( preg_match( '@/spreadsheets/d/([a-zA-Z0-9-_]+)@', $import_file_url, $google_sheets_id ) ) {

                $extension = 'csv';

            }
            else
                $extension = 'json';    // Assume JSON
        }

        if ( ! empty( $extension ) /*&& array_key_exists( strtolower( $extension ), $import_mimes )*/ ) {

            $import_schedule = get_option( 'wpgmza_import_schedule' );

            if ( empty( $import_schedule ) || ! is_array( $import_schedule ) ) {

                $import_schedule = array();

            }

            if ( ! empty( $_POST['schedule_id'] ) ) {

                $schedule_id = $_POST['schedule_id'];

            } else {

                $schedule_id = md5( ( ! empty( $import_file ) ? $import_file : ( ! empty( $import_file_url ) ? $import_file_url : '' ) ) . time() );

            }

            $start    = get_gmt_from_date( $_POST['start'], 'U' );
            $interval = sanitize_text_field( $_POST['interval'] );
            $next_run = wp_next_scheduled( 'wpgmza_import_cron', array( $schedule_id ) );

            if ( false !== $next_run ) {

                if ( ! isset( $import_schedule[ $schedule_id ]['start'], $import_schedule[ $schedule_id ]['interval'] ) ||
                     $import_schedule[ $schedule_id ]['start'] !== $start || $import_schedule[ $schedule_id ]['interval'] !== $interval ) {

                    wp_clear_scheduled_hook( 'wpgmza_import_cron', array( $schedule_id ) );
                    $next_run = wp_next_scheduled( 'wpgmza_import_cron', array( $schedule_id ) );

                }
            }

            if ( isset( $import_schedule[ $schedule_id ] ) ) {

                unset( $import_schedule[ $schedule_id ] );

            }

            $import_schedule = array(
                $schedule_id => array(
                    'start'      => $start,
                    'interval'   => $interval,
                    'title'      => sanitize_text_field( ! empty( $import_file ) ? basename( $import_file ) : $import_file_url ),
                    'options'    => $_POST['options'],
                    'import_id'  => ! empty( $id ) ? $id : 0,
                    'import_url' => $import_file_url,
            ) ) + $import_schedule;

            update_option( 'wpgmza_import_schedule', $import_schedule );

            if ( false === $next_run ) {

                wp_schedule_event( $import_schedule[ $schedule_id ]['start'], $import_schedule[ $schedule_id ]['interval'], 'wpgmza_import_cron', array( $schedule_id ) );
                $next_run = wp_next_scheduled( 'wpgmza_import_cron', array( $schedule_id ) );

            }

            if ( ! empty( $next_run ) ) {

                $import_schedule[ $schedule_id ]['next_run'] = get_date_from_gmt( date( 'Y-m-d H:i:s', $next_run ), get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) );
                $import_schedule[ $schedule_id ]['schedule_id'] = $schedule_id;
                wp_send_json_success( $import_schedule[ $schedule_id ] );

            }
        } // End if().

        wp_send_json_error( __( 'Unable to schedule import.', 'wp-google-maps' ) );

    }

    add_action( 'wp_ajax_wpgmza_import_delete_schedule', 'WPGMZA\\import_ajax_delete_schedule' );
    /**
     * AJAX delete import CRON schedule.
     */
    function import_ajax_delete_schedule() {

        if ( ! wpgmza_user_can_edit_maps() || ! isset( $_POST['schedule_id'], $_POST['wpgmaps_security'] ) ||
             ! wp_verify_nonce( $_POST['wpgmaps_security'], 'wpgmaps_import' ) ) {

            wp_send_json_error( __( 'No scheduled import specified or failed security check.', 'wp-google-maps' ) );

        }

        $import_schedule = get_option( 'wpgmza_import_schedule' );

        if ( ! isset( $import_schedule[ $_POST['schedule_id'] ] ) ) {

            wp_send_json_error( __( 'Scheduled import not found.', 'wp-google-maps' ) );

        }

        wp_clear_scheduled_hook( 'wpgmza_import_cron', array( $_POST['schedule_id'] ) );
        $next_run = wp_next_scheduled( 'wpgmza_import_cron', array( $_POST['schedule_id'] ) );

        if ( false === $next_run ) {

            unset( $import_schedule[ $_POST['schedule_id'] ] );
            update_option( 'wpgmza_import_schedule', $import_schedule );
            wp_send_json_success( array(
                'schedule_id' => $_POST['schedule_id'],
            ) );

        }

        wp_send_json_error( __( 'Unable to remove scheduled import.', 'wp-google-maps' ) );

    }

    add_action( 'wp_ajax_wpgmaps_get_import_progress', 'WPGMZA\\import_get_progress' );
    /**
     * AJAX get import progress.
     */
    function import_get_progress() {

        @session_start();

        $key = 'wpgmza_import_progress_' . $_POST['wpgmaps_security'];
        $json = (object) array( 'progress' => 0.0 );

        if ( isset( $_SESSION[ $key ] ) ) {

            $json = $_SESSION[ $key ];

        }

        session_write_close();
        wp_send_json_success( $json );

    }

    /**
     * Get import CRON schedule.
     *
     * @return array Array of scheduled imports.
     */
    function import_get_schedule() {

        $import_schedule = get_option( 'wpgmza_import_schedule' );

        if ( empty( $import_schedule ) || ! is_array( $import_schedule ) ) {

            return array();

        }

        foreach ( $import_schedule as $schedule_id => $schedule ) {

            $next_run = wp_next_scheduled( 'wpgmza_import_cron', array( $schedule_id ) );

            if ( false === $next_run ) {

                wp_schedule_event( $schedule['start'], $schedule['interval'], 'wpgmza_import_cron', array( $schedule_id ) );
                $next_run = wp_next_scheduled( 'wpgmza_import_cron', array( $schedule_id ) );

            }

            if ( ! empty( $next_run ) ) {

                $next_run = get_date_from_gmt( date( 'Y-m-d H:i:s', $next_run ), get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) );

            }

            $import_schedule[ $schedule_id ]['next_run'] = $next_run;

        }

        return $import_schedule;

    }

    /**
     * Script and localized variables to pass to page
     */
    add_action('admin_enqueue_scripts', function() {

        global $wpgmza;

        $version = 'null';

        if(!empty($wpgmza) && method_exists($wpgmza, 'getProVersion'))
            $version = $wpgmza->getProVersion();

        wp_enqueue_script('wpgmza-import-export-page', plugin_dir_url(dirname(__DIR__)) . 'js/import-export-page.js', $version);

    });

    /**
     * Data to pass to JavaScript
     */
    add_filter('wpgmza_plugin_get_localized_data', function($arr) {

        return array_merge($arr, array(

            'import_security_nonce'     => wp_create_nonce('wpgmaps_import'),
            'export_security_nonce'     => wp_create_nonce('wpgmza_export_file')

        ));

    });

    /**
     * Localized strings to pass to page
     */
    add_filter('wpgmza_localized_strings', function($arr) {

        return array_merge($arr, array(

            'please_select_a_file_to_upload'            => __('Please select a file to upload.', 'wp-google-maps'),
            'import_reservedwordsfix'                   => __('Import', 'wp-google-maps'),
            'delete_reservedwordsfix'                   => __('Delete', 'wp-google-maps'),
            'back_to_import_data'                       => __('Back to Import Data', 'wp-google-maps'),
            'are_you_sure_you_wish_to_delete_this_file' => __('Are you sure you wish to delete this file?', 'wp-google-maps' ),
            'file_deleted'                              => __('File deleted.', 'wp-google-maps'),
            'please_enter_a_url_to_import_from'         => __('Please enter a URL to import from.', 'wp-google-maps'),
            'back_to_import_data'                       => __('Back to Import Data', 'wp-google-maps'),
            'loading_import_options'                    => __( 'Loading import options...', 'wp-google-maps' ),
            'are_you_sure_you_wish_to_delete_this_scheduled_import' => __( 'Are you sure you wish to delete this scheduled import?', 'wp-google-maps' ),
            'scheduled_import_deleted'                  => __( 'Scheduled import deleted.', 'wp-google-maps' ),
            'please_select_at_least_one_map_to_export'  => __( 'Please select at least one map to export.', 'wp-google-maps' )
        ));

    });

    add_action( 'wpgmza_admin_advanced_options', 'WPGMZA\\import_export_admin_options' );

    /**
     * Import/export admin page options.
     */
    function import_export_admin_options() {

        $import_mimes = import_mimes();
        $import_accepts_attr = '';
        $import_accepts      = __( 'Accepts', 'wp-google-maps' ) . ': ';
        foreach ( $import_mimes as $ext => $mime ) {
            $import_accepts_attr .= "$mime,.$ext,";
            $import_accepts      .= "*.$ext, ";
        }
        $import_accepts_attr = rtrim( $import_accepts_attr, ',' );
        $import_accepts      = rtrim( $import_accepts, ', ' );

        $bytes = apply_filters( 'import_upload_size_limit', wp_max_upload_size() );
        $size  = size_format( $bytes );

        ?>
        <div id="import-tab">
            <div id="import_files">
                <h2><?php esc_html_e( 'Import Data', 'wp-google-maps' ); ?></h2>
                <table style="width:100%;">
                    <tbody>
                    <tr><td style="width:100px;vertical-align:top;">
                        <p><?php esc_html_e( 'Import via:', 'wp-google-maps' ); ?></p>
                    </td><td style="vertical-align:top;">
                        <p>
                            <label><input type="radio" name="import_data_type" class="import_data_type" value="URL" checked="checked"> <?php esc_html_e( 'URL', 'wp-google-maps' ); ?></label><br>
                            <label><input type="radio" name="import_data_type" class="import_data_type" value="file"> <?php esc_html_e( 'File', 'wp-google-maps' ); ?></label>
                        </p>
                        <br>
                        <div id="import_from_url">
                            <p>
                                <input id="wpgmaps_import_url" placeholder="<?php esc_attr_e( 'Import URL', 'wp-google-maps' ); ?>" type="text" style="max-width:500px;width:100%;"><br>
                                <span class="description" style="display:inline-block;max-width:500px;"><?php esc_html_e( 'If using a Google Sheet URL, the sheet must be public or have link sharing turned on.', 'wp-google-maps' ); ?></span><br><br>
                                <button id="wpgmaps_import_url_button" class="wpgmza_general_btn"><?php esc_html_e( 'Import', 'wp-google-maps' ); ?></button>
                            </p>
                        </div>
                        <div id="import_from_file" style="display:none;">
                            <p>
                                <?php echo esc_html( $import_accepts ); ?><br><br>
                                <input name="wpgmaps_import_file" id="wpgmaps_import_file" type="file" style="display:none;" accept="<?php echo esc_attr( $import_accepts_attr ); ?>,.json">
                                <label for="wpgmaps_import_file" class="wpgmza_file_select_btn"><i class="fa fa-download"></i> <?php esc_html_e( 'Select File', 'wp-google-map' ); ?>
                                </label>
                                <span id="wpgmaps_import_file_name" style="margin-left:10px;"></span><br><br>
                                <?php esc_html_e( 'Max upload size', 'wp-google-maps' ); ?>: <?php echo esc_html( $size ); ?><br><br>
                                <button id="wpgmaps_import_upload_button" class="wpgmza_general_btn"><?php esc_html_e( 'Upload', 'wp-google-maps' ); ?></button> <span id="wpgmaps_import_upload_spinner" class="spinner" style="float:none;margin-bottom:8px;"></span>
                            </p>
                            <?php
                            $import_files = new \WP_Query( array(
                                'post_type'      => 'attachment',
                                'meta_key'       => '_wp_attachment_context',
                                'meta_value'     => 'wpgmaps-import',
                                'posts_per_page' => - 1,
                            ) );
                            ?>
                            <div id="wpgmaps_import_file_list" <?php echo $import_files->found_posts < 1 ? 'style="display:none;"' : ''; ?>>
                                <br>
                                <table id="wpgmap_import_file_list_table" class="wp-list-table widefat fixed striped wpgmza-listing" style="width:100%;padding:0;border:0 !important;">
                                    <thead>
                                    <tr>
                                        <th style="font-weight:bold;"><?php esc_html_e( 'Import Uploads', 'wp-google-maps' ); ?></th>
                                    </tr>
                                    </thead>
                                    <tbody>
                                    <?php foreach ( $import_files->posts as $import_file ) { ?>
                                        <tr id="import-list-item-<?php echo esc_attr( $import_file->ID ); ?>">
                                            <td>
                                                <strong><span class="import_file_title" style="font-size:larger;"><?php echo esc_html( $import_file->post_title ); ?></span></strong><br>
                                                <a href="javascript:void(0);" class="import_import" data-import-id="<?php echo esc_attr( $import_file->ID ); ?>"><?php esc_html_e( 'Import', 'wp-google-maps' ); ?></a>
                                                |
                                                <a href="javascript:void(0);" class="import_delete" data-import-id="<?php echo esc_attr( $import_file->ID ); ?>"><?php esc_html_e( 'Delete', 'wp-google-maps' ); ?></a>
                                            </td>
                                        </tr>
                                    <?php } ?>
                                    </tbody>
                                </table>
                            </div>
                            <br>
                        </div>
                    </td></tr>
                    </tbody>
                </table>
            </div>
            <div id="import_loader" style="display:none;">
                <div style="text-align:center;padding:50px 0;">
                    <div class="spinner is-active" style="float:none;"></div>
                    <div id="import_loader_text"></div>
                </div>
            </div>
            <div id="import_options" style="display:none;"></div>
        </div>
        <?php $import_schedule = import_get_schedule(); ?>
        <div id="schedule-tab" style="display:none;">
            <h2><?php esc_html_e( 'Schedule', 'wp-google-maps' ); ?></h2>
            <p class="description" style="max-width:600px;">
                <?php esc_html_e( 'Imports can be scheduled by url or uploaded file. To schedule an import, import as normal and select the Schedule button. Scheduled imports will be listed on this page and can be edited or deleted from here.', 'wp-google-maps' ); ?>
            </p>
            <div id="wpgmaps_import_schedule_list"<?php if ( empty( $import_schedule ) ) { ?> style="display:none;"<?php } ?>>
                <br>
                <table id="wpgmap_import_schedule_list_table" class="wp-list-table widefat fixed striped wpgmza-listing" style="width:100%;">
                    <thead>
                    <tr>
                        <th><?php esc_html_e( 'URL / Filename', 'wp-google-maps' ); ?></th>
                    </tr>
                    </thead>
                    <tbody>
                    <?php if ( ! empty( $import_schedule ) ) {
                        foreach ( $import_schedule as $schedule_id => $schedule ) { ?>
                            <tr id="import-schedule-list-item-<?php echo esc_attr( $schedule_id ); ?>">
                                <td>
                                    <strong><span class="import_schedule_title" style="font-size:larger;"><?php echo esc_html( $schedule['title'] ); ?></span></strong><br>
                                    <a href="javascript:void(0);" class="import_schedule_edit" data-schedule-id="<?php echo esc_attr( $schedule_id ); ?>"><?php esc_html_e( 'Edit', 'wp-google-maps' ); ?></a>
                                    |
                                    <a href="javascript:void(0);" class="import_schedule_delete" data-schedule-id="<?php echo esc_attr( $schedule_id ); ?>"><?php esc_html_e( 'Delete', 'wp-google-maps' ); ?></a>
                                    |
                                    <?php if ( empty( $schedule['next_run'] ) ) { ?>
                                        <?php esc_html_e( 'No schedule found', 'wp-google-maps' ); ?>
                                    <?php } else { ?>
                                        <?php esc_html_e( 'Next Scheduled Run', 'wp-google-maps' ); ?>: <?php echo esc_html( $schedule['next_run'] ); ?>
                                    <?php } ?>
                                    <?php if ( ! empty( $schedule['last_run_message'] ) ) { ?>
                                        <br><?php echo esc_html( $schedule['last_run_message'] ); ?>
                                    <?php } ?>
                                </td>
                            </tr>
                        <?php }
                    } ?>
                    </tbody>
                </table>
            </div>
        </div>
        <?php $maps = import_export_get_maps_list( 'export' ); ?>
        <div id="export-tab" style="display:none;">
            <h2><?php esc_html_e( 'Export Data', 'wp-google-maps' ); ?></h2>
            <p class="description" style="max-width:600px;">
                <?php esc_html_e( 'Select which maps and map data you\'d like to export. Click the Export button to download a JSON file of the exported maps and their data.', 'wp-google-maps' ); ?>
            </p>
            <div style="margin:0 0 1em 0;width:100%;">
                <?php if ( empty( $maps ) ) { ?>
                    <br><?php esc_html_e( 'No maps available for export.', 'wp-google-maps' ); ?>
                <?php } else { ?>
                    <table class="wp-list-table widefat fixed striped wpgmza-listing" style="width:100%;">
                        <thead style="display:block;border-bottom:1px solid #e1e1e1;">
                        <tr style="display:block;width:100%;">
                            <th style="width:2.2em;border:none;"></th>
                            <th style="width:80px;border:none;"><?php esc_html_e( 'ID', 'wp-google-maps' ); ?></th>
                            <th style="border:none;"><?php esc_html_e( 'Title', 'wp-google-maps' ); ?></th>
                        </tr>
                        </thead>
                        <tbody style="display:block;max-height:370px;overflow-y:scroll;">
                        <?php echo $maps; ?>
                        </tbody>
                    </table>
                    <button id="maps_export_select_all" class="wpgmza_general_btn"><?php esc_html_e( 'Select All', 'wp-google-maps' ); ?></button> <button id='maps_export_select_none' class='wpgmza_general_btn'><?php esc_html_e( 'Select None', 'wp-google-maps' ); ?></button><br><br>
                <?php } ?>
            </div>
            <p>
            <h2>Map Data</h2>
            </p>
            <div class="switch"><input id="categories_export" class="map_data_export cmn-toggle cmn-toggle-round-flat" type="checkbox" checked><label for="categories_export"></label></div><?php esc_html_e( 'Categories', 'wp-google-maps' ); ?><br>
            <div class="switch"><input id="customfields_export" class="map_data_export cmn-toggle cmn-toggle-round-flat" type="checkbox" checked><label for="customfields_export"></label></div><?php esc_html_e( 'Custom Fields', 'wp-google-maps' ); ?><br>
            <div class="switch"><input id="markers_export" class="map_data_export cmn-toggle cmn-toggle-round-flat" type="checkbox" checked><label for="markers_export"></label></div><?php esc_html_e( 'Markers', 'wp-google-maps' ); ?><br>
            <div class="switch"><input id="circles_export" class="map_data_export cmn-toggle cmn-toggle-round-flat" type="checkbox" checked><label for="circles_export"></label></div><?php esc_html_e( 'Circles', 'wp-google-maps' ); ?><br>
            <div class="switch"><input id="polygons_export" class="map_data_export cmn-toggle cmn-toggle-round-flat" type="checkbox" checked><label for="polygons_export"></label></div><?php esc_html_e( 'Polygons', 'wp-google-maps' ); ?><br>
            <div class="switch"><input id="polylines_export" class="map_data_export cmn-toggle cmn-toggle-round-flat" type="checkbox" checked><label for="polylines_export"></label></div><?php esc_html_e( 'Polylines', 'wp-google-maps' ); ?><br>
            <div class="switch"><input id="rectangles_export" class="map_data_export cmn-toggle cmn-toggle-round-flat" type="checkbox" checked><label for="rectangles_export"></label></div><?php esc_html_e( 'Rectangles', 'wp-google-maps' ); ?><br>
            <div class="switch"><input id="datasets_export" class="map_data_export cmn-toggle cmn-toggle-round-flat" type="checkbox" checked><label for="datasets_export"></label></div><?php esc_html_e( 'Heatmap Datasets', 'wp-google-maps' ); ?><br>
            <br>
            <p>
                <button id="export-json" class="wpgmza_general_btn"><?php esc_html_e( 'Export', 'wp-google-maps' ); ?></button>
            </p>
        </div>
        <?php

    }