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( "_" == $type[ 0 ] && ! $return_empty ) {
 598:       $return_empty = true;
 599:     }
 600: 
 601:     $string = trim( $string );
 602: 
 603:     //C = Category
 604:     $s = ( $type == "C" ) ? strtolower( $string ) : $string;
 605: 
 606:     //Look if I already translated it...
 607:     if( isset( self::$_keys[ $lang ] ) && 
 608:       in_array( sanitize_title( $s ), self::$_keys[ $lang ] ) ) {
 609: 
 610:       $index = array_search( sanitize_title( $s ), self::$_keys[ $lang ] );
 611:       return self::$_translations[ $lang ][ $index ];
 612:     }
 613: 
 614:     if( CML_GET_TRANSLATIONS_FROM_PO &&
 615:        ! $ignore_po &&
 616:        1 == CMLUtils::_get( '_po_loaded' ) ) {
 617: 
 618:       $translations = get_translations_for_domain( 'cmltrans' );
 619:       if( isset( $translations->entries[ $string ] ) ) {
 620:         return __( $s, 'cmltrans' );
 621:       } else {
 622:         if( $return_empty ) return "";
 623:       }
 624:     }
 625: 
 626:     if( ! is_numeric( $lang ) ) {
 627:       $lang = CMLLanguage::get_id_by_slug( $lang );
 628:     }
 629: 
 630:     $query = sprintf(" SELECT UNHEX(cml_translation) FROM %s WHERE cml_text = '%s' AND cml_lang_id = %d AND cml_type LIKE '%s'",
 631:                                     CECEPPA_ML_TRANSLATIONS, bin2hex( $s ), $lang, "%" . $type . "%" );
 632: 
 633:     $return = $wpdb->get_var( $query );
 634: 
 635:     if( $return_empty && empty( $return ) ) return "";
 636: 
 637:     $return = ( empty( $return ) ) ?  $string : html_entity_decode( stripslashes( $return ) );
 638:     
 639:     self::$_translations[$lang][] = $return;
 640:     self::$_keys[ $lang ][] = sanitize_title( $string );
 641: 
 642:     return $return;
 643:   }
 644:   
 645:   /*
 646:    * get translation from wordpress
 647:    *
 648:    * @ignore
 649:    */
 650:   public static function gettext( $lang, $string, $type, $ignore_po = false ) {
 651:     $ret = self::get( $lang, $string, $type, true, $ignore_po );
 652: 
 653:     if( ! empty( $ret ) ) return $ret;
 654: 
 655:     //Recupero la traduzione dalle frasi di wordpress ;)
 656:     require_once( CML_PLUGIN_PATH . "gettext/gettext.inc" );
 657:     
 658:     $locale = CMLLanguage::get_current()->cml_locale;
 659: 
 660:     // gettext setup
 661:     T_setlocale( LC_MESSAGES, $locale );
 662:     // Set the text domain as 'messages'
 663: 
 664:     $domain = $locale;
 665:     T_bindtextdomain( $domain, CML_WP_LOCALE_DIR );
 666:     T_bind_textdomain_codeset( $domain, 'UTF-8' );
 667:     T_textdomain( $domain );
 668: 
 669:     $ret = T_gettext( $string );
 670: 
 671:     return ( empty( $ret ) ) ?  $string : html_entity_decode( stripslashes( $ret ) );
 672:   }
 673:   
 674:   /**
 675:    * delete all records with cml_type = xx
 676:    *
 677:    * @ignore
 678:    */
 679:   public static function delete( $type ) {
 680:     global $wpdb;
 681:     
 682:     $wpdb->delete( CECEPPA_ML_TRANSLATIONS,
 683:                   array( "cml_type" => $type ),
 684:                   array( "%s" ) );
 685:   }
 686: }
 687: 
 688: /**
 689:  * This class is used to get/set post translation/language or get language by its id
 690:  * 
 691:  */
 692: class CMLPost {
 693:   /** @ignore */
 694:   private static $_indexes = null;
 695:   /** @ignore */
 696:   private static $_uniques = null;
 697:   /** @ignore */
 698:   private static $_posts_meta = array();
 699: 
 700:   /**
 701:    * return language object by post id
 702:    *
 703:    * this function return "null" if post doesn't exists in any language
 704:    * 
 705:    * @param int/string $post_id - id of post/page
 706:    *
 707:    * @return stdObject
 708:    */
 709:   public static function get_language_by_id( $post_id ) {
 710:     if( empty( self::$_indexes ) ) self::_load_indexes();
 711: 
 712:     /*
 713:      * search in current language first.
 714:      * because if post exists in multiple languages, included current one,
 715:      * I have to return current language id, not random :)
 716:      */
 717:     if( @in_array( $post_id, self::$_indexes[ CMLLanguage::get_current_id() ] ) ) {
 718:       return CMLLanguage::get_current();
 719:     }
 720: 
 721:     foreach( CMLLanguage::get_others() as $lang ) {
 722:       if( @in_array( $post_id, self::$_indexes[ $lang->id ] ) )
 723:         return $lang;
 724:     }
 725: 
 726:     return null;
 727:   }
 728:   
 729:   /**
 730:    * return language id by post id
 731:    *
 732:    * @param int $post_id - id of post/page
 733:    * @param boolean $unique check if $post_id exists in all languages, if true return
 734:    *                        0, otherwise return 
 735:    *                        In backend I need to get information by post meta, or I'll lost
 736:    *                        "all languages" ( = 0 ) information.
 737:    *
 738:    * @return int
 739:    */
 740:   public static function get_language_id_by_id( $post_id, $unique = false ) {
 741:     if( $unique ) {
 742:       if( self::is_unique( $post_id ) ) {
 743:         return 0;
 744:       }
 745:     }
 746: 
 747:     $lang = self::get_language_by_id( $post_id );
 748: 
 749:     if( null === $lang ) {
 750:       //Get from meta
 751:       $m = get_post_meta( $post_id, "_cml_meta", true );
 752: 
 753:       if( $unique && empty( $m ) ) {
 754:         $lang = self::get_language_by_id( $post_id );
 755:   
 756:         if( is_object( $lang ) ) {
 757:           //update meta
 758:           self::update_meta( $lang->id, $post_id );
 759:         }
 760:   
 761:         return is_object( $lang ) ? $lang->id : 0;
 762:       } else {
 763:         return @$meta[ "lang" ];
 764:       }
 765:     }
 766: 
 767:     return $lang->id;
 768:   }
 769:   
 770:   /**
 771:    * get language slug by post id
 772:    *
 773:    * @param int $post_id post/page id
 774:    *
 775:    * @return string
 776:    */
 777:   public static function get_language_slug_by_id( $post_id ) {
 778:     $lang = self::get_language_by_id( $post_id );
 779:     
 780:     return is_object( $lang ) ? $lang->cml_language_slug : "";
 781:   }
 782: 
 783:   /**
 784:    * get the translation id, if exists, in selected language
 785:    *
 786:    * this function will return 0 if no translation is found.
 787:    * 
 788:    * @param int/string $lang - language id/slug in which return translation
 789:    * @param int $post_id - post id
 790:    *
 791:    * @return int
 792:    */
 793:   public static function get_translation( $lang, $post_id ) {
 794:     global $wpdb;
 795: 
 796:     if( is_numeric( $lang ) ) $lang = CMLLanguage::get_slug( $lang );
 797:     if( empty( $post_id ) ) return 0;
 798: 
 799:     //if( ! CECEPPA_ML_MIGRATED ) {
 800:     //  return cml_old_get_linked_post( $wpCeceppaML->get_language_id_by_post_id( $post_id ), null, $post_id, $lang );
 801:     //}
 802:   
 803:     $linked = self::get_translations( $post_id );
 804: 
 805:     return ( ! array_key_exists( $lang, $linked) ) ? 0 : $linked[ $lang ];
 806:   }
 807: 
 808:   /**
 809:    * get all available translations of post
 810:    *
 811:    * This function will return Array containing all info about linked posts
 812:    *
 813:    * Array(
 814:    * <ul>
 815:    *   <li>[language slug] => [post_id]</li>
 816:    *   <li>...</li>
 817:    *   <li>[indexes] => Array<br />
 818:    *    <i>In this subarray there are all linked posts, including $post_id</i>
 819:    *    <ul>
 820:    *      <li>[language slug] => [post_id]</li>
 821:    *      <li>...</li>
 822:    *    </ul>
 823:    *   </li>
 824:    *   <li>
 825:    *    [linked] => Array<br />
 826:    *    <i>In this subarray there are only linked post indexes</i> 
 827:    *    <ul>
 828:    *      <li>[linked language slug] => [linked_id]</li>
 829:    *      <li>...</li>
 830:    *    </ul>
 831:    *  </li>
 832:    * </ul>
 833:    * )
 834:    * 
 835:    * @example
 836:    * <br />
 837:    * Array (
 838:    * <ul>
 839:    *   <li>[it] => 2552</li>
 840:    *   <li>[en] => 541</li>
 841:    *   <li>[eo] => 0</li>
 842:    *   <li>[indexes] => Array
 843:    *       (
 844:    *       <ul>
 845:    *        <li>[it] => 2552</li>
 846:    *       </ul>
 847:    *       )
 848:    *    </li>
 849:    *    <li>
 850:    *   [linked] => Array
 851:    *       (
 852:    *       <ul>
 853:    *        <li>[en] => 541</li>
 854:    *       )
 855:    *    </li>
 856:    *  </ul>
 857:    * )
 858:    *
 859:    * @param int $post_id - post id
 860:    * @param boolean $force - force to rebuild meta. ( This parameter is used internally by CML )
 861:    *
 862:    * return Array
 863:    */
 864:   public static function get_translations( $post_id, $force = false ) {
 865:     global $wpdb;
 866:   
 867:     if( empty( $post_id ) ) return array();
 868: 
 869:     if( ! isset( self::$_posts_meta[ $post_id ] ) || $force ) {
 870:       $row = ""; //get_post_meta( $post_id, "_cml_meta", true );
 871: 
 872:       if( empty( $row ) || empty( $row[ 'lang' ] ) || $force ) {
 873:         if( empty( $GLOBALS[ '_cml_language_columns' ] ) ) {
 874:           require_once ( CML_PLUGIN_ADMIN_PATH . 'admin-settings-gen.php' );
 875: 
 876:           cml_generate_lang_columns();
 877:         }
 878:       
 879:         $_cml_language_columns = & $GLOBALS[ '_cml_language_columns' ];
 880:         $_conv = & $GLOBALS[ '_cml_language_keys' ];
 881: 
 882:         $query = "SELECT ";
 883:         foreach( $_conv as $key => $label ) {
 884:           $select[] = "$key as $label";
 885:         }
 886: 
 887:         /*
 888:          * something happend that $_conv is empty and that couse a warning
 889:          * and I can't store post relations properly.
 890:          */
 891:         if( empty( $select ) ) {
 892:           $keys = array_keys( CMLLanguage::get_all() );
 893:           $langs = array_keys( CMLLanguage::get_slugs() );
 894: 
 895:           foreach( $keys as $k => $v ) {
 896:             $select[] = "lang_{$v} as " . $langs[ $k ];
 897:           }
 898:         }
 899: 
 900:         $query .= join( ",", $select ) . " FROM " . CECEPPA_ML_RELATIONS . " WHERE ";
 901:         foreach( $_cml_language_columns as $l ) {
 902:           $where[] = "$l = $post_id";
 903:         }
 904:         $query .= join( " OR ", $where );
 905:       
 906:         $row = $wpdb->get_row( $query, ARRAY_A );
 907:         unset( $row[ "id" ] );
 908: 
 909:         $keys = @array_filter( $row );
 910:         $keys = @array_replace( $keys, $_conv );
 911:         $others = @array_filter( is_array( $row ) ? $row : array() );
 912:         unset( $others[ CMLPost::get_language_slug_by_id( $post_id ) ] );
 913:       
 914:         $row = @array_merge( (array) $row, array( "indexes" => array_filter( $row ),
 915:                                                  "linked" => $others ) );
 916: 
 917:         if( ! $force && isset( $row[ 'lang' ] ) ) {
 918:           self::update_meta( self::get_language_id_by_id( $post_id ), $post_id, $row );
 919:         } else {
 920:         }
 921:       } else {
 922:         $row = $row[ 'translations' ];
 923:       }
 924: 
 925:       self::$_posts_meta[ $post_id ] = $row;
 926:     } else {
 927:       $row = self::$_posts_meta[ $post_id ];
 928:     }
 929: 
 930:     return $row;
 931:   }
 932:   
 933:   /**
 934:    * check if $post_id exists in all languages
 935:    *
 936:    * @param int $post_id post id to search
 937:    *
 938:    * return boolean
 939:    */
 940:   public static function is_unique( $post_id ) {
 941:     if( null === self::$_uniques ) self::_load_indexes();
 942: 
 943:     return in_array( $post_id, self::$_uniques );
 944:   }
 945: 
 946:   /**
 947:    * set language of post
 948:    *
 949:    * This function will unlink $post_id by its translations
 950:    * 
 951:    * @param int/string $lang - post language id/slug 
 952:    * @param int $post_id - post id
 953:    */
 954:   public static function set_language( $lang, $post_id ) {
 955:     if( ! is_numeric( $lang ) ) $lang = CMLLanguage::get_id_by_slug( $lang );
 956: 
 957:     cml_migrate_database_add_item( $lang, $post_id, 0, 0 );
 958:   }
 959: 
 960:   /**
 961:    * set single translation to post id
 962:    *
 963:    * This function is used to link 2 posts
 964:    *
 965:    * When you link a post to single translation, relations with other language will not be losed.
 966:    * If you want remove other relations, you have to use set_language method first.
 967:    * 
 968:    * @param int $post_id - post to set translation
 969:    * @param int/string $linked_lang - language id/slug of linked post
 970:    * @param int $linked_post - post id of translation
 971:    * @param int $post_lang ( optional ) - language of $post_id. If null, It will get from database
 972:    *
 973:    * @return void
 974:    */
 975:   public static function set_translation( $post_id, $linked_lang, $linked_post, $post_lang = null ) {
 976:     self::set_translations( $post_id, array( $linked_lang => $linked_post ), $post_lang );
 977:   }
 978: 
 979:   /**
 980:    * add multiple translations to post id
 981:    *
 982:    * This function will update relations only from $post_id with $translations posts, so relations
 983:    * from $post_id and languages than doesn't exists in $translations array will not be broken.
 984:    * 
 985:    * If you need to set relation only from $post_id and $translations, and remove the other one, you
 986:    * have to "break" them using set_language method first.
 987:    * 
 988:    * @param $post_id - post to set translation+
 989:    * @param $translations - array with language_slug as key and post_id as value.
 990:    *                        array( "it" => 1, "en" => 2 )...
 991:    * @param $post_lang ( optional ) - set also the language of $post_id
 992:    *
 993:    * @example:
 994:    *
 995:    *    CMLPost::set_translation( 1, array( "it" => 2, "en" => 3 ) )
 996:    */
 997:   public static function set_translations( $post_id, $translations, $post_lang = null ) {
 998:     //$_cml_language_columns = & $GLOBALS[ '_cml_language_columns' ];
 999:     if( null === $post_lang ) $post_lang = CMLPost::get_language_id_by_id( $post_id );
1000: 
1001:     $tot = count( $translations );
1002:     if( $tot < count( CMLLanguage::get_no_default() ) ) {
1003: 
1004:     }
1005: 
1006:     $old = CMLPost::get_translations( $post_id, true );
1007: 
1008:     foreach( $translations as $key => $id ) {
1009:       if( ! is_numeric( $key ) ) $key = CMLLanguage::get_id_by_slug( $key );
1010: 
1011:       cml_migrate_database_add_item( $post_lang, $post_id, $key, $id );
1012:     }
1013: 
1014:     // //Update info
1015:     cml_fix_rebuild_posts_info();
1016:     self::_load_indexes();
1017:   }
1018:   
1019:   /*
1020:    * update post meta
1021:    * @ignore
1022:    */
1023:   public static function update_meta( $lang, $post_id, $translations = null ) {
1024:     /*
1025:      * I just updated post relation, so I have to rebuild meta :)
1026:      */
1027:     //Add my meta to post
1028:     if( null == $translations ) {
1029:       $translations = CMLPost::get_translations( $post_id, true );
1030:     }
1031: 
1032:     if( ! is_numeric( $lang ) ) $lang = CMLLanguage::get_id_by_slug( $lang );
1033: 
1034:     $meta = array( "lang" => $lang,
1035:                     "translations" => $translations );
1036: 
1037:     update_post_meta( $post_id, "_cml_meta", $meta );
1038:   }
1039: 
1040:   /**
1041:    * get indexes of posts that exists in selected language
1042:    *
1043:    * @param int/slug $lang ( optional, if not set will be = current language id )
1044:    *                      id / slug of language
1045:    *
1046:    * @return array
1047:    */
1048:   public static function get_posts_by_language( $lang = null ) {
1049:     if( empty( $lang ) ) $lang = CMLLanguage::get_current_id();
1050:     if( ! is_numeric( $lang ) ) $lang = CMLLanguage::get_id_by_slug( $lang );
1051:   
1052:     //Gli articoli senza lingua sono "figli di tutti"
1053:     if( empty( self::$_indexes ) ) self::_load_indexes();
1054: 
1055:     $posts = @self::$_indexes[ $lang ];
1056: 
1057:     return ! empty( $posts ) ? array_unique( $posts ) : array();
1058:   }
1059: 
1060:   /*
1061:    * for private use only, update post indexes by language
1062:    * @ignore
1063:    */
1064:   public static function _update_posts_by_language( $lang, $ids ) {
1065:     self::$_indexes[ $lang ] = $ids;
1066:   }
1067: 
1068:   /**
1069:    * return all posts by languages.
1070:    *
1071:    * The key of array is the language id
1072:    *
1073:    * @return array
1074:    */
1075:   public static function get_posts_by_languages() {
1076:     //Gli articoli senza lingua sono "figli di tutti"
1077:     if( empty( self::$_indexes ) ) self::_load_indexes();
1078: 
1079:     return self::$_indexes;
1080:   }
1081: 
1082:   /**
1083:    * check if $post_id has translation in selected language.
1084:    *
1085:    * @param int/string $lang - language id/slug
1086:    * @param int $post_id - post id
1087:    * 
1088:    * return boolean
1089:    */
1090:   public static function has_translation( $lang, $post_id ) {
1091:     if( ! isset( self::$_posts_meta[ $post_id ] ) ) {
1092:       self::$_posts_meta[ $post_id ] = self::get_translations( $post_id );
1093:     }
1094: 
1095:     if( is_numeric( $lang ) ) $lang = CMLLanguage::get_slug( $lang );
1096: 
1097:     return ( isset( self::$_posts_meta[ $post_id ]['indexes'] ) &&
1098:             self::$_posts_meta[ $post_id ]['indexes'][ $lang ] > 0 );
1099:   }
1100: 
1101:   /**
1102:    * check if $post_id has any translation
1103:    *
1104:    * @param int $post_id - post id
1105:    *
1106:    * @return boolean
1107:    */
1108:   public static function has_translations( $post_id ) {
1109:     if( ! isset( self::$_posts_meta[ $post_id ] ) ) {
1110:       self::$_posts_meta[ $post_id ] = self::get_translations( $post_id );
1111:     }
1112: 
1113:     return ! empty( self::$_posts_meta[ $post_id ][ 'linked' ] );
1114:   }
1115: 
1116:   /**
1117:    * check if $post1 is translation of $post2
1118:    *
1119:    * @param int $post1 post id
1120:    * @param int $post2 post id
1121:    *
1122:    * @return boolean
1123:    */
1124:   public static function is_translation( $post1, $post2 ) {
1125:     $translations = CMLPost::get_translations( $post1 );
1126: 
1127:     return in_array( $post2, $translations[ 'indexes' ] );
1128:   }
1129: 
1130:   /** @ignore */
1131:   private static function _load_indexes() {
1132:     $langs = cml_get_languages( false );
1133: 
1134:     foreach($langs as $lang) {
1135:       self::$_indexes[ $lang->id ] = get_option( "cml_posts_of_lang_" . $lang->id );
1136:     }
1137: 
1138:     self::$_uniques = get_option( 'cml_unique_posts', array() );
1139:   }
1140: 
1141:   /**
1142:    * @ignore
1143:    *
1144:    * Remove extra "-##" add by wordpress when more than one post has
1145:    * same titles, but ONLY on translations.
1146:    */
1147:   public static function remove_extra_number( $permalink, $post ) {
1148:     global $wpdb;
1149: 
1150:     $removed = false;
1151: 
1152:     if( is_object( $post ) ) {
1153:       //Remove last "/"
1154:       $url = untrailingslashit( $permalink );
1155:       $url = str_replace( CMLUtils::home_url(), "", $url );
1156:   
1157:       /*
1158:        * Post/page link contains "-d"
1159:        */
1160:       preg_match_all( "/-\d+/", $url, $out );
1161:   
1162:       /*
1163:        * if true I have to check if it was added by "wordpress" :)
1164:        */
1165:       if( count( $out[ 0 ] ) > 0 ) {
1166:         /*
1167:          * when hook get_page_link, wordpress pass me only post id, not full object
1168:          */
1169:         $post_title = $post->post_title; //( ! isset( $post->post_name ) ) ?
1170:           //$post->post_title : $post->post_name;
1171:           // $a = $wpdb->get_var( "SELECT post_title FROM $wpdb->posts WHERE id = $post->ID" );
1172: 
1173:         /*
1174:          * got how many number occourrences ( -d ) are in the "real title"
1175:          */
1176:         preg_match_all( "/\d+/", $post_title, $pout );
1177: 
1178:         /*
1179:          * compare occourrences between permalink and title,
1180:          * if title contains more one, I remove it :)
1181:          */
1182:         //Remove autoinserted -## from url
1183:         if( count( $pout[0] ) < count( $out[ 0 ] ) && CMLPost::has_translations( $post->ID ) ) {
1184:           $permalink = trailingslashit( preg_replace( "/-\d*$/", "",
1185:                                                      untrailingslashit( $permalink ) ) );
1186: 
1187:           $removed = true;
1188:         }
1189:       }
1190: 
1191:       if( $removed &&
1192:           CMLUtils::get_url_mode() == PRE_NONE ) {
1193:         $post_id = is_object( $post ) ? $post->ID : $post;
1194: 
1195:         $lang = CMLLanguage::get_by_post_id( $post_id );
1196:         if( empty( $lang ) ) {
1197:           $lang = CMLLanguage::get_current();
1198:         }
1199: 
1200:         $permalink = add_query_arg( array(
1201:                                           "lang" => $lang->cml_language_slug,
1202:                                           ), $permalink );
1203:       }
1204:     }
1205: 
1206:     return $permalink;
1207:   }
1208: }
1209: 
1210: /**
1211:  * utility class
1212:  *
1213:  */
1214: class CMLUtils {
1215:   /** @ignore */
1216:   private static $_permalink_structure;
1217:   /** @ignore */
1218:   private static $_url_mode;
1219:   /** @ignore */
1220:   private static $_date_format;
1221:   /** @ignore */
1222:   private static $_home_url;
1223:   /** @ignore */
1224:   private static $_clean_url;
1225:   /** @ignore */
1226:   private static $_clean_request;
1227:   /** @ignore */
1228:   private static $_request_url;
1229:   /** @ignore */
1230:   private static $_clean_applied = false;
1231:   /** @ignore */
1232:   private static $_url;
1233:   /** @ignore */
1234:   private static $_language_detected = null;
1235:   /** @ignore */
1236:   private static $_vars = array();
1237: 
1238:   /**
1239:    * @ignore
1240:    * 
1241:    * return wordpress permalink structure option
1242:    *
1243:    * @return string
1244:    */
1245:   public static function get_permalink_structure() {
1246:     if( ! isset( self::$_permalink_structure ) ) self::$_permalink_structure = get_option( "permalink_structure" );
1247:     
1248:     return self::$_permalink_structure;
1249:   }
1250:   
1251:   /**
1252:    * return home_url link in according to language slug.
1253:    *
1254:    * This function format home_url in according to $slug parameter
1255:    *
1256:    * @param string $slug - language slug. If null current slug will be used
1257:    *
1258:    * @return string
1259:    */
1260:   public static function get_home_url( $slug = null ) {
1261:     $_cml_settings = & $GLOBALS[ '_cml_settings' ];
1262: 
1263:     if( null === $slug ) $slug = CMLLanguage::get_default()->cml_language_slug;
1264: 
1265:     switch( CMLUtils::get_url_mode() ) {
1266:     case PRE_PATH:
1267:       if( $slug == CMLLanguage::get_default()->cml_language_slug &&
1268:           $_cml_settings[ 'url_mode_remove_default' ] ) {
1269:         $slug = "";
1270:       } else
1271:         $slug = "/$slug";
1272: 
1273:       $link = CMLUtils::home_url() . $slug;
1274:       break;
1275:     case PRE_DOMAIN:
1276:       $link = CMLUtils::home_url();
1277:       break;
1278:     default:
1279:       $link = CMLUtils::home_url() . "?lang=$slug";
1280:       break;
1281:     } //endswitch;
1282: 
1283:     return $link;
1284:   }
1285: 
1286:   /**
1287:    * @ignore
1288:    */
1289:   public static function get_url_mode() {
1290:     if( empty( self::$_url_mode ) )  {
1291:       global $_cml_settings;
1292:     
1293:       self::$_url_mode = $_cml_settings[ 'url_mode' ];  //more easy
1294:       
1295:       $permalink = self::get_permalink_structure();
1296:       if( empty( $permalink ) && self::$_url_mode == PRE_PATH )
1297:         self::$_url_mode = PRE_LANG;
1298:     }
1299: 
1300:     return self::$_url_mode;
1301:   }
1302:   
1303:   public static function get_category_url_mode() {
1304:     return CMLUtils::_get( 'cml_category_mode' );
1305:   }
1306: 
1307:   /**
1308:    * get wordpress date format option
1309:    * @ignore
1310:    */
1311:   public static function get_date_format() {
1312:     if( empty( self::$_date_format ) ) self::$_date_format = get_option( 'date_format' );
1313:     
1314:     return self::$_date_format;
1315:   }
1316:   
1317:   /**
1318:    * get "clean" home_url.
1319:    *
1320:    * The plugin translate home url in according to current language.
1321:    * So if you call the wp function "home_url" it will home url with language information,
1322:    * in according to url modification mode.
1323:    *
1324:    * This function will return "real" home without any language information.
1325:    *
1326:    * @example
1327:    *
1328:    * home_url()<br />
1329:    *  www.example.com/it<br />
1330:    * <br />
1331:    * CMLUtils::home_url()<br />
1332:    *  www.example.com<br />
1333:    * 
1334:    * @return string
1335:    */
1336:   public static function home_url() {
1337:     if( empty( self::$_home_url ) ) {
1338:       $GLOBALS[ '_cml_no_translate_home_url' ] = true;
1339:       self::$_home_url = home_url();
1340: 
1341:       unset( $GLOBALS[ '_cml_no_translate_home_url' ] );
1342:     }
1343: 
1344:     return self::$_home_url;
1345:   }
1346:   
1347:   /**
1348:    * remove language information from url
1349:    * 
1350:    * @ignore
1351:    */
1352:   public static function clear_url( $url = null ) {
1353:     global $wp_rewrite;
1354: 
1355:     if( self::get_url_mode() != PRE_PATH 
1356:         || ( self::$_clean_applied == true &&
1357:         null === $url ) ) {
1358:       return self::$_language_detected;
1359:     }
1360: 
1361:     if( empty( self::$_url ) ) {
1362:       self::$_url = "http://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
1363:       self::$_request_url = str_replace( trailingslashit( self::home_url() ),
1364:                                         "", self::$_url );
1365:     }
1366: 
1367:     if( null === $url ) {
1368:       $_url = self::$_url;
1369:       $request_url = self::$_request_url;
1370:       
1371:       /*
1372:        * remove all parameters in url
1373:        */
1374:       self::$_clean_url = preg_replace( "/\?.*/", "", $_url );
1375:       self::$_clean_request = $request_url;
1376:     } else {
1377:       $_url = $url;
1378:       $request_url = str_replace( trailingslashit( self::home_url() ),
1379:                                         "", $url );
1380:     }
1381: 
1382:     $_url = $request_url;
1383:     $base_url = str_replace( "http://" . $_SERVER['HTTP_HOST'], "", get_option( 'home' ) );
1384: 
1385:     if( preg_match( "#^([a-z]{2})(/.*)?$#i", $_url, $match ) ) {
1386:       $lang = CMLLanguage::get_id_by_slug( $match[1] );
1387:       if( empty( $lang ) ) {
1388:         return $url;
1389:       }
1390: 
1391:       $_url = substr( $_url, 3 );
1392:       $_url = preg_replace( "/\?.*/", "", $_url );
1393: 
1394:       if( null === $url ) {
1395:         self::$_language_detected = $lang;
1396: 
1397:         CMLLanguage::set_current( self::$_language_detected );
1398: 
1399:         self::$_clean_url = trailingslashit( self::$_home_url ) . $_url;
1400:         self::$_clean_request = trailingslashit( $base_url ) . $_url;
1401:       } else {
1402:         $_url = trailingslashit( CMLUtils::home_url() ) . $_url;
1403:       }
1404:     }
1405:     
1406:     if( null === $url ) {
1407:       self::$_clean_applied = true;
1408:     }
1409: 
1410:     return ( null === $url ) ? self::$_language_detected : $_url;
1411:   }
1412: 
1413:   /**
1414:    * return current url withouth any language information.
1415:    *
1416:    * @example
1417:    * 
1418:    *  www.example.com/en/example<br />
1419:    *<br />
1420:    *  CMLUtils::get_clean_url() will return:<br />
1421:    *<br />
1422:    *    www.example.com/example
1423:    *
1424:    * @return string
1425:    */
1426:   public static function get_clean_url() {
1427:     return self::$_clean_url;
1428:   }
1429:   
1430:   /**
1431:    * get $_SERVER[ 'REQUEST_URI' ] with no language information.
1432:    *
1433:    * @return string
1434:    */
1435:   public static function get_clean_request() {
1436:     return self::$_clean_request;
1437:   }
1438:   
1439:   /**
1440:    * @ignore
1441:    */
1442:   public static function _set( $key, $value ) {
1443:     self::$_vars[ $key ] = $value;
1444:   }
1445:   
1446:   /**
1447:    * @ignore
1448:    */
1449:   public static function _get( $key ) {
1450:     return isset( self::$_vars[ $key ] ) ? self::$_vars[ $key ] : null;
1451:   }
1452:   
1453:   /**
1454:    *@ignore
1455:    */
1456:   public static function _del( $key ) {
1457:     unset( self::$_vars[ $key ] );
1458:   }
1459: 
1460:   /**
1461:    * @ignore
1462:    */
1463:   public static function _append( $key, $value ) {
1464:     if( ! isset( self::$_vars[ $key ] ) ) {
1465:       self::$_vars[ $key ] = array();
1466:     }
1467:     
1468:     self::$_vars[ $key ][] = $value;
1469:   }
1470: }
1471: ?>
API documentation generated by ApiGen 2.8.0