Overview

Classes

  • CMLLanguage
  • CMLPost
  • CMLTranslations
  • CMLUtils

Functions

  • cml_dropdown_langs
  • cml_get_browser_lang
  • cml_get_menu
  • cml_get_notice
  • cml_get_the_link
  • cml_is_homepage
  • cml_show_flags
  • Overview
  • Class
  • Tree
   1: <?php
   2: if ( ! defined( 'ABSPATH' ) ) die( "Access denied" );
   3: 
   4: /*
   5:  * Ceceppa Multilingua API 1.4
   6:  */
   7: 
   8:  /**
   9:   * This class provide information about configured languages
  10:   *
  11:   * @api
  12:   * 
  13:   * The structure of language object is:
  14:   * <p>
  15:   * stdClass Object (
  16:   * <ul>
  17:   *   <li>[id] => id of language</li>
  18:   *   <li>[cml_default] => ( boolean ) - is it default?</li>
  19:   *   <li>[cml_flag] => name of flag</li>
  20:   *   <li>[cml_language] => name of language</li>
  21:   *   <li>[cml_language_slug] => language slug</li>
  22:   *   <li>[cml_locale] => wordpress locale</li>
  23:   *   <li>[cml_enabled] => enabled?</li>
  24:   *   <li>[cml_sort_id] => language order</li>
  25:   *   <li>[cml_custom_flag] => (boolean) - use custom flag?</li>
  26:   *   <li>[cml_rtl] => 0</li>
  27:   *   <li>[cml_date_format] => j M Y</li>
  28:   * )
  29:   * </p>
  30:   */
  31: class CMLLanguage {
  32:   /** @ignore */
  33:   private static $_default_language;
  34:   /** @ignore */
  35:   private static $_all_languages; //All languages (enabled and not)
  36:   /** @ignore */
  37:   private static $_all_enabled;   //Only enabled languages
  38:   /** @ignore */
  39:   private static $_all_others;    //All language except default one
  40:   /** @ignore */
  41:   private static $_all_by_slug;   //All languages indexed by slug
  42:   /** @ignore */
  43:   private static $_current_id;    //Current language id
  44: 
  45:   /**
  46:    * Tiny ~= 16x11
  47:    */
  48:   const FLAG_TINY = "tiny";
  49: 
  50:   /**  
  51:    * Small ~= 32x21
  52:    */
  53:   const FLAG_SMALL = "small";
  54: 
  55:   /**
  56:    * return object of default language 
  57:    *
  58:    * @return stdObject
  59:    */
  60:   public static function get_default() {
  61:     if( empty( self::$_all_languages ) ) self::get_all();
  62: 
  63:     return self::$_default_language;
  64:   }
  65: 
  66:   /**
  67:    * return default language id
  68:    *
  69:    * @return int
  70:    */
  71:   public static function get_default_id() {
  72:     return self::get_default()->id;
  73:   }
  74: 
  75:   /**
  76:    * return default language slug
  77:    *
  78:    * return string
  79:    */
  80:   public static function get_default_slug() {
  81:     return self::get_default()->cml_language_slug;
  82:   }
  83:   
  84:   /**
  85:    * return all configured languages, enabled or not...
  86:    *
  87:    * @return stdObject
  88:    */
  89:   public static function get_all() {
  90:     global $wpdb;
  91:   
  92:     /*
  93:      * Prevent a lot of calls to database and store the result into this class
  94:      */
  95:     if( empty( self::$_all_languages) ) {
  96:       self::$_all_languages = $wpdb->get_results( sprintf( "SELECT * FROM %s ORDER BY cml_sort_id ", CECEPPA_ML_TABLE ) );
  97: 
  98:       $all_languages_by_keys = array();
  99:       $sorted = array();
 100:       $enableds = array();
 101:       $byslug = array();
 102:       $others = array();
 103:       foreach( self::$_all_languages as $l ) {
 104:         $all_languages_by_keys[ $l->id ] = $l;
 105:         $byslug[ $l->cml_language_slug ] = $l;
 106:         $sorted[] = $l;
 107: 
 108:         if( $l->cml_default == 1 )
 109:           self::$_default_language = $l;
 110:         else
 111:           $others[ $l->id ] = $l;
 112: 
 113:         if( $l->cml_enabled == 1 ) $enableds[$l->id] = $l;
 114:       }
 115:       
 116:       if( empty( self::$_default_language ) ) {
 117:         update_option( "cml_warning_no_default_language", true );
 118:         
 119:         self::$_default_language = end( $enableds );
 120:       }
 121: 
 122:       self::$_all_enabled = $enableds;
 123:       self::$_all_others = $others;
 124:       self::$_all_languages = $all_languages_by_keys;
 125:       self::$_all_by_slug = $byslug;
 126:       
 127:       if( ! empty( self::$_default_language ) ) {
 128:         self::$_current_id = self::$_default_language->id;
 129:       }
 130:     }
 131: 
 132:     return self::$_all_languages;
 133:   }
 134: 
 135:   /**
 136:    * return all configured languages except default one
 137:    *
 138:    * @return stdObject
 139:    */
 140:   public static function get_no_default() {
 141:     if( empty( self::$_all_languages) ) self::get_all();
 142:     
 143:     return self::$_all_others;
 144:   }
 145: 
 146:   /**
 147:    * return all enabled languages
 148:    *
 149:    * @return stdObject
 150:    */
 151:   public static function get_enableds() {
 152:     if( empty( self::$_all_languages ) ) self::get_all();
 153:     
 154:     return self::$_all_enabled;
 155:   }
 156: 
 157:   /*
 158:    * return all enabled languages except current one
 159:    *
 160:    * @param boolean $only_enableds return only enabled languages
 161:    * @return stdObject
 162:    */
 163:   public static function get_others( $only_enableds = true ) {
 164:     if( empty( self::$_all_languages ) ) self::get_all();
 165:     
 166:     $langs = ( $only_enableds ) ? self::$_all_enabled : self::$_all_languages;
 167:     unset( $langs[ self::get_current_id() ] );
 168:     
 169:     return $langs;
 170:   }
 171: 
 172:   /**
 173:    * return associative array where index
 174:    * is the language slug
 175:    *
 176:    * @example
 177:    * Array (
 178:    * <ul>
 179:    *   <li>"it" => [stdObject..],</li>
 180:    *   <li>"en" => [stdObject...]</li>
 181:    * </ul>
 182:    * )
 183:    *
 184:    * @return Array
 185:    */
 186:   public static function get_slugs() {
 187:     if( empty( self::$_all_languages ) ) self::get_all();
 188:     
 189:     return self::$_all_by_slug;
 190:   }
 191: 
 192:   /**
 193:    * return current language
 194:    *
 195:    * @return stdobject
 196:    */
 197:   public static function get_current() {
 198:     if( empty( self::$_all_languages ) ) self::get_all();
 199: 
 200:     return self::$_all_languages[ self::$_current_id ];
 201:   }
 202: 
 203:   /**
 204:    * return current language id
 205:    *
 206:    * @return int
 207:    */
 208:   public static function get_current_id() {
 209:     return self::get_current()->id;
 210:   }
 211: 
 212:   /**
 213:    * return current language slug
 214:    */
 215:   public static function get_current_slug() {
 216:     return self::get_current()->cml_language_slug;
 217:   }
 218: 
 219:   /**
 220:    * return the name of language
 221:    *
 222:    * @param int/string $lang - id or slug of language
 223:    *
 224:    * @return string
 225:    */
 226:   public static function get_name( $lang ) {
 227:     if( empty( self::$_all_languages ) ) self::get_all();
 228:     if( empty( self::$_default_language ) ) self::get_default();
 229:     if( ! is_numeric( $lang ) ) $lang = self::get_id_by_slug( $lang );
 230: 
 231:     return isset( self::$_all_languages[ $lang ] ) ? self::$_all_languages[ $lang ]->cml_language : "";
 232:   }
 233: 
 234:   /**
 235:    * return the slug of language
 236:    *
 237:    * @param int/string $lang - id or slug of language
 238:    *
 239:    * @return string
 240:    */
 241:   public static function get_slug( $lang ) {
 242:     if( empty( self::$_all_languages ) ) self::get_all();
 243:     if( empty( self::$_default_language ) ) self::get_default();
 244:     if( is_object( $lang ) ) $lang = $lang->id;
 245: 
 246:     if( $lang == 0 ) return self::$_default_language->cml_language_slug;
 247: 
 248:     return @self::$_all_languages[ $lang ]->cml_language_slug;
 249:   }
 250: 
 251:   /**
 252:    * return language by id
 253:    *
 254:    * @param int/string $lang id or slug of language to search
 255:    *
 256:    * @return stdObject
 257:    */
 258:   public static function get_by_id( $id ) {
 259:     if( empty( self::$_all_languages ) ) self::get_all();
 260:     if( ! is_numeric( $id ) ) $id = CMLLanguage::get_by_slug( $id );
 261: 
 262:     return self::$_all_languages[ $id ];
 263:   }
 264: 
 265:   /**
 266:    * get language by slug
 267:    *
 268:    * @param string $slug - language slug
 269:    * @param boolean $empty - If false return default language if $slug doesn't exists.
 270:    *                           If true and $slug doesn't exists return empty array
 271:    *
 272:    * @return stdObject
 273:    */
 274:   public static function get_by_slug( $slug, $empty = false ) {
 275:     if( empty( self::$_all_languages ) ) self::get_all();
 276: 
 277:     foreach( self::$_all_languages as $lang ) {
 278:       if( $lang->cml_language_slug == $slug ) return $lang;
 279:     }
 280:     
 281:     return ( ! $empty ) ? self::get_default() : array();
 282:   }
 283: 
 284:   /**
 285:    * return language id by slug
 286:    *
 287:    * @param string $slug - language slug
 288:    *
 289:    * @return int
 290:    */
 291:   public static function get_id_by_slug( $slug ) {
 292:     $lang = self::get_by_slug( $slug );
 293: 
 294:     return $lang->id;
 295:   }
 296: 
 297:   /**
 298:    * return language id by locale
 299:    *
 300:    * @param string $language locale
 301:    *
 302:    * @return int
 303:    */
 304:   public static function get_id_by_locale( $locale ) {
 305:     $langs = self::get_all();
 306:     
 307:     foreach( $langs as $lang ) {
 308:       if( $lang->cml_locale == $locale ) return $lang;
 309:     }
 310:     
 311:     return null;
 312:   }
 313: 
 314:   /**
 315:    * return the flag filename ( withouth extension )
 316:    *
 317:    * @param int/string $lang ( optional ) - id/slug of language, if empty default one will be used
 318:    * @param string $size ( optional ) - size of flag: "tiny" or "small"
 319:    *
 320:    * @return string
 321:    */
 322:   public static function get_flag( $lang = null, $size = "small" ) {
 323:     if( empty( $lang ) ) $lang = self::default_language_id();
 324:     if( ! is_numeric( $lang ) ) $lang = self::get_id_by_slug( $lang );
 325: 
 326:     if( empty( self::$_all_languages ) ) self::get_all();
 327: 
 328:     return self::$_all_languages[ $lang ]->cml_flag;
 329:   }
 330: 
 331:   /**
 332:    * return flag filename with the full path.
 333:    *
 334:    * Example
 335:    * www.example.com/wp-content/plugin/ceceppa-multilingua/flags/tiny/it_IT.png
 336:    *
 337:    * @param int/string $lang ( optional ) - id or slug of language, if empty default one will be used
 338:    * @param string $size ( optional ) - size of flag: "tiny" or "small"
 339:    *
 340:    * @return string: flag filename with the full path.
 341:    */
 342:   public static function get_flag_src( $lang = null, $size = CML_FLAG_TINY ) {
 343:     if( empty( self::$_all_languages ) ) self::get_all();
 344:     if( empty( self::$_default_language ) ) self::get_default();
 345:     if( $lang == null ) $lang = self::get_default_id();
 346:     if( ! is_numeric( $lang ) ) $lang = self::get_id_by_slug( $lang );
 347: 
 348:     if( ! isset( self::$_all_languages[ $lang ] ) ) {
 349:       return "";
 350:     }
 351: 
 352:     $lang = self::$_all_languages[ $lang ];
 353:     $flag = $lang->cml_flag;
 354: 
 355:     if( $lang->cml_custom_flag == 1 && file_exists( CML_UPLOAD_DIR . "/$size/$flag.png" ) )
 356:       $url = CML_UPLOAD_URL . "/$size/$flag.png";
 357:     else
 358:       $url = CML_PLUGIN_URL . "flags/$size/$flag.png";
 359: 
 360:     return esc_url( $url );
 361:   }
 362:   
 363:   /**
 364:    * return html <img> object of flag
 365:    *
 366:    * @param int/string $lang - id or slug of language
 367:    * @param string $size - flag size ( tiny or small )
 368:    *
 369:    * @return string
 370:    */
 371:   public static function get_flag_img( $lang, $size = CML_FLAG_TINY ) {
 372:     $url = self::get_flag_src( $lang, $size );
 373:     $name = self::get_name( $lang );
 374:     $slug = self::get_slug( $lang );
 375: 
 376:     return "<img src='$url' border='0' alt='$slug' title='$name' />";
 377:   }
 378:    
 379:    /**
 380:     * @ignore
 381:     *
 382:     * force "reload" languages
 383:     */
 384:    public static function reload() {
 385:     self::$_all_languages = null;
 386:    }
 387: 
 388:   /**
 389:    * get language object by post id
 390:    *
 391:    * @param int $post_id - id of post/page
 392:    *
 393:    * @return stdObject
 394:    */
 395:   public static function get_by_post_id( $post_id ) {
 396:     return CMLPost::get_language_by_id( $post_id );
 397:   }
 398: 
 399:   /**
 400:    * get language id by post id
 401:    *
 402:    * @param int $post_id - id of post
 403:    *
 404:    * @return int
 405:    */
 406:   public static function get_id_by_post_id( $post_id ) {
 407:     return CMLPost::get_language_id_by_id( $post_id );
 408:   }
 409:   
 410:   /**
 411:    * Is $lang the default one?
 412:    *
 413:    * @param int/string $lang ( optional ) id/slug. check if $lang is the default language, if null is passed
 414:    *                        current language will be assumed
 415:    * @return boolean
 416:    */
 417:   public static function is_default( $lang = null) {
 418:     if( null == $lang ) {
 419:       $lang = CMLUtils::_get( '_real_language');
 420:     } else {
 421:       if( ! is_numeric( $lang ) ) {
 422:         $lang = CMLLanguage::get_id_by_slug( $lang );
 423:       }
 424:     }
 425: 
 426:     return $lang == CMLLanguage::get_default_id();
 427:   }
 428:  
 429:   /**
 430:    * check if $lang is the current language
 431:    *
 432:    * @param int/string $lang language id/slug to compare
 433:    *
 434:    * @return boolean
 435:    */
 436:   public static function is_current( $lang ) {
 437:     if( null == $lang ) {
 438:       $lang = CMLLanguage::get_current_id();
 439:     } else {
 440:       if( ! is_numeric( $lang ) ) {
 441:         $lang = CMLLanguage::get_id_by_slug( $lang );
 442:       }
 443:     }
 444:     
 445:     return $lang == CMLLanguage::get_current_id();
 446:   }
 447: 
 448:   /**
 449:    * @ignore
 450:    * 
 451:    * set current language
 452:    *
 453:    * @param $lang - language object or id
 454:    *
 455:    * @return void
 456:    */
 457:   public static function set_current( $lang ) {
 458:     $id = is_object( $lang ) ? $lang->id : $lang;
 459:     
 460:     self::$_current_id = $id;
 461:   }
 462: }
 463: 
 464: /**
 465:  * This class is used to get and store custom translations in CECEPPA_ML_TRANSLATIONS table.
 466:  */
 467: class CMLTranslations {
 468:   //store "get" translations
 469:   /** @ignore */
 470:   private static $_translations = array();
 471:   /** @ignore */
 472:   private static $_keys = array();
 473: 
 474:   /**
 475:    * This function can be used by 3rd part plugin/theme to allow translation of its strings.
 476:    * Added string can be translated in "My Languages" page.
 477:    *
 478:    * @example
 479:    * Full example is provided here:<br />
 480:    *  http://www.alessandrosenese.eu/en/ceceppa-multilingua/extend-plugin-theme-compatibility/
 481:    *
 482:    * @param string $key used to store/get your own value from database. To avoid duplicated key use your own
 483:    *                        prefix for your key. Example: "_yoast_rssafter"
 484:    * @param string $default default value to use
 485:    * @param string $group The group name of your own strings, this name will be displayed in "My Translations" page
 486:    *                      in "Group" column. Group name should be preceded by "_" symbol.<br />
 487:    *                      Example: "_YOAST"
 488:    *
 489:    * @return void
 490:    */
 491:   public static function add( $key, $default, $group, $no_default = false ) {
 492:     global $wpdb;
 493: 
 494:     $default = bin2hex( $default );
 495:     $langs = ( $no_default ) ? CMLLanguage::get_no_default() : CMLLanguage::get_all();
 496:     foreach( $langs as $lang ) {
 497:       $query = sprintf( "SELECT id FROM %s WHERE cml_text = '%s' AND cml_lang_id = %d AND cml_type = '%s'",
 498:                         CECEPPA_ML_TRANSLATIONS,
 499:                         bin2hex( strtolower( $key ) ),
 500:                         $lang->id,
 501:                         $group );
 502:   
 503:       $record = $wpdb->get_var( $query );
 504:       if( empty( $record ) ) {
 505:         $wpdb->insert( CECEPPA_ML_TRANSLATIONS,
 506:                       array(
 507:                             'cml_text' => bin2hex( strtolower( $key ) ),
 508:                             'cml_lang_id' => $lang->id,
 509:                             'cml_translation' => $default,
 510:                             'cml_type' => $group
 511:                             ),
 512:                       array(
 513:                         '%s', '%d', '%s', '%s',
 514:                       )
 515:                      );
 516:       }
 517:     }
 518:   }
 519:   
 520:   /**
 521:    * Store custom translation in database.
 522:    *
 523:    * Since 1.4 CML generate GNUTEXT mo file from stored translations. 
 524:    * The domain used to generate translation is: "cmltrans".
 525:    *
 526:    * Mo file isn't generated automatically, but you have to call manually
 527:    * the function cml_generate_mo_from_translations()
 528:    * 
 529:    * This function will return the id of inserted record.
 530:    * 
 531:    * @example
 532:    *
 533:    * <?php _e( "Hello", "cmltrans" ); ?>
 534:    *
 535:    * Use "get" function instead of __, _e, because if "mo" generation fails,
 536:    * this function will get translation from database
 537:    * 
 538:    * @param int/string $lang - id/slug of language
 539:    * @param string $original - original string
 540:    * @param string $translation - translated string
 541:    * @param string $type - type of translation( W: Widget, S: Custom strings ).
 542:    *                Type field is used "internally" to show records in correct table, like
 543:    *                Widget titles, My translations...
 544:    *
 545:    * @return string
 546:    */
 547:   public static function set( $lang, $original, $translated, $type ) {
 548:     global $wpdb;
 549: 
 550:     if( ! is_numeric( $lang ) ) $lang = CMLLanguage::get_id_by_slug( $lang );
 551:     $original = trim( $original );
 552: 
 553:     $wpdb->delete( CECEPPA_ML_TRANSLATIONS,
 554:                     array( "cml_text" => bin2hex( $original ),
 555:                            "cml_type" => $type,
 556:                            "cml_lang_id" => $lang ),
 557:                     array( "%s", "%s", "%d" ) );
 558: 
 559:     return $wpdb->insert( CECEPPA_ML_TRANSLATIONS, 
 560:                           array( 'cml_text' => bin2hex( $original ),
 561:                                 'cml_lang_id' => $lang,
 562:                                 'cml_translation' => bin2hex( $translated ),
 563:                                 'cml_type' => $type ),
 564:                           array( '%s', '%d', '%s', '%s' ) );
 565:   }
 566:   
 567:   /**
 568:    * return translation stored in cml_trans table.
 569:    *
 570:    * This function will get translation from ".mo" file if:
 571:    *    1) it's generated correctly
 572:    *    2) $lang == current language
 573:    *
 574:    * otherwise will get translation from database
 575:    *
 576:    * <strong>string match is case sensitive</strong>
 577:    * 
 578:    * @param int/string $lang - language id or slug
 579:    * @param string $string - string to translate
 580:    * @param string $type - ( optional ) This is used internally by Ceceppa Multilingua, only in admin interface
 581:    *                  T - Site Title/Tagline,
 582:    *                  W - Widget,
 583:    *                  M - My translations
 584:    *                  
 585:    * @param boolean $return_empty - If true, return empty string if no translation is found
 586:    * @param boolean $ignore_po  Since 1.4 the plugin will generate mo file for all translation stored
 587:    *                                in CECEPPA_ML_TRANSLATIONS ( widget titles, my translations, site title/tagline... ).
 588:    *                                So by default if $lang == current language, the plugin will get translation
 589:    *                                from ".mo" file instead query the database.
 590:    *                                You can force to retive translation from database.
 591:    *
 592:    * @return string                 
 593:    */
 594:   public static function get( $lang, $string, $type = "", $return_empty = false, $ignore_po = false ) {
 595:     global $wpdb;
 596: 
 597:     // if( CMLLanguage::is_current( $lang ) && 
 598:     //     "_" != $type[ 0 ] &&
 599:     //     ! ( isset( $string[0] ) && "_" == $string[ 0 ] ) ) {
 600:     //   return $string;
 601:     // }
 602: 
 603:     if( "_" == $type[ 0 ] && ! $return_empty ) {
 604:       $return_empty = true;
 605:     }
 606: 
 607:     $string = trim( $string );
 608: 
 609:     //C = Category
 610:     $s = ( $type == "C" ) ? strtolower( $string ) : $string;
 611: 
 612:     //Look if I already translated it...
 613:     if( isset( self::$_keys[ $lang ] ) && in_array( sanitize_title( $s ), self::$_keys[ $lang ] ) ) {
 614:       $index = array_search( sanitize_title( $s ), self::$_keys[ $lang ] );
 615:       return self::$_translations[ $lang ][ $index ];
 616:     }
 617: 
 618:     if( CML_GET_TRANSLATIONS_FROM_PO &&
 619:        ! $ignore_po &&
 620:        1 == CMLUtils::_get( '_po_loaded' ) ) {
 621:          //file_exists( CML_PLUGIN_CACHE_PATH . "cmltrans-" . CMLLanguage::get_current()->cml_locale . ".mo" ) ) {
 622:       $ret = __( $s, 'cmltrans' );
 623:     }
 624: 
 625:     if( ! is_numeric( $lang ) ) {
 626:       $lang = CMLLanguage::get_id_by_slug( $lang );
 627:     }
 628: 
 629:     $query = sprintf(" SELECT UNHEX(cml_translation) FROM %s WHERE cml_text = '%s' AND cml_lang_id = %d AND cml_type LIKE '%s'",
 630:                                     CECEPPA_ML_TRANSLATIONS, bin2hex( $s ), $lang, "%" . $type . "%" );
 631: 
 632:     $return = $wpdb->get_var( $query );
 633: 
 634:     if( $return_empty && empty( $return ) ) return "";
 635: 
 636:     $return = ( empty( $return ) ) ?  $string : html_entity_decode( stripslashes( $return ) );
 637:     
 638:     self::$_translations[$lang][] = $return;
 639:     self::$_keys[ $lang ][] = sanitize_title( $string );
 640: 
 641:     return $return;
 642:   }
 643:   
 644:   /*
 645:    * get translation from wordpress
 646:    *
 647:    * @ignore
 648:    */
 649:   public static function gettext( $lang, $string, $type, $ignore_po = false ) {
 650:     $ret = self::get( $lang, $string, $type, true, $ignore_po );
 651: 
 652:     if( ! empty( $ret ) ) return $ret;
 653: 
 654:     //Recupero la traduzione dalle frasi di wordpress ;)
 655:     require_once( CML_PLUGIN_PATH . "gettext/gettext.inc" );
 656:     
 657:     $locale = CMLLanguage::get_current()->cml_locale;
 658: 
 659:     // gettext setup
 660:     T_setlocale( LC_MESSAGES, $locale );
 661:     // Set the text domain as 'messages'
 662: 
 663:     $domain = $locale;
 664:     T_bindtextdomain( $domain, CML_WP_LOCALE_DIR );
 665:     T_bind_textdomain_codeset( $domain, 'UTF-8' );
 666:     T_textdomain( $domain );
 667: 
 668:     $ret = T_gettext( $string );
 669: 
 670:     return ( empty( $ret ) ) ?  $string : html_entity_decode( stripslashes( $ret ) );
 671:   }
 672:   
 673:   /**
 674:    * delete all records with cml_type = xx
 675:    *
 676:    * @ignore
 677:    */
 678:   public static function delete( $type ) {
 679:     global $wpdb;
 680:     
 681:     $wpdb->delete( CECEPPA_ML_TRANSLATIONS,
 682:                   array( "cml_type" => $type ),
 683:                   array( "%s" ) );
 684:   }
 685: }
 686: 
 687: /**
 688:  * This class is used to get/set post translation/language or get language by its id
 689:  * 
 690:  */
 691: class CMLPost {
 692:   /** @ignore */
 693:   private static $_indexes = null;
 694:   /** @ignore */
 695:   private static $_posts_meta = array();
 696: 
 697:   /**
 698:    * return language object by post id
 699:    *
 700:    * this function return "null" if post doesn't exists in any language
 701:    * 
 702:    * @param int/string $post_id - id of post/page
 703:    *
 704:    * @return stdObject
 705:    */
 706:   public static function get_language_by_id( $post_id ) {
 707:     if( empty( self::$_indexes ) ) self::_load_indexes();
 708: 
 709:     /*
 710:      * search in current language first.
 711:      * because if post exists in multiple languages, included current one,
 712:      * I have to return current language id, not random :)
 713:      */
 714:     if( @in_array( $post_id, self::$_indexes[ CMLLanguage::get_current_id() ] ) ) {
 715:       return CMLLanguage::get_current();
 716:     }
 717: 
 718:     foreach( CMLLanguage::get_others() as $lang ) {
 719:       if( @in_array( $post_id, self::$_indexes[ $lang->id ] ) )
 720:         return $lang;
 721:     }
 722: 
 723:     return null;
 724:   }
 725:   
 726:   /**
 727:    * return language id by post id
 728:    *
 729:    * @param int $post_id - id of post/page
 730:    * @param boolean $meta - default false.
 731:    *                        If true use wp function "get_post_meta", instead of get_language_by_id method
 732:    *                        to get language of post.
 733:    *                        In backend I need to get information by post meta, or I'll lost
 734:    *                        "all languages" ( = 0 ) information.
 735:    *
 736:    * @return int
 737:    */
 738:   public static function get_language_id_by_id( $post_id, $meta = false ) {
 739:     if( $meta ) {
 740:       //Get from meta
 741:       $m = get_post_meta( $post_id, "_cml_meta", true );
 742: 
 743:       if( ! empty( $m ) && isset( $m[ "lang" ] ) ) {
 744:         return $m[ "lang"];
 745:       }
 746:     }
 747: 
 748:     $lang = self::get_language_by_id( $post_id );
 749: 
 750:     if( null === $lang ) {
 751:       //Get from meta
 752:       $m = get_post_meta( $post_id, "_cml_meta", true );
 753: 
 754:       if( $meta && empty( $m ) ) {
 755:         $lang = self::get_language_by_id( $post_id );
 756:   
 757:         if( is_object( $lang ) ) {
 758:           //update meta
 759:           self::update_meta( $lang->id, $post_id );
 760:         }
 761:   
 762:         return is_object( $lang ) ? $lang->id : 0;
 763:       } else {
 764:         return @$meta[ "lang" ];
 765:       }
 766:     }
 767: 
 768:     return $lang->id;
 769:   }
 770:   
 771:   /**
 772:    * get language slug by post id
 773:    *
 774:    * @param int $post_id post/page id
 775:    *
 776:    * @return string
 777:    */
 778:   public static function get_language_slug_by_id( $post_id ) {
 779:     $lang = self::get_language_by_id( $post_id );
 780:     
 781:     return is_object( $lang ) ? $lang->cml_language_slug : "";
 782:   }
 783: 
 784:   /**
 785:    * get the translation id, if exists, in selected language
 786:    *
 787:    * this function will return 0 if no translation is found.
 788:    * 
 789:    * @param int/string $lang - language id/slug in which return translation
 790:    * @param int $post_id - post id
 791:    *
 792:    * @return int
 793:    */
 794:   public static function get_translation( $lang, $post_id ) {
 795:     global $wpdb;
 796: 
 797:     if( is_numeric( $lang ) ) $lang = CMLLanguage::get_slug( $lang );
 798:     if( empty( $post_id ) ) return 0;
 799: 
 800:     //if( ! CECEPPA_ML_MIGRATED ) {
 801:     //  return cml_old_get_linked_post( $wpCeceppaML->get_language_id_by_post_id( $post_id ), null, $post_id, $lang );
 802:     //}
 803:   
 804:     $linked = self::get_translations( $post_id );
 805: 
 806:     return ( ! array_key_exists( $lang, $linked) ) ? 0 : $linked[ $lang ];
 807:   }
 808: 
 809:   /**
 810:    * get all available translations of post
 811:    *
 812:    * This function will return Array containing all info about linked posts
 813:    *
 814:    * Array(
 815:    * <ul>
 816:    *   <li>[language slug] => [post_id]</li>
 817:    *   <li>...</li>
 818:    *   <li>[indexes] => Array<br />
 819:    *    <i>In this subarray there are all linked posts, including $post_id</i>
 820:    *    <ul>
 821:    *      <li>[language slug] => [post_id]</li>
 822:    *      <li>...</li>
 823:    *    </ul>
 824:    *   </li>
 825:    *   <li>
 826:    *    [linked] => Array<br />
 827:    *    <i>In this subarray there are only linked post indexes</i> 
 828:    *    <ul>
 829:    *      <li>[linked language slug] => [linked_id]</li>
 830:    *      <li>...</li>
 831:    *    </ul>
 832:    *  </li>
 833:    * </ul>
 834:    * )
 835:    * 
 836:    * @example
 837:    * <br />
 838:    * Array (
 839:    * <ul>
 840:    *   <li>[it] => 2552</li>
 841:    *   <li>[en] => 541</li>
 842:    *   <li>[eo] => 0</li>
 843:    *   <li>[indexes] => Array
 844:    *       (
 845:    *       <ul>
 846:    *        <li>[it] => 2552</li>
 847:    *       </ul>
 848:    *       )
 849:    *    </li>
 850:    *    <li>
 851:    *   [linked] => Array
 852:    *       (
 853:    *       <ul>
 854:    *        <li>[en] => 541</li>
 855:    *       )
 856:    *    </li>
 857:    *  </ul>
 858:    * )
 859:    *
 860:    * @param int $post_id - post id
 861:    * @param boolean $force - force to rebuild meta. ( This parameter is used internally by CML )
 862:    *
 863:    * return Array
 864:    */
 865:   public static function get_translations( $post_id, $force = false ) {
 866:     global $wpdb;
 867:   
 868:     if( empty( $post_id ) ) return array();
 869: 
 870:     if( ! isset( self::$_posts_meta[ $post_id ] ) || $force ) {
 871:       $row = ""; //get_post_meta( $post_id, "_cml_meta", true );
 872: 
 873:       if( empty( $row ) || empty( $row[ 'lang' ] ) || $force ) {
 874:         if( empty( $GLOBALS[ '_cml_language_columns' ] ) ) {
 875:           require_once ( CML_PLUGIN_ADMIN_PATH . 'admin-settings-gen.php' );
 876: 
 877:           cml_generate_lang_columns();
 878:         }
 879:       
 880:         $_cml_language_columns = & $GLOBALS[ '_cml_language_columns' ];
 881:         $_conv = & $GLOBALS[ '_cml_language_keys' ];
 882: 
 883:         $query = "SELECT ";
 884:         foreach( $_conv as $key => $label ) {
 885:           $select[] = "$key as $label";
 886:         }
 887: 
 888:         /*
 889:          * something happend that $_conv is empty and that couse a warning
 890:          * and I can't store post relations properly.
 891:          */
 892:         if( empty( $select ) ) {
 893:           $keys = array_keys( CMLLanguage::get_all() );
 894:           $langs = array_keys( CMLLanguage::get_slugs() );
 895: 
 896:           foreach( $keys as $k => $v ) {
 897:             $select[] = "lang_{$v} as " . $langs[ $k ];
 898:           }
 899:         }
 900: 
 901:         $query .= join( ",", $select ) . " FROM " . CECEPPA_ML_RELATIONS . " WHERE ";
 902:         foreach( $_cml_language_columns as $l ) {
 903:           $where[] = "$l = $post_id";
 904:         }
 905:         $query .= join( " OR ", $where );
 906:       
 907:         $row = $wpdb->get_row( $query, ARRAY_A );
 908:         unset( $row[ "id" ] );
 909: 
 910:         $keys = @array_filter( $row );
 911:         $keys = @array_replace( $keys, $_conv );
 912:         $others = @array_filter( is_array( $row ) ? $row : array() );
 913:         unset( $others[ CMLPost::get_language_slug_by_id( $post_id ) ] );
 914:       
 915:         $row = @array_merge( (array) $row, array( "indexes" => array_filter( $row ),
 916:                                                  "linked" => $others ) );
 917: 
 918:         if( ! $force && isset( $row[ 'lang' ] ) ) {
 919:           self::update_meta( self::get_language_id_by_id( $post_id ), $post_id, $row );
 920:         } else {
 921:         }
 922:       } else {
 923:         $row = $row[ 'translations' ];
 924:       }
 925: 
 926:       self::$_posts_meta[ $post_id ] = $row;
 927:     } else {
 928:       $row = self::$_posts_meta[ $post_id ];
 929:     }
 930: 
 931:     return $row;
 932:   }
 933:   
 934:   /**
 935:    * set language of post
 936:    *
 937:    * This function will unlink $post_id by its translations
 938:    * 
 939:    * @param int/string $lang - post language id/slug 
 940:    * @param int $post_id - post id
 941:    */
 942:   public static function set_language( $lang, $post_id ) {
 943:     if( ! is_numeric( $lang ) ) $lang = CMLLanguage::get_id_by_slug( $lang );
 944: 
 945:     cml_migrate_database_add_item( $lang, $post_id, 0, 0 );
 946:   }
 947: 
 948:   /**
 949:    * set single translation to post id
 950:    *
 951:    * This function is used to link 2 posts
 952:    *
 953:    * When you link a post to single translation, relations with other language will not be losed.
 954:    * If you want remove other relations, you have to use set_language method first.
 955:    * 
 956:    * @param int $post_id - post to set translation
 957:    * @param int/string $linked_lang - language id/slug of linked post
 958:    * @param int $linked_post - post id of translation
 959:    * @param int $post_lang ( optional ) - language of $post_id. If null, It will get from database
 960:    *
 961:    * @return void
 962:    */
 963:   public static function set_translation( $post_id, $linked_lang, $linked_post, $post_lang = null ) {
 964:     self::set_translations( $post_id, array( $linked_lang => $linked_post ), $post_lang );
 965:   }
 966: 
 967:   /**
 968:    * add multiple translations to post id
 969:    *
 970:    * This function will update relations only from $post_id with $translations posts, so relations
 971:    * from $post_id and languages than doesn't exists in $translations array will not be broken.
 972:    * 
 973:    * If you need to set relation only from $post_id and $translations, and remove the other one, you
 974:    * have to "break" them using set_language method first.
 975:    * 
 976:    * @param $post_id - post to set translation+
 977:    * @param $translations - array with language_slug as key and post_id as value.
 978:    *                        array( "it" => 1, "en" => 2 )...
 979:    * @param $post_lang ( optional ) - set also the language of $post_id
 980:    *
 981:    * @example:
 982:    *
 983:    *    CMLPost::set_translation( 1, array( "it" => 2, "en" => 3 ) )
 984:    */
 985:   public static function set_translations( $post_id, $translations, $post_lang = null ) {
 986:     //$_cml_language_columns = & $GLOBALS[ '_cml_language_columns' ];
 987:     if( null === $post_lang ) $post_lang = CMLPost::get_language_id_by_id( $post_id );
 988: 
 989:     foreach( $translations as $key => $id ) {
 990:       if( ! is_numeric( $key ) ) $key = CMLLanguage::get_id_by_slug( $key );
 991: 
 992:       cml_migrate_database_add_item( $post_lang, $post_id, $key, $id );
 993: 
 994:       //I have to update meta for $post_id and its translation
 995:       self::update_meta( $key, $post_id );
 996:     }
 997: 
 998:     //Update info
 999:     cml_fix_rebuild_posts_info();
1000:     self::_load_indexes();
1001: 
1002:     self::update_meta( $post_lang, $post_id );
1003:   }
1004:   
1005:   /*
1006:    * update post meta
1007:    * @ignore
1008:    */
1009:   public static function update_meta( $lang, $post_id, $translations = null ) {
1010:     /*
1011:      * I just updated post relation, so I have to rebuild meta :)
1012:      */
1013:     //Add my meta to post
1014:     if( null == $translations ) {
1015:       $translations = CMLPost::get_translations( $post_id, true );
1016:     }
1017:     $meta = array( "lang" => $lang,
1018:                     "translations" => $translations );
1019: 
1020:     // if( ! isset( $meta[ 'lang' ] ) || empty( $translations ) ) {
1021:       // delete_post_meta( $post_id, "_cml_meta" );
1022:     // } else {
1023:     update_post_meta( $post_id, "_cml_meta", $meta );
1024:     // }
1025:   }
1026: 
1027:   /**
1028:    * get indexes of posts that exists in selected language
1029:    *
1030:    * @param int/slug $lang ( optional, if not set will be = current language id )
1031:    *                      id / slug of language
1032:    *
1033:    * @return array
1034:    */
1035:   public static function get_posts_by_language( $lang = null ) {
1036:     if( empty( $lang ) ) $lang = CMLLanguage::get_current_id();
1037:     if( ! is_numeric( $lang ) ) $lang = CMLLanguage::get_id_by_slug( $lang );
1038:   
1039:     //Gli articoli senza lingua sono "figli di tutti"
1040:     if( empty( self::$_indexes ) ) self::_load_indexes();
1041: 
1042:     $posts = @self::$_indexes[ $lang ];
1043: 
1044:     return ! empty( $posts ) ? array_unique( $posts ) : array();
1045:   }
1046: 
1047:   /*
1048:    * for private use only, update post indexes by language
1049:    * @ignore
1050:    */
1051:   public static function _update_posts_by_language( $lang, $ids ) {
1052:     self::$_indexes[ $lang ] = $ids;
1053:   }
1054: 
1055:   /**
1056:    * return all posts by languages.
1057:    *
1058:    * The key of array is the language id
1059:    *
1060:    * @return array
1061:    */
1062:   public static function get_posts_by_languages() {
1063:     //Gli articoli senza lingua sono "figli di tutti"
1064:     if( empty( self::$_indexes ) ) self::_load_indexes();
1065: 
1066:     return self::$_indexes;
1067:   }
1068: 
1069:   /**
1070:    * check if $post_id has translation in selected language.
1071:    *
1072:    * @param int/string $lang - language id/slug
1073:    * @param int $post_id - post id
1074:    * 
1075:    * return boolean
1076:    */
1077:   public static function has_translation( $lang, $post_id ) {
1078:     if( ! isset( self::$_posts_meta[ $post_id ] ) ) {
1079:       self::$_posts_meta[ $post_id ] = self::get_translations( $post_id );
1080:     }
1081: 
1082:     if( is_numeric( $lang ) ) $lang = CMLLanguage::get_slug( $lang );
1083: 
1084:     return ( isset( self::$_posts_meta[ $post_id ]['indexes'] ) &&
1085:             self::$_posts_meta[ $post_id ]['indexes'][ $lang ] > 0 );
1086:   }
1087: 
1088:   /**
1089:    * check if $post_id has any translation
1090:    *
1091:    * @param int $post_id - post id
1092:    *
1093:    * @return boolean
1094:    */
1095:   public static function has_translations( $post_id ) {
1096:     if( ! isset( self::$_posts_meta[ $post_id ] ) ) {
1097:       self::$_posts_meta[ $post_id ] = self::get_translations( $post_id );
1098:     }
1099: 
1100:     return ! empty( self::$_posts_meta[ $post_id ][ 'linked' ] );
1101:   }
1102: 
1103:   /**
1104:    * check if $post1 is translation of $post2
1105:    *
1106:    * @param int $post1 post id
1107:    * @param int $post2 post id
1108:    *
1109:    * @return boolean
1110:    */
1111:   public static function is_translation( $post1, $post2 ) {
1112:     $translations = CMLPost::get_translations( $post1 );
1113: 
1114:     return in_array( $post2, $translations[ 'indexes' ] );
1115:   }
1116: 
1117:   /** @ignore */
1118:   private static function _load_indexes() {
1119:     $langs = cml_get_languages( false );
1120: 
1121:     foreach($langs as $lang) {
1122:       self::$_indexes[ $lang->id ] = get_option( "cml_posts_of_lang_" . $lang->id );
1123:     }
1124:   }
1125: 
1126:   /**
1127:    * @ignore
1128:    *
1129:    * Remove extra "-##" add by wordpress when more than one post has
1130:    * same titles, but ONLY on translations.
1131:    */
1132:   public static function remove_extra_number( $permalink, $post ) {
1133:     global $wpdb;
1134: 
1135:     $removed = false;
1136: 
1137:     if( is_object( $post ) && CMLPost::has_translations( $post->ID ) ) {
1138:       //Remove last "/"
1139:       $url = untrailingslashit( $permalink );
1140:       $url = str_replace( CMLUtils::home_url(), "", $url );
1141:   
1142:       /*
1143:        * Post/page link contains "-d"
1144:        */
1145:       preg_match_all( "/-\d+/", $url, $out );
1146:   
1147:       /*
1148:        * if true I have to check if it was added by "wordpress" :)
1149:        */
1150:       if( count( $out[ 0 ] ) > 0 ) {
1151:         /*
1152:          * when hook get_page_link, wordpress pass me only post id, not full object
1153:          */
1154:         $post_title = $post->post_title; //( ! isset( $post->post_name ) ) ?
1155:           //$post->post_title : $post->post_name;
1156:           // $a = $wpdb->get_var( "SELECT post_title FROM $wpdb->posts WHERE id = $post->ID" );
1157: 
1158:         /*
1159:          * got how many number occourrences ( -d ) are in the "real title"
1160:          */
1161:         preg_match_all( "/\d+/", $post_title, $pout );
1162: 
1163:         /*
1164:          * compare occourrences between permalink and title,
1165:          * if title contains more one, I remove it :)
1166:          */
1167:         //Remove autoinserted -## from url
1168:         if( count( $pout[0] ) < count( $out[ 0 ] ) ) {
1169:           $permalink = trailingslashit( preg_replace( "/-\d*$/", "",
1170:                                                      untrailingslashit( $permalink ) ) );
1171: 
1172:           $removed = true;
1173:         }
1174:       }
1175: 
1176:       if( $removed &&
1177:           CMLUtils::get_url_mode() == PRE_NONE ) {
1178:         $post_id = is_object( $post ) ? $post->ID : $post;
1179: 
1180:         $lang = CMLLanguage::get_by_post_id( $post_id );
1181:         if( empty( $lang ) ) {
1182:           $lang = CMLLanguage::get_current();
1183:         }
1184: 
1185:         $permalink = add_query_arg( array(
1186:                                           "lang" => $lang->cml_language_slug,
1187:                                           ), $permalink );
1188:       }
1189:     }
1190: 
1191:     return $permalink;
1192:   }
1193: }
1194: 
1195: /**
1196:  * utility class
1197:  *
1198:  */
1199: class CMLUtils {
1200:   /** @ignore */
1201:   private static $_permalink_structure;
1202:   /** @ignore */
1203:   private static $_url_mode;
1204:   /** @ignore */
1205:   private static $_date_format;
1206:   /** @ignore */
1207:   private static $_home_url;
1208:   /** @ignore */
1209:   private static $_clean_url;
1210:   /** @ignore */
1211:   private static $_clean_request;
1212:   /** @ignore */
1213:   private static $_request_url;
1214:   /** @ignore */
1215:   private static $_clean_applied = false;
1216:   /** @ignore */
1217:   private static $_url;
1218:   /** @ignore */
1219:   private static $_language_detected = null;
1220:   /** @ignore */
1221:   private static $_vars = array();
1222: 
1223:   /**
1224:    * @ignore
1225:    * 
1226:    * return wordpress permalink structure option
1227:    *
1228:    * @return string
1229:    */
1230:   public static function get_permalink_structure() {
1231:     if( ! isset( self::$_permalink_structure ) ) self::$_permalink_structure = get_option( "permalink_structure" );
1232:     
1233:     return self::$_permalink_structure;
1234:   }
1235:   
1236:   /**
1237:    * return home_url link in according to language slug.
1238:    *
1239:    * This function format home_url in according to $slug parameter
1240:    *
1241:    * @param string $slug - language slug. If null current slug will be used
1242:    *
1243:    * @return string
1244:    */
1245:   public static function get_home_url( $slug = null ) {
1246:     $_cml_settings = & $GLOBALS[ '_cml_settings' ];
1247: 
1248:     if( null === $slug ) $slug = CMLLanguage::get_default()->cml_language_slug;
1249: 
1250:     switch( CMLUtils::get_url_mode() ) {
1251:     case PRE_PATH:
1252:       if( $slug == CMLLanguage::get_default()->cml_language_slug &&
1253:           $_cml_settings[ 'url_mode_remove_default' ] ) {
1254:         $slug = "";
1255:       } else
1256:         $slug = "/$slug";
1257: 
1258:       $link = CMLUtils::home_url() . $slug;
1259:       break;
1260:     case PRE_DOMAIN:
1261:       $link = CMLUtils::home_url();
1262:       break;
1263:     default:
1264:       $link = CMLUtils::home_url() . "?lang=$slug";
1265:       break;
1266:     } //endswitch;
1267: 
1268:     return $link;
1269:   }
1270: 
1271:   /**
1272:    * @ignore
1273:    */
1274:   public static function get_url_mode() {
1275:     if( empty( self::$_url_mode ) )  {
1276:       global $_cml_settings;
1277:     
1278:       self::$_url_mode = $_cml_settings[ 'url_mode' ];  //more easy
1279:       
1280:       $permalink = self::get_permalink_structure();
1281:       if( empty( $permalink ) && self::$_url_mode == PRE_PATH )
1282:         self::$_url_mode = PRE_LANG;
1283:     }
1284: 
1285:     return self::$_url_mode;
1286:   }
1287:   
1288:   /**
1289:    * get wordpress date format option
1290:    * @ignore
1291:    */
1292:   public static function get_date_format() {
1293:     if( empty( self::$_date_format ) ) self::$_date_format = get_option( 'date_format' );
1294:     
1295:     return self::$_date_format;
1296:   }
1297:   
1298:   /**
1299:    * get "clean" home_url.
1300:    *
1301:    * The plugin translate home url in according to current language.
1302:    * So if you call the wp function "home_url" it will home url with language information,
1303:    * in according to url modification mode.
1304:    *
1305:    * This function will return "real" home without any language information.
1306:    *
1307:    * @example
1308:    *
1309:    * home_url()<br />
1310:    *  www.example.com/it<br />
1311:    * <br />
1312:    * CMLUtils::home_url()<br />
1313:    *  www.example.com<br />
1314:    * 
1315:    * @return string
1316:    */
1317:   public static function home_url() {
1318:     if( empty( self::$_home_url ) ) {
1319:       $GLOBALS[ '_cml_no_translate_home_url' ] = true;
1320:       self::$_home_url = home_url();
1321: 
1322:       unset( $GLOBALS[ '_cml_no_translate_home_url' ] );
1323:     }
1324: 
1325:     return self::$_home_url;
1326:   }
1327:   
1328:   /**
1329:    * remove language information from url
1330:    * 
1331:    * @ignore
1332:    */
1333:   public static function clear_url( $url = null ) {
1334:     global $wp_rewrite;
1335: 
1336:     if( self::get_url_mode() != PRE_PATH 
1337:         || ( self::$_clean_applied == true &&
1338:         null === $url ) ) {
1339:       return self::$_language_detected;
1340:     }
1341: 
1342:     if( empty( self::$_url ) ) {
1343:       self::$_url = "http://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
1344:       self::$_request_url = str_replace( trailingslashit( self::home_url() ),
1345:                                         "", self::$_url );
1346:     }
1347: 
1348:     if( null === $url ) {
1349:       $_url = self::$_url;
1350:       $request_url = self::$_request_url;
1351:       
1352:       /*
1353:        * remove all parameters in url
1354:        */
1355:       self::$_clean_url = preg_replace( "/\?.*/", "", $_url );
1356:       self::$_clean_request = $request_url;
1357:     } else {
1358:       $_url = $url;
1359:       $request_url = str_replace( trailingslashit( self::home_url() ),
1360:                                         "", $url );
1361:     }
1362: 
1363:     $_url = $request_url;
1364:     $base_url = str_replace( "http://" . $_SERVER['HTTP_HOST'], "", get_option( 'home' ) );
1365: 
1366:     if( preg_match( "#^([a-z]{2})(/.*)?$#i", $_url, $match ) ) {
1367:       $lang = CMLLanguage::get_id_by_slug( $match[1] );
1368:       if( empty( $lang ) ) {
1369:         return $url;
1370:       }
1371: 
1372:       $_url = substr( $_url, 3 );
1373:       $_url = preg_replace( "/\?.*/", "", $_url );
1374: 
1375:       if( null === $url ) {
1376:         self::$_language_detected = $lang;
1377: 
1378:         CMLLanguage::set_current( self::$_language_detected );
1379: 
1380:         self::$_clean_url = trailingslashit( self::$_home_url ) . $_url;
1381:         self::$_clean_request = trailingslashit( $base_url ) . $_url;
1382:       } else {
1383:         $_url = trailingslashit( CMLUtils::home_url() ) . $_url;
1384:       }
1385:     }
1386:     
1387:     if( null === $url ) {
1388:       self::$_clean_applied = true;
1389:     }
1390: 
1391:     return ( null === $url ) ? self::$_language_detected : $_url;
1392:   }
1393: 
1394:   /**
1395:    * return current url withouth any language information.
1396:    *
1397:    * @example
1398:    * 
1399:    *  www.example.com/en/example<br />
1400:    *<br />
1401:    *  CMLUtils::get_clean_url() will return:<br />
1402:    *<br />
1403:    *    www.example.com/example
1404:    *
1405:    * @return string
1406:    */
1407:   public static function get_clean_url() {
1408:     return self::$_clean_url;
1409:   }
1410:   
1411:   /**
1412:    * get $_SERVER[ 'REQUEST_URI' ] with no language information.
1413:    *
1414:    * @return string
1415:    */
1416:   public static function get_clean_request() {
1417:     return self::$_clean_request;
1418:   }
1419:   
1420:   /**
1421:    * @ignore
1422:    */
1423:   public static function _set( $key, $value ) {
1424:     self::$_vars[ $key ] = $value;
1425:   }
1426:   
1427:   /**
1428:    * @ignore
1429:    */
1430:   public static function _get( $key ) {
1431:     return isset( self::$_vars[ $key ] ) ? self::$_vars[ $key ] : null;
1432:   }
1433:   
1434:   /**
1435:    *@ignore
1436:    */
1437:   public static function _del( $key ) {
1438:     unset( self::$_vars[ $key ] );
1439:   }
1440: 
1441:   /**
1442:    * @ignore
1443:    */
1444:   public static function _append( $key, $value ) {
1445:     if( ! isset( self::$_vars[ $key ] ) ) {
1446:       self::$_vars[ $key ] = array();
1447:     }
1448:     
1449:     self::$_vars[ $key ][] = $value;
1450:   }
1451: }
1452: ?>
API documentation generated by ApiGen 2.8.0