Plugin Directory

Changeset 3741840


Ignore:
Timestamp:
10/12/2026 02:08:34 PM (3 weeks ago)
Author:
nsp-code
Message:

Version: 1.3

Location:
software-license-lite
Files:
59 added
13 edited

Legend:

Unmodified
Added
Removed
  • software-license-lite/trunk/api/class.sl.api.1.2.php

    r3619649 r3741840  
    736736                   
    737737                    $allowed_html_tags   =   $this->get_allowed_html_tags();
    738                                        
    739                     if(get_post_meta($product_id, '_sl_description', TRUE) != '')
    740                         {
    741                             $post_html_content   =   get_post( get_post_meta($product_id, '_sl_description', TRUE))->post_content;
    742                             $data->sections['description']  =   wp_kses( $post_html_content, $allowed_html_tags );
    743                         }
    744                     if(get_post_meta($product_id, '_sl_installation', TRUE) != '')
    745                         {
    746                             $post_html_content   =   get_post( get_post_meta($product_id, '_sl_installation', TRUE))->post_content;
    747                             $data->sections['installation']  =   wp_kses( $post_html_content, $allowed_html_tags );
    748                         }
    749                     if(get_post_meta($product_id, '_sl_faq', TRUE) != '')
    750                         {
    751                             $post_html_content   =   get_post( get_post_meta($product_id, '_sl_faq', TRUE))->post_content;
    752                             $data->sections['faq']  =   wp_kses( $post_html_content, $allowed_html_tags );
    753                         }
    754                     if(get_post_meta($product_id, '_sl_screenshots', TRUE) != '')
    755                         {
    756                             $post_html_content   =   get_post( get_post_meta($product_id, '_sl_screenshots', TRUE))->post_content;
    757                             $data->sections['screenshots']  =   wp_kses( $post_html_content, $allowed_html_tags );
    758                         }
    759                     if(get_post_meta($product_id, '_sl_changelog', TRUE) != '')
    760                         {
    761                             $post_html_content   =   get_post( get_post_meta($product_id, '_sl_changelog', TRUE))->post_content;
    762                             $data->sections['changelog']  =   wp_kses( $post_html_content, $allowed_html_tags );
    763                         }
    764                     if(get_post_meta($product_id, '_sl_reviews', TRUE) != '')
    765                         {
    766                             $post_html_content   =   get_post( get_post_meta($product_id, '_sl_reviews', TRUE))->post_content;
    767                             $data->sections['reviews']  =   wp_kses( $post_html_content, $allowed_html_tags );
    768                         }
    769                     if(get_post_meta($product_id, '_sl_other_notes', TRUE) != '')
    770                         {
    771                             $post_html_content   =   get_post( get_post_meta($product_id, '_sl_other_notes', TRUE))->post_content;
    772                             $data->sections['other_notes']  =   wp_kses( $post_html_content, $allowed_html_tags );
    773                         }
    774 
     738                   
     739                    $data->sections = $this->get_product_information_sections( $product_id, $allowed_html_tags );
    775740                   
    776741                    $data->banners             =  array(
    … …  
    915880                   
    916881                    $allowed_html_tags   =   $this->get_allowed_html_tags();
    917                                        
    918                     if(get_post_meta($product_id, '_sl_description', TRUE) != '')
    919                         {
    920                             $post_html_content   =   get_post( get_post_meta($product_id, '_sl_description', TRUE))->post_content;
    921                             $data->sections['description']  =   wp_kses( $post_html_content, $allowed_html_tags );
    922                         }
    923                     if(get_post_meta($product_id, '_sl_installation', TRUE) != '')
    924                         {
    925                             $post_html_content   =   get_post( get_post_meta($product_id, '_sl_installation', TRUE))->post_content;
    926                             $data->sections['installation']  =   wp_kses( $post_html_content, $allowed_html_tags );
    927                         }
    928                     if(get_post_meta($product_id, '_sl_faq', TRUE) != '')
    929                         {
    930                             $post_html_content   =   get_post( get_post_meta($product_id, '_sl_faq', TRUE))->post_content;
    931                             $data->sections['faq']  =   wp_kses( $post_html_content, $allowed_html_tags );
    932                         }
    933                     if(get_post_meta($product_id, '_sl_screenshots', TRUE) != '')
    934                         {
    935                             $post_html_content   =   get_post( get_post_meta($product_id, '_sl_screenshots', TRUE))->post_content;
    936                             $data->sections['screenshots']  =   wp_kses( $post_html_content, $allowed_html_tags );
    937                         }
    938                     if(get_post_meta($product_id, '_sl_changelog', TRUE) != '')
    939                         {
    940                             $post_html_content   =   get_post( get_post_meta($product_id, '_sl_changelog', TRUE))->post_content;
    941                             $data->sections['changelog']  =   wp_kses( $post_html_content, $allowed_html_tags );
    942                         }
    943                     if(get_post_meta($product_id, '_sl_reviews', TRUE) != '')
    944                         {
    945                             $post_html_content   =   get_post( get_post_meta($product_id, '_sl_reviews', TRUE))->post_content;
    946                             $data->sections['reviews']  =   wp_kses( $post_html_content, $allowed_html_tags );
    947                         }
    948                     if(get_post_meta($product_id, '_sl_other_notes', TRUE) != '')
    949                         {
    950                             $post_html_content   =   get_post( get_post_meta($product_id, '_sl_other_notes', TRUE))->post_content;
    951                             $data->sections['other_notes']  =   wp_kses( $post_html_content, $allowed_html_tags );
    952                         }
    953 
     882                   
     883                    $data->sections = $this->get_product_information_sections( $product_id, $allowed_html_tags );
    954884                   
    955885                    $data->banners             =  array(
    … …  
    1057987                   
    1058988                    $allowed_html_tags   =   $this->get_allowed_html_tags();
    1059                                        
    1060                     if(get_post_meta($product_id, '_sl_description', TRUE) != '')
    1061                         {
    1062                             $post_html_content   =   get_post( get_post_meta($product_id, '_sl_description', TRUE))->post_content;
    1063                             $data->sections['description']  =   wp_kses( $post_html_content, $allowed_html_tags );
    1064                         }
    1065                     if(get_post_meta($product_id, '_sl_installation', TRUE) != '')
    1066                         {
    1067                             $post_html_content   =   get_post( get_post_meta($product_id, '_sl_installation', TRUE))->post_content;
    1068                             $data->sections['installation']  =   wp_kses( $post_html_content, $allowed_html_tags );
    1069                         }
    1070                     if(get_post_meta($product_id, '_sl_faq', TRUE) != '')
    1071                         {
    1072                             $post_html_content   =   get_post( get_post_meta($product_id, '_sl_faq', TRUE))->post_content;
    1073                             $data->sections['faq']  =   wp_kses( $post_html_content, $allowed_html_tags );
    1074                         }
    1075                     if(get_post_meta($product_id, '_sl_screenshots', TRUE) != '')
    1076                         {
    1077                             $post_html_content   =   get_post( get_post_meta($product_id, '_sl_screenshots', TRUE))->post_content;
    1078                             $data->sections['screenshots']  =   wp_kses( $post_html_content, $allowed_html_tags );
    1079                         }
    1080                     if(get_post_meta($product_id, '_sl_changelog', TRUE) != '')
    1081                         {
    1082                             $post_html_content   =   get_post( get_post_meta($product_id, '_sl_changelog', TRUE))->post_content;
    1083                             $data->sections['changelog']  =   wp_kses( $post_html_content, $allowed_html_tags );
    1084                         }
    1085                     if(get_post_meta($product_id, '_sl_reviews', TRUE) != '')
    1086                         {
    1087                             $post_html_content   =   get_post( get_post_meta($product_id, '_sl_reviews', TRUE))->post_content;
    1088                             $data->sections['reviews']  =   wp_kses( $post_html_content, $allowed_html_tags );
    1089                         }
    1090                     if(get_post_meta($product_id, '_sl_other_notes', TRUE) != '')
    1091                         {
    1092                             $post_html_content   =   get_post( get_post_meta($product_id, '_sl_other_notes', TRUE))->post_content;
    1093                             $data->sections['other_notes']  =   wp_kses( $post_html_content, $allowed_html_tags );
    1094                         }
    1095 
    1096                    
     989                   
     990                    $data->sections = $this->get_product_information_sections( $product_id, $allowed_html_tags );
     991                               
    1097992                    $data->banners             =  array(
    1098993                                                        'low'   =>  get_post_meta($product_id, '_sl_screenshots_high', TRUE),
  • software-license-lite/trunk/api/class.sl.api.php

    r3619649 r3741840  
    243243               
    244244               
     245               
     246               
     247            /**
     248             * Builds plugin and theme information sections from a local post or custom URL.
     249             *
     250             * @param int   $product_id Product ID.
     251             * @param array $allowed_html_tags Allowed HTML for local post content.
     252             * @return array
     253             */
     254            function get_product_information_sections( $product_id, $allowed_html_tags )
     255                {
     256                    $section_fields = array(
     257                                                'description'  => '_sl_description',
     258                                                'installation' => '_sl_installation',
     259                                                'faq'          => '_sl_faq',
     260                                                'screenshots'  => '_sl_screenshots',
     261                                                'changelog'    => '_sl_changelog',
     262                                                'reviews'      => '_sl_reviews',
     263                                                'other_notes'  => '_sl_other_notes'
     264                                            );
     265                    $sections = array();
     266
     267                    foreach ( $section_fields as $section_name => $meta_key )
     268                        {
     269                            $custom_url = get_post_meta( $product_id, $meta_key . '_url', true );
     270                            if ( ! empty( $custom_url ) )
     271                                {
     272                                    $section_content = $this->get_custom_url_section_content( $custom_url, $allowed_html_tags );
     273                                    if ( $section_content !== '' )
     274                                        $sections[ $section_name ] = $section_content;
     275
     276                                    continue;
     277                                }
     278
     279                            $post_id = absint( get_post_meta( $product_id, $meta_key, true ) );
     280                            if ( empty( $post_id ) )
     281                                continue;
     282
     283                            $section_post = get_post( $post_id );
     284                            if ( ! is_object( $section_post ) || ! isset( $section_post->post_content ) )
     285                                continue;
     286
     287                            $sections[ $section_name ] = wp_kses( $section_post->post_content, $allowed_html_tags );
     288                        }
     289
     290                    return $sections;
     291                }
     292
     293            /**
     294             * Gets a custom URL section from the local cache or retrieves and caches it.
     295             *
     296             * This deliberately uses PHP's filesystem and HTTP extensions only. The API can
     297             * execute outside WordPress; wp_kses() is the sole WordPress function used here.
     298             *
     299             * @param string $custom_url        Remote section URL.
     300             * @param array  $allowed_html_tags Allowed HTML for the section response.
     301             * @return string
     302             */
     303            function get_custom_url_section_content( $custom_url, $allowed_html_tags )
     304                {
     305                    $custom_url = trim( $custom_url );
     306                    if ( ! $this->is_custom_url_section_url( $custom_url ) )
     307                        return '';
     308
     309                    $cache_directory = $this->get_custom_url_section_cache_directory();
     310                    $cache_key       = hash( 'sha256', $custom_url );
     311                    $cached_content  = $this->get_cached_custom_url_section_content( $cache_directory, $cache_key );
     312
     313                    if ( $cached_content !== false )
     314                        return $cached_content;
     315
     316                    $remote_content = $this->fetch_custom_url_section_content( $custom_url );
     317                    if ( $remote_content === '' )
     318                        return '';
     319
     320                    $section_content = $this->extract_custom_url_section_content( $remote_content );
     321                    if ( $section_content === '' )
     322                        return '';
     323
     324                    $section_content = wp_kses( $section_content, $allowed_html_tags );
     325                    if ( $section_content === '' )
     326                        return '';
     327
     328                    $this->cache_custom_url_section_content( $cache_directory, $cache_key, $section_content );
     329
     330                    return $section_content;
     331                }
     332
     333            /**
     334             * Validates that a custom section URL uses HTTP(S).
     335             *
     336             * @param string $url Remote section URL.
     337             * @return bool
     338             */
     339            function is_custom_url_section_url( $url )
     340                {
     341                    $url_parts = parse_url( $url );
     342                    if ( ! is_array( $url_parts ) || empty( $url_parts['scheme'] ) || empty( $url_parts['host'] ) )
     343                        return false;
     344
     345                    return in_array( strtolower( $url_parts['scheme'] ), array( 'http', 'https' ), true );
     346                }
     347
     348            /**
     349             * Returns the uploads subdirectory used for remote section caches.
     350             *
     351             * @return string
     352             */
     353            function get_custom_url_section_cache_directory()
     354                {
     355                    if ( defined( 'WP_UPLOADS' ) && WP_UPLOADS ) {
     356                        $base_directory = rtrim( WP_UPLOADS, '/\\' );
     357                    } elseif ( defined( 'UPLOADS' ) && UPLOADS ) {
     358                        $base_directory = rtrim( ABSPATH . UPLOADS, '/\\' );
     359                    } elseif ( defined( 'WP_CONTENT_DIR' ) && WP_CONTENT_DIR ) {
     360                        $base_directory = rtrim( WP_CONTENT_DIR, '/\\' ) . DIRECTORY_SEPARATOR . 'uploads';
     361                    } else {
     362                        $base_directory = dirname( dirname( dirname( dirname( __FILE__ ) ) ) ) . DIRECTORY_SEPARATOR . 'uploads';
     363                    }
     364
     365                    $cache_directory = $base_directory . DIRECTORY_SEPARATOR . 'software-license-sections';
     366
     367                    if ( ! is_dir( $cache_directory ) ) {
     368                        @mkdir( $cache_directory, 0755, true );
     369                    }
     370
     371                    return is_dir( $cache_directory ) && is_writable( $cache_directory ) ? $cache_directory : '';
     372                }
     373
     374            /**
     375             * Returns an unexpired cached custom section and deletes matching expired files.
     376             * Cache filenames end in their Unix expiry timestamp for easy administration.
     377             *
     378             * @param string $cache_directory Cache directory.
     379             * @param string $cache_key       URL hash.
     380             * @return string|false
     381             */
     382            function get_cached_custom_url_section_content( $cache_directory, $cache_key )
     383                {
     384                    if ( $cache_directory === '' )
     385                        return false;
     386
     387                    $cache_files = glob( $cache_directory . DIRECTORY_SEPARATOR . 'section-' . $cache_key . '-*.html' );
     388                    if ( ! is_array( $cache_files ) )
     389                        return false;
     390
     391                    $now = time();
     392                    foreach ( $cache_files as $cache_file )
     393                        {
     394                            if ( ! preg_match( '/-(\d+)\.html$/', basename( $cache_file ), $matches ) )
     395                                continue;
     396
     397                            $expires_at = (int) $matches[1];
     398                            if ( $expires_at <= $now )
     399                                {
     400                                    @unlink( $cache_file );
     401                                    continue;
     402                                }
     403
     404                            $cached_content = @file_get_contents( $cache_file );
     405                            if ( $cached_content !== false && $cached_content !== '' )
     406                                return $cached_content;
     407                        }
     408
     409                    return false;
     410                }
     411
     412            /**
     413             * Stores a sanitized section in uploads for twelve hours.
     414             *
     415             * @param string $cache_directory Cache directory.
     416             * @param string $cache_key       URL hash.
     417             * @param string $content         Section HTML.
     418             * @return void
     419             */
     420            function cache_custom_url_section_content( $cache_directory, $cache_key, $content )
     421                {
     422                    if ( $cache_directory === '' )
     423                        return;
     424
     425                    $expires_at = time() + ( 12 * 60 * 60 );
     426                    $cache_file = $cache_directory . DIRECTORY_SEPARATOR . 'section-' . $cache_key . '-' . $expires_at . '.html';
     427                    $temporary_file = tempnam( $cache_directory, 'section-' );
     428
     429                    if ( $temporary_file === false )
     430                        return;
     431
     432                    if ( @file_put_contents( $temporary_file, $content, LOCK_EX ) === false )
     433                        {
     434                            @unlink( $temporary_file );
     435                            return;
     436                        }
     437
     438                    if ( file_exists( $cache_file ) || ! @rename( $temporary_file, $cache_file ) )
     439                        @unlink( $temporary_file );
     440                }
     441
     442            /**
     443             * Retrieves a remote custom section with cURL when available, then PHP streams.
     444             *
     445             * @param string $url Remote section URL.
     446             * @return string
     447             */
     448            function fetch_custom_url_section_content( $url )
     449                {
     450                    if ( function_exists( 'curl_init' ) )
     451                        {
     452                            $curl = curl_init( $url );
     453                            curl_setopt( $curl, CURLOPT_RETURNTRANSFER, true );
     454                            curl_setopt( $curl, CURLOPT_FOLLOWLOCATION, true );
     455                            curl_setopt( $curl, CURLOPT_MAXREDIRS, 3 );
     456                            curl_setopt( $curl, CURLOPT_CONNECTTIMEOUT, 5 );
     457                            curl_setopt( $curl, CURLOPT_TIMEOUT, 15 );
     458                            curl_setopt( $curl, CURLOPT_USERAGENT, 'Software-License-Section-Cache/1.0' );
     459
     460                            $content     = curl_exec( $curl );
     461                            $status_code = (int) curl_getinfo( $curl, CURLINFO_HTTP_CODE );
     462                            curl_close( $curl );
     463
     464                            return is_string( $content ) && $status_code >= 200 && $status_code < 300 ? $content : '';
     465                        }
     466
     467                    $context = stream_context_create(
     468                                                        array(
     469                                                                'http' => array(
     470                                                                                'method'           => 'GET',
     471                                                                                'timeout'          => 15,
     472                                                                                'follow_location'  => 1,
     473                                                                                'max_redirects'    => 3,
     474                                                                                'ignore_errors'    => true,
     475                                                                                'header'           => "User-Agent: Software-License-Section-Cache/1.0\r\n"
     476                                                                            )
     477                                                            )
     478                                                    );
     479                    $content = @file_get_contents( $url, false, $context );
     480
     481                    $status_code = 0;
     482                    if ( isset( $http_response_header ) && is_array( $http_response_header ) )
     483                        {
     484                            foreach ( $http_response_header as $header )
     485                                {
     486                                    if ( preg_match( '#^HTTP/[^ ]+\s+(\d+)#i', $header, $matches ) )
     487                                        $status_code = (int) $matches[1];
     488                                }
     489                        }
     490
     491                    return is_string( $content ) && $status_code >= 200 && $status_code < 300 ? $content : '';
     492                }
     493
     494            /**
     495             * Extracts the HTML inside a remote document's body element.
     496             *
     497             * @param string $content Remote document content.
     498             * @return string
     499             */
     500            function extract_custom_url_section_content( $content )
     501                {
     502                    if ( class_exists( 'DOMDocument' ) )
     503                        {
     504                            $previous_libxml_errors = libxml_use_internal_errors( true );
     505                            $document = new DOMDocument();
     506                            $loaded   = @$document->loadHTML( $content );
     507                            libxml_clear_errors();
     508                            libxml_use_internal_errors( $previous_libxml_errors );
     509
     510                            if ( $loaded )
     511                                {
     512                                    $body = $document->getElementsByTagName( 'body' )->item( 0 );
     513                                    if ( $body )
     514                                        {
     515                                            $section_content = '';
     516                                            foreach ( $body->childNodes as $child )
     517                                                $section_content .= $document->saveHTML( $child );
     518
     519                                            return trim( $section_content );
     520                                        }
     521                                }
     522                        }
     523
     524                    if ( preg_match( '#<body[^>]*>(.*)</body>#is', $content, $matches ) )
     525                        return trim( $matches[1] );
     526
     527                    return trim( $content );
     528                }
     529               
     530               
    245531        }
  • software-license-lite/trunk/css/admin-product.css

    r3379472 r3741840  
    88#soliw_keys_root textarea {height: 150px}
    99#soliw_keys_root .soliw_keys_groups {min-height: 30px}
    10 .select2-container {min-width:200px !important; max-width: 100% !important}
     10.select2-container { max-width: 470px !important}
    1111h2#soliw_keys_menu {padding-bottom: 0px; margin-bottom: 0px}
    1212#soliw_keys_menu a {font-size: 12px; min-height: 24px;}
    … …  
    1515a#add_license_group_type {border: none; background-color: transparent; font-weight: bold; font-size: 16px; margin-bottom: 0px}
    1616 #woocommerce-product-data ul.wc-tabs li.sl_tab a::before {content: "\f173";}
     17 
     18 #sl_data.woocommerce_options_panel .sl-custom-select-field .sl-custom-select-controls {
     19    display: inline-flex;
     20    align-items: center;
     21    width: calc(100% - 160px);
     22    max-width: 960px;
     23    vertical-align: middle;
     24}
     25#sl_data.woocommerce_options_panel .sl-custom-select-field .sl-custom-select-controls .select2-container {
     26    flex: 1 1 auto;
     27    width: auto !important;
     28    min-width: 200px !important;
     29}
     30#sl_data.woocommerce_options_panel .sl-custom-select-field .sl-custom-select-or {
     31    margin: 0 16px;
     32    color: #646970;
     33}
     34#sl_data.woocommerce_options_panel .sl-custom-select-field .sl-custom-url-toggle {
     35    flex: 0 0 auto;
     36    min-height: 32px;
     37}
     38#sl_data.woocommerce_options_panel .sl-custom-select-field.is-custom-url .sl-custom-url-toggle {
     39    color: #2271b1;
     40    border-color: #2271b1;
     41    box-shadow: 0 0 0 1px #2271b1;
     42}
     43#sl_data.woocommerce_options_panel .sl-custom-select-field .sl-custom-url-row {
     44    display: flex;
     45    align-items: stretch;
     46    width: calc(100% - 160px);
     47    max-width: 960px;
     48    margin: 10px 0 0 0px;
     49}
     50#sl_data.woocommerce_options_panel .sl-custom-select-field .sl-custom-url-row[hidden] {
     51    display: none;
     52}
     53#sl_data.woocommerce_options_panel .sl-custom-select-field .sl-custom-url-row .dashicons {
     54    box-sizing: border-box;
     55    width: 42px;
     56    height: 42px;
     57    padding: 10px 9px;
     58    border: 1px solid #8c8f94;
     59    border-right: 0;
     60    border-radius: 3px 0 0 3px;
     61    background: #f6f7f7;
     62    color: #646970;
     63}
     64#sl_data.woocommerce_options_panel .sl-custom-select-field .sl-custom-url-input {
     65    flex: 1 1 auto;
     66    width: auto;
     67    min-height: 32px;
     68    margin: 0;
     69    border-radius: 0;
     70    max-width: 428px;
     71}
     72#sl_data.woocommerce_options_panel .sl-custom-select-field .sl-custom-url-clear {
     73    min-height: 32px;
     74    margin-left: 0;
     75}
     76
     77@media screen and (max-width: 782px) {
     78    #sl_data.woocommerce_options_panel .sl-custom-select-field .sl-custom-select-controls,
     79    #sl_data.woocommerce_options_panel .sl-custom-select-field .sl-custom-url-row {
     80        width: 100%;
     81        margin-left: 0;
     82    }
     83    #sl_data.woocommerce_options_panel .sl-custom-select-field .sl-custom-select-or {
     84        margin: 0 8px;
     85    }
     86    #sl_data.woocommerce_options_panel .sl-custom-select-field > .description {
     87        margin-left: 0;
     88    }
     89}
  • software-license-lite/trunk/include/class.sl.admin.product.php

    r3465087 r3741840  
    475475                                       
    476476                                        case  'woo_custom_select'   :
     477                                                    $custom_url_meta_key = $field['id'] . '_url';
     478                                                    $custom_url          = get_post_meta( $post->ID, $custom_url_meta_key, true );
     479
     480                                                    // A custom URL and a WordPress post are mutually exclusive sources.
     481                                                    if ( ! empty( $custom_url ) )
     482                                                        $field['selected'] = 0;
    477483                                                    ?>
    478                                                         <p class="form-field <?php echo esc_html (  $field['class'] ) ?>"<?php  if( isset($field['style']) ) { ?> style="<?php echo esc_html ( $field['style'] ) ?>"<?php }  ?>>
    479                                                             <label for="<?php echo esc_html (  $field['id'] ) ?>"><?php echo esc_html (  $field['label'] ) ?></label>
     484                                                        <p class="form-field sl-custom-select-field <?php echo esc_attr( $field['class'] ) ?><?php echo ! empty( $custom_url ) ? ' is-custom-url' : ''; ?>" data-field-id="<?php echo esc_attr( $field['id'] ); ?>"<?php  if( isset($field['style']) ) { ?> style="<?php echo esc_attr( $field['style'] ) ?>"<?php }  ?>>
     485                                                            <label for="<?php echo esc_attr( $field['id'] ) ?>"><?php echo esc_html( $field['label'] ); ?></label>
    480486                                                   
    481487                                                    <?php
    … …  
    537543                                                            }
    538544                                                           
    539                                                         if  ( ! empty ($output_html))
    540                                                             {
    541                                                                 ?><select name='<?php echo esc_html ( $field['id'] ) ?>' class='wc-enhanced-select-nostd wc_sl_chosen' data-placeholder='<?php esc_html_e ( 'Select a page', 'software-license-lite' ) ?>' id='<?php echo esc_html ( $field['id'] ) ?>'>
     545                                                        {
     546                                                                ?><span class="sl-custom-select-controls">
     547                                                                    <select name="<?php echo esc_attr( $field['id'] ); ?>" class="wc-enhanced-select-nostd wc_sl_chosen sl-custom-select" data-placeholder="<?php esc_attr_e( 'Select a page', 'software-license-lite' ); ?>" id="<?php echo esc_attr( $field['id'] ); ?>"<?php echo ! empty( $custom_url ) ? ' disabled="disabled"' : ''; ?>>
    542548                                                                            <option value=''></option>
    543549                                                                            <?php
    … …  
    557563                                                                                                );
    558564                                                                           
    559                                                                             echo wp_kses ( $output_html, $allowed_tags ) ?>
    560                                                                        </select>
    561                                                                        <span class='description'><?php echo esc_html ( $field['description'] ) ?></span>   
    562                                                                         <?php
    563                                                                
    564                                                             }
    565                                          
     565                                                                            echo wp_kses ( $output_html, $allowed_tags ); ?>
     566                                                                    </select>
     567                                                                    <span class="sl-custom-select-or"><?php esc_html_e( 'or', 'software-license-lite' ); ?></span>
     568                                                                    <button type="button" class="button sl-custom-url-toggle" aria-expanded="<?php echo ! empty( $custom_url ) ? 'true' : 'false'; ?>"><?php esc_html_e( 'Custom URL', 'software-license-lite' ); ?></button>
     569                                                                </span>
     570                                                                <span class="sl-custom-url-row"<?php echo empty( $custom_url ) ? ' hidden' : ''; ?>>
     571                                                                    <span class="dashicons dashicons-admin-links" aria-hidden="true"></span>
     572                                                                    <input type="text" inputmode="url" class="sl-custom-url-input" name="<?php echo esc_attr( $custom_url_meta_key ); ?>" id="<?php echo esc_attr( $custom_url_meta_key ); ?>" value="<?php echo esc_attr( $custom_url ); ?>" placeholder="<?php esc_attr_e( 'https://example.com/details.html', 'software-license-lite' ); ?>" />
     573                                                                    <span class="sl-custom-select-or"><?php esc_html_e( 'or', 'software-license-lite' ); ?></span>
     574                                                                    <button type="button" class="button sl-custom-url-clear"><?php esc_html_e( 'Post/Page', 'software-license-lite' ); ?></button>
     575                                                                </span>
     576                                                                <span class="description"><?php echo esc_html( $field['description'] ); ?></span>
     577                                                                <?php
     578                                                        }
     579
    566580                                                    ?>
    567581                                                        </p>
    … …  
    694708                                            call_user_func($field['function'] . '_save', $product_id);     
    695709                                        }
     710                                        elseif ( $field['type'] === 'woo_custom_select' )
     711                                        {
     712                                            $custom_url_field = $field['id'] . '_url';
     713                                            // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
     714                                            $custom_url = isset( $_POST[ $custom_url_field ] ) ? $this->sanitize_custom_url( wp_unslash( $_POST[ $custom_url_field ] ) ) : '';
     715
     716                                            if ( ! empty( $custom_url ) )
     717                                                {
     718                                                    update_post_meta( $product_id, $field['id'], '' );
     719                                                    update_post_meta( $product_id, $custom_url_field, $custom_url );
     720                                                }
     721                                                else
     722                                                {
     723                                                    // phpcs:ignore WordPress.Security.NonceVerification.Missing
     724                                                    $data = isset( $_POST[ $field['id'] ] ) ? absint( $_POST[ $field['id'] ] ) : '';
     725                                                    update_post_meta( $product_id, $field['id'], $data );
     726                                                    update_post_meta( $product_id, $custom_url_field, '' );
     727                                                }
     728                                        }
    696729                                        else
    697730                                        {
    … …  
    703736                        }
    704737
     738                }
     739               
     740               
     741            /**
     742             * Normalizes a custom section URL and only permits HTTP(S) targets.
     743             *
     744             * @param string $url URL entered in the product editor.
     745             * @return string
     746             */
     747            private function sanitize_custom_url( $url )
     748                {
     749                    $url = trim( $url );
     750                    if ( $url === '' )
     751                        return '';
     752
     753                    if ( strpos( $url, '//' ) === 0 )
     754                        $url = 'https:' . $url;
     755                    elseif ( ! preg_match( '#^[a-z][a-z0-9+.-]*://#i', $url ) )
     756                        $url = 'https://' . $url;
     757
     758                    $url_parts = wp_parse_url( $url );
     759                    if ( empty( $url_parts['scheme'] ) || empty( $url_parts['host'] ) || ! in_array( strtolower( $url_parts['scheme'] ), array( 'http', 'https' ), true ) )
     760                        return '';
     761
     762                    return esc_url_raw( $url, array( 'http', 'https' ) );
    705763                }
    706764       
  • software-license-lite/trunk/js/admin-product.js

    r3465087 r3741840  
    1111
    1212            /* Searchable pull-down menus */
     13            /*
    1314            jQuery( 'select.wc_sl_chosen' ).select2({
    1415                allow_single_deselect: true,
    1516                width: '60%'
    1617            });
     18            */
     19           
     20            jQuery( '.sl-custom-select-field.is-custom-url' ).each( function() {
     21                sl_custom_url_toggle( jQuery( this ), true, false );
     22            } );
     23
     24            jQuery( '#sl_data' ).on( 'click', '.sl-custom-url-toggle', function() {
     25                var field = jQuery( this ).closest( '.sl-custom-select-field' );
     26               
     27                field.find( 'select.sl-custom-select' ).val( '' ).trigger( 'change' );
     28                sl_custom_url_toggle( field, true );
     29                field.find( '.sl-custom-url-input' ).trigger( 'focus' );
     30            } );
     31
     32            jQuery( '#sl_data' ).on( 'click', '.sl-custom-url-clear', function() {
     33                var field = jQuery( this ).closest( '.sl-custom-select-field' );
     34               
     35                field.find( '.sl-custom-url-input' ).val( '' );
     36                sl_custom_url_toggle( field, false );
     37            } );
     38
     39            jQuery( '#sl_data' ).on( 'change', 'select.sl-custom-select', function() {
     40                var field = jQuery( this ).closest( '.sl-custom-select-field' );
     41               
     42                if ( jQuery( this ).val() ) {
     43                    field.find( '.sl-custom-url-input' ).val( '' );
     44                    sl_custom_url_toggle( field, false );
     45                }
     46            } );
     47           
    1748
    1849            // Tooltips
    … …  
    89120            }   
    90121        }
     122       
     123    function sl_custom_url_toggle( field, show, animate )
     124        {
     125            var controls = field.find( '.sl-custom-select-controls' );
     126            var url_row  = field.find( '.sl-custom-url-row' );
     127
     128            if ( typeof animate === 'undefined' ) {
     129                animate = true;
     130            }
     131
     132            field.toggleClass( 'is-custom-url', show );
     133            field.find( '.sl-custom-url-toggle' ).attr( 'aria-expanded', show ? 'true' : 'false' );
     134            field.find( 'select.sl-custom-select' ).prop( 'disabled', show ).trigger( 'change.select2' );
     135
     136            if ( show ) {
     137                url_row.prop( 'hidden', false );
     138                if ( animate ) {
     139                    controls.stop( true, true ).slideUp( 200 );
     140                    url_row.stop( true, true ).hide().slideDown( 200 );
     141                } else {
     142                    controls.hide();
     143                    url_row.show();
     144                }
     145            } else if ( animate ) {
     146                url_row.stop( true, true ).slideUp( 200, function() {
     147                    jQuery( this ).prop( 'hidden', true );
     148                } );
     149                controls.stop( true, true ).slideDown( 200 );
     150            } else {
     151                url_row.prop( 'hidden', true );
     152                controls.show();
     153            }
     154        }
    91155   
    92156    function sl_predefined_keys_toggle(element)
  • software-license-lite/trunk/readme.txt

    r3619649 r3741840  
    33Tags: license manager, software license, license key, licence
    44Requires at least: 3.0
    5 Tested up to: 7.0.2
    6 Stable tag: 1.2.9
     5Tested up to: 7.1.3
     6Stable tag: 1.3
    77License: GPLv2 or later
    88
    … …  
    190190
    191191== Changelog ==
     192
     193= 1.3 =
     194 - 'Select a page' or 'Custom URL' functionality for Product Meta.
     195 - WordPress 7.1.3 compatibility check and tag update.
     196 - WooCommerce 11.2.1 compatibility check and tag update.
    192197
    193198= 1.2.9 =
  • software-license-lite/trunk/software-license-lite.php

    r3619649 r3741840  
    66* Author: Nsp Code
    77* Author URI: https://nsp-code.com/
    8 * Version: 1.2.9
     8* Version: 1.3
    99* Text Domain: software-license-lite
    1010* License: GPLv2 or later
    … …  
    2323    define('SOLIW_URL',    plugins_url('', __FILE__));
    2424   
    25     define('SOLIW_VERSION',   '1.2.9');
     25    define('SOLIW_VERSION',   '1.3');
    2626    define('SOLIW_DB_VERSION',   '1.1');
    2727   
  • software-license-lite/trunk/templates/emails/licence-expire.php

    r3619649 r3741840  
    1212 *
    1313 * @package WOO_SL/Templates/Emails
    14  * @version 1.0.0
     14 * @version 1.2.9
    1515 */
    1616
  • software-license-lite/trunk/templates/emails/licence-expired.php

    r3619649 r3741840  
    1212 *
    1313 * @package WOO_SL/Templates/Emails
    14  * @version 1.0.0
     14 * @version 1.2.9
    1515 */
    1616
  • software-license-lite/trunk/templates/emails/plain/licence-expire.php

    r3619649 r3741840  
    1212 *
    1313 * @package WOO_SL/Templates/Emails/Plain
    14  * @version 1.0.0
     14 * @version 1.2.9
    1515 */
    1616
  • software-license-lite/trunk/templates/emails/plain/licence-expired.php

    r3619649 r3741840  
    1212 *
    1313 * @package WOO_SL/Templates/Emails/Plain
    14  * @version 1.0.0
     14 * @version 1.2.9
    1515 */
    1616
  • software-license-lite/trunk/templates/myaccount/my-licence-manage.php

    r3619649 r3741840  
    1212 *
    1313 * @package WOO_SL/Templates
    14  * @version 1.0.0
     14 * @version 1.2.9
    1515 */
    1616     
  • software-license-lite/trunk/templates/myaccount/my-licences.php

    r3619649 r3741840  
    1414 *
    1515 * @package WOO_SL/Templates
    16  * @version 1.0.0
     16 * @version 1.2.9
    1717 */
    1818
Note: See TracChangeset for help on using the changeset viewer.